• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_assists::utils::test_related_attribute;
6 use ide_db::RootDatabase;
7 use syntax::{ast, ast::HasName, AstNode, SyntaxNode, TextRange};
8 
9 use crate::FileId;
10 
find_all_methods( db: &RootDatabase, file_id: FileId, ) -> Vec<(TextRange, Option<TextRange>)>11 pub(super) fn find_all_methods(
12     db: &RootDatabase,
13     file_id: FileId,
14 ) -> Vec<(TextRange, Option<TextRange>)> {
15     let sema = Semantics::new(db);
16     let source_file = sema.parse(file_id);
17     source_file.syntax().descendants().filter_map(|it| method_range(it)).collect()
18 }
19 
method_range(item: SyntaxNode) -> Option<(TextRange, Option<TextRange>)>20 fn method_range(item: SyntaxNode) -> Option<(TextRange, Option<TextRange>)> {
21     ast::Fn::cast(item).and_then(|fn_def| {
22         if test_related_attribute(&fn_def).is_some() {
23             None
24         } else {
25             Some((
26                 fn_def.syntax().text_range(),
27                 fn_def.name().map(|name| name.syntax().text_range()),
28             ))
29         }
30     })
31 }
32 
33 #[cfg(test)]
34 mod tests {
35     use syntax::TextRange;
36 
37     use crate::fixture;
38     use crate::TextSize;
39     use std::ops::RangeInclusive;
40 
41     #[test]
test_find_all_methods()42     fn test_find_all_methods() {
43         let (analysis, pos) = fixture::position(
44             r#"
45             fn private_fn() {$0}
46 
47             pub fn pub_fn() {}
48 
49             pub fn generic_fn<T>(arg: T) {}
50         "#,
51         );
52 
53         let refs = super::find_all_methods(&analysis.db, pos.file_id);
54         check_result(&refs, &[3..=13, 27..=33, 47..=57]);
55     }
56 
57     #[test]
test_find_trait_methods()58     fn test_find_trait_methods() {
59         let (analysis, pos) = fixture::position(
60             r#"
61             trait Foo {
62                 fn bar() {$0}
63                 fn baz() {}
64             }
65         "#,
66         );
67 
68         let refs = super::find_all_methods(&analysis.db, pos.file_id);
69         check_result(&refs, &[19..=22, 35..=38]);
70     }
71 
72     #[test]
test_skip_tests()73     fn test_skip_tests() {
74         let (analysis, pos) = fixture::position(
75             r#"
76             //- /lib.rs
77             #[test]
78             fn foo() {$0}
79 
80             pub fn pub_fn() {}
81 
82             mod tests {
83                 #[test]
84                 fn bar() {}
85             }
86         "#,
87         );
88 
89         let refs = super::find_all_methods(&analysis.db, pos.file_id);
90         check_result(&refs, &[28..=34]);
91     }
92 
check_result(refs: &[(TextRange, Option<TextRange>)], expected: &[RangeInclusive<u32>])93     fn check_result(refs: &[(TextRange, Option<TextRange>)], expected: &[RangeInclusive<u32>]) {
94         assert_eq!(refs.len(), expected.len());
95 
96         for (i, &(full, focus)) in refs.iter().enumerate() {
97             let range = &expected[i];
98             let item = focus.unwrap_or(full);
99             assert_eq!(TextSize::from(*range.start()), item.start());
100             assert_eq!(TextSize::from(*range.end()), item.end());
101         }
102     }
103 }
104