about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2024-12-17 21:37:10 +0000
committerGitHub <noreply@github.com>2024-12-17 21:37:10 +0000
commitf8da18cdef55fb9262f8ac2b530b565ebf4126a7 (patch)
tree59d2ab1f3efbc7481d17697b62a860627c76bdbb
parent0f9cc8d58b82ff6d6b9380a10a8cbed22734eac0 (diff)
parent092bfefa49ca113e5e82d33879593fde8fa91830 (diff)
downloadrust-f8da18cdef55fb9262f8ac2b530b565ebf4126a7.tar.gz
rust-f8da18cdef55fb9262f8ac2b530b565ebf4126a7.zip
Do not mark attributes with unknown namespace as useless (#13766)
Fixes #13764

changelog: [`useless_attribute`]: do not trigger on attributes with
unknown namespace
-rw-r--r--clippy_lints/src/attrs/useless_attribute.rs22
-rw-r--r--clippy_lints/src/attrs/utils.rs21
-rw-r--r--tests/ui/useless_attribute.fixed9
-rw-r--r--tests/ui/useless_attribute.rs9
4 files changed, 43 insertions, 18 deletions
diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs
index e21853598c3..e7158a6a6b6 100644
--- a/clippy_lints/src/attrs/useless_attribute.rs
+++ b/clippy_lints/src/attrs/useless_attribute.rs
@@ -1,8 +1,8 @@
 use super::USELESS_ATTRIBUTE;
-use super::utils::{extract_clippy_lint, is_lint_level, is_word};
+use super::utils::{is_lint_level, is_word, namespace_and_lint};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{SpanRangeExt, first_line_of_span};
-use rustc_ast::{Attribute, Item, ItemKind, MetaItemInner};
+use rustc_ast::{Attribute, Item, ItemKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -20,11 +20,13 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
                 for lint in lint_list {
                     match item.kind {
                         ItemKind::Use(..) => {
-                            if let MetaItemInner::MetaItem(meta_item) = lint
-                                && meta_item.is_word()
-                                && let Some(ident) = meta_item.ident()
+                            let (namespace @ (Some(sym::clippy) | None), Some(name)) = namespace_and_lint(lint) else {
+                                return;
+                            };
+
+                            if namespace.is_none()
                                 && matches!(
-                                    ident.name.as_str(),
+                                    name.as_str(),
                                     "ambiguous_glob_reexports"
                                         | "dead_code"
                                         | "deprecated"
@@ -39,9 +41,9 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
                                 return;
                             }
 
-                            if extract_clippy_lint(lint).is_some_and(|symbol| {
-                                matches!(
-                                    symbol.as_str(),
+                            if namespace == Some(sym::clippy)
+                                && matches!(
+                                    name.as_str(),
                                     "wildcard_imports"
                                         | "enum_glob_use"
                                         | "redundant_pub_crate"
@@ -52,7 +54,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
                                         | "disallowed_types"
                                         | "unused_trait_names"
                                 )
-                            }) {
+                            {
                                 return;
                             }
                         },
diff --git a/clippy_lints/src/attrs/utils.rs b/clippy_lints/src/attrs/utils.rs
index 3bb02688bf2..96de0642904 100644
--- a/clippy_lints/src/attrs/utils.rs
+++ b/clippy_lints/src/attrs/utils.rs
@@ -75,13 +75,18 @@ fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>
 
 /// Returns the lint name if it is clippy lint.
 pub(super) fn extract_clippy_lint(lint: &MetaItemInner) -> Option<Symbol> {
-    if let Some(meta_item) = lint.meta_item()
-        && meta_item.path.segments.len() > 1
-        && let tool_name = meta_item.path.segments[0].ident
-        && tool_name.name == sym::clippy
-    {
-        let lint_name = meta_item.path.segments.last().unwrap().ident.name;
-        return Some(lint_name);
+    match namespace_and_lint(lint) {
+        (Some(sym::clippy), name) => name,
+        _ => None,
+    }
+}
+
+/// Returns the lint namespace, if any, as well as the lint name. (`None`, `None`) means
+/// the lint had less than 1 or more than 2 segments.
+pub(super) fn namespace_and_lint(lint: &MetaItemInner) -> (Option<Symbol>, Option<Symbol>) {
+    match lint.meta_item().map(|m| m.path.segments.as_slice()).unwrap_or_default() {
+        [name] => (None, Some(name.ident.name)),
+        [namespace, name] => (Some(namespace.ident.name), Some(name.ident.name)),
+        _ => (None, None),
     }
-    None
 }
diff --git a/tests/ui/useless_attribute.fixed b/tests/ui/useless_attribute.fixed
index 231fc0a892a..de1062f123b 100644
--- a/tests/ui/useless_attribute.fixed
+++ b/tests/ui/useless_attribute.fixed
@@ -134,3 +134,12 @@ pub mod ambiguous_glob_exports {
     pub use my_prelude::*;
     pub use my_type::*;
 }
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/13764
+pub mod unknown_namespace {
+    pub mod some_module {
+        pub struct SomeType;
+    }
+    #[allow(rustc::non_glob_import_of_type_ir_inherent)]
+    use some_module::SomeType;
+}
diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs
index 8dfcd2110a4..94657dd1ca3 100644
--- a/tests/ui/useless_attribute.rs
+++ b/tests/ui/useless_attribute.rs
@@ -134,3 +134,12 @@ pub mod ambiguous_glob_exports {
     pub use my_prelude::*;
     pub use my_type::*;
 }
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/13764
+pub mod unknown_namespace {
+    pub mod some_module {
+        pub struct SomeType;
+    }
+    #[allow(rustc::non_glob_import_of_type_ir_inherent)]
+    use some_module::SomeType;
+}