aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ssr
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ssr')
-rw-r--r--crates/ra_ssr/src/lib.rs50
-rw-r--r--crates/ra_ssr/src/search.rs54
2 files changed, 56 insertions, 48 deletions
diff --git a/crates/ra_ssr/src/lib.rs b/crates/ra_ssr/src/lib.rs
index b28913a65..dac73c07c 100644
--- a/crates/ra_ssr/src/lib.rs
+++ b/crates/ra_ssr/src/lib.rs
@@ -6,6 +6,7 @@
6mod matching; 6mod matching;
7mod parsing; 7mod parsing;
8mod replacing; 8mod replacing;
9mod search;
9#[macro_use] 10#[macro_use]
10mod errors; 11mod errors;
11#[cfg(test)] 12#[cfg(test)]
@@ -83,7 +84,7 @@ impl<'db> MatchFinder<'db> {
83 let file = self.sema.parse(file_id); 84 let file = self.sema.parse(file_id);
84 let code = file.syntax(); 85 let code = file.syntax();
85 let mut matches = SsrMatches::default(); 86 let mut matches = SsrMatches::default();
86 self.find_matches(code, &None, &mut matches); 87 self.slow_scan_node(code, &None, &mut matches.matches);
87 matches 88 matches
88 } 89 }
89 90
@@ -120,53 +121,6 @@ impl<'db> MatchFinder<'db> {
120 } 121 }
121 } 122 }
122 123
123 fn find_matches(
124 &self,
125 code: &SyntaxNode,
126 restrict_range: &Option<FileRange>,
127 matches_out: &mut SsrMatches,
128 ) {
129 for rule in &self.rules {
130 if let Ok(mut m) = matching::get_match(false, rule, &code, restrict_range, &self.sema) {
131 // Continue searching in each of our placeholders.
132 for placeholder_value in m.placeholder_values.values_mut() {
133 if let Some(placeholder_node) = &placeholder_value.node {
134 // Don't search our placeholder if it's the entire matched node, otherwise we'd
135 // find the same match over and over until we got a stack overflow.
136 if placeholder_node != code {
137 self.find_matches(
138 placeholder_node,
139 restrict_range,
140 &mut placeholder_value.inner_matches,
141 );
142 }
143 }
144 }
145 matches_out.matches.push(m);
146 return;
147 }
148 }
149 // If we've got a macro call, we already tried matching it pre-expansion, which is the only
150 // way to match the whole macro, now try expanding it and matching the expansion.
151 if let Some(macro_call) = ast::MacroCall::cast(code.clone()) {
152 if let Some(expanded) = self.sema.expand(&macro_call) {
153 if let Some(tt) = macro_call.token_tree() {
154 // When matching within a macro expansion, we only want to allow matches of
155 // nodes that originated entirely from within the token tree of the macro call.
156 // i.e. we don't want to match something that came from the macro itself.
157 self.find_matches(
158 &expanded,
159 &Some(self.sema.original_range(tt.syntax())),
160 matches_out,
161 );
162 }
163 }
164 }
165 for child in code.children() {
166 self.find_matches(&child, restrict_range, matches_out);
167 }
168 }
169
170 fn output_debug_for_nodes_at_range( 124 fn output_debug_for_nodes_at_range(
171 &self, 125 &self,
172 node: &SyntaxNode, 126 node: &SyntaxNode,
diff --git a/crates/ra_ssr/src/search.rs b/crates/ra_ssr/src/search.rs
new file mode 100644
index 000000000..6f21452ac
--- /dev/null
+++ b/crates/ra_ssr/src/search.rs
@@ -0,0 +1,54 @@
1//! Searching for matches.
2
3use crate::{matching, Match, MatchFinder};
4use ra_db::FileRange;
5use ra_syntax::{ast, AstNode, SyntaxNode};
6
7impl<'db> MatchFinder<'db> {
8 pub(crate) fn slow_scan_node(
9 &self,
10 code: &SyntaxNode,
11 restrict_range: &Option<FileRange>,
12 matches_out: &mut Vec<Match>,
13 ) {
14 for rule in &self.rules {
15 if let Ok(mut m) = matching::get_match(false, rule, &code, restrict_range, &self.sema) {
16 // Continue searching in each of our placeholders.
17 for placeholder_value in m.placeholder_values.values_mut() {
18 if let Some(placeholder_node) = &placeholder_value.node {
19 // Don't search our placeholder if it's the entire matched node, otherwise we'd
20 // find the same match over and over until we got a stack overflow.
21 if placeholder_node != code {
22 self.slow_scan_node(
23 placeholder_node,
24 restrict_range,
25 &mut placeholder_value.inner_matches.matches,
26 );
27 }
28 }
29 }
30 matches_out.push(m);
31 return;
32 }
33 }
34 // If we've got a macro call, we already tried matching it pre-expansion, which is the only
35 // way to match the whole macro, now try expanding it and matching the expansion.
36 if let Some(macro_call) = ast::MacroCall::cast(code.clone()) {
37 if let Some(expanded) = self.sema.expand(&macro_call) {
38 if let Some(tt) = macro_call.token_tree() {
39 // When matching within a macro expansion, we only want to allow matches of
40 // nodes that originated entirely from within the token tree of the macro call.
41 // i.e. we don't want to match something that came from the macro itself.
42 self.slow_scan_node(
43 &expanded,
44 &Some(self.sema.original_range(tt.syntax())),
45 matches_out,
46 );
47 }
48 }
49 }
50 for child in code.children() {
51 self.slow_scan_node(&child, restrict_range, matches_out);
52 }
53 }
54}