Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #18128 - ChayimFriedman2:external-macros-lint, r=Veykril
fix: Handle errors and lints from external macros
Some lints should not be reported if they originate from an external macro, and quickfixes should be disabled (or they'll change library code).
Fixes #18122.
Closes #18124.
| -rw-r--r-- | crates/ide-diagnostics/src/handlers/incorrect_case.rs | 17 | ||||
| -rw-r--r-- | crates/ide-diagnostics/src/lib.rs | 46 |
2 files changed, 62 insertions, 1 deletions
diff --git a/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/crates/ide-diagnostics/src/handlers/incorrect_case.rs index ec25c3d52b..96d8313cc1 100644 --- a/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/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/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs index 7edc55a743..d46d099f6f 100644 --- a/crates/ide-diagnostics/src/lib.rs +++ b/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], |