aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_db/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_db/src')
-rw-r--r--crates/ide_db/src/search.rs177
1 files changed, 94 insertions, 83 deletions
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index ff958c757..3634b2b26 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -7,7 +7,7 @@
7use std::{convert::TryInto, mem}; 7use std::{convert::TryInto, mem};
8 8
9use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; 9use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
10use hir::{DefWithBody, HasAttrs, HasSource, Module, ModuleSource, Semantics, Visibility}; 10use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility};
11use once_cell::unsync::Lazy; 11use once_cell::unsync::Lazy;
12use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
13use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; 13use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
@@ -78,6 +78,76 @@ impl SearchScope {
78 SearchScope { entries } 78 SearchScope { entries }
79 } 79 }
80 80
81 fn crate_graph(db: &RootDatabase) -> SearchScope {
82 let mut entries = FxHashMap::default();
83
84 let graph = db.crate_graph();
85 for krate in graph.iter() {
86 let root_file = graph[krate].root_file_id;
87 let source_root_id = db.file_source_root(root_file);
88 let source_root = db.source_root(source_root_id);
89 entries.extend(source_root.iter().map(|id| (id, None)));
90 }
91 SearchScope { entries }
92 }
93
94 fn reverse_dependencies(db: &RootDatabase, of: hir::Crate) -> SearchScope {
95 let mut entries = FxHashMap::default();
96 for rev_dep in of.transitive_reverse_dependencies(db) {
97 let root_file = rev_dep.root_file(db);
98 let source_root_id = db.file_source_root(root_file);
99 let source_root = db.source_root(source_root_id);
100 entries.extend(source_root.iter().map(|id| (id, None)));
101 }
102 SearchScope { entries }
103 }
104
105 fn krate(db: &RootDatabase, of: hir::Crate) -> SearchScope {
106 let root_file = of.root_file(db);
107 let source_root_id = db.file_source_root(root_file);
108 let source_root = db.source_root(source_root_id);
109 SearchScope {
110 entries: source_root.iter().map(|id| (id, None)).collect::<FxHashMap<_, _>>(),
111 }
112 }
113
114 fn module(db: &RootDatabase, module: hir::Module) -> SearchScope {
115 let mut entries = FxHashMap::default();
116
117 let mut to_visit = vec![module];
118 let mut is_first = true;
119 while let Some(module) = to_visit.pop() {
120 let src = module.definition_source(db);
121 let file_id = src.file_id.original_file(db);
122 match src.value {
123 ModuleSource::Module(m) => {
124 if is_first {
125 let range = Some(m.syntax().text_range());
126 entries.insert(file_id, range);
127 } else {
128 // We have already added the enclosing file to the search scope,
129 // so do nothing.
130 }
131 }
132 ModuleSource::BlockExpr(b) => {
133 if is_first {
134 let range = Some(b.syntax().text_range());
135 entries.insert(file_id, range);
136 } else {
137 // We have already added the enclosing file to the search scope,
138 // so do nothing.
139 }
140 }
141 ModuleSource::SourceFile(_) => {
142 entries.insert(file_id, None);
143 }
144 };
145 is_first = false;
146 to_visit.extend(module.children(db));
147 }
148 SearchScope { entries }
149 }
150
81 pub fn empty() -> SearchScope { 151 pub fn empty() -> SearchScope {
82 SearchScope::new(FxHashMap::default()) 152 SearchScope::new(FxHashMap::default())
83 } 153 }
@@ -140,24 +210,15 @@ impl Definition {
140 let _p = profile::span("search_scope"); 210 let _p = profile::span("search_scope");
141 211
142 if let Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) = self { 212 if let Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) = self {
143 let mut res = FxHashMap::default(); 213 return SearchScope::crate_graph(db);
144
145 let graph = db.crate_graph();
146 for krate in graph.iter() {
147 let root_file = graph[krate].root_file_id;
148 let source_root_id = db.file_source_root(root_file);
149 let source_root = db.source_root(source_root_id);
150 res.extend(source_root.iter().map(|id| (id, None)));
151 }
152 return SearchScope::new(res);
153 } 214 }
154 215
155 let module = match self.module(db) { 216 let module = match self.module(db) {
156 Some(it) => it, 217 Some(it) => it,
157 None => return SearchScope::empty(), 218 None => return SearchScope::empty(),
158 }; 219 };
159 let module_src = module.definition_source(db); 220 let InFile { file_id, value: module_source } = module.definition_source(db);
160 let file_id = module_src.file_id.original_file(db); 221 let file_id = file_id.original_file(db);
161 222
162 if let Definition::Local(var) = self { 223 if let Definition::Local(var) = self {
163 let range = match var.parent(db) { 224 let range = match var.parent(db) {
@@ -165,9 +226,10 @@ impl Definition {
165 DefWithBody::Const(c) => c.source(db).map(|src| src.value.syntax().text_range()), 226 DefWithBody::Const(c) => c.source(db).map(|src| src.value.syntax().text_range()),
166 DefWithBody::Static(s) => s.source(db).map(|src| src.value.syntax().text_range()), 227 DefWithBody::Static(s) => s.source(db).map(|src| src.value.syntax().text_range()),
167 }; 228 };
168 let mut res = FxHashMap::default(); 229 return match range {
169 res.insert(file_id, range); 230 Some(range) => SearchScope::file_range(FileRange { file_id, range }),
170 return SearchScope::new(res); 231 None => SearchScope::single_file(file_id),
232 };
171 } 233 }
172 234
173 if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self { 235 if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self {
@@ -198,90 +260,39 @@ impl Definition {
198 it.source(db).map(|src| src.value.syntax().text_range()) 260 it.source(db).map(|src| src.value.syntax().text_range())
199 } 261 }
200 }; 262 };
201 let mut res = FxHashMap::default(); 263 return match range {
202 res.insert(file_id, range); 264 Some(range) => SearchScope::file_range(FileRange { file_id, range }),
203 return SearchScope::new(res); 265 None => SearchScope::single_file(file_id),
204 } 266 };
205
206 let vis = self.visibility(db);
207
208 if let Some(Visibility::Module(module)) = vis.and_then(|it| it.into()) {
209 let module: Module = module.into();
210 let mut res = FxHashMap::default();
211
212 let mut to_visit = vec![module];
213 let mut is_first = true;
214 while let Some(module) = to_visit.pop() {
215 let src = module.definition_source(db);
216 let file_id = src.file_id.original_file(db);
217 match src.value {
218 ModuleSource::Module(m) => {
219 if is_first {
220 let range = Some(m.syntax().text_range());
221 res.insert(file_id, range);
222 } else {
223 // We have already added the enclosing file to the search scope,
224 // so do nothing.
225 }
226 }
227 ModuleSource::BlockExpr(b) => {
228 if is_first {
229 let range = Some(b.syntax().text_range());
230 res.insert(file_id, range);
231 } else {
232 // We have already added the enclosing file to the search scope,
233 // so do nothing.
234 }
235 }
236 ModuleSource::SourceFile(_) => {
237 res.insert(file_id, None);
238 }
239 };
240 is_first = false;
241 to_visit.extend(module.children(db));
242 }
243
244 return SearchScope::new(res);
245 } 267 }
246 268
247 let rev_dep_scope = || {
248 let mut res = FxHashMap::default();
249 let krate = module.krate();
250 for rev_dep in krate.transitive_reverse_dependencies(db) {
251 let root_file = rev_dep.root_file(db);
252 let source_root_id = db.file_source_root(root_file);
253 let source_root = db.source_root(source_root_id);
254 res.extend(source_root.iter().map(|id| (id, None)));
255 }
256 SearchScope::new(res)
257 };
258
259 if let Definition::Macro(macro_def) = self { 269 if let Definition::Macro(macro_def) = self {
260 if macro_def.kind() == hir::MacroKind::Declarative { 270 if macro_def.kind() == hir::MacroKind::Declarative {
261 return if macro_def.attrs(db).by_key("macro_export").exists() { 271 return if macro_def.attrs(db).by_key("macro_export").exists() {
262 rev_dep_scope() 272 SearchScope::reverse_dependencies(db, module.krate())
263 } else { 273 } else {
264 let source_root_id = db.file_source_root(file_id); 274 SearchScope::krate(db, module.krate())
265 let source_root = db.source_root(source_root_id);
266 SearchScope::new(
267 source_root.iter().map(|id| (id, None)).collect::<FxHashMap<_, _>>(),
268 )
269 }; 275 };
270 } 276 }
271 } 277 }
272 278
279 let vis = self.visibility(db);
273 if let Some(Visibility::Public) = vis { 280 if let Some(Visibility::Public) = vis {
274 return rev_dep_scope(); 281 return SearchScope::reverse_dependencies(db, module.krate());
282 }
283 if let Some(Visibility::Module(module)) = vis {
284 return SearchScope::module(db, module.into());
275 } 285 }
276 286
277 let mut res = FxHashMap::default(); 287 let range = match module_source {
278 let range = match module_src.value {
279 ModuleSource::Module(m) => Some(m.syntax().text_range()), 288 ModuleSource::Module(m) => Some(m.syntax().text_range()),
280 ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()), 289 ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()),
281 ModuleSource::SourceFile(_) => None, 290 ModuleSource::SourceFile(_) => None,
282 }; 291 };
283 res.insert(file_id, range); 292 match range {
284 SearchScope::new(res) 293 Some(range) => SearchScope::file_range(FileRange { file_id, range }),
294 None => SearchScope::single_file(file_id),
295 }
285 } 296 }
286 297
287 pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> { 298 pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {