about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs46
2 files changed, 62 insertions, 1 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index ec25c3d52bb..96d8313cc1b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -370,6 +370,23 @@ mod F {
     }
 
     #[test]
+    fn external_macro() {
+        check_diagnostics(
+            r#"
+//- /library.rs library crate:library
+#[macro_export]
+macro_rules! trigger_lint {
+    () => { let FOO: () };
+}
+//- /user.rs crate:user deps:library
+fn foo() {
+    library::trigger_lint!();
+}
+    "#,
+        );
+    }
+
+    #[test]
     fn complex_ignore() {
         check_diagnostics(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 7edc55a743f..d46d099f6fe 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -78,7 +78,7 @@ mod tests;
 
 use std::{collections::hash_map, sync::LazyLock};
 
-use hir::{diagnostics::AnyDiagnostic, HirFileId, InFile, Semantics};
+use hir::{db::ExpandDatabase, diagnostics::AnyDiagnostic, Crate, HirFileId, InFile, Semantics};
 use ide_db::{
     assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
     base_db::SourceDatabase,
@@ -501,6 +501,17 @@ pub fn semantic_diagnostics(
 
     res.retain(|d| d.severity != Severity::Allow);
 
+    res.retain_mut(|diag| {
+        if let Some(node) = diag
+            .main_node
+            .map(|ptr| ptr.map(|node| node.to_node(&ctx.sema.parse_or_expand(ptr.file_id))))
+        {
+            handle_diag_from_macros(&ctx.sema, diag, &node)
+        } else {
+            true
+        }
+    });
+
     res
 }
 
@@ -517,6 +528,35 @@ pub fn full_diagnostics(
     res
 }
 
+/// Returns whether to keep this diagnostic (or remove it).
+fn handle_diag_from_macros(
+    sema: &Semantics<'_, RootDatabase>,
+    diag: &mut Diagnostic,
+    node: &InFile<SyntaxNode>,
+) -> bool {
+    let Some(macro_file) = node.file_id.macro_file() else { return true };
+    let span_map = sema.db.expansion_span_map(macro_file);
+    let mut spans = span_map.spans_for_range(node.text_range());
+    if spans.any(|span| {
+        sema.db.lookup_intern_syntax_context(span.ctx).outer_expn.is_some_and(|expansion| {
+            let macro_call =
+                sema.db.lookup_intern_macro_call(expansion.as_macro_file().macro_call_id);
+            !Crate::from(macro_call.def.krate).origin(sema.db).is_local()
+        })
+    }) {
+        // Disable suggestions for external macros, they'll change library code and it's just bad.
+        diag.fixes = None;
+
+        // All Clippy lints report in macros, see https://github.com/rust-lang/rust-clippy/blob/903293b199364/declare_clippy_lint/src/lib.rs#L172.
+        if let DiagnosticCode::RustcLint(lint) = diag.code {
+            if !LINTS_TO_REPORT_IN_EXTERNAL_MACROS.contains(lint) {
+                return false;
+            }
+        };
+    }
+    true
+}
+
 // `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros
 
 static RUSTC_LINT_GROUPS_DICT: LazyLock<FxHashMap<&str, Vec<&str>>> =
@@ -525,6 +565,10 @@ static RUSTC_LINT_GROUPS_DICT: LazyLock<FxHashMap<&str, Vec<&str>>> =
 static CLIPPY_LINT_GROUPS_DICT: LazyLock<FxHashMap<&str, Vec<&str>>> =
     LazyLock::new(|| build_group_dict(CLIPPY_LINT_GROUPS, &["__RA_EVERY_LINT"], "clippy::"));
 
+// FIXME: Autogenerate this instead of enumerating by hand.
+static LINTS_TO_REPORT_IN_EXTERNAL_MACROS: LazyLock<FxHashSet<&str>> =
+    LazyLock::new(|| FxHashSet::from_iter([]));
+
 fn build_group_dict(
     lint_group: &'static [LintGroup],
     all_groups: &'static [&'static str],