mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-10 07:04:22 +00:00
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).
This commit is contained in:
parent
94b526fc86
commit
30f53583c8
2 changed files with 62 additions and 1 deletions
|
@ -369,6 +369,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(
|
||||
|
|
|
@ -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],
|
||||
|
|
Loading…
Reference in a new issue