aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ssr/src/search.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ssr/src/search.rs')
-rw-r--r--crates/ra_ssr/src/search.rs65
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,