aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ssr/src/search.rs
diff options
context:
space:
mode:
authorDavid Lattimore <[email protected]>2020-07-22 07:48:12 +0100
committerDavid Lattimore <[email protected]>2020-07-24 12:34:00 +0100
commit02fc3d50ee4d179cc5a443a790544c2a5e439cb0 (patch)
treeebef46263fa32fc04f1838b8b6a5191ce8809184 /crates/ra_ssr/src/search.rs
parent699619a65cf816b927fffa77b2b38f611d8460bc (diff)
SSR: Refactor to not rely on recursive search for nesting of matches
Previously, submatches were handled simply by searching in placeholders for more matches. That only works if we search all nodes in the tree recursively. In a subsequent commit, I intend to make search not always be recursive recursive. This commit prepares for that by finding all matches, even if they overlap, then nesting them and removing overlapping matches.
Diffstat (limited to 'crates/ra_ssr/src/search.rs')
-rw-r--r--crates/ra_ssr/src/search.rs38
1 files changed, 13 insertions, 25 deletions
diff --git a/crates/ra_ssr/src/search.rs b/crates/ra_ssr/src/search.rs
index ec3addcf8..a28e9f341 100644
--- a/crates/ra_ssr/src/search.rs
+++ b/crates/ra_ssr/src/search.rs
@@ -1,17 +1,20 @@
1//! Searching for matches. 1//! Searching for matches.
2 2
3use crate::{matching, Match, MatchFinder}; 3use crate::{matching, parsing::ParsedRule, Match, MatchFinder};
4use ra_db::FileRange; 4use ra_db::FileRange;
5use ra_syntax::{ast, AstNode, SyntaxNode}; 5use ra_syntax::{ast, AstNode, SyntaxNode};
6 6
7impl<'db> MatchFinder<'db> { 7impl<'db> MatchFinder<'db> {
8 pub(crate) fn find_all_matches(&self, matches_out: &mut Vec<Match>) { 8 /// Adds all matches for `rule` to `matches_out`. Matches may overlap in ways that make
9 /// replacement impossible, so further processing is required in order to properly nest matches
10 /// and remove overlapping matches. This is done in the `nesting` module.
11 pub(crate) fn find_matches_for_rule(&self, rule: &ParsedRule, matches_out: &mut Vec<Match>) {
9 // FIXME: Use resolved paths in the pattern to find places to search instead of always 12 // FIXME: Use resolved paths in the pattern to find places to search instead of always
10 // scanning every node. 13 // scanning every node.
11 self.slow_scan(matches_out); 14 self.slow_scan(rule, matches_out);
12 } 15 }
13 16
14 fn slow_scan(&self, matches_out: &mut Vec<Match>) { 17 fn slow_scan(&self, rule: &ParsedRule, matches_out: &mut Vec<Match>) {
15 use ra_db::SourceDatabaseExt; 18 use ra_db::SourceDatabaseExt;
16 use ra_ide_db::symbol_index::SymbolsDatabase; 19 use ra_ide_db::symbol_index::SymbolsDatabase;
17 for &root in self.sema.db.local_roots().iter() { 20 for &root in self.sema.db.local_roots().iter() {
@@ -19,7 +22,7 @@ impl<'db> MatchFinder<'db> {
19 for file_id in sr.iter() { 22 for file_id in sr.iter() {
20 let file = self.sema.parse(file_id); 23 let file = self.sema.parse(file_id);
21 let code = file.syntax(); 24 let code = file.syntax();
22 self.slow_scan_node(code, &None, matches_out); 25 self.slow_scan_node(code, rule, &None, matches_out);
23 } 26 }
24 } 27 }
25 } 28 }
@@ -27,28 +30,12 @@ impl<'db> MatchFinder<'db> {
27 fn slow_scan_node( 30 fn slow_scan_node(
28 &self, 31 &self,
29 code: &SyntaxNode, 32 code: &SyntaxNode,
33 rule: &ParsedRule,
30 restrict_range: &Option<FileRange>, 34 restrict_range: &Option<FileRange>,
31 matches_out: &mut Vec<Match>, 35 matches_out: &mut Vec<Match>,
32 ) { 36 ) {
33 for rule in &self.rules { 37 if let Ok(m) = matching::get_match(false, rule, &code, restrict_range, &self.sema) {
34 if let Ok(mut m) = matching::get_match(false, rule, &code, restrict_range, &self.sema) { 38 matches_out.push(m);
35 // Continue searching in each of our placeholders.
36 for placeholder_value in m.placeholder_values.values_mut() {
37 if let Some(placeholder_node) = &placeholder_value.node {
38 // Don't search our placeholder if it's the entire matched node, otherwise we'd
39 // find the same match over and over until we got a stack overflow.
40 if placeholder_node != code {
41 self.slow_scan_node(
42 placeholder_node,
43 restrict_range,
44 &mut placeholder_value.inner_matches.matches,
45 );
46 }
47 }
48 }
49 matches_out.push(m);
50 return;
51 }
52 } 39 }
53 // If we've got a macro call, we already tried matching it pre-expansion, which is the only 40 // If we've got a macro call, we already tried matching it pre-expansion, which is the only
54 // way to match the whole macro, now try expanding it and matching the expansion. 41 // way to match the whole macro, now try expanding it and matching the expansion.
@@ -60,6 +47,7 @@ impl<'db> MatchFinder<'db> {
60 // i.e. we don't want to match something that came from the macro itself. 47 // i.e. we don't want to match something that came from the macro itself.
61 self.slow_scan_node( 48 self.slow_scan_node(
62 &expanded, 49 &expanded,
50 rule,
63 &Some(self.sema.original_range(tt.syntax())), 51 &Some(self.sema.original_range(tt.syntax())),
64 matches_out, 52 matches_out,
65 ); 53 );
@@ -67,7 +55,7 @@ impl<'db> MatchFinder<'db> {
67 } 55 }
68 } 56 }
69 for child in code.children() { 57 for child in code.children() {
70 self.slow_scan_node(&child, restrict_range, matches_out); 58 self.slow_scan_node(&child, rule, restrict_range, matches_out);
71 } 59 }
72 } 60 }
73} 61}