Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide/src/call_hierarchy.rs118
-rw-r--r--crates/ide/src/lib.rs18
-rw-r--r--crates/rust-analyzer/src/config.rs15
-rw-r--r--crates/rust-analyzer/src/handlers/request.rs6
-rw-r--r--docs/user/generated_config.adoc2
-rw-r--r--editors/code/package.json2
6 files changed, 141 insertions, 20 deletions
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index 155259a138..1b82c00d1d 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/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/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index c46c4c8ce9..3a8f7bb7a1 100644
--- a/crates/ide/src/lib.rs
+++ b/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/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index ef2e542cf2..518b588cb7 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/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/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 3a1770d770..a9f8ac3a80 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/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/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 708fc2b789..babeb4272b 100644
--- a/docs/user/generated_config.adoc
+++ b/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/editors/code/package.json b/editors/code/package.json
index a823e5bb96..a52b3d1ec5 100644
--- a/editors/code/package.json
+++ b/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"
}