diff options
Diffstat (limited to 'crates/ra_ssr/src/search.rs')
-rw-r--r-- | crates/ra_ssr/src/search.rs | 65 |
1 files changed, 44 insertions, 21 deletions
diff --git a/crates/ra_ssr/src/search.rs b/crates/ra_ssr/src/search.rs index 141e7d026..bcf0f0468 100644 --- a/crates/ra_ssr/src/search.rs +++ b/crates/ra_ssr/src/search.rs | |||
@@ -46,35 +46,58 @@ impl<'db> MatchFinder<'db> { | |||
46 | usage_cache: &mut UsageCache, | 46 | usage_cache: &mut UsageCache, |
47 | matches_out: &mut Vec<Match>, | 47 | matches_out: &mut Vec<Match>, |
48 | ) { | 48 | ) { |
49 | if let Some(first_path) = pick_path_for_usages(pattern) { | 49 | if let Some(resolved_path) = pick_path_for_usages(pattern) { |
50 | let definition: Definition = first_path.resolution.clone().into(); | 50 | let definition: Definition = resolved_path.resolution.clone().into(); |
51 | for reference in self.find_usages(usage_cache, definition) { | 51 | for reference in self.find_usages(usage_cache, definition) { |
52 | let file = self.sema.parse(reference.file_range.file_id); | 52 | if let Some(node_to_match) = self.find_node_to_match(resolved_path, reference) { |
53 | if let Some(path) = self.sema.find_node_at_offset_with_descend::<ast::Path>( | 53 | if !is_search_permitted_ancestors(&node_to_match) { |
54 | file.syntax(), | 54 | mark::hit!(use_declaration_with_braces); |
55 | reference.file_range.range.start(), | 55 | continue; |
56 | ) { | 56 | } |
57 | if let Some(node_to_match) = self | 57 | if let Ok(m) = |
58 | .sema | 58 | matching::get_match(false, rule, &node_to_match, &None, &self.sema) |
59 | .ancestors_with_macros(path.syntax().clone()) | ||
60 | .skip(first_path.depth as usize) | ||
61 | .next() | ||
62 | { | 59 | { |
63 | if !is_search_permitted_ancestors(&node_to_match) { | 60 | matches_out.push(m); |
64 | mark::hit!(use_declaration_with_braces); | ||
65 | continue; | ||
66 | } | ||
67 | if let Ok(m) = | ||
68 | matching::get_match(false, rule, &node_to_match, &None, &self.sema) | ||
69 | { | ||
70 | matches_out.push(m); | ||
71 | } | ||
72 | } | 61 | } |
73 | } | 62 | } |
74 | } | 63 | } |
75 | } | 64 | } |
76 | } | 65 | } |
77 | 66 | ||
67 | fn find_node_to_match( | ||
68 | &self, | ||
69 | resolved_path: &ResolvedPath, | ||
70 | reference: &Reference, | ||
71 | ) -> Option<SyntaxNode> { | ||
72 | let file = self.sema.parse(reference.file_range.file_id); | ||
73 | let depth = resolved_path.depth as usize; | ||
74 | let offset = reference.file_range.range.start(); | ||
75 | if let Some(path) = | ||
76 | self.sema.find_node_at_offset_with_descend::<ast::Path>(file.syntax(), offset) | ||
77 | { | ||
78 | self.sema.ancestors_with_macros(path.syntax().clone()).skip(depth).next() | ||
79 | } else if let Some(path) = | ||
80 | self.sema.find_node_at_offset_with_descend::<ast::MethodCallExpr>(file.syntax(), offset) | ||
81 | { | ||
82 | // If the pattern contained a path and we found a reference to that path that wasn't | ||
83 | // itself a path, but was a method call, then we need to adjust how far up to try | ||
84 | // matching by how deep the path was within a CallExpr. The structure would have been | ||
85 | // CallExpr, PathExpr, Path - i.e. a depth offset of 2. We don't need to check if the | ||
86 | // path was part of a CallExpr because if it wasn't then all that will happen is we'll | ||
87 | // fail to match, which is the desired behavior. | ||
88 | const PATH_DEPTH_IN_CALL_EXPR: usize = 2; | ||
89 | if depth < PATH_DEPTH_IN_CALL_EXPR { | ||
90 | return None; | ||
91 | } | ||
92 | self.sema | ||
93 | .ancestors_with_macros(path.syntax().clone()) | ||
94 | .skip(depth - PATH_DEPTH_IN_CALL_EXPR) | ||
95 | .next() | ||
96 | } else { | ||
97 | None | ||
98 | } | ||
99 | } | ||
100 | |||
78 | fn find_usages<'a>( | 101 | fn find_usages<'a>( |
79 | &self, | 102 | &self, |
80 | usage_cache: &'a mut UsageCache, | 103 | usage_cache: &'a mut UsageCache, |