@@ -83,12 +83,11 @@ mod handlers {
83
83
#[ cfg( test) ]
84
84
mod tests;
85
85
86
- use std:: { collections :: hash_map , iter, sync:: LazyLock } ;
86
+ use std:: { iter, sync:: LazyLock } ;
87
87
88
88
use either:: Either ;
89
89
use hir:: {
90
- Crate , DisplayTarget , HirFileId , InFile , Semantics , db:: ExpandDatabase ,
91
- diagnostics:: AnyDiagnostic ,
90
+ Crate , DisplayTarget , InFile , Semantics , db:: ExpandDatabase , diagnostics:: AnyDiagnostic ,
92
91
} ;
93
92
use ide_db:: {
94
93
EditionedFileId , FileId , FileRange , FxHashMap , FxHashSet , RootDatabase , Severity , SnippetCap ,
@@ -513,13 +512,7 @@ pub fn semantic_diagnostics(
513
512
514
513
// The edition isn't accurate (each diagnostics may have its own edition due to macros),
515
514
// but it's okay as it's only being used for error recovery.
516
- handle_lints (
517
- & ctx. sema ,
518
- & mut FxHashMap :: default ( ) ,
519
- & mut lints,
520
- & mut Vec :: new ( ) ,
521
- editioned_file_id. edition ( db) ,
522
- ) ;
515
+ handle_lints ( & ctx. sema , & mut lints, editioned_file_id. edition ( db) ) ;
523
516
524
517
res. retain ( |d| d. severity != Severity :: Allow ) ;
525
518
@@ -584,8 +577,6 @@ fn handle_diag_from_macros(
584
577
true
585
578
}
586
579
587
- // `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros
588
-
589
580
struct BuiltLint {
590
581
lint : & ' static Lint ,
591
582
groups : Vec < & ' static str > ,
@@ -629,9 +620,7 @@ fn build_lints_map(
629
620
630
621
fn handle_lints (
631
622
sema : & Semantics < ' _ , RootDatabase > ,
632
- cache : & mut FxHashMap < HirFileId , FxHashMap < SmolStr , SeverityAttr > > ,
633
623
diagnostics : & mut [ ( InFile < SyntaxNode > , & mut Diagnostic ) ] ,
634
- cache_stack : & mut Vec < HirFileId > ,
635
624
edition : Edition ,
636
625
) {
637
626
for ( node, diag) in diagnostics {
@@ -645,7 +634,8 @@ fn handle_lints(
645
634
diag. severity = default_severity;
646
635
}
647
636
648
- let mut diag_severity = fill_lint_attrs ( sema, node, cache, cache_stack, diag, edition) ;
637
+ let mut diag_severity =
638
+ lint_severity_at ( sema, node, & lint_groups ( & diag. code , edition) , edition) ;
649
639
650
640
if let outline_diag_severity @ Some ( _) =
651
641
find_outline_mod_lint_severity ( sema, node, diag, edition)
@@ -698,155 +688,22 @@ fn find_outline_mod_lint_severity(
698
688
result
699
689
}
700
690
701
- #[ derive( Debug , Clone , Copy ) ]
702
- struct SeverityAttr {
703
- severity : Severity ,
704
- /// This field counts how far we are from the main node. Bigger values mean more far.
705
- ///
706
- /// Note this isn't accurate: there can be gaps between values (created when merging severity maps).
707
- /// The important thing is that if an attr is closer to the main node, it will have smaller value.
708
- ///
709
- /// This is necessary even though we take care to never overwrite a value from deeper nesting
710
- /// because of lint groups. For example, in the following code:
711
- /// ```
712
- /// #[warn(non_snake_case)]
713
- /// mod foo {
714
- /// #[allow(nonstandard_style)]
715
- /// mod bar {}
716
- /// }
717
- /// ```
718
- /// We want to not warn on non snake case inside `bar`. If we are traversing this for the first
719
- /// time, everything will be fine, because we will set `diag_severity` on the first matching group
720
- /// and never overwrite it since then. But if `bar` is cached, the cache will contain both
721
- /// `#[warn(non_snake_case)]` and `#[allow(nonstandard_style)]`, and without this field, we have
722
- /// no way of differentiating between the two.
723
- depth : u32 ,
724
- }
725
-
726
- fn fill_lint_attrs (
691
+ fn lint_severity_at (
727
692
sema : & Semantics < ' _ , RootDatabase > ,
728
693
node : & InFile < SyntaxNode > ,
729
- cache : & mut FxHashMap < HirFileId , FxHashMap < SmolStr , SeverityAttr > > ,
730
- cache_stack : & mut Vec < HirFileId > ,
731
- diag : & Diagnostic ,
694
+ lint_groups : & LintGroups ,
732
695
edition : Edition ,
733
696
) -> Option < Severity > {
734
- let mut collected_lint_attrs = FxHashMap :: < SmolStr , SeverityAttr > :: default ( ) ;
735
- let mut diag_severity = None ;
736
-
737
- let mut ancestors = node. value . ancestors ( ) . peekable ( ) ;
738
- let mut depth = 0 ;
739
- loop {
740
- let ancestor = ancestors. next ( ) . expect ( "we always return from top-level nodes" ) ;
741
- depth += 1 ;
742
-
743
- if ancestors. peek ( ) . is_none ( ) {
744
- // We don't want to insert too many nodes into cache, but top level nodes (aka. outline modules
745
- // or macro expansions) need to touch the database so they seem like a good fit to cache.
746
-
747
- if let Some ( cached) = cache. get_mut ( & node. file_id ) {
748
- // This node (and everything above it) is already cached; the attribute is either here or nowhere.
749
-
750
- // Workaround for the borrow checker.
751
- let cached = std:: mem:: take ( cached) ;
752
-
753
- cached. iter ( ) . for_each ( |( lint, severity) | {
754
- for item in & * cache_stack {
755
- let node_cache_entry = cache
756
- . get_mut ( item)
757
- . expect ( "we always insert cached nodes into the cache map" ) ;
758
- let lint_cache_entry = node_cache_entry. entry ( lint. clone ( ) ) ;
759
- if let hash_map:: Entry :: Vacant ( lint_cache_entry) = lint_cache_entry {
760
- // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
761
- // overwrite top attrs.
762
- lint_cache_entry. insert ( SeverityAttr {
763
- severity : severity. severity ,
764
- depth : severity. depth + depth,
765
- } ) ;
766
- }
767
- }
768
- } ) ;
769
-
770
- let lints = lint_groups ( & diag. code , edition) ;
771
- let all_matching_groups =
772
- lints. iter ( ) . filter_map ( |lint_group| cached. get ( lint_group) ) ;
773
- let cached_severity =
774
- all_matching_groups. min_by_key ( |it| it. depth ) . map ( |it| it. severity ) ;
775
-
776
- cache. insert ( node. file_id , cached) ;
777
-
778
- return diag_severity. or ( cached_severity) ;
779
- }
780
-
781
- // Insert this node's descendants' attributes into any outline descendant, but not including this node.
782
- // This must come before inserting this node's own attributes to preserve order.
783
- collected_lint_attrs. drain ( ) . for_each ( |( lint, severity) | {
784
- if diag_severity. is_none ( ) && lint_groups ( & diag. code , edition) . contains ( & lint) {
785
- diag_severity = Some ( severity. severity ) ;
786
- }
787
-
788
- for item in & * cache_stack {
789
- let node_cache_entry = cache
790
- . get_mut ( item)
791
- . expect ( "we always insert cached nodes into the cache map" ) ;
792
- let lint_cache_entry = node_cache_entry. entry ( lint. clone ( ) ) ;
793
- if let hash_map:: Entry :: Vacant ( lint_cache_entry) = lint_cache_entry {
794
- // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
795
- // overwrite top attrs.
796
- lint_cache_entry. insert ( severity) ;
797
- }
798
- }
799
- } ) ;
800
-
801
- cache_stack. push ( node. file_id ) ;
802
- cache. insert ( node. file_id , FxHashMap :: default ( ) ) ;
803
-
804
- if let Some ( ancestor) = ast:: AnyHasAttrs :: cast ( ancestor) {
805
- // Insert this node's attributes into any outline descendant, including this node.
806
- lint_attrs ( sema, ancestor, edition) . for_each ( |( lint, severity) | {
807
- if diag_severity. is_none ( ) && lint_groups ( & diag. code , edition) . contains ( & lint) {
808
- diag_severity = Some ( severity) ;
809
- }
810
-
811
- for item in & * cache_stack {
812
- let node_cache_entry = cache
813
- . get_mut ( item)
814
- . expect ( "we always insert cached nodes into the cache map" ) ;
815
- let lint_cache_entry = node_cache_entry. entry ( lint. clone ( ) ) ;
816
- if let hash_map:: Entry :: Vacant ( lint_cache_entry) = lint_cache_entry {
817
- // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
818
- // overwrite top attrs.
819
- lint_cache_entry. insert ( SeverityAttr { severity, depth } ) ;
820
- }
821
- }
822
- } ) ;
823
- }
824
-
825
- let parent_node = sema. find_parent_file ( node. file_id ) ;
826
- if let Some ( parent_node) = parent_node {
827
- let parent_severity =
828
- fill_lint_attrs ( sema, & parent_node, cache, cache_stack, diag, edition) ;
829
- if diag_severity. is_none ( ) {
830
- diag_severity = parent_severity;
831
- }
832
- }
833
- cache_stack. pop ( ) ;
834
- return diag_severity;
835
- } else if let Some ( ancestor) = ast:: AnyHasAttrs :: cast ( ancestor) {
836
- lint_attrs ( sema, ancestor, edition) . for_each ( |( lint, severity) | {
837
- if diag_severity. is_none ( ) && lint_groups ( & diag. code , edition) . contains ( & lint) {
838
- diag_severity = Some ( severity) ;
839
- }
840
-
841
- let lint_cache_entry = collected_lint_attrs. entry ( lint) ;
842
- if let hash_map:: Entry :: Vacant ( lint_cache_entry) = lint_cache_entry {
843
- // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
844
- // overwrite top attrs.
845
- lint_cache_entry. insert ( SeverityAttr { severity, depth } ) ;
846
- }
847
- } ) ;
848
- }
849
- }
697
+ node. value
698
+ . ancestors ( )
699
+ . filter_map ( ast:: AnyHasAttrs :: cast)
700
+ . find_map ( |ancestor| {
701
+ lint_attrs ( sema, ancestor, edition)
702
+ . find_map ( |( lint, severity) | lint_groups. contains ( & lint) . then_some ( severity) )
703
+ } )
704
+ . or_else ( || {
705
+ lint_severity_at ( sema, & sema. find_parent_file ( node. file_id ) ?, lint_groups, edition)
706
+ } )
850
707
}
851
708
852
709
fn lint_attrs < ' a > (
@@ -945,10 +802,6 @@ impl LintGroups {
945
802
fn contains ( & self , group : & str ) -> bool {
946
803
self . groups . contains ( & group) || ( self . inside_warnings && group == "warnings" )
947
804
}
948
-
949
- fn iter ( & self ) -> impl Iterator < Item = & ' static str > {
950
- self . groups . iter ( ) . copied ( ) . chain ( self . inside_warnings . then_some ( "warnings" ) )
951
- }
952
805
}
953
806
954
807
fn lint_groups ( lint : & DiagnosticCode , edition : Edition ) -> LintGroups {
0 commit comments