about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-10-14 12:50:40 +0000
committerbors <bors@rust-lang.org>2024-10-14 12:50:40 +0000
commitd764d87c9fcd439d8b09c2bd59776bbea868cc46 (patch)
treeb6be33e291bc0b966357834d1bc499c63cba0172
parentb2048dfb9bef87dc325a31b46d28315895500396 (diff)
parent7bc615050f3d9bfd241360aabfc74943e0578060 (diff)
downloadrust-d764d87c9fcd439d8b09c2bd59776bbea868cc46.tar.gz
rust-d764d87c9fcd439d8b09c2bd59776bbea868cc46.zip
Auto merge of #18291 - roife:fix-issue-18212, r=Veykril
feat: respect references.exclude_tests in call-hierarchy

close #18212

### Changes

1. feat: respect `references.exclude_tests` in call-hierarchy
2. Modified the description of `references.exclude_tests`
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs118
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs18
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs15
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs6
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc2
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json2
6 files changed, 141 insertions, 20 deletions
diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
index 155259a1380..1b82c00d1dc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
@@ -19,6 +19,12 @@ pub struct CallItem {
     pub ranges: Vec<FileRange>,
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct CallHierarchyConfig {
+    /// Whether to exclude tests from the call hierarchy
+    pub exclude_tests: bool,
+}
+
 pub(crate) fn call_hierarchy(
     db: &RootDatabase,
     position: FilePosition,
@@ -28,6 +34,7 @@ pub(crate) fn call_hierarchy(
 
 pub(crate) fn incoming_calls(
     db: &RootDatabase,
+    CallHierarchyConfig { exclude_tests }: CallHierarchyConfig,
     FilePosition { file_id, offset }: FilePosition,
 ) -> Option<Vec<CallItem>> {
     let sema = &Semantics::new(db);
@@ -56,11 +63,18 @@ pub(crate) fn incoming_calls(
             references.iter().filter_map(|FileReference { name, .. }| name.as_name_ref());
         for name in references {
             // This target is the containing function
-            let nav = sema.ancestors_with_macros(name.syntax().clone()).find_map(|node| {
+            let def_nav = sema.ancestors_with_macros(name.syntax().clone()).find_map(|node| {
                 let def = ast::Fn::cast(node).and_then(|fn_| sema.to_def(&fn_))?;
-                def.try_to_nav(sema.db)
+                // We should return def before check if it is a test, so that we
+                // will not continue to search for outer fn in nested fns
+                def.try_to_nav(sema.db).map(|nav| (def, nav))
             });
-            if let Some(nav) = nav {
+
+            if let Some((def, nav)) = def_nav {
+                if exclude_tests && def.is_test(db) {
+                    continue;
+                }
+
                 let range = sema.original_range(name.syntax());
                 calls.add(nav.call_site, range.into());
                 if let Some(other) = nav.def_site {
@@ -75,6 +89,7 @@ pub(crate) fn incoming_calls(
 
 pub(crate) fn outgoing_calls(
     db: &RootDatabase,
+    CallHierarchyConfig { exclude_tests }: CallHierarchyConfig,
     FilePosition { file_id, offset }: FilePosition,
 ) -> Option<Vec<CallItem>> {
     let sema = Semantics::new(db);
@@ -103,7 +118,12 @@ pub(crate) fn outgoing_calls(
                     let expr = call.expr()?;
                     let callable = sema.type_of_expr(&expr)?.original.as_callable(db)?;
                     match callable.kind() {
-                        hir::CallableKind::Function(it) => it.try_to_nav(db),
+                        hir::CallableKind::Function(it) => {
+                            if exclude_tests && it.is_test(db) {
+                                return None;
+                            }
+                            it.try_to_nav(db)
+                        }
                         hir::CallableKind::TupleEnumVariant(it) => it.try_to_nav(db),
                         hir::CallableKind::TupleStruct(it) => it.try_to_nav(db),
                         _ => None,
@@ -112,6 +132,9 @@ pub(crate) fn outgoing_calls(
                 }
                 ast::CallableExpr::MethodCall(expr) => {
                     let function = sema.resolve_method_call(&expr)?;
+                    if exclude_tests && function.is_test(db) {
+                        return None;
+                    }
                     function
                         .try_to_nav(db)
                         .zip(Some(sema.original_range(expr.name_ref()?.syntax())))
@@ -149,6 +172,7 @@ mod tests {
     use crate::fixture;
 
     fn check_hierarchy(
+        exclude_tests: bool,
         ra_fixture: &str,
         expected_nav: Expect,
         expected_incoming: Expect,
@@ -172,18 +196,21 @@ mod tests {
         let nav = navs.pop().unwrap();
         expected_nav.assert_eq(&nav.debug_render());
 
+        let config = crate::CallHierarchyConfig { exclude_tests };
+
         let item_pos =
             FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
-        let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap();
+        let incoming_calls = analysis.incoming_calls(config, item_pos).unwrap().unwrap();
         expected_incoming.assert_eq(&incoming_calls.into_iter().map(debug_render).join("\n"));
 
-        let outgoing_calls = analysis.outgoing_calls(item_pos).unwrap().unwrap();
+        let outgoing_calls = analysis.outgoing_calls(config, item_pos).unwrap().unwrap();
         expected_outgoing.assert_eq(&outgoing_calls.into_iter().map(debug_render).join("\n"));
     }
 
     #[test]
     fn test_call_hierarchy_on_ref() {
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 fn callee() {}
@@ -200,6 +227,7 @@ fn caller() {
     #[test]
     fn test_call_hierarchy_on_def() {
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 fn call$0ee() {}
@@ -216,6 +244,7 @@ fn caller() {
     #[test]
     fn test_call_hierarchy_in_same_fn() {
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 fn callee() {}
@@ -233,6 +262,7 @@ fn caller() {
     #[test]
     fn test_call_hierarchy_in_different_fn() {
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 fn callee() {}
@@ -255,6 +285,7 @@ fn caller2() {
     #[test]
     fn test_call_hierarchy_in_tests_mod() {
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs cfg:test
 fn callee() {}
@@ -283,6 +314,7 @@ mod tests {
     #[test]
     fn test_call_hierarchy_in_different_files() {
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 mod foo;
@@ -304,6 +336,7 @@ pub fn callee() {}
     #[test]
     fn test_call_hierarchy_outgoing() {
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 fn callee() {}
@@ -321,6 +354,7 @@ fn call$0er() {
     #[test]
     fn test_call_hierarchy_outgoing_in_different_files() {
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 mod foo;
@@ -342,6 +376,7 @@ pub fn callee() {}
     #[test]
     fn test_call_hierarchy_incoming_outgoing() {
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 fn caller1() {
@@ -365,6 +400,7 @@ fn caller3() {
     #[test]
     fn test_call_hierarchy_issue_5103() {
         check_hierarchy(
+            false,
             r#"
 fn a() {
     b()
@@ -382,6 +418,7 @@ fn main() {
         );
 
         check_hierarchy(
+            false,
             r#"
 fn a() {
     b$0()
@@ -402,6 +439,7 @@ fn main() {
     #[test]
     fn test_call_hierarchy_in_macros_incoming() {
         check_hierarchy(
+            false,
             r#"
 macro_rules! define {
     ($ident:ident) => {
@@ -423,6 +461,7 @@ fn caller() {
             expect![[]],
         );
         check_hierarchy(
+            false,
             r#"
 macro_rules! define {
     ($ident:ident) => {
@@ -448,6 +487,7 @@ fn caller() {
     #[test]
     fn test_call_hierarchy_in_macros_outgoing() {
         check_hierarchy(
+            false,
             r#"
 macro_rules! define {
     ($ident:ident) => {
@@ -473,6 +513,7 @@ fn caller$0() {
     #[test]
     fn test_call_hierarchy_in_macros_incoming_different_files() {
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 #[macro_use]
@@ -498,6 +539,7 @@ macro_rules! call {
             expect![[]],
         );
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 #[macro_use]
@@ -523,6 +565,7 @@ macro_rules! call {
             expect![[]],
         );
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 #[macro_use]
@@ -558,6 +601,7 @@ macro_rules! call {
     #[test]
     fn test_call_hierarchy_in_macros_outgoing_different_files() {
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 #[macro_use]
@@ -585,6 +629,7 @@ macro_rules! call {
             expect![[]],
         );
         check_hierarchy(
+            false,
             r#"
 //- /lib.rs
 #[macro_use]
@@ -616,6 +661,7 @@ macro_rules! call {
     #[test]
     fn test_trait_method_call_hierarchy() {
         check_hierarchy(
+            false,
             r#"
 trait T1 {
     fn call$0ee();
@@ -636,4 +682,64 @@ fn caller() {
             expect![[]],
         );
     }
+
+    #[test]
+    fn test_call_hierarchy_excluding_tests() {
+        check_hierarchy(
+            false,
+            r#"
+fn main() {
+    f1();
+}
+
+fn f1$0() {
+    f2(); f3();
+}
+
+fn f2() {
+    f1(); f3();
+}
+
+#[test]
+fn f3() {
+    f1(); f2();
+}
+"#,
+            expect!["f1 Function FileId(0) 25..52 28..30"],
+            expect![[r#"
+                main Function FileId(0) 0..23 3..7 : FileId(0):16..18
+                f2 Function FileId(0) 54..81 57..59 : FileId(0):68..70
+                f3 Function FileId(0) 83..118 94..96 : FileId(0):105..107"#]],
+            expect![[r#"
+                f2 Function FileId(0) 54..81 57..59 : FileId(0):39..41
+                f3 Function FileId(0) 83..118 94..96 : FileId(0):45..47"#]],
+        );
+
+        check_hierarchy(
+            true,
+            r#"
+fn main() {
+    f1();
+}
+
+fn f1$0() {
+    f2(); f3();
+}
+
+fn f2() {
+    f1(); f3();
+}
+
+#[test]
+fn f3() {
+    f1(); f2();
+}
+"#,
+            expect!["f1 Function FileId(0) 25..52 28..30"],
+            expect![[r#"
+                main Function FileId(0) 0..23 3..7 : FileId(0):16..18
+                f2 Function FileId(0) 54..81 57..59 : FileId(0):68..70"#]],
+            expect!["f2 Function FileId(0) 54..81 57..59 : FileId(0):39..41"],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index c46c4c8ce94..3a8f7bb7a1a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -79,7 +79,7 @@ use crate::navigation_target::ToNav;
 
 pub use crate::{
     annotations::{Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation},
-    call_hierarchy::CallItem,
+    call_hierarchy::{CallHierarchyConfig, CallItem},
     expand_macro::ExpandedMacro,
     file_structure::{StructureNode, StructureNodeKind},
     folding_ranges::{Fold, FoldKind},
@@ -564,13 +564,21 @@ impl Analysis {
     }
 
     /// Computes incoming calls for the given file position.
-    pub fn incoming_calls(&self, position: FilePosition) -> Cancellable<Option<Vec<CallItem>>> {
-        self.with_db(|db| call_hierarchy::incoming_calls(db, position))
+    pub fn incoming_calls(
+        &self,
+        config: CallHierarchyConfig,
+        position: FilePosition,
+    ) -> Cancellable<Option<Vec<CallItem>>> {
+        self.with_db(|db| call_hierarchy::incoming_calls(db, config, position))
     }
 
     /// Computes outgoing calls for the given file position.
-    pub fn outgoing_calls(&self, position: FilePosition) -> Cancellable<Option<Vec<CallItem>>> {
-        self.with_db(|db| call_hierarchy::outgoing_calls(db, position))
+    pub fn outgoing_calls(
+        &self,
+        config: CallHierarchyConfig,
+        position: FilePosition,
+    ) -> Cancellable<Option<Vec<CallItem>>> {
+        self.with_db(|db| call_hierarchy::outgoing_calls(db, config, position))
     }
 
     /// Returns a `mod name;` declaration which created the current module.
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index ef2e542cf22..518b588cb7d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -12,10 +12,11 @@ use std::{
 use cfg::{CfgAtom, CfgDiff};
 use hir::Symbol;
 use ide::{
-    AssistConfig, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, DiagnosticsConfig,
-    ExprFillDefaultMode, GenericParameterHints, HighlightConfig, HighlightRelatedConfig,
-    HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig,
-    MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope, SourceRootId,
+    AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
+    CompletionFieldsToResolve, DiagnosticsConfig, ExprFillDefaultMode, GenericParameterHints,
+    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
+    InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
+    Snippet, SnippetScope, SourceRootId,
 };
 use ide_db::{
     imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
@@ -262,7 +263,7 @@ config_data! {
         /// Exclude imports from find-all-references.
         references_excludeImports: bool = false,
 
-        /// Exclude tests from find-all-references.
+        /// Exclude tests from find-all-references and call-hierarchy.
         references_excludeTests: bool = false,
 
         /// Inject additional highlighting into doc comments.
@@ -1392,6 +1393,10 @@ impl Config {
         }
     }
 
+    pub fn call_hierarchy(&self) -> CallHierarchyConfig {
+        CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned() }
+    }
+
     pub fn completion(&self, source_root: Option<SourceRootId>) -> CompletionConfig {
         let client_capability_fields = self.completion_resolve_support_properties();
         CompletionConfig {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 3a1770d770d..a9f8ac3a80a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -1708,7 +1708,8 @@ pub(crate) fn handle_call_hierarchy_incoming(
     let frange = from_proto::file_range(&snap, &doc, item.selection_range)?;
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 
-    let call_items = match snap.analysis.incoming_calls(fpos)? {
+    let config = snap.config.call_hierarchy();
+    let call_items = match snap.analysis.incoming_calls(config, fpos)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -1745,7 +1746,8 @@ pub(crate) fn handle_call_hierarchy_outgoing(
     let frange = from_proto::file_range(&snap, &doc, item.selection_range)?;
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 
-    let call_items = match snap.analysis.outgoing_calls(fpos)? {
+    let config = snap.config.call_hierarchy();
+    let call_items = match snap.analysis.outgoing_calls(config, fpos)? {
         None => return Ok(None),
         Some(it) => it,
     };
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index 708fc2b7891..babeb4272be 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -852,7 +852,7 @@ Exclude imports from find-all-references.
 [[rust-analyzer.references.excludeTests]]rust-analyzer.references.excludeTests (default: `false`)::
 +
 --
-Exclude tests from find-all-references.
+Exclude tests from find-all-references and call-hierarchy.
 --
 [[rust-analyzer.runnables.command]]rust-analyzer.runnables.command (default: `null`)::
 +
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index a823e5bb96c..a52b3d1ec5c 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -2333,7 +2333,7 @@
                 "title": "references",
                 "properties": {
                     "rust-analyzer.references.excludeTests": {
-                        "markdownDescription": "Exclude tests from find-all-references.",
+                        "markdownDescription": "Exclude tests from find-all-references and call-hierarchy.",
                         "default": false,
                         "type": "boolean"
                     }