From 6f303f49fed35a0101b5fce1977bf719045d97df Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Sun, 28 Jan 2024 18:28:13 +0800 Subject: [PATCH 1/4] feat: enable excluding refs search results in test --- crates/ide-db/src/search.rs | 37 +++++++++++++++++++- crates/ide/src/highlight_related.rs | 1 + crates/ide/src/references.rs | 3 +- crates/rust-analyzer/src/config.rs | 7 ++++ crates/rust-analyzer/src/handlers/request.rs | 4 ++- crates/rust-analyzer/src/lsp/to_proto.rs | 1 + docs/user/generated_config.adoc | 5 +++ editors/code/package.json | 5 +++ 8 files changed, 60 insertions(+), 3 deletions(-) diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 7769d8fba1..5aa4186f82 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -15,7 +15,10 @@ use memchr::memmem::Finder; use nohash_hasher::IntMap; use once_cell::unsync::Lazy; use parser::SyntaxKind; -use syntax::{ast, match_ast, AstNode, AstToken, SyntaxElement, TextRange, TextSize}; +use syntax::{ + ast::{self, HasAttrs as _}, + match_ast, AstNode, AstToken, SyntaxElement, TextRange, TextSize, +}; use triomphe::Arc; use crate::{ @@ -134,6 +137,7 @@ pub enum ReferenceCategory { // FIXME: Some day should be able to search in doc comments. Would probably // need to switch from enum to bitflags then? // DocComment + Test, } /// Generally, `search_scope` returns files that might contain references for the element. @@ -872,6 +876,10 @@ fn def_to_ty(sema: &Semantics<'_, RootDatabase>, def: &Definition) -> Option Option { + if is_name_ref_in_test(r) { + return Some(ReferenceCategory::Test); + } + // Only Locals and Fields have accesses for now. if !matches!(def, Definition::Local(_) | Definition::Field(_)) { return is_name_ref_in_import(r).then_some(ReferenceCategory::Import); @@ -910,3 +918,30 @@ fn is_name_ref_in_import(name_ref: &ast::NameRef) -> bool { .and_then(|it| it.parent_path().top_path().syntax().parent()) .map_or(false, |it| it.kind() == SyntaxKind::USE_TREE) } + +fn is_name_ref_in_test(name_ref: &ast::NameRef) -> bool { + let mode = name_ref.syntax().ancestors().find_map(|node| { + match_ast! { + match node { + ast::Fn(f) => { + let attrs = f.attrs(); + let mut is_test = false; + for attr in attrs { + if attr.to_string() == "#[test]" { + is_test = true; + break; + } + } + if is_test { + Some(ReferenceCategory::Test) + } + else { + None + } + }, + _ => None + } + } + }); + mode.is_some() +} diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs index c3a403b107..53ed117060 100644 --- a/crates/ide/src/highlight_related.rs +++ b/crates/ide/src/highlight_related.rs @@ -519,6 +519,7 @@ mod tests { ReferenceCategory::Read => "read", ReferenceCategory::Write => "write", ReferenceCategory::Import => "import", + ReferenceCategory::Test => "test", } .to_string() }), diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 78fe84f70d..bcf862012a 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -454,6 +454,7 @@ fn main() { "#]], ); } + #[test] fn test_variant_tuple_before_paren() { check( @@ -1435,7 +1436,7 @@ fn test$0() { expect![[r#" test Function FileId(0) 0..33 11..15 - FileId(0) 24..28 + FileId(0) 24..28 Test "#]], ); } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 3c1b464c3c..eeb28b8fe4 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -494,6 +494,9 @@ config_data! { /// Exclude imports from find-all-references. references_excludeImports: bool = "false", + /// Exclude tests from find-all-references. + references_excludeTests: bool = "false", + /// Allow renaming of items not belonging to the loaded workspaces. rename_allowExternalItems: bool = "false", @@ -1545,6 +1548,10 @@ impl Config { self.data.references_excludeImports } + pub fn find_all_refs_exclude_tests(&self) -> bool { + self.data.references_excludeTests + } + pub fn snippet_cap(&self) -> bool { self.experimental("snippetTextEdit") } diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index f3c2df24d9..03725daedd 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -1055,6 +1055,7 @@ pub(crate) fn handle_references( let position = from_proto::file_position(&snap, params.text_document_position)?; let exclude_imports = snap.config.find_all_refs_exclude_imports(); + let exclude_tests = snap.config.find_all_refs_exclude_tests(); let refs = match snap.analysis.find_all_refs(position, None)? { None => return Ok(None), @@ -1078,7 +1079,8 @@ pub(crate) fn handle_references( .flat_map(|(file_id, refs)| { refs.into_iter() .filter(|&(_, category)| { - !exclude_imports || category != Some(ReferenceCategory::Import) + (!exclude_imports || category != Some(ReferenceCategory::Import)) + && (!exclude_tests || category != Some(ReferenceCategory::Test)) }) .map(move |(range, _)| FileRange { file_id, range }) }) diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs index fe381fbeb3..f221863aff 100644 --- a/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/crates/rust-analyzer/src/lsp/to_proto.rs @@ -92,6 +92,7 @@ pub(crate) fn document_highlight_kind( ReferenceCategory::Read => Some(lsp_types::DocumentHighlightKind::READ), ReferenceCategory::Write => Some(lsp_types::DocumentHighlightKind::WRITE), ReferenceCategory::Import => None, + ReferenceCategory::Test => None, } } diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index f887bb9df3..cfa7503d73 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -777,6 +777,11 @@ Internal config, path to proc-macro server executable. -- Exclude imports from find-all-references. -- +[[rust-analyzer.references.excludeTests]]rust-analyzer.references.excludeTests (default: `false`):: ++ +-- +Exclude tests from find-all-references. +-- [[rust-analyzer.rename.allowExternalItems]]rust-analyzer.rename.allowExternalItems (default: `false`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index 5ed5146ea1..841e364ed8 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -1505,6 +1505,11 @@ "default": false, "type": "boolean" }, + "rust-analyzer.references.excludeTests": { + "markdownDescription": "Exclude tests from find-all-references.", + "default": false, + "type": "boolean" + }, "rust-analyzer.rename.allowExternalItems": { "markdownDescription": "Allow renaming of items not belonging to the loaded workspaces.", "default": false, From 1bd21e98c0b67097b7c242e6ebc24085bfba982c Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Sun, 28 Jan 2024 18:39:42 +0800 Subject: [PATCH 2/4] test: add test for excluding refs --- crates/ide/src/references.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index bcf862012a..4b695612a6 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -307,6 +307,30 @@ mod tests { use crate::{fixture, SearchScope}; + #[test] + fn exclude_tests() { + check( + r#" +fn test_func() {} + +fn func() { + test_func$0(); +} + +#[test] +fn test() { + test_func(); +} +"#, + expect![[r#" + test_func Function FileId(0) 0..17 3..12 + + FileId(0) 35..44 + FileId(0) 75..84 Test + "#]], + ); + } + #[test] fn test_struct_literal_after_space() { check( From 618110256752ce2c3b5873b51f458609cca901bc Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Mon, 29 Jan 2024 18:42:41 +0800 Subject: [PATCH 3/4] fix: use Semantics to judge whether a func is marked as #[test] --- crates/ide-db/src/search.rs | 53 ++++++++++++------------------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/crates/ide-db/src/search.rs b/crates/ide-db/src/search.rs index 5aa4186f82..7be3ddd7e3 100644 --- a/crates/ide-db/src/search.rs +++ b/crates/ide-db/src/search.rs @@ -15,10 +15,7 @@ use memchr::memmem::Finder; use nohash_hasher::IntMap; use once_cell::unsync::Lazy; use parser::SyntaxKind; -use syntax::{ - ast::{self, HasAttrs as _}, - match_ast, AstNode, AstToken, SyntaxElement, TextRange, TextSize, -}; +use syntax::{ast, match_ast, AstNode, AstToken, SyntaxElement, TextRange, TextSize}; use triomphe::Arc; use crate::{ @@ -747,7 +744,7 @@ impl<'a> FindUsages<'a> { let reference = FileReference { range, name: FileReferenceNode::NameRef(name_ref.clone()), - category: ReferenceCategory::new(&def, name_ref), + category: ReferenceCategory::new(self.sema, &def, name_ref), }; sink(file_id, reference) } @@ -763,7 +760,7 @@ impl<'a> FindUsages<'a> { let reference = FileReference { range, name: FileReferenceNode::NameRef(name_ref.clone()), - category: ReferenceCategory::new(&def, name_ref), + category: ReferenceCategory::new(self.sema, &def, name_ref), }; sink(file_id, reference) } @@ -773,7 +770,7 @@ impl<'a> FindUsages<'a> { let reference = FileReference { range, name: FileReferenceNode::NameRef(name_ref.clone()), - category: ReferenceCategory::new(&def, name_ref), + category: ReferenceCategory::new(self.sema, &def, name_ref), }; sink(file_id, reference) } else { @@ -787,10 +784,10 @@ impl<'a> FindUsages<'a> { let local = Definition::Local(local); let access = match self.def { Definition::Field(_) if field == self.def => { - ReferenceCategory::new(&field, name_ref) + ReferenceCategory::new(self.sema, &field, name_ref) } Definition::Local(_) if local == self.def => { - ReferenceCategory::new(&local, name_ref) + ReferenceCategory::new(self.sema, &local, name_ref) } _ => return false, }; @@ -875,8 +872,12 @@ fn def_to_ty(sema: &Semantics<'_, RootDatabase>, def: &Definition) -> Option Option { - if is_name_ref_in_test(r) { + fn new( + sema: &Semantics<'_, RootDatabase>, + def: &Definition, + r: &ast::NameRef, + ) -> Option { + if is_name_ref_in_test(sema, r) { return Some(ReferenceCategory::Test); } @@ -919,29 +920,9 @@ fn is_name_ref_in_import(name_ref: &ast::NameRef) -> bool { .map_or(false, |it| it.kind() == SyntaxKind::USE_TREE) } -fn is_name_ref_in_test(name_ref: &ast::NameRef) -> bool { - let mode = name_ref.syntax().ancestors().find_map(|node| { - match_ast! { - match node { - ast::Fn(f) => { - let attrs = f.attrs(); - let mut is_test = false; - for attr in attrs { - if attr.to_string() == "#[test]" { - is_test = true; - break; - } - } - if is_test { - Some(ReferenceCategory::Test) - } - else { - None - } - }, - _ => None - } - } - }); - mode.is_some() +fn is_name_ref_in_test(sema: &Semantics<'_, RootDatabase>, name_ref: &ast::NameRef) -> bool { + name_ref.syntax().ancestors().any(|node| match ast::Fn::cast(node) { + Some(it) => sema.to_def(&it).map_or(false, |func| func.is_test(sema.db)), + None => false, + }) } From 2b71acac4f07565907cc19737b92b63750911c3f Mon Sep 17 00:00:00 2001 From: Young-Flash Date: Mon, 29 Jan 2024 18:47:58 +0800 Subject: [PATCH 4/4] test: add full path ref exclude test case --- crates/ide/src/references.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 4b695612a6..9a58e0b406 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -329,6 +329,27 @@ fn test() { FileId(0) 75..84 Test "#]], ); + + check( + r#" +fn test_func() {} + +fn func() { + test_func$0(); +} + +#[::core::prelude::v1::test] +fn test() { + test_func(); +} +"#, + expect![[r#" + test_func Function FileId(0) 0..17 3..12 + + FileId(0) 35..44 + FileId(0) 96..105 Test + "#]], + ); } #[test]