commit
3b282feee6
26 changed files with 141 additions and 111 deletions
|
|
@ -1,6 +1,7 @@
|
|||
use super::ALLOW_ATTRIBUTES;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use rustc_ast::attr::AttributeExt;
|
||||
use rustc_ast::{AttrStyle, Attribute};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, LintContext};
|
||||
|
|
@ -9,17 +10,12 @@ use rustc_lint::{EarlyContext, LintContext};
|
|||
pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) {
|
||||
if !attr.span.in_external_macro(cx.sess().source_map())
|
||||
&& let AttrStyle::Outer = attr.style
|
||||
&& let Some(ident) = attr.ident()
|
||||
&& let Some(path_span) = attr.path_span()
|
||||
&& !is_from_proc_macro(cx, attr)
|
||||
{
|
||||
#[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
|
||||
span_lint_and_then(cx, ALLOW_ATTRIBUTES, ident.span, "#[allow] attribute found", |diag| {
|
||||
diag.span_suggestion(
|
||||
ident.span,
|
||||
"replace it with",
|
||||
"expect",
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
span_lint_and_then(cx, ALLOW_ATTRIBUTES, path_span, "#[allow] attribute found", |diag| {
|
||||
diag.span_suggestion(path_span, "replace it with", "expect", Applicability::MachineApplicable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ mod utils;
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::msrvs::{self, Msrv, MsrvStack};
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind};
|
||||
use rustc_ast::{self as ast, AttrArgs, AttrItemKind, AttrKind, Attribute, MetaItemInner, MetaItemKind};
|
||||
use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
|
@ -574,16 +574,16 @@ impl EarlyLintPass for PostExpansionEarlyAttributes {
|
|||
|
||||
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
|
||||
if let Some(items) = &attr.meta_item_list()
|
||||
&& let Some(ident) = attr.ident()
|
||||
&& let Some(name) = attr.name()
|
||||
{
|
||||
if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
|
||||
if matches!(name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
|
||||
allow_attributes::check(cx, attr);
|
||||
}
|
||||
if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
|
||||
allow_attributes_without_reason::check(cx, ident.name, items, attr);
|
||||
if matches!(name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
|
||||
allow_attributes_without_reason::check(cx, name, items, attr);
|
||||
}
|
||||
if is_lint_level(ident.name, attr.id) {
|
||||
blanket_clippy_restriction_lints::check(cx, ident.name, items);
|
||||
if is_lint_level(name, attr.id) {
|
||||
blanket_clippy_restriction_lints::check(cx, name, items);
|
||||
}
|
||||
if items.is_empty() || !attr.has_name(sym::deprecated) {
|
||||
return;
|
||||
|
|
@ -604,7 +604,9 @@ impl EarlyLintPass for PostExpansionEarlyAttributes {
|
|||
|
||||
if attr.has_name(sym::ignore)
|
||||
&& match &attr.kind {
|
||||
AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrArgs::Eq { .. }),
|
||||
AttrKind::Normal(normal_attr) => {
|
||||
!matches!(normal_attr.item.args, AttrItemKind::Unparsed(AttrArgs::Eq { .. }))
|
||||
},
|
||||
AttrKind::DocComment(..) => true,
|
||||
}
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,19 +2,19 @@ use super::{Attribute, SHOULD_PANIC_WITHOUT_EXPECT};
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use rustc_ast::token::{Token, TokenKind};
|
||||
use rustc_ast::tokenstream::TokenTree;
|
||||
use rustc_ast::{AttrArgs, AttrKind};
|
||||
use rustc_ast::{AttrArgs, AttrItemKind, AttrKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::EarlyContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) {
|
||||
if let AttrKind::Normal(normal_attr) = &attr.kind {
|
||||
if let AttrArgs::Eq { .. } = &normal_attr.item.args {
|
||||
if let AttrItemKind::Unparsed(AttrArgs::Eq { .. }) = &normal_attr.item.args {
|
||||
// `#[should_panic = ".."]` found, good
|
||||
return;
|
||||
}
|
||||
|
||||
if let AttrArgs::Delimited(args) = &normal_attr.item.args
|
||||
if let AttrItemKind::Unparsed(AttrArgs::Delimited(args)) = &normal_attr.item.args
|
||||
&& let mut tt_iter = args.tokens.iter()
|
||||
&& let Some(TokenTree::Token(
|
||||
Token {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
|
|||
return;
|
||||
}
|
||||
if let Some(lint_list) = &attr.meta_item_list()
|
||||
&& attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id))
|
||||
&& attr.name().is_some_and(|name| is_lint_level(name, attr.id))
|
||||
{
|
||||
for lint in lint_list {
|
||||
match item.kind {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use rustc_ast::MetaItemInner;
|
||||
use rustc_ast::attr::data_structures::CfgEntry;
|
||||
use rustc_ast::{AttrItemKind, EarlyParsedAttribute};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -32,29 +34,32 @@ declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]);
|
|||
|
||||
impl EarlyLintPass for CfgNotTest {
|
||||
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) {
|
||||
if attr.has_name(rustc_span::sym::cfg_trace) && contains_not_test(attr.meta_item_list().as_deref(), false) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
CFG_NOT_TEST,
|
||||
attr.span,
|
||||
"code is excluded from test builds",
|
||||
|diag| {
|
||||
diag.help("consider not excluding any code from test builds");
|
||||
diag.note_once("this could increase code coverage despite not actually being tested");
|
||||
},
|
||||
);
|
||||
if attr.has_name(sym::cfg_trace) {
|
||||
let AttrItemKind::Parsed(EarlyParsedAttribute::CfgTrace(cfg)) = &attr.get_normal_item().args else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
if contains_not_test(cfg, false) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
CFG_NOT_TEST,
|
||||
attr.span,
|
||||
"code is excluded from test builds",
|
||||
|diag| {
|
||||
diag.help("consider not excluding any code from test builds");
|
||||
diag.note_once("this could increase code coverage despite not actually being tested");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_not_test(list: Option<&[MetaItemInner]>, not: bool) -> bool {
|
||||
list.is_some_and(|list| {
|
||||
list.iter().any(|item| {
|
||||
item.ident().is_some_and(|ident| match ident.name {
|
||||
rustc_span::sym::not => contains_not_test(item.meta_item_list(), !not),
|
||||
rustc_span::sym::test => not,
|
||||
_ => contains_not_test(item.meta_item_list(), not),
|
||||
})
|
||||
})
|
||||
})
|
||||
fn contains_not_test(cfg: &CfgEntry, not: bool) -> bool {
|
||||
match cfg {
|
||||
CfgEntry::All(subs, _) | CfgEntry::Any(subs, _) => subs.iter().any(|item| contains_not_test(item, not)),
|
||||
CfgEntry::Not(sub, _) => contains_not_test(sub, !not),
|
||||
CfgEntry::NameValue { name: sym::test, .. } => not,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute};
|
||||
use rustc_ast::{AttrArgs, AttrItemKind, AttrKind, AttrStyle, Attribute};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::EarlyContext;
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
|
|||
if !attr.span.from_expansion()
|
||||
&& let AttrKind::Normal(ref item) = attr.kind
|
||||
&& attr.doc_str().is_some()
|
||||
&& let AttrArgs::Eq { expr: meta, .. } = &item.item.args
|
||||
&& let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args
|
||||
&& !attr.span.contains(meta.span)
|
||||
// Since the `include_str` is already expanded at this point, we can only take the
|
||||
// whole attribute snippet and then modify for our suggestion.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ use clippy_utils::diagnostics::span_lint_and_then;
|
|||
use clippy_utils::msrvs::Msrv;
|
||||
use clippy_utils::{is_in_const_context, is_in_test, sym};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, HirId, RustcVersion, StabilityLevel, StableSince};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::{self as hir, AmbigArg, Expr, ExprKind, HirId, RustcVersion, StabilityLevel, StableSince, find_attr};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
|
@ -268,11 +269,9 @@ impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv {
|
|||
/// attribute.
|
||||
fn is_under_cfg_attribute(cx: &LateContext<'_>, hir_id: HirId) -> bool {
|
||||
cx.tcx.hir_parent_id_iter(hir_id).any(|id| {
|
||||
cx.tcx.hir_attrs(id).iter().any(|attr| {
|
||||
matches!(
|
||||
attr.ident().map(|ident| ident.name),
|
||||
Some(sym::cfg_trace | sym::cfg_attr_trace)
|
||||
)
|
||||
})
|
||||
find_attr!(
|
||||
cx.tcx.hir_attrs(id),
|
||||
AttributeKind::CfgTrace(..) | AttributeKind::CfgAttrTrace
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use clippy_config::Conf;
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::root_macro_call_first_node;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use rustc_ast::{AttrArgs, AttrKind, Attribute, LitKind};
|
||||
use rustc_ast::{AttrArgs, AttrItemKind, AttrKind, Attribute, LitKind};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
|
@ -92,7 +92,7 @@ impl EarlyLintPass for LargeIncludeFile {
|
|||
&& let AttrKind::Normal(ref item) = attr.kind
|
||||
&& let Some(doc) = attr.doc_str()
|
||||
&& doc.as_str().len() as u64 > self.max_file_size
|
||||
&& let AttrArgs::Eq { expr: meta, .. } = &item.item.args
|
||||
&& let AttrItemKind::Unparsed(AttrArgs::Eq { expr: meta, .. }) = &item.item.args
|
||||
&& !attr.span.contains(meta.span)
|
||||
// Since the `include_str` is already expanded at this point, we can only take the
|
||||
// whole attribute snippet and then modify for our suggestion.
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ use clippy_utils::diagnostics::span_lint;
|
|||
use clippy_utils::macros::{is_assert_macro, root_macro_call};
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context};
|
||||
use rustc_hir::{Expr, HirId};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::{Expr, HirId, find_attr};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::CONST_IS_EMPTY;
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_
|
|||
fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool {
|
||||
cx.tcx
|
||||
.hir_parent_id_iter(id)
|
||||
.any(|id| cx.tcx.hir_attrs(id).iter().any(|attr| attr.has_name(sym::cfg_trace)))
|
||||
.any(|id| find_attr!(cx.tcx.hir_attrs(id), AttributeKind::CfgTrace(..)))
|
||||
}
|
||||
|
||||
/// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization
|
||||
|
|
|
|||
|
|
@ -287,8 +287,8 @@ fn is_doc_attr(attr: &Attribute) -> bool {
|
|||
match attr {
|
||||
Attribute::Parsed(AttributeKind::DocComment { .. }) => true,
|
||||
Attribute::Unparsed(attr)
|
||||
if let [ident] = &*attr.path.segments
|
||||
&& ident.name == sym::doc =>
|
||||
if let [name] = &*attr.path.segments
|
||||
&& *name == sym::doc =>
|
||||
{
|
||||
matches!(attr.args, AttrArgs::Eq { .. })
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicabi
|
|||
use clippy_utils::sugg::DiagExt;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::HirIdSet;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::{Attribute, HirIdSet};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::ty::AssocKind;
|
||||
use rustc_session::impl_lint_pass;
|
||||
|
|
@ -122,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
|
|||
let attrs_sugg = {
|
||||
let mut sugg = String::new();
|
||||
for attr in cx.tcx.hir_attrs(assoc_item_hir_id) {
|
||||
if !attr.has_name(sym::cfg_trace) {
|
||||
let Attribute::Parsed(AttributeKind::CfgTrace(attrs)) = attr else {
|
||||
// This might be some other attribute that the `impl Default` ought to inherit.
|
||||
// But it could also be one of the many attributes that:
|
||||
// - can't be put on an impl block -- like `#[inline]`
|
||||
|
|
@ -132,10 +133,12 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
|
|||
// reduce the applicability
|
||||
app = Applicability::MaybeIncorrect;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
sugg.push_str(&snippet_with_applicability(cx.sess(), attr.span(), "_", &mut app));
|
||||
sugg.push('\n');
|
||||
for (_, attr_span) in attrs {
|
||||
sugg.push_str(&snippet_with_applicability(cx.sess(), *attr_span, "_", &mut app));
|
||||
sugg.push('\n');
|
||||
}
|
||||
}
|
||||
sugg
|
||||
};
|
||||
|
|
|
|||
|
|
@ -320,6 +320,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
self.body(field!(anon_const.body));
|
||||
},
|
||||
ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"),
|
||||
ConstArgKind::TupleCall(..) => chain!(self, "let ConstArgKind::TupleCall(..) = {const_arg}.kind"),
|
||||
ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"),
|
||||
ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"),
|
||||
}
|
||||
|
|
@ -724,7 +725,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
kind!("Lit {{ ref {lit}, {negated} }}");
|
||||
self.lit(lit);
|
||||
},
|
||||
PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"),
|
||||
PatExprKind::Path(_) => self.maybe_path(pat),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,8 +250,8 @@ pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<
|
|||
if let hir::Attribute::Unparsed(attr_kind) = &attr
|
||||
// Identify attribute
|
||||
&& let [tool_name, attr_name] = &attr_kind.path.segments[..]
|
||||
&& tool_name.name == sym::clippy
|
||||
&& attr_name.name == sym::version
|
||||
&& tool_name == &sym::clippy
|
||||
&& attr_name == &sym::version
|
||||
&& let Some(version) = attr.value_str()
|
||||
{
|
||||
Some(version)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
|
|||
|
||||
<!-- begin autogenerated nightly -->
|
||||
```
|
||||
nightly-2025-12-25
|
||||
nightly-2026-01-08
|
||||
```
|
||||
<!-- end autogenerated nightly -->
|
||||
|
||||
|
|
|
|||
|
|
@ -976,11 +976,21 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool {
|
|||
l.style == r.style
|
||||
&& match (&l.kind, &r.kind) {
|
||||
(DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2,
|
||||
(Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_attr_args(&l.item.args, &r.item.args),
|
||||
(Normal(l), Normal(r)) => {
|
||||
eq_path(&l.item.path, &r.item.path) && eq_attr_item_kind(&l.item.args, &r.item.args)
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq_attr_item_kind(l: &AttrItemKind, r: &AttrItemKind) -> bool {
|
||||
match (l, r) {
|
||||
(AttrItemKind::Unparsed(l), AttrItemKind::Unparsed(r)) => eq_attr_args(l, r),
|
||||
(AttrItemKind::Parsed(_l), AttrItemKind::Parsed(_r)) => todo!(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool {
|
||||
use AttrArgs::*;
|
||||
match (l, r) {
|
||||
|
|
|
|||
|
|
@ -20,10 +20,13 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>(
|
|||
name: Symbol,
|
||||
) -> impl Iterator<Item = &'a A> {
|
||||
attrs.iter().filter(move |attr| {
|
||||
if let Some([clippy, segment2]) = attr.ident_path().as_deref()
|
||||
&& clippy.name == sym::clippy
|
||||
if let [clippy, segment2] = &*attr.path()
|
||||
&& *clippy == sym::clippy
|
||||
{
|
||||
let new_name = match segment2.name {
|
||||
let path_span = attr
|
||||
.path_span()
|
||||
.expect("Clippy attributes are unparsed and have a span");
|
||||
let new_name = match *segment2 {
|
||||
sym::cyclomatic_complexity => Some("cognitive_complexity"),
|
||||
sym::author
|
||||
| sym::version
|
||||
|
|
@ -35,7 +38,7 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>(
|
|||
| sym::has_significant_drop
|
||||
| sym::format_args => None,
|
||||
_ => {
|
||||
sess.dcx().span_err(segment2.span, "usage of unknown attribute");
|
||||
sess.dcx().span_err(path_span, "usage of unknown attribute");
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
|
@ -43,17 +46,17 @@ pub fn get_builtin_attr<'a, A: AttributeExt + 'a>(
|
|||
match new_name {
|
||||
Some(new_name) => {
|
||||
sess.dcx()
|
||||
.struct_span_err(segment2.span, "usage of deprecated attribute")
|
||||
.struct_span_err(path_span, "usage of deprecated attribute")
|
||||
.with_span_suggestion(
|
||||
segment2.span,
|
||||
path_span,
|
||||
"consider using",
|
||||
new_name,
|
||||
format!("clippy::{new_name}"),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
false
|
||||
},
|
||||
None => segment2.name == name,
|
||||
None => *segment2 == name,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
|
|
|
|||
|
|
@ -348,9 +348,9 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI
|
|||
fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) {
|
||||
match attr.kind {
|
||||
AttrKind::Normal(..) => {
|
||||
if let Some(ident) = attr.ident() {
|
||||
if let Some(name) = attr.name() {
|
||||
// NOTE: This will likely have false positives, like `allow = 1`
|
||||
let ident_string = ident.to_string();
|
||||
let ident_string = name.to_string();
|
||||
if attr.style == AttrStyle::Outer {
|
||||
(
|
||||
Pat::OwnedMultiStr(vec!["#[".to_owned() + &ident_string, ident_string]),
|
||||
|
|
|
|||
|
|
@ -578,7 +578,6 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
|
|||
Some(val)
|
||||
}
|
||||
},
|
||||
PatExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir_body(*body).value),
|
||||
PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id),
|
||||
}
|
||||
}
|
||||
|
|
@ -1141,9 +1140,11 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx
|
|||
ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value),
|
||||
ConstItemRhs::TypeConst(const_arg) => match const_arg.kind {
|
||||
ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value),
|
||||
ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => {
|
||||
None
|
||||
},
|
||||
ConstArgKind::Struct(..)
|
||||
| ConstArgKind::TupleCall(..)
|
||||
| ConstArgKind::Path(_)
|
||||
| ConstArgKind::Error(..)
|
||||
| ConstArgKind::Infer(..) => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -672,10 +672,18 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
.zip(*inits_b)
|
||||
.all(|(init_a, init_b)| self.eq_const_arg(init_a.expr, init_b.expr))
|
||||
},
|
||||
(ConstArgKind::TupleCall(path_a, args_a), ConstArgKind::TupleCall(path_b, args_b)) => {
|
||||
self.eq_qpath(path_a, path_b)
|
||||
&& args_a
|
||||
.iter()
|
||||
.zip(*args_b)
|
||||
.all(|(arg_a, arg_b)| self.eq_const_arg(arg_a, arg_b))
|
||||
},
|
||||
// Use explicit match for now since ConstArg is undergoing flux.
|
||||
(
|
||||
ConstArgKind::Path(..)
|
||||
| ConstArgKind::Anon(..)
|
||||
| ConstArgKind::TupleCall(..)
|
||||
| ConstArgKind::Infer(..)
|
||||
| ConstArgKind::Struct(..)
|
||||
| ConstArgKind::Error(..),
|
||||
|
|
@ -705,9 +713,8 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
negated: right_neg,
|
||||
},
|
||||
) => left_neg == right_neg && left.node == right.node,
|
||||
(PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body),
|
||||
(PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right),
|
||||
(PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false,
|
||||
(PatExprKind::Lit { .. } | PatExprKind::Path(..), _) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1312,7 +1319,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
lit.node.hash(&mut self.s);
|
||||
negated.hash(&mut self.s);
|
||||
},
|
||||
PatExprKind::ConstBlock(c) => self.hash_body(c.body),
|
||||
PatExprKind::Path(qpath) => self.hash_qpath(qpath),
|
||||
}
|
||||
}
|
||||
|
|
@ -1548,6 +1554,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
self.hash_const_arg(init.expr);
|
||||
}
|
||||
},
|
||||
ConstArgKind::TupleCall(path, args) => {
|
||||
self.hash_qpath(path);
|
||||
for arg in *args {
|
||||
self.hash_const_arg(arg);
|
||||
}
|
||||
},
|
||||
ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ use rustc_data_structures::indexmap;
|
|||
use rustc_data_structures::packed::Pu128;
|
||||
use rustc_data_structures::unhash::UnindexMap;
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::attrs::{AttributeKind, CfgEntry};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::definitions::{DefPath, DefPathData};
|
||||
|
|
@ -2412,17 +2412,15 @@ pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool {
|
|||
/// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent
|
||||
/// use [`is_in_cfg_test`]
|
||||
pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool {
|
||||
tcx.hir_attrs(id).iter().any(|attr| {
|
||||
if attr.has_name(sym::cfg_trace)
|
||||
&& let Some(items) = attr.meta_item_list()
|
||||
&& let [item] = &*items
|
||||
&& item.has_name(sym::test)
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
if let Some(cfgs) = find_attr!(tcx.hir_attrs(id), AttributeKind::CfgTrace(cfgs) => cfgs)
|
||||
&& cfgs
|
||||
.iter()
|
||||
.any(|(cfg, _)| matches!(cfg, CfgEntry::NameValue { name: sym::test, .. }))
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied
|
||||
|
|
@ -2437,11 +2435,12 @@ pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
|
|||
|
||||
/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
|
||||
pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||
tcx.has_attr(def_id, sym::cfg_trace)
|
||||
|| tcx
|
||||
.hir_parent_iter(tcx.local_def_id_to_hir_id(def_id))
|
||||
.flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id))
|
||||
.any(|attr| attr.has_name(sym::cfg_trace))
|
||||
find_attr!(tcx.get_all_attrs(def_id), AttributeKind::CfgTrace(..))
|
||||
|| find_attr!(
|
||||
tcx.hir_parent_iter(tcx.local_def_id_to_hir_id(def_id))
|
||||
.flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)),
|
||||
AttributeKind::CfgTrace(..)
|
||||
)
|
||||
}
|
||||
|
||||
/// Walks up the HIR tree from the given expression in an attempt to find where the value is
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ impl<'tcx> MaybeQPath<'tcx> for &'tcx PatExpr<'_> {
|
|||
fn opt_qpath(self) -> Option<QPathId<'tcx>> {
|
||||
match &self.kind {
|
||||
PatExprKind::Path(qpath) => Some((qpath, self.hir_id)),
|
||||
_ => None,
|
||||
PatExprKind::Lit { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -419,7 +419,7 @@ impl<'a> MaybeResPath<'a> for &PatExpr<'a> {
|
|||
fn opt_res_path(self) -> OptResPath<'a> {
|
||||
match &self.kind {
|
||||
PatExprKind::Path(qpath) => qpath.opt_res_path(),
|
||||
_ => (None, None),
|
||||
PatExprKind::Lit { .. } => (None, None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[toolchain]
|
||||
# begin autogenerated nightly
|
||||
channel = "nightly-2025-12-25"
|
||||
channel = "nightly-2026-01-08"
|
||||
# end autogenerated nightly
|
||||
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||
profile = "minimal"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error: usage of deprecated attribute
|
||||
--> tests/ui/renamed_builtin_attr.rs:3:11
|
||||
--> tests/ui/renamed_builtin_attr.rs:3:3
|
||||
|
|
||||
LL | #[clippy::cyclomatic_complexity = "1"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `cognitive_complexity`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `clippy::cognitive_complexity`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![deny(clippy::trait_duplication_in_bounds)]
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![feature(min_generic_const_args)]
|
||||
|
||||
trait AssocConstTrait {
|
||||
#[type_const]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![deny(clippy::trait_duplication_in_bounds)]
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(associated_const_equality, min_generic_const_args)]
|
||||
#![feature(min_generic_const_args)]
|
||||
|
||||
trait AssocConstTrait {
|
||||
#[type_const]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error: usage of unknown attribute
|
||||
--> tests/ui/unknown_attribute.rs:3:11
|
||||
--> tests/ui/unknown_attribute.rs:3:3
|
||||
|
|
||||
LL | #[clippy::unknown]
|
||||
| ^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue