]> git.lizzy.rs Git - rust.git/blob - crates/ide/src/fn_references.rs
rename mock_analysis -> fixture
[rust.git] / crates / ide / src / fn_references.rs
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
4 use hir::Semantics;
5 use ide_db::RootDatabase;
6 use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode};
7
8 use crate::{runnables::has_test_related_attribute, FileId, FileRange};
9
10 pub(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
16 fn 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)]
27 mod tests {
28     use crate::fixture;
29     use crate::{FileRange, TextSize};
30     use std::ops::RangeInclusive;
31
32     #[test]
33     fn test_find_all_methods() {
34         let (analysis, pos) = fixture::position(
35             r#"
36             fn private_fn() {<|>}
37
38             pub fn pub_fn() {}
39
40             pub fn generic_fn<T>(arg: T) {}
41         "#,
42         );
43
44         let refs = analysis.find_all_methods(pos.file_id).unwrap();
45         check_result(&refs, &[3..=13, 27..=33, 47..=57]);
46     }
47
48     #[test]
49     fn test_find_trait_methods() {
50         let (analysis, pos) = fixture::position(
51             r#"
52             trait Foo {
53                 fn bar() {<|>}
54                 fn baz() {}
55             }
56         "#,
57         );
58
59         let refs = analysis.find_all_methods(pos.file_id).unwrap();
60         check_result(&refs, &[19..=22, 35..=38]);
61     }
62
63     #[test]
64     fn test_skip_tests() {
65         let (analysis, pos) = fixture::position(
66             r#"
67             //- /lib.rs
68             #[test]
69             fn foo() {<|>}
70
71             pub fn pub_fn() {}
72
73             mod tests {
74                 #[test]
75                 fn bar() {}
76             }
77         "#,
78         );
79
80         let refs = analysis.find_all_methods(pos.file_id).unwrap();
81         check_result(&refs, &[28..=34]);
82     }
83
84     fn check_result(refs: &[FileRange], expected: &[RangeInclusive<u32>]) {
85         assert_eq!(refs.len(), expected.len());
86
87         for (i, item) in refs.iter().enumerate() {
88             let range = &expected[i];
89             assert_eq!(TextSize::from(*range.start()), item.range.start());
90             assert_eq!(TextSize::from(*range.end()), item.range.end());
91         }
92     }
93 }