From 75ee986f4981f0feeb266b7ed02c21e408ca1f08 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Sun, 29 Mar 2026 16:05:11 +0800 Subject: [PATCH 1/5] feat: exclude refs from deps and stdlib --- crates/ide-db/src/search.rs | 52 +++++++++++++++++++- crates/ide/src/annotations.rs | 8 ++- crates/ide/src/references.rs | 22 ++++++++- crates/rust-analyzer/src/config.rs | 7 +++ crates/rust-analyzer/src/handlers/request.rs | 19 ++++--- docs/book/src/configuration_generated.md | 7 +++ editors/code/package.json | 10 ++++ 7 files changed, 112 insertions(+), 13 deletions(-) diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 69459a4b72da..a0655341fa36 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -449,6 +449,8 @@ impl Definition { scope: None, include_self_kw_refs: None, search_self_mod: false, + excluded_categories: ReferenceCategory::empty(), + exclude_library_files: false, } } } @@ -465,6 +467,10 @@ pub struct FindUsages<'a> { include_self_kw_refs: Option>, /// whether to search for the `self` module search_self_mod: bool, + /// categories to exclude while collecting usages + excluded_categories: ReferenceCategory, + /// whether to skip files from library source roots + exclude_library_files: bool, } impl<'a> FindUsages<'a> { @@ -495,6 +501,16 @@ impl<'a> FindUsages<'a> { self } + pub fn set_excluded_categories(mut self, categories: ReferenceCategory) -> Self { + self.excluded_categories = categories; + self + } + + pub fn set_exclude_library_files(mut self, exclude_library_files: bool) -> Self { + self.exclude_library_files = exclude_library_files; + self + } + pub fn at_least_one(&self) -> bool { let mut found = false; self.search(&mut |_, _| { @@ -599,7 +615,7 @@ impl<'a> FindUsages<'a> { search_scope: &SearchScope, name: &str, ) -> bool { - if self.scope.is_some() { + if self.scope.is_some() || self.exclude_library_files { return false; } @@ -922,7 +938,7 @@ impl<'a> FindUsages<'a> { let _p = tracing::info_span!("FindUsages:search").entered(); let sema = self.sema; - let search_scope = { + let mut search_scope = { // FIXME: Is the trait scope needed for trait impl assoc items? let base = as_trait_assoc_def(sema.db, self.def).unwrap_or(self.def).search_scope(sema.db); @@ -931,6 +947,14 @@ impl<'a> FindUsages<'a> { Some(scope) => base.intersection(scope), } }; + if self.exclude_library_files { + search_scope + .entries + .retain(|&file_id, _| !is_library_file(sema.db, file_id.file_id(sema.db))); + } + if search_scope.entries.is_empty() { + return; + } let name = match (self.rename, self.def) { (Some(rename), _) => { @@ -1118,6 +1142,10 @@ impl<'a> FindUsages<'a> { name_ref: &ast::NameRef, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, ) -> bool { + if self.is_excluded_name_ref(name_ref) { + return false; + } + // See https://github.com/rust-lang/rust-analyzer/pull/15864/files/e0276dc5ddc38c65240edb408522bb869f15afb4#r1389848845 let ty_eq = |ty: hir::Type<'_>| match (ty.as_adt(), self_ty.as_adt()) { (Some(ty), Some(self_ty)) => ty == self_ty, @@ -1146,6 +1174,10 @@ impl<'a> FindUsages<'a> { name_ref: &ast::NameRef, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, ) -> bool { + if self.is_excluded_name_ref(name_ref) { + return false; + } + match NameRefClass::classify(self.sema, name_ref) { Some(NameRefClass::Definition(def @ Definition::Module(_), _)) if def == self.def => { let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax()); @@ -1210,6 +1242,10 @@ impl<'a> FindUsages<'a> { name_ref: &ast::NameRef, sink: &mut dyn FnMut(EditionedFileId, FileReference) -> bool, ) -> bool { + if self.is_excluded_name_ref(name_ref) { + return false; + } + match NameRefClass::classify(self.sema, name_ref) { Some(NameRefClass::Definition(def, _)) if self.def == def @@ -1283,6 +1319,13 @@ impl<'a> FindUsages<'a> { } } + fn is_excluded_name_ref(&self, name_ref: &ast::NameRef) -> bool { + (self.excluded_categories.contains(ReferenceCategory::TEST) + && is_name_ref_in_test(self.sema, name_ref)) + || (self.excluded_categories.contains(ReferenceCategory::IMPORT) + && is_name_ref_in_import(name_ref)) + } + fn found_name( &self, name: &ast::Name, @@ -1409,3 +1452,8 @@ fn is_name_ref_in_test(sema: &Semantics<'_, RootDatabase>, name_ref: &ast::NameR None => false, }) } + +fn is_library_file(db: &RootDatabase, file_id: span::FileId) -> bool { + let source_root = db.file_source_root(file_id).source_root_id(db); + db.source_root(source_root).source_root(db).is_library +} diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 21b2339c722c..3d61b9d35fd1 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -216,7 +216,13 @@ pub(crate) fn resolve_annotation( *data = find_all_refs( &Semantics::new(db), pos, - &FindAllRefsConfig { search_scope: None, ra_fixture: config.ra_fixture }, + &FindAllRefsConfig { + search_scope: None, + ra_fixture: config.ra_fixture, + exclude_imports: false, + exclude_tests: false, + exclude_library_refs: false, + }, ) .map(|result| { result diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 0288099bbcc2..c35e3dc3aaf7 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -91,6 +91,9 @@ pub struct Declaration { pub struct FindAllRefsConfig<'a> { pub search_scope: Option, pub ra_fixture: RaFixtureConfig<'a>, + pub exclude_imports: bool, + pub exclude_tests: bool, + pub exclude_library_refs: bool, } /// Find all references to the item at the given position. @@ -127,8 +130,20 @@ pub(crate) fn find_all_refs( let syntax = sema.parse_guess_edition(position.file_id).syntax().clone(); let make_searcher = |literal_search: bool| { move |def: Definition| { - let mut usages = - def.usages(sema).set_scope(config.search_scope.as_ref()).include_self_refs().all(); + let mut excluded_categories = ReferenceCategory::empty(); + if config.exclude_imports { + excluded_categories |= ReferenceCategory::IMPORT; + } + if config.exclude_tests { + excluded_categories |= ReferenceCategory::TEST; + } + let mut usages = def + .usages(sema) + .set_scope(config.search_scope.as_ref()) + .set_excluded_categories(excluded_categories) + .set_exclude_library_files(config.exclude_library_refs) + .include_self_refs() + .all(); if literal_search { retain_adt_literal_usages(&mut usages, def, sema); } @@ -1568,6 +1583,9 @@ fn main() { let config = FindAllRefsConfig { search_scope: search_scope.map(|it| it(&analysis.db)), ra_fixture: RaFixtureConfig::default(), + exclude_imports: false, + exclude_tests: false, + exclude_library_refs: false, }; let refs = analysis.find_all_refs(pos, &config).unwrap().unwrap(); diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 3a88a8fe8480..27546b50ca40 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -409,6 +409,9 @@ config_data! { /// Exclude imports from find-all-references. references_excludeImports: bool = false, + /// Exclude references from dependencies and stdlib in find-all-references. + references_excludeLibraries: bool = false, + /// Exclude tests from find-all-references and call-hierarchy. references_excludeTests: bool = false, @@ -2652,6 +2655,10 @@ impl Config { *self.references_excludeImports() } + pub fn find_all_refs_exclude_libraries(&self) -> bool { + *self.references_excludeLibraries() + } + pub fn find_all_refs_exclude_tests(&self) -> bool { *self.references_excludeTests() } diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index 86516b6079c7..c6485badd4cc 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -9,8 +9,8 @@ use base64::{Engine, prelude::BASE64_STANDARD}; use ide::{ AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve, FilePosition, FileRange, FileStructureConfig, FindAllRefsConfig, HoverAction, HoverGotoTypeData, - InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind, - SingleResolve, SourceChange, TextEdit, + InlayFieldsToResolve, Query, RangeInfo, Runnable, RunnableKind, SingleResolve, SourceChange, + TextEdit, }; use ide_db::{FxHashMap, SymbolKind}; use itertools::Itertools; @@ -1396,12 +1396,16 @@ pub(crate) fn handle_references( let exclude_imports = snap.config.find_all_refs_exclude_imports(); let exclude_tests = snap.config.find_all_refs_exclude_tests(); + let exclude_library_refs = snap.config.find_all_refs_exclude_libraries(); let Some(refs) = snap.analysis.find_all_refs( position, &FindAllRefsConfig { search_scope: None, ra_fixture: snap.config.ra_fixture(snap.minicore()), + exclude_imports, + exclude_library_refs, + exclude_tests, }, )? else { @@ -1423,12 +1427,7 @@ pub(crate) fn handle_references( refs.references .into_iter() .flat_map(|(file_id, refs)| { - refs.into_iter() - .filter(|&(_, category)| { - (!exclude_imports || !category.contains(ReferenceCategory::IMPORT)) - && (!exclude_tests || !category.contains(ReferenceCategory::TEST)) - }) - .map(move |(range, _)| FileRange { file_id, range }) + refs.into_iter().map(move |(range, _)| FileRange { file_id, range }) }) .chain(decl) }) @@ -2211,7 +2210,11 @@ fn show_ref_command_link( *position, &FindAllRefsConfig { search_scope: None, + ra_fixture: snap.config.ra_fixture(snap.minicore()), + exclude_imports: snap.config.find_all_refs_exclude_imports(), + exclude_tests: snap.config.find_all_refs_exclude_tests(), + exclude_library_refs: snap.config.find_all_refs_exclude_libraries(), }, ) .unwrap_or(None) diff --git a/docs/book/src/configuration_generated.md b/docs/book/src/configuration_generated.md index da37fc158234..245e77f088f2 100644 --- a/docs/book/src/configuration_generated.md +++ b/docs/book/src/configuration_generated.md @@ -1376,6 +1376,13 @@ Default: `false` Exclude imports from find-all-references. +## rust-analyzer.references.excludeLibraries {#references.excludeLibraries} + +Default: `false` + +Exclude references from dependencies and stdlib in find-all-references. + + ## rust-analyzer.references.excludeTests {#references.excludeTests} Default: `false` diff --git a/editors/code/package.json b/editors/code/package.json index 29cbc8bd4fda..2f1d75816a94 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -2875,6 +2875,16 @@ } } }, + { + "title": "References", + "properties": { + "rust-analyzer.references.excludeLibraries": { + "markdownDescription": "Exclude references from dependencies and stdlib in find-all-references.", + "default": false, + "type": "boolean" + } + } + }, { "title": "References", "properties": { From 9376701b4303ae2b82acf8103f1a11f9b5629e5c Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Sun, 29 Mar 2026 16:13:25 +0800 Subject: [PATCH 2/5] fix: exclude declartion --- crates/ide/src/references.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index c35e3dc3aaf7..199dea5e86c4 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -181,6 +181,9 @@ pub(crate) fn find_all_refs( is_mut: matches!(def, Definition::Local(l) if l.is_mut(sema.db)), nav, } + }) + .filter(|decl| { + !(config.exclude_library_refs && is_library_file(sema.db, decl.nav.file_id)) }); ReferenceSearchResult { declaration, references } } @@ -222,6 +225,11 @@ pub(crate) fn find_all_refs( } } +fn is_library_file(db: &RootDatabase, file_id: FileId) -> bool { + let source_root = db.file_source_root(file_id).source_root_id(db); + db.source_root(source_root).source_root(db).is_library +} + pub(crate) fn find_defs( sema: &Semantics<'_, RootDatabase>, syntax: &SyntaxNode, From bacf7e50713f8fca7b9af1669fd416f7d5914cc1 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Sun, 29 Mar 2026 16:31:57 +0800 Subject: [PATCH 3/5] test: add test case for exclude refs from deps and stdlib --- crates/ide/src/references.rs | 140 ++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 199dea5e86c4..2dd13ecbcea7 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -492,7 +492,7 @@ mod tests { #[test] fn exclude_tests() { - check( + check_with_filters( r#" fn test_func() {} @@ -505,6 +505,9 @@ fn test() { test_func(); } "#, + false, + false, + false, expect![[r#" test_func Function FileId(0) 0..17 3..12 @@ -513,7 +516,7 @@ fn test() { "#]], ); - check( + check_with_filters( r#" fn test_func() {} @@ -526,6 +529,9 @@ fn test() { test_func(); } "#, + false, + false, + false, expect![[r#" test_func Function FileId(0) 0..17 3..12 @@ -533,6 +539,103 @@ fn test() { FileId(0) 96..105 test "#]], ); + + check_with_filters( + r#" +fn test_func() {} + +fn func() { + test_func$0(); +} + +#[test] +fn test() { + test_func(); +} +"#, + false, + true, + false, + expect![[r#" + test_func Function FileId(0) 0..17 3..12 + + FileId(0) 35..44 + "#]], + ); + } + + #[test] + fn exclude_library_refs_filtering() { + // exclude refs in 3rd party lib + check_with_filters( + r#" +//- /main.rs crate:main deps:dep +use dep::foo; + +fn main() { + foo$0(); +} + +//- /dep/lib.rs crate:dep new_source_root:library +pub fn foo() {} + +pub fn also_calls_foo() { + foo(); +} +"#, + false, + false, + true, + expect![[r#" + FileId(0) 9..12 import + FileId(0) 31..34 + "#]], + ); + + // exclude refs in stdlib + check_with_filters( + r#" +//- minicore: option +fn main() { + let _ = core::option::Option::Some$0(0); +} +"#, + false, + false, + true, + expect![[r#" + FileId(0) 46..50 + "#]], + ); + + // keep refs in local lib + check_with_filters( + r#" +//- /main.rs crate:main deps:dep +use dep::foo; + +fn main() { + foo$0(); +} + +//- /dep/lib.rs crate:dep +pub fn foo() {} + +pub fn also_calls_foo() { + foo(); +} +"#, + false, + false, + true, + expect![[r#" + foo Function FileId(1) 0..15 7..10 + + FileId(0) 9..12 import + FileId(0) 31..34 + FileId(1) 47..50 + "#]], + ); } #[test] @@ -1579,18 +1682,49 @@ fn main() { } fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { - check_with_scope(ra_fixture, None, expect) + check_with_filters(ra_fixture, false, false, false, expect) + } + + fn check_with_filters( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + exclude_imports: bool, + exclude_tests: bool, + exclude_library_refs: bool, + expect: Expect, + ) { + check_with_scope_and_filters( + ra_fixture, + None, + exclude_imports, + exclude_tests, + exclude_library_refs, + expect, + ) } fn check_with_scope( #[rust_analyzer::rust_fixture] ra_fixture: &str, search_scope: Option<&mut dyn FnMut(&RootDatabase) -> SearchScope>, expect: Expect, + ) { + check_with_scope_and_filters(ra_fixture, search_scope, false, false, false, expect) + } + + fn check_with_scope_and_filters( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + search_scope: Option<&mut dyn FnMut(&RootDatabase) -> SearchScope>, + exclude_imports: bool, + exclude_tests: bool, + exclude_library_refs: bool, + expect: Expect, ) { let (analysis, pos) = fixture::position(ra_fixture); let config = FindAllRefsConfig { search_scope: search_scope.map(|it| it(&analysis.db)), ra_fixture: RaFixtureConfig::default(), + exclude_imports, + exclude_tests, + exclude_library_refs, exclude_imports: false, exclude_tests: false, exclude_library_refs: false, From 7490a86f806da7fd936e146517696a6fc01b8b11 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Sat, 11 Apr 2026 13:28:08 +0800 Subject: [PATCH 4/5] internal: auto exclude --- crates/ide-db/src/search.rs | 8 ++- crates/ide/src/annotations.rs | 1 - crates/ide/src/references.rs | 70 +++++++++++--------- crates/rust-analyzer/src/config.rs | 7 -- crates/rust-analyzer/src/handlers/request.rs | 4 -- docs/book/src/configuration_generated.md | 7 -- editors/code/package.json | 10 --- 7 files changed, 43 insertions(+), 64 deletions(-) diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index a0655341fa36..8922eb65877b 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -615,7 +615,7 @@ impl<'a> FindUsages<'a> { search_scope: &SearchScope, name: &str, ) -> bool { - if self.scope.is_some() || self.exclude_library_files { + if self.scope.is_some() { return false; } @@ -897,12 +897,16 @@ impl<'a> FindUsages<'a> { let finder = Finder::new(name.as_bytes()); // The search for `Self` may return duplicate results with `ContainerName`, so deduplicate them. let mut self_positions = FxHashSet::default(); + let is_possibly_self = is_possibly_self.into_iter().filter(|position| { + !self.exclude_library_files + || !is_library_file(self.sema.db, position.file_id.file_id(self.sema.db)) + }); tracing::info_span!("Self_search").in_scope(|| { search( self, &finder, name, - is_possibly_self.into_iter().map(|position| { + is_possibly_self.map(|position| { (position.file_text(self.sema.db).clone(), position.file_id, position.range) }), |path, name_position| { diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 3d61b9d35fd1..f716f94d7141 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -221,7 +221,6 @@ pub(crate) fn resolve_annotation( ra_fixture: config.ra_fixture, exclude_imports: false, exclude_tests: false, - exclude_library_refs: false, }, ) .map(|result| { diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 2dd13ecbcea7..ea32f0226783 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -20,6 +20,7 @@ use hir::{PathResolution, Semantics}; use ide_db::{ FileId, RootDatabase, + base_db::SourceDatabase, defs::{Definition, NameClass, NameRefClass}, helpers::pick_best_token, ra_fixture::{RaFixtureConfig, UpmapFromRaFixture}, @@ -93,7 +94,6 @@ pub struct FindAllRefsConfig<'a> { pub ra_fixture: RaFixtureConfig<'a>, pub exclude_imports: bool, pub exclude_tests: bool, - pub exclude_library_refs: bool, } /// Find all references to the item at the given position. @@ -128,6 +128,7 @@ pub(crate) fn find_all_refs( ) -> Option> { let _p = tracing::info_span!("find_all_refs").entered(); let syntax = sema.parse_guess_edition(position.file_id).syntax().clone(); + let exclude_library_refs = !is_library_file(sema.db, position.file_id); let make_searcher = |literal_search: bool| { move |def: Definition| { let mut excluded_categories = ReferenceCategory::empty(); @@ -141,7 +142,7 @@ pub(crate) fn find_all_refs( .usages(sema) .set_scope(config.search_scope.as_ref()) .set_excluded_categories(excluded_categories) - .set_exclude_library_files(config.exclude_library_refs) + .set_exclude_library_files(exclude_library_refs) .include_self_refs() .all(); if literal_search { @@ -182,9 +183,7 @@ pub(crate) fn find_all_refs( nav, } }) - .filter(|decl| { - !(config.exclude_library_refs && is_library_file(sema.db, decl.nav.file_id)) - }); + .filter(|decl| !(exclude_library_refs && is_library_file(sema.db, decl.nav.file_id))); ReferenceSearchResult { declaration, references } } }; @@ -505,7 +504,6 @@ fn test() { test_func(); } "#, - false, false, false, expect![[r#" @@ -529,7 +527,6 @@ fn test() { test_func(); } "#, - false, false, false, expect![[r#" @@ -555,7 +552,6 @@ fn test() { "#, false, true, - false, expect![[r#" test_func Function FileId(0) 0..17 3..12 @@ -585,7 +581,6 @@ pub fn also_calls_foo() { "#, false, false, - true, expect![[r#" FileId(0) 9..12 import FileId(0) 31..34 @@ -602,7 +597,6 @@ fn main() { "#, false, false, - true, expect![[r#" FileId(0) 46..50 "#]], @@ -627,7 +621,36 @@ pub fn also_calls_foo() { "#, false, false, - true, + expect![[r#" + foo Function FileId(1) 0..15 7..10 + + FileId(0) 9..12 import + FileId(0) 31..34 + FileId(1) 47..50 + "#]], + ); + } + + #[test] + fn find_refs_from_library_source_keeps_library_refs() { + check_with_filters( + r#" +//- /main.rs crate:main deps:dep +use dep::foo; + +fn main() { + foo(); +} + +//- /dep/lib.rs crate:dep new_source_root:library +pub fn foo$0() {} + +pub fn also_calls_foo() { + foo(); +} +"#, + false, + false, expect![[r#" foo Function FileId(1) 0..15 7..10 @@ -1682,24 +1705,16 @@ fn main() { } fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { - check_with_filters(ra_fixture, false, false, false, expect) + check_with_filters(ra_fixture, false, false, expect) } fn check_with_filters( #[rust_analyzer::rust_fixture] ra_fixture: &str, exclude_imports: bool, exclude_tests: bool, - exclude_library_refs: bool, expect: Expect, ) { - check_with_scope_and_filters( - ra_fixture, - None, - exclude_imports, - exclude_tests, - exclude_library_refs, - expect, - ) + check_with_scope_and_filters(ra_fixture, None, exclude_imports, exclude_tests, expect) } fn check_with_scope( @@ -1707,7 +1722,7 @@ fn main() { search_scope: Option<&mut dyn FnMut(&RootDatabase) -> SearchScope>, expect: Expect, ) { - check_with_scope_and_filters(ra_fixture, search_scope, false, false, false, expect) + check_with_scope_and_filters(ra_fixture, search_scope, false, false, expect) } fn check_with_scope_and_filters( @@ -1715,7 +1730,6 @@ fn main() { search_scope: Option<&mut dyn FnMut(&RootDatabase) -> SearchScope>, exclude_imports: bool, exclude_tests: bool, - exclude_library_refs: bool, expect: Expect, ) { let (analysis, pos) = fixture::position(ra_fixture); @@ -1724,10 +1738,6 @@ fn main() { ra_fixture: RaFixtureConfig::default(), exclude_imports, exclude_tests, - exclude_library_refs, - exclude_imports: false, - exclude_tests: false, - exclude_library_refs: false, }; let refs = analysis.find_all_refs(pos, &config).unwrap().unwrap(); @@ -2234,8 +2244,6 @@ use proc_macros::identity; fn func() {} "#, expect![[r#" - identity Attribute FileId(1) 1..107 32..40 - FileId(0) 17..25 import FileId(0) 43..51 "#]], @@ -2265,8 +2273,6 @@ use proc_macros::mirror; mirror$0! {} "#, expect![[r#" - mirror ProcMacro FileId(1) 1..77 22..28 - FileId(0) 17..23 import FileId(0) 26..32 "#]], @@ -2285,8 +2291,6 @@ use proc_macros::DeriveIdentity; struct Foo; "#, expect![[r#" - derive_identity Derive FileId(2) 1..107 45..60 - FileId(0) 17..31 import FileId(0) 56..70 "#]], diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 27546b50ca40..3a88a8fe8480 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -409,9 +409,6 @@ config_data! { /// Exclude imports from find-all-references. references_excludeImports: bool = false, - /// Exclude references from dependencies and stdlib in find-all-references. - references_excludeLibraries: bool = false, - /// Exclude tests from find-all-references and call-hierarchy. references_excludeTests: bool = false, @@ -2655,10 +2652,6 @@ impl Config { *self.references_excludeImports() } - pub fn find_all_refs_exclude_libraries(&self) -> bool { - *self.references_excludeLibraries() - } - pub fn find_all_refs_exclude_tests(&self) -> bool { *self.references_excludeTests() } diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index c6485badd4cc..35c5df6e917a 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -1396,15 +1396,12 @@ pub(crate) fn handle_references( let exclude_imports = snap.config.find_all_refs_exclude_imports(); let exclude_tests = snap.config.find_all_refs_exclude_tests(); - let exclude_library_refs = snap.config.find_all_refs_exclude_libraries(); - let Some(refs) = snap.analysis.find_all_refs( position, &FindAllRefsConfig { search_scope: None, ra_fixture: snap.config.ra_fixture(snap.minicore()), exclude_imports, - exclude_library_refs, exclude_tests, }, )? @@ -2214,7 +2211,6 @@ fn show_ref_command_link( ra_fixture: snap.config.ra_fixture(snap.minicore()), exclude_imports: snap.config.find_all_refs_exclude_imports(), exclude_tests: snap.config.find_all_refs_exclude_tests(), - exclude_library_refs: snap.config.find_all_refs_exclude_libraries(), }, ) .unwrap_or(None) diff --git a/docs/book/src/configuration_generated.md b/docs/book/src/configuration_generated.md index 245e77f088f2..da37fc158234 100644 --- a/docs/book/src/configuration_generated.md +++ b/docs/book/src/configuration_generated.md @@ -1376,13 +1376,6 @@ Default: `false` Exclude imports from find-all-references. -## rust-analyzer.references.excludeLibraries {#references.excludeLibraries} - -Default: `false` - -Exclude references from dependencies and stdlib in find-all-references. - - ## rust-analyzer.references.excludeTests {#references.excludeTests} Default: `false` diff --git a/editors/code/package.json b/editors/code/package.json index 2f1d75816a94..29cbc8bd4fda 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -2875,16 +2875,6 @@ } } }, - { - "title": "References", - "properties": { - "rust-analyzer.references.excludeLibraries": { - "markdownDescription": "Exclude references from dependencies and stdlib in find-all-references.", - "default": false, - "type": "boolean" - } - } - }, { "title": "References", "properties": { From 8b707e3846ab5d979f6d70597d86e47985f4e1c2 Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Sat, 18 Apr 2026 20:40:30 +0800 Subject: [PATCH 5/5] internal: code review tweak --- crates/ide-db/src/search.rs | 67 +++++++++++++++++++----------------- crates/ide/src/references.rs | 21 +++++++---- 2 files changed, 51 insertions(+), 37 deletions(-) diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 8922eb65877b..cb52a3f567e3 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -449,7 +449,7 @@ impl Definition { scope: None, include_self_kw_refs: None, search_self_mod: false, - excluded_categories: ReferenceCategory::empty(), + included_categories: ReferenceCategory::all(), exclude_library_files: false, } } @@ -467,8 +467,8 @@ pub struct FindUsages<'a> { include_self_kw_refs: Option>, /// whether to search for the `self` module search_self_mod: bool, - /// categories to exclude while collecting usages - excluded_categories: ReferenceCategory, + /// categories to include while collecting usages + included_categories: ReferenceCategory, /// whether to skip files from library source roots exclude_library_files: bool, } @@ -501,8 +501,8 @@ impl<'a> FindUsages<'a> { self } - pub fn set_excluded_categories(mut self, categories: ReferenceCategory) -> Self { - self.excluded_categories = categories; + pub fn set_included_categories(mut self, categories: ReferenceCategory) -> Self { + self.included_categories = categories; self } @@ -532,14 +532,21 @@ impl<'a> FindUsages<'a> { fn scope_files<'b>( db: &'b RootDatabase, scope: &'b SearchScope, + exclude_library_files: bool, ) -> impl Iterator, EditionedFileId, TextRange)> + 'b { - scope.entries.iter().map(|(&file_id, &search_range)| { - let text = db.file_text(file_id.file_id(db)).text(db); - let search_range = - search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&**text))); + scope + .entries + .iter() + .filter(move |(file_id, _)| { + !exclude_library_files || !is_library_file(db, file_id.file_id(db)) + }) + .map(|(&file_id, &search_range)| { + let text = db.file_text(file_id.file_id(db)).text(db); + let search_range = + search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&**text))); - (text.clone(), file_id, search_range) - }) + (text.clone(), file_id, search_range) + }) } fn match_indices<'b>( @@ -665,6 +672,7 @@ impl<'a> FindUsages<'a> { fn collect_possible_aliases( sema: &Semantics<'_, RootDatabase>, container: Adt, + exclude_library_files: bool, ) -> Option<(FxHashSet, Vec>)> { fn insert_type_alias( db: &RootDatabase, @@ -698,9 +706,11 @@ impl<'a> FindUsages<'a> { }; let finder = Finder::new(current_to_process.as_bytes()); - for (file_text, file_id, search_range) in - FindUsages::scope_files(db, ¤t_to_process_search_scope) - { + for (file_text, file_id, search_range) in FindUsages::scope_files( + db, + ¤t_to_process_search_scope, + exclude_library_files, + ) { let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); for offset in FindUsages::match_indices(&file_text, &finder, search_range) { @@ -885,7 +895,7 @@ impl<'a> FindUsages<'a> { } let Some((container_possible_aliases, is_possibly_self)) = - collect_possible_aliases(self.sema, container) + collect_possible_aliases(self.sema, container, self.exclude_library_files) else { return false; }; @@ -897,16 +907,12 @@ impl<'a> FindUsages<'a> { let finder = Finder::new(name.as_bytes()); // The search for `Self` may return duplicate results with `ContainerName`, so deduplicate them. let mut self_positions = FxHashSet::default(); - let is_possibly_self = is_possibly_self.into_iter().filter(|position| { - !self.exclude_library_files - || !is_library_file(self.sema.db, position.file_id.file_id(self.sema.db)) - }); tracing::info_span!("Self_search").in_scope(|| { search( self, &finder, name, - is_possibly_self.map(|position| { + is_possibly_self.into_iter().map(|position| { (position.file_text(self.sema.db).clone(), position.file_id, position.range) }), |path, name_position| { @@ -926,7 +932,7 @@ impl<'a> FindUsages<'a> { self, &finder, name, - FindUsages::scope_files(self.sema.db, search_scope), + FindUsages::scope_files(self.sema.db, search_scope, self.exclude_library_files), |path, name_position| { has_any_name(path, |name| container_possible_aliases.contains(name)) && !self_positions.contains(&name_position) @@ -942,7 +948,7 @@ impl<'a> FindUsages<'a> { let _p = tracing::info_span!("FindUsages:search").entered(); let sema = self.sema; - let mut search_scope = { + let search_scope = { // FIXME: Is the trait scope needed for trait impl assoc items? let base = as_trait_assoc_def(sema.db, self.def).unwrap_or(self.def).search_scope(sema.db); @@ -951,11 +957,6 @@ impl<'a> FindUsages<'a> { Some(scope) => base.intersection(scope), } }; - if self.exclude_library_files { - search_scope - .entries - .retain(|&file_id, _| !is_library_file(sema.db, file_id.file_id(sema.db))); - } if search_scope.entries.is_empty() { return; } @@ -1010,7 +1011,9 @@ impl<'a> FindUsages<'a> { let finder = &Finder::new(name); let include_self_kw_refs = self.include_self_kw_refs.as_ref().map(|ty| (ty, Finder::new("Self"))); - for (text, file_id, search_range) in Self::scope_files(sema.db, &search_scope) { + for (text, file_id, search_range) in + Self::scope_files(sema.db, &search_scope, self.exclude_library_files) + { let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); // Search for occurrences of the items name @@ -1067,7 +1070,9 @@ impl<'a> FindUsages<'a> { let is_crate_root = module.is_crate_root(self.sema.db).then(|| Finder::new("crate")); let finder = &Finder::new("super"); - for (text, file_id, search_range) in Self::scope_files(sema.db, &scope) { + for (text, file_id, search_range) in + Self::scope_files(sema.db, &scope, self.exclude_library_files) + { self.sema.db.unwind_if_revision_cancelled(); let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone()); @@ -1324,9 +1329,9 @@ impl<'a> FindUsages<'a> { } fn is_excluded_name_ref(&self, name_ref: &ast::NameRef) -> bool { - (self.excluded_categories.contains(ReferenceCategory::TEST) + (!self.included_categories.contains(ReferenceCategory::TEST) && is_name_ref_in_test(self.sema, name_ref)) - || (self.excluded_categories.contains(ReferenceCategory::IMPORT) + || (!self.included_categories.contains(ReferenceCategory::IMPORT) && is_name_ref_in_import(name_ref)) } diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index ea32f0226783..6b60d9a621dd 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -131,17 +131,17 @@ pub(crate) fn find_all_refs( let exclude_library_refs = !is_library_file(sema.db, position.file_id); let make_searcher = |literal_search: bool| { move |def: Definition| { - let mut excluded_categories = ReferenceCategory::empty(); + let mut included_categories = ReferenceCategory::all(); if config.exclude_imports { - excluded_categories |= ReferenceCategory::IMPORT; + included_categories.remove(ReferenceCategory::IMPORT); } if config.exclude_tests { - excluded_categories |= ReferenceCategory::TEST; + included_categories.remove(ReferenceCategory::TEST); } let mut usages = def .usages(sema) .set_scope(config.search_scope.as_ref()) - .set_excluded_categories(excluded_categories) + .set_included_categories(included_categories) .set_exclude_library_files(exclude_library_refs) .include_self_refs() .all(); @@ -182,8 +182,7 @@ pub(crate) fn find_all_refs( is_mut: matches!(def, Definition::Local(l) if l.is_mut(sema.db)), nav, } - }) - .filter(|decl| !(exclude_library_refs && is_library_file(sema.db, decl.nav.file_id))); + }); ReferenceSearchResult { declaration, references } } }; @@ -582,6 +581,8 @@ pub fn also_calls_foo() { false, false, expect![[r#" + foo Function FileId(1) 0..15 7..10 + FileId(0) 9..12 import FileId(0) 31..34 "#]], @@ -598,6 +599,8 @@ fn main() { false, false, expect![[r#" + Some Variant FileId(1) 5999..6031 6024..6028 + FileId(0) 46..50 "#]], ); @@ -2244,6 +2247,8 @@ use proc_macros::identity; fn func() {} "#, expect![[r#" + identity Attribute FileId(1) 1..107 32..40 + FileId(0) 17..25 import FileId(0) 43..51 "#]], @@ -2273,6 +2278,8 @@ use proc_macros::mirror; mirror$0! {} "#, expect![[r#" + mirror ProcMacro FileId(1) 1..77 22..28 + FileId(0) 17..23 import FileId(0) 26..32 "#]], @@ -2291,6 +2298,8 @@ use proc_macros::DeriveIdentity; struct Foo; "#, expect![[r#" + derive_identity Derive FileId(2) 1..107 45..60 + FileId(0) 17..31 import FileId(0) 56..70 "#]],