diff options
Diffstat (limited to 'crates/ra_ssr/src/search.rs')
-rw-r--r-- | crates/ra_ssr/src/search.rs | 54 |
1 files changed, 54 insertions, 0 deletions
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 | |||
3 | use crate::{matching, Match, MatchFinder}; | ||
4 | use ra_db::FileRange; | ||
5 | use ra_syntax::{ast, AstNode, SyntaxNode}; | ||
6 | |||
7 | impl<'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(¯o_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 | } | ||