diff options
Diffstat (limited to 'crates/ide_db/src')
-rw-r--r-- | crates/ide_db/src/search.rs | 177 |
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 @@ | |||
7 | use std::{convert::TryInto, mem}; | 7 | use std::{convert::TryInto, mem}; |
8 | 8 | ||
9 | use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; | 9 | use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; |
10 | use hir::{DefWithBody, HasAttrs, HasSource, Module, ModuleSource, Semantics, Visibility}; | 10 | use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility}; |
11 | use once_cell::unsync::Lazy; | 11 | use once_cell::unsync::Lazy; |
12 | use rustc_hash::FxHashMap; | 12 | use rustc_hash::FxHashMap; |
13 | use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; | 13 | use 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> { |