aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/fn_references.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-09-29 13:36:11 +0100
committerGitHub <[email protected]>2020-09-29 13:36:11 +0100
commitbdc1f76cbda7478f39c190cc6ba296bc0030928f (patch)
tree91d3312e41626d40387d59e9243ae32b099eecb1 /crates/ide/src/fn_references.rs
parente813de6cdd53e542bce8d4a554288dc2f17bbf5e (diff)
parent91da41b3b13129007920943d7300459921faf3c5 (diff)
Merge #5928
5928: Add method references CodeLens r=vsrs a=vsrs The PR adds CodeLens for methods and free-standing functions: ![method_refs](https://user-images.githubusercontent.com/62505555/91858244-95fbfb00-ec71-11ea-90c7-5b3ee067e305.png) Relates to #5836 Co-authored-by: vsrs <[email protected]>
Diffstat (limited to 'crates/ide/src/fn_references.rs')
-rw-r--r--crates/ide/src/fn_references.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/crates/ide/src/fn_references.rs b/crates/ide/src/fn_references.rs
new file mode 100644
index 000000000..1989a562b
--- /dev/null
+++ b/crates/ide/src/fn_references.rs
@@ -0,0 +1,95 @@
1//! This module implements a methods and free functions search in the specified file.
2//! We have to skip tests, so cannot reuse file_structure module.
3
4use hir::Semantics;
5use ide_db::RootDatabase;
6use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode};
7
8use crate::{runnables::has_test_related_attribute, FileId, FileRange};
9
10pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRange> {
11 let sema = Semantics::new(db);
12 let source_file = sema.parse(file_id);
13 source_file.syntax().descendants().filter_map(|it| method_range(it, file_id)).collect()
14}
15
16fn method_range(item: SyntaxNode, file_id: FileId) -> Option<FileRange> {
17 ast::Fn::cast(item).and_then(|fn_def| {
18 if has_test_related_attribute(&fn_def) {
19 None
20 } else {
21 fn_def.name().map(|name| FileRange { file_id, range: name.syntax().text_range() })
22 }
23 })
24}
25
26#[cfg(test)]
27mod tests {
28 use crate::mock_analysis::analysis_and_position;
29 use crate::{FileRange, TextSize};
30 use std::ops::RangeInclusive;
31
32 #[test]
33 fn test_find_all_methods() {
34 let (analysis, pos) = analysis_and_position(
35 r#"
36 //- /lib.rs
37 fn private_fn() {<|>}
38
39 pub fn pub_fn() {}
40
41 pub fn generic_fn<T>(arg: T) {}
42 "#,
43 );
44
45 let refs = analysis.find_all_methods(pos.file_id).unwrap();
46 check_result(&refs, &[3..=13, 27..=33, 47..=57]);
47 }
48
49 #[test]
50 fn test_find_trait_methods() {
51 let (analysis, pos) = analysis_and_position(
52 r#"
53 //- /lib.rs
54 trait Foo {
55 fn bar() {<|>}
56 fn baz() {}
57 }
58 "#,
59 );
60
61 let refs = analysis.find_all_methods(pos.file_id).unwrap();
62 check_result(&refs, &[19..=22, 35..=38]);
63 }
64
65 #[test]
66 fn test_skip_tests() {
67 let (analysis, pos) = analysis_and_position(
68 r#"
69 //- /lib.rs
70 #[test]
71 fn foo() {<|>}
72
73 pub fn pub_fn() {}
74
75 mod tests {
76 #[test]
77 fn bar() {}
78 }
79 "#,
80 );
81
82 let refs = analysis.find_all_methods(pos.file_id).unwrap();
83 check_result(&refs, &[28..=34]);
84 }
85
86 fn check_result(refs: &[FileRange], expected: &[RangeInclusive<u32>]) {
87 assert_eq!(refs.len(), expected.len());
88
89 for (i, item) in refs.iter().enumerate() {
90 let range = &expected[i];
91 assert_eq!(TextSize::from(*range.start()), item.range.start());
92 assert_eq!(TextSize::from(*range.end()), item.range.end());
93 }
94 }
95}