@@ -449,6 +449,8 @@ impl Definition {
449449 scope : None ,
450450 include_self_kw_refs : None ,
451451 search_self_mod : false ,
452+ excluded_categories : ReferenceCategory :: empty ( ) ,
453+ exclude_library_files : false ,
452454 }
453455 }
454456}
@@ -465,6 +467,10 @@ pub struct FindUsages<'a> {
465467 include_self_kw_refs : Option < hir:: Type < ' a > > ,
466468 /// whether to search for the `self` module
467469 search_self_mod : bool ,
470+ /// categories to exclude while collecting usages
471+ excluded_categories : ReferenceCategory ,
472+ /// whether to skip files from library source roots
473+ exclude_library_files : bool ,
468474}
469475
470476impl < ' a > FindUsages < ' a > {
@@ -495,6 +501,16 @@ impl<'a> FindUsages<'a> {
495501 self
496502 }
497503
504+ pub fn set_excluded_categories ( mut self , categories : ReferenceCategory ) -> Self {
505+ self . excluded_categories = categories;
506+ self
507+ }
508+
509+ pub fn set_exclude_library_files ( mut self , exclude_library_files : bool ) -> Self {
510+ self . exclude_library_files = exclude_library_files;
511+ self
512+ }
513+
498514 pub fn at_least_one ( & self ) -> bool {
499515 let mut found = false ;
500516 self . search ( & mut |_, _| {
@@ -599,7 +615,7 @@ impl<'a> FindUsages<'a> {
599615 search_scope : & SearchScope ,
600616 name : & str ,
601617 ) -> bool {
602- if self . scope . is_some ( ) {
618+ if self . scope . is_some ( ) || self . exclude_library_files {
603619 return false ;
604620 }
605621
@@ -922,7 +938,7 @@ impl<'a> FindUsages<'a> {
922938 let _p = tracing:: info_span!( "FindUsages:search" ) . entered ( ) ;
923939 let sema = self . sema ;
924940
925- let search_scope = {
941+ let mut search_scope = {
926942 // FIXME: Is the trait scope needed for trait impl assoc items?
927943 let base =
928944 as_trait_assoc_def ( sema. db , self . def ) . unwrap_or ( self . def ) . search_scope ( sema. db ) ;
@@ -931,6 +947,14 @@ impl<'a> FindUsages<'a> {
931947 Some ( scope) => base. intersection ( scope) ,
932948 }
933949 } ;
950+ if self . exclude_library_files {
951+ search_scope
952+ . entries
953+ . retain ( |& file_id, _| !is_library_file ( sema. db , file_id. file_id ( sema. db ) ) ) ;
954+ }
955+ if search_scope. entries . is_empty ( ) {
956+ return ;
957+ }
934958
935959 let name = match ( self . rename , self . def ) {
936960 ( Some ( rename) , _) => {
@@ -1118,6 +1142,10 @@ impl<'a> FindUsages<'a> {
11181142 name_ref : & ast:: NameRef ,
11191143 sink : & mut dyn FnMut ( EditionedFileId , FileReference ) -> bool ,
11201144 ) -> bool {
1145+ if self . is_excluded_name_ref ( name_ref) {
1146+ return false ;
1147+ }
1148+
11211149 // See https://github.com/rust-lang/rust-analyzer/pull/15864/files/e0276dc5ddc38c65240edb408522bb869f15afb4#r1389848845
11221150 let ty_eq = |ty : hir:: Type < ' _ > | match ( ty. as_adt ( ) , self_ty. as_adt ( ) ) {
11231151 ( Some ( ty) , Some ( self_ty) ) => ty == self_ty,
@@ -1146,6 +1174,10 @@ impl<'a> FindUsages<'a> {
11461174 name_ref : & ast:: NameRef ,
11471175 sink : & mut dyn FnMut ( EditionedFileId , FileReference ) -> bool ,
11481176 ) -> bool {
1177+ if self . is_excluded_name_ref ( name_ref) {
1178+ return false ;
1179+ }
1180+
11491181 match NameRefClass :: classify ( self . sema , name_ref) {
11501182 Some ( NameRefClass :: Definition ( def @ Definition :: Module ( _) , _) ) if def == self . def => {
11511183 let FileRange { file_id, range } = self . sema . original_range ( name_ref. syntax ( ) ) ;
@@ -1210,6 +1242,10 @@ impl<'a> FindUsages<'a> {
12101242 name_ref : & ast:: NameRef ,
12111243 sink : & mut dyn FnMut ( EditionedFileId , FileReference ) -> bool ,
12121244 ) -> bool {
1245+ if self . is_excluded_name_ref ( name_ref) {
1246+ return false ;
1247+ }
1248+
12131249 match NameRefClass :: classify ( self . sema , name_ref) {
12141250 Some ( NameRefClass :: Definition ( def, _) )
12151251 if self . def == def
@@ -1283,6 +1319,13 @@ impl<'a> FindUsages<'a> {
12831319 }
12841320 }
12851321
1322+ fn is_excluded_name_ref ( & self , name_ref : & ast:: NameRef ) -> bool {
1323+ ( self . excluded_categories . contains ( ReferenceCategory :: TEST )
1324+ && is_name_ref_in_test ( self . sema , name_ref) )
1325+ || ( self . excluded_categories . contains ( ReferenceCategory :: IMPORT )
1326+ && is_name_ref_in_import ( name_ref) )
1327+ }
1328+
12861329 fn found_name (
12871330 & self ,
12881331 name : & ast:: Name ,
@@ -1409,3 +1452,8 @@ fn is_name_ref_in_test(sema: &Semantics<'_, RootDatabase>, name_ref: &ast::NameR
14091452 None => false ,
14101453 } )
14111454}
1455+
1456+ fn is_library_file ( db : & RootDatabase , file_id : span:: FileId ) -> bool {
1457+ let source_root = db. file_source_root ( file_id) . source_root_id ( db) ;
1458+ db. source_root ( source_root) . source_root ( db) . is_library
1459+ }
0 commit comments