@@ -83,12 +83,11 @@ mod handlers {
8383#[ cfg( test) ]
8484mod tests;
8585
86- use std:: { collections :: hash_map , iter, sync:: LazyLock } ;
86+ use std:: { iter, sync:: LazyLock } ;
8787
8888use either:: Either ;
8989use hir:: {
90- Crate , DisplayTarget , HirFileId , InFile , Semantics , db:: ExpandDatabase ,
91- diagnostics:: AnyDiagnostic ,
90+ Crate , DisplayTarget , InFile , Semantics , db:: ExpandDatabase , diagnostics:: AnyDiagnostic ,
9291} ;
9392use ide_db:: {
9493 EditionedFileId , FileId , FileRange , FxHashMap , FxHashSet , RootDatabase , Severity , SnippetCap ,
@@ -513,13 +512,7 @@ pub fn semantic_diagnostics(
513512
514513 // The edition isn't accurate (each diagnostics may have its own edition due to macros),
515514 // 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) ) ;
523516
524517 res. retain ( |d| d. severity != Severity :: Allow ) ;
525518
@@ -584,8 +577,6 @@ fn handle_diag_from_macros(
584577 true
585578}
586579
587- // `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros
588-
589580struct BuiltLint {
590581 lint : & ' static Lint ,
591582 groups : Vec < & ' static str > ,
@@ -629,9 +620,7 @@ fn build_lints_map(
629620
630621fn handle_lints (
631622 sema : & Semantics < ' _ , RootDatabase > ,
632- cache : & mut FxHashMap < HirFileId , FxHashMap < SmolStr , SeverityAttr > > ,
633623 diagnostics : & mut [ ( InFile < SyntaxNode > , & mut Diagnostic ) ] ,
634- cache_stack : & mut Vec < HirFileId > ,
635624 edition : Edition ,
636625) {
637626 for ( node, diag) in diagnostics {
@@ -645,7 +634,8 @@ fn handle_lints(
645634 diag. severity = default_severity;
646635 }
647636
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) ;
649639
650640 if let outline_diag_severity @ Some ( _) =
651641 find_outline_mod_lint_severity ( sema, node, diag, edition)
@@ -698,155 +688,22 @@ fn find_outline_mod_lint_severity(
698688 result
699689}
700690
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 (
727692 sema : & Semantics < ' _ , RootDatabase > ,
728693 node : & InFile < SyntaxNode > ,
729- cache : & mut FxHashMap < HirFileId , FxHashMap < SmolStr , SeverityAttr > > ,
730- cache_stack : & mut Vec < HirFileId > ,
731- diag : & Diagnostic ,
694+ lint_groups : & LintGroups ,
732695 edition : Edition ,
733696) -> 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+ } )
850707}
851708
852709fn lint_attrs < ' a > (
@@ -945,10 +802,6 @@ impl LintGroups {
945802 fn contains ( & self , group : & str ) -> bool {
946803 self . groups . contains ( & group) || ( self . inside_warnings && group == "warnings" )
947804 }
948-
949- fn iter ( & self ) -> impl Iterator < Item = & ' static str > {
950- self . groups . iter ( ) . copied ( ) . chain ( self . inside_warnings . then_some ( "warnings" ) )
951- }
952805}
953806
954807fn lint_groups ( lint : & DiagnosticCode , edition : Edition ) -> LintGroups {
0 commit comments