@@ -78,7 +78,7 @@ mod tests;
78
78
79
79
use std:: { collections:: hash_map, sync:: LazyLock } ;
80
80
81
- use hir:: { diagnostics:: AnyDiagnostic , HirFileId , InFile , Semantics } ;
81
+ use hir:: { db :: ExpandDatabase , diagnostics:: AnyDiagnostic , Crate , HirFileId , InFile , Semantics } ;
82
82
use ide_db:: {
83
83
assists:: { Assist , AssistId , AssistKind , AssistResolveStrategy } ,
84
84
base_db:: SourceDatabase ,
@@ -501,6 +501,17 @@ pub fn semantic_diagnostics(
501
501
502
502
res. retain ( |d| d. severity != Severity :: Allow ) ;
503
503
504
+ res. retain_mut ( |diag| {
505
+ if let Some ( node) = diag
506
+ . main_node
507
+ . map ( |ptr| ptr. map ( |node| node. to_node ( & ctx. sema . parse_or_expand ( ptr. file_id ) ) ) )
508
+ {
509
+ handle_diag_from_macros ( & ctx. sema , diag, & node)
510
+ } else {
511
+ true
512
+ }
513
+ } ) ;
514
+
504
515
res
505
516
}
506
517
@@ -517,6 +528,35 @@ pub fn full_diagnostics(
517
528
res
518
529
}
519
530
531
+ /// Returns whether to keep this diagnostic (or remove it).
532
+ fn handle_diag_from_macros (
533
+ sema : & Semantics < ' _ , RootDatabase > ,
534
+ diag : & mut Diagnostic ,
535
+ node : & InFile < SyntaxNode > ,
536
+ ) -> bool {
537
+ let Some ( macro_file) = node. file_id . macro_file ( ) else { return true } ;
538
+ let span_map = sema. db . expansion_span_map ( macro_file) ;
539
+ let mut spans = span_map. spans_for_range ( node. text_range ( ) ) ;
540
+ if spans. any ( |span| {
541
+ sema. db . lookup_intern_syntax_context ( span. ctx ) . outer_expn . is_some_and ( |expansion| {
542
+ let macro_call =
543
+ sema. db . lookup_intern_macro_call ( expansion. as_macro_file ( ) . macro_call_id ) ;
544
+ !Crate :: from ( macro_call. def . krate ) . origin ( sema. db ) . is_local ( )
545
+ } )
546
+ } ) {
547
+ // Disable suggestions for external macros, they'll change library code and it's just bad.
548
+ diag. fixes = None ;
549
+
550
+ // All Clippy lints report in macros, see https://github.com/rust-lang/rust-clippy/blob/903293b199364/declare_clippy_lint/src/lib.rs#L172.
551
+ if let DiagnosticCode :: RustcLint ( lint) = diag. code {
552
+ if !LINTS_TO_REPORT_IN_EXTERNAL_MACROS . contains ( lint) {
553
+ return false ;
554
+ }
555
+ } ;
556
+ }
557
+ true
558
+ }
559
+
520
560
// `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros
521
561
522
562
static RUSTC_LINT_GROUPS_DICT : LazyLock < FxHashMap < & str , Vec < & str > > > =
@@ -525,6 +565,10 @@ static RUSTC_LINT_GROUPS_DICT: LazyLock<FxHashMap<&str, Vec<&str>>> =
525
565
static CLIPPY_LINT_GROUPS_DICT : LazyLock < FxHashMap < & str , Vec < & str > > > =
526
566
LazyLock :: new ( || build_group_dict ( CLIPPY_LINT_GROUPS , & [ "__RA_EVERY_LINT" ] , "clippy::" ) ) ;
527
567
568
+ // FIXME: Autogenerate this instead of enumerating by hand.
569
+ static LINTS_TO_REPORT_IN_EXTERNAL_MACROS : LazyLock < FxHashSet < & str > > =
570
+ LazyLock :: new ( || FxHashSet :: from_iter ( [ ] ) ) ;
571
+
528
572
fn build_group_dict (
529
573
lint_group : & ' static [ LintGroup ] ,
530
574
all_groups : & ' static [ & ' static str ] ,
0 commit comments