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.rs87
1 files changed, 64 insertions, 23 deletions
diff --git a/crates/ra_ssr/src/search.rs b/crates/ra_ssr/src/search.rs
index bcf0f0468..0f512cb62 100644
--- a/crates/ra_ssr/src/search.rs
+++ b/crates/ra_ssr/src/search.rs
@@ -5,12 +5,13 @@ use crate::{
5 resolving::{ResolvedPath, ResolvedPattern, ResolvedRule}, 5 resolving::{ResolvedPath, ResolvedPattern, ResolvedRule},
6 Match, MatchFinder, 6 Match, MatchFinder,
7}; 7};
8use ra_db::FileRange; 8use ra_db::{FileId, FileRange};
9use ra_ide_db::{ 9use ra_ide_db::{
10 defs::Definition, 10 defs::Definition,
11 search::{Reference, SearchScope}, 11 search::{Reference, SearchScope},
12}; 12};
13use ra_syntax::{ast, AstNode, SyntaxKind, SyntaxNode}; 13use ra_syntax::{ast, AstNode, SyntaxKind, SyntaxNode};
14use rustc_hash::FxHashSet;
14use test_utils::mark; 15use test_utils::mark;
15 16
16/// A cache for the results of find_usages. This is for when we have multiple patterns that have the 17/// A cache for the results of find_usages. This is for when we have multiple patterns that have the
@@ -54,11 +55,7 @@ impl<'db> MatchFinder<'db> {
54 mark::hit!(use_declaration_with_braces); 55 mark::hit!(use_declaration_with_braces);
55 continue; 56 continue;
56 } 57 }
57 if let Ok(m) = 58 self.try_add_match(rule, &node_to_match, &None, matches_out);
58 matching::get_match(false, rule, &node_to_match, &None, &self.sema)
59 {
60 matches_out.push(m);
61 }
62 } 59 }
63 } 60 }
64 } 61 }
@@ -121,25 +118,39 @@ impl<'db> MatchFinder<'db> {
121 // FIXME: We should ideally have a test that checks that we edit local roots and not library 118 // FIXME: We should ideally have a test that checks that we edit local roots and not library
122 // roots. This probably would require some changes to fixtures, since currently everything 119 // roots. This probably would require some changes to fixtures, since currently everything
123 // seems to get put into a single source root. 120 // seems to get put into a single source root.
124 use ra_db::SourceDatabaseExt;
125 use ra_ide_db::symbol_index::SymbolsDatabase;
126 let mut files = Vec::new(); 121 let mut files = Vec::new();
127 for &root in self.sema.db.local_roots().iter() { 122 self.search_files_do(|file_id| {
128 let sr = self.sema.db.source_root(root); 123 files.push(file_id);
129 files.extend(sr.iter()); 124 });
130 }
131 SearchScope::files(&files) 125 SearchScope::files(&files)
132 } 126 }
133 127
134 fn slow_scan(&self, rule: &ResolvedRule, matches_out: &mut Vec<Match>) { 128 fn slow_scan(&self, rule: &ResolvedRule, matches_out: &mut Vec<Match>) {
135 use ra_db::SourceDatabaseExt; 129 self.search_files_do(|file_id| {
136 use ra_ide_db::symbol_index::SymbolsDatabase; 130 let file = self.sema.parse(file_id);
137 for &root in self.sema.db.local_roots().iter() { 131 let code = file.syntax();
138 let sr = self.sema.db.source_root(root); 132 self.slow_scan_node(code, rule, &None, matches_out);
139 for file_id in sr.iter() { 133 })
140 let file = self.sema.parse(file_id); 134 }
141 let code = file.syntax(); 135
142 self.slow_scan_node(code, rule, &None, matches_out); 136 fn search_files_do(&self, mut callback: impl FnMut(FileId)) {
137 if self.restrict_ranges.is_empty() {
138 // Unrestricted search.
139 use ra_db::SourceDatabaseExt;
140 use ra_ide_db::symbol_index::SymbolsDatabase;
141 for &root in self.sema.db.local_roots().iter() {
142 let sr = self.sema.db.source_root(root);
143 for file_id in sr.iter() {
144 callback(file_id);
145 }
146 }
147 } else {
148 // Search is restricted, deduplicate file IDs (generally only one).
149 let mut files = FxHashSet::default();
150 for range in &self.restrict_ranges {
151 if files.insert(range.file_id) {
152 callback(range.file_id);
153 }
143 } 154 }
144 } 155 }
145 } 156 }
@@ -154,9 +165,7 @@ impl<'db> MatchFinder<'db> {
154 if !is_search_permitted(code) { 165 if !is_search_permitted(code) {
155 return; 166 return;
156 } 167 }
157 if let Ok(m) = matching::get_match(false, rule, &code, restrict_range, &self.sema) { 168 self.try_add_match(rule, &code, restrict_range, matches_out);
158 matches_out.push(m);
159 }
160 // If we've got a macro call, we already tried matching it pre-expansion, which is the only 169 // If we've got a macro call, we already tried matching it pre-expansion, which is the only
161 // way to match the whole macro, now try expanding it and matching the expansion. 170 // way to match the whole macro, now try expanding it and matching the expansion.
162 if let Some(macro_call) = ast::MacroCall::cast(code.clone()) { 171 if let Some(macro_call) = ast::MacroCall::cast(code.clone()) {
@@ -178,6 +187,38 @@ impl<'db> MatchFinder<'db> {
178 self.slow_scan_node(&child, rule, restrict_range, matches_out); 187 self.slow_scan_node(&child, rule, restrict_range, matches_out);
179 } 188 }
180 } 189 }
190
191 fn try_add_match(
192 &self,
193 rule: &ResolvedRule,
194 code: &SyntaxNode,
195 restrict_range: &Option<FileRange>,
196 matches_out: &mut Vec<Match>,
197 ) {
198 if !self.within_range_restrictions(code) {
199 mark::hit!(replace_nonpath_within_selection);
200 return;
201 }
202 if let Ok(m) = matching::get_match(false, rule, code, restrict_range, &self.sema) {
203 matches_out.push(m);
204 }
205 }
206
207 /// Returns whether `code` is within one of our range restrictions if we have any. No range
208 /// restrictions is considered unrestricted and always returns true.
209 fn within_range_restrictions(&self, code: &SyntaxNode) -> bool {
210 if self.restrict_ranges.is_empty() {
211 // There is no range restriction.
212 return true;
213 }
214 let node_range = self.sema.original_range(code);
215 for range in &self.restrict_ranges {
216 if range.file_id == node_range.file_id && range.range.contains_range(node_range.range) {
217 return true;
218 }
219 }
220 false
221 }
181} 222}
182 223
183/// Returns whether we support matching within `node` and all of its ancestors. 224/// Returns whether we support matching within `node` and all of its ancestors.