diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index b027100c5136..ae90c74c7e06 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -578,6 +578,8 @@ fn opt_span_lint>( } } + /// Only appropriate for use inside of the compiler + /// since the compiler doesn't track levels of tool lints fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource { self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs) } diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index c15a378053e3..372defbb4d7e 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -583,7 +583,7 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { 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(name, attr.id) { + if is_lint_level(name) { blanket_clippy_restriction_lints::check(cx, name, items); } if items.is_empty() || !attr.has_name(sym::deprecated) { diff --git a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs index 6ee3290fa761..5d095c9b27ad 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs @@ -1,10 +1,12 @@ +use crate::attrs::is_lint_level; + use super::{Attribute, UNNECESSARY_CLIPPY_CFG}; use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::SpanRangeExt; use itertools::Itertools; use rustc_ast::AttrStyle; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, Level}; +use rustc_lint::{EarlyContext}; use rustc_span::sym; pub(super) fn check( @@ -13,9 +15,10 @@ pub(super) fn check( behind_cfg_attr: &rustc_ast::MetaItem, attr: &Attribute, ) { + // FIXME use proper attr parsing here if cfg_attr.has_name(sym::clippy) && let Some(ident) = behind_cfg_attr.ident() - && Level::from_symbol(ident.name, || Some(attr.id)).is_some() + && is_lint_level(ident.name) && let Some(items) = behind_cfg_attr.meta_item_list() { let nb_items = items.len(); diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index 9a1e315ae530..2d56086a9602 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -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.name().is_some_and(|name| is_lint_level(name, attr.id)) + && attr.name().is_some_and(is_lint_level) { for lint in lint_list { match item.kind { diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs index 7b66f91f6c07..512f961228b1 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs @@ -1,5 +1,5 @@ use clippy_utils::macros::{is_panic, macro_backtrace}; -use rustc_ast::{AttrId, MetaItemInner}; +use rustc_ast::{MetaItemInner}; use rustc_hir::{ Block, Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, StmtKind, TraitFn, TraitItem, TraitItemKind, }; @@ -16,8 +16,8 @@ pub(super) fn is_word(nmi: &MetaItemInner, expected: Symbol) -> bool { } } -pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool { - Level::from_symbol(symbol, || Some(attr_id)).is_some() +pub(super) fn is_lint_level(symbol: Symbol) -> bool { + Level::from_symbol(symbol).is_some() } pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index 3850c55c49f8..7f5bc520dc4d 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -3,11 +3,12 @@ use clippy_utils::msrvs::Msrv; use clippy_utils::source::{HasSession, IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability}; use clippy_utils::{can_use_if_let_chains, span_contains_non_whitespace, sym, tokenize_with_text}; -use rustc_ast::{BinOpKind, MetaItemInner}; +use rustc_ast::BinOpKind; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, StmtKind}; +use rustc_hir::attrs::{AttributeKind, LintAttributeKind}; +use rustc_hir::{Attribute, Block, Expr, ExprKind, StmtKind}; use rustc_lexer::TokenKind; -use rustc_lint::{LateContext, LateLintPass, Level}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Span, Symbol}; @@ -237,19 +238,26 @@ fn check_significant_tokens_and_expect_attrs( !span_contains_non_whitespace(cx, span, self.lint_commented_code) }, - [attr] - if matches!(Level::from_attr(attr), Some((Level::Expect, _))) - && let Some(metas) = attr.meta_item_list() - && let Some(MetaItemInner::MetaItem(meta_item)) = metas.first() - && let [tool, lint_name] = meta_item.path.segments.as_slice() - && tool.ident.name == sym::clippy - && [expected_lint_name, sym::style, sym::all].contains(&lint_name.ident.name) => - { - // There is an `expect` attribute -- check that there is no _other_ significant text - let span_before_attr = inner_if.span.split_at(1).1.until(attr.span()); - let span_after_attr = attr.span().between(inner_if_expr.span); - !span_contains_non_whitespace(cx, span_before_attr, self.lint_commented_code) - && !span_contains_non_whitespace(cx, span_after_attr, self.lint_commented_code) + [ + Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs)), + ] => { + sub_attrs + .into_iter() + .filter(|attr|attr.kind == LintAttributeKind::Expect) + .flat_map(|attr| attr.lint_instances.iter().map(|group| (attr.attr_span, group))) + .filter(|(_, lint_id)| { + lint_id.tool_is_named(sym::clippy) + && (expected_lint_name == lint_id.lint_name() + || [expected_lint_name, sym::style, sym::all] + .contains(&lint_id.original_name_without_tool())) + }) + .any(|(attr_span, _)| { + // There is an `expect` attribute -- check that there is no _other_ significant text + let span_before_attr = inner_if.span.split_at(1).1.until(attr_span); + let span_after_attr = attr_span.between(inner_if_expr.span); + !span_contains_non_whitespace(cx, span_before_attr, self.lint_commented_code) + && !span_contains_non_whitespace(cx, span_after_attr, self.lint_commented_code) + }) }, // There are other attributes, which are significant tokens -- check failed diff --git a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs index 04e4f379e37c..aab6adf5d19a 100644 --- a/src/tools/clippy/clippy_lints/src/returns/needless_return.rs +++ b/src/tools/clippy/clippy_lints/src/returns/needless_return.rs @@ -4,11 +4,11 @@ binary_expr_needs_parentheses, is_from_proc_macro, leaks_droppable_temporary_with_limited_lifetime, span_contains_cfg, span_find_starting_semi, sym, }; -use rustc_ast::MetaItemInner; use rustc_errors::Applicability; +use rustc_hir::attrs::{AttributeKind, LintAttributeKind}; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, Expr, ExprKind, HirId, LangItem, MatchSource, StmtKind}; -use rustc_lint::{LateContext, Level, LintContext}; +use rustc_hir::{Attribute, Body, Expr, ExprKind, HirId, LangItem, MatchSource, StmtKind}; +use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty::{self, Ty}; use rustc_span::{BytePos, Pos, Span}; use std::borrow::Cow; @@ -180,20 +180,18 @@ fn check_final_expr<'tcx>( // actually fulfill the expectation (clippy::#12998) match cx.tcx.hir_attrs(expr.hir_id) { [] => {}, - [attr] => { - if matches!(Level::from_attr(attr), Some((Level::Expect, _))) - && let metas = attr.meta_item_list() - && let Some(lst) = metas - && let [MetaItemInner::MetaItem(meta_item), ..] = lst.as_slice() - && let [tool, lint_name] = meta_item.path.segments.as_slice() - && tool.ident.name == sym::clippy - && matches!( - lint_name.ident.name, - sym::needless_return | sym::style | sym::all | sym::warnings - ) + [Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs))] => { + if !sub_attrs + .into_iter() + .filter(|attr| attr.kind == LintAttributeKind::Expect) + .flat_map(|attr| &attr.lint_instances) + .any(|lint| { + matches!( + lint.original_name_without_tool(), + sym::needless_return | sym::style | sym::all | sym::warnings + ) + }) { - // This is an expectation of the `needless_return` lint - } else { return; } },