Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/references.rs')
-rw-r--r--crates/ide/src/references.rs184
1 files changed, 179 insertions, 5 deletions
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 0288099bbc..4ed3d1c7d7 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},
@@ -91,6 +92,8 @@ pub struct Declaration {
pub struct FindAllRefsConfig<'a> {
pub search_scope: Option<SearchScope>,
pub ra_fixture: RaFixtureConfig<'a>,
+ pub exclude_imports: bool,
+ pub exclude_tests: bool,
}
/// Find all references to the item at the given position.
@@ -125,10 +128,23 @@ pub(crate) fn find_all_refs(
) -> Option<Vec<ReferenceSearchResult>> {
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 usages =
- def.usages(sema).set_scope(config.search_scope.as_ref()).include_self_refs().all();
+ let mut included_categories = ReferenceCategory::all();
+ if config.exclude_imports {
+ included_categories.remove(ReferenceCategory::IMPORT);
+ }
+ if config.exclude_tests {
+ included_categories.remove(ReferenceCategory::TEST);
+ }
+ let mut usages = def
+ .usages(sema)
+ .set_scope(config.search_scope.as_ref())
+ .set_included_categories(included_categories)
+ .set_exclude_library_files(exclude_library_refs)
+ .include_self_refs()
+ .all();
if literal_search {
retain_adt_literal_usages(&mut usages, def, sema);
}
@@ -207,6 +223,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,
@@ -469,7 +490,7 @@ mod tests {
#[test]
fn exclude_tests() {
- check(
+ check_with_filters(
r#"
fn test_func() {}
@@ -482,6 +503,8 @@ fn test() {
test_func();
}
"#,
+ false,
+ false,
expect![[r#"
test_func Function FileId(0) 0..17 3..12
@@ -490,7 +513,7 @@ fn test() {
"#]],
);
- check(
+ check_with_filters(
r#"
fn test_func() {}
@@ -503,6 +526,8 @@ fn test() {
test_func();
}
"#,
+ false,
+ false,
expect![[r#"
test_func Function FileId(0) 0..17 3..12
@@ -510,6 +535,133 @@ 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,
+ 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,
+ expect![[r#"
+ foo Function FileId(1) 0..15 7..10
+
+ 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,
+ expect![[r#"
+ Some Variant FileId(1) 5999..6031 6024..6028
+
+ 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,
+ 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
+
+ FileId(0) 9..12 import
+ FileId(0) 31..34
+ FileId(1) 47..50
+ "#]],
+ );
}
#[test]
@@ -1556,7 +1708,16 @@ 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, expect)
+ }
+
+ fn check_with_filters(
+ #[rust_analyzer::rust_fixture] ra_fixture: &str,
+ exclude_imports: bool,
+ exclude_tests: bool,
+ expect: Expect,
+ ) {
+ check_with_scope_and_filters(ra_fixture, None, exclude_imports, exclude_tests, expect)
}
fn check_with_scope(
@@ -1564,10 +1725,22 @@ fn main() {
search_scope: Option<&mut dyn FnMut(&RootDatabase) -> SearchScope>,
expect: Expect,
) {
+ check_with_scope_and_filters(ra_fixture, search_scope, 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,
+ 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,
};
let refs = analysis.find_all_refs(pos, &config).unwrap().unwrap();
@@ -2567,6 +2740,7 @@ fn test() {
fn goto_ref_fn_kw() {
check(
r#"
+//- minicore: fn
macro_rules! N {
($i:ident, $x:expr, $blk:expr) => {
for $i in 0..$x {