diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-03-23 12:05:45 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-03-23 12:05:45 +0000 |
commit | 258afb8fb8331e43a75e4f19df255d85d2430be7 (patch) | |
tree | 41bafbd0806672f10882aa02d4558e44137beea7 /crates | |
parent | 1efd220f2f844596dd22bfd73a8a0c596354be38 (diff) | |
parent | 395183e0b7609dfb0d21f135879dc8f3d8e97e41 (diff) |
Merge #8138
8138: Set up a search scope when searching for mbe macro references r=Veykril a=Veykril
Closes #6184
Co-authored-by: Lukas Wirth <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir/src/lib.rs | 26 | ||||
-rw-r--r-- | crates/ide/src/references.rs | 30 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/attribute.rs | 3 | ||||
-rw-r--r-- | crates/ide_db/src/search.rs | 168 |
4 files changed, 147 insertions, 80 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 68f4551c0..5da6a0340 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -1117,6 +1117,14 @@ impl BuiltinType { | |||
1117 | } | 1117 | } |
1118 | 1118 | ||
1119 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1119 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
1120 | pub enum MacroKind { | ||
1121 | Declarative, | ||
1122 | ProcMacro, | ||
1123 | Derive, | ||
1124 | BuiltIn, | ||
1125 | } | ||
1126 | |||
1127 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
1120 | pub struct MacroDef { | 1128 | pub struct MacroDef { |
1121 | pub(crate) id: MacroDefId, | 1129 | pub(crate) id: MacroDefId, |
1122 | } | 1130 | } |
@@ -1140,15 +1148,15 @@ impl MacroDef { | |||
1140 | } | 1148 | } |
1141 | } | 1149 | } |
1142 | 1150 | ||
1143 | /// Indicate it is a proc-macro | 1151 | pub fn kind(&self) -> MacroKind { |
1144 | pub fn is_proc_macro(&self) -> bool { | 1152 | match self.id.kind { |
1145 | matches!(self.id.kind, MacroDefKind::ProcMacro(..)) | 1153 | MacroDefKind::Declarative(_) => MacroKind::Declarative, |
1146 | } | 1154 | MacroDefKind::BuiltIn(_, _) => MacroKind::BuiltIn, |
1147 | 1155 | MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, | |
1148 | /// Indicate it is a derive macro | 1156 | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, |
1149 | pub fn is_derive_macro(&self) -> bool { | 1157 | // FIXME might be a derive |
1150 | // FIXME: wrong for `ProcMacro` | 1158 | MacroDefKind::ProcMacro(_, _) => MacroKind::ProcMacro, |
1151 | matches!(self.id.kind, MacroDefKind::ProcMacro(..) | MacroDefKind::BuiltInDerive(..)) | 1159 | } |
1152 | } | 1160 | } |
1153 | } | 1161 | } |
1154 | 1162 | ||
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 379674530..95ed8a045 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -1294,4 +1294,34 @@ pub use level1::Foo; | |||
1294 | "#]], | 1294 | "#]], |
1295 | ); | 1295 | ); |
1296 | } | 1296 | } |
1297 | |||
1298 | #[test] | ||
1299 | fn test_decl_macro_references() { | ||
1300 | check( | ||
1301 | r#" | ||
1302 | //- /lib.rs crate:lib | ||
1303 | #[macro_use] | ||
1304 | mod qux; | ||
1305 | mod bar; | ||
1306 | |||
1307 | pub use self::foo; | ||
1308 | //- /qux.rs | ||
1309 | #[macro_export] | ||
1310 | macro_rules! foo$0 { | ||
1311 | () => {struct Foo;}; | ||
1312 | } | ||
1313 | //- /bar.rs | ||
1314 | foo!(); | ||
1315 | //- /other.rs crate:other deps:lib new_source_root: | ||
1316 | lib::foo!(); | ||
1317 | "#, | ||
1318 | expect![[r#" | ||
1319 | foo Macro FileId(1) 0..61 29..32 | ||
1320 | |||
1321 | FileId(0) 46..49 | ||
1322 | FileId(2) 0..3 | ||
1323 | FileId(3) 5..8 | ||
1324 | "#]], | ||
1325 | ); | ||
1326 | } | ||
1297 | } | 1327 | } |
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index e846678b4..b1505c74b 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs | |||
@@ -246,7 +246,8 @@ fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { | |||
246 | let mut result = FxHashSet::default(); | 246 | let mut result = FxHashSet::default(); |
247 | ctx.scope.process_all_names(&mut |name, scope_def| { | 247 | ctx.scope.process_all_names(&mut |name, scope_def| { |
248 | if let hir::ScopeDef::MacroDef(mac) = scope_def { | 248 | if let hir::ScopeDef::MacroDef(mac) = scope_def { |
249 | if mac.is_derive_macro() { | 249 | // FIXME kind() doesn't check whether proc-macro is a derive |
250 | if mac.kind() == hir::MacroKind::Derive || mac.kind() == hir::MacroKind::ProcMacro { | ||
250 | result.insert(name.to_string()); | 251 | result.insert(name.to_string()); |
251 | } | 252 | } |
252 | } | 253 | } |
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index 8e93de277..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, 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,73 +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), |
266 | }; | ||
204 | } | 267 | } |
205 | 268 | ||
206 | let vis = self.visibility(db); | 269 | if let Definition::Macro(macro_def) = self { |
207 | 270 | if macro_def.kind() == hir::MacroKind::Declarative { | |
208 | if let Some(Visibility::Module(module)) = vis.and_then(|it| it.into()) { | 271 | return if macro_def.attrs(db).by_key("macro_export").exists() { |
209 | let module: Module = module.into(); | 272 | SearchScope::reverse_dependencies(db, module.krate()) |
210 | let mut res = FxHashMap::default(); | 273 | } else { |
211 | 274 | SearchScope::krate(db, module.krate()) | |
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 | }; | 275 | }; |
240 | is_first = false; | ||
241 | to_visit.extend(module.children(db)); | ||
242 | } | 276 | } |
243 | |||
244 | return SearchScope::new(res); | ||
245 | } | 277 | } |
246 | 278 | ||
279 | let vis = self.visibility(db); | ||
247 | if let Some(Visibility::Public) = vis { | 280 | if let Some(Visibility::Public) = vis { |
248 | let mut res = FxHashMap::default(); | 281 | return SearchScope::reverse_dependencies(db, module.krate()); |
249 | 282 | } | |
250 | let krate = module.krate(); | 283 | if let Some(Visibility::Module(module)) = vis { |
251 | for rev_dep in krate.transitive_reverse_dependencies(db) { | 284 | return SearchScope::module(db, module.into()); |
252 | let root_file = rev_dep.root_file(db); | ||
253 | let source_root_id = db.file_source_root(root_file); | ||
254 | let source_root = db.source_root(source_root_id); | ||
255 | res.extend(source_root.iter().map(|id| (id, None))); | ||
256 | } | ||
257 | return SearchScope::new(res); | ||
258 | } | 285 | } |
259 | 286 | ||
260 | let mut res = FxHashMap::default(); | 287 | let range = match module_source { |
261 | let range = match module_src.value { | ||
262 | ModuleSource::Module(m) => Some(m.syntax().text_range()), | 288 | ModuleSource::Module(m) => Some(m.syntax().text_range()), |
263 | ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()), | 289 | ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()), |
264 | ModuleSource::SourceFile(_) => None, | 290 | ModuleSource::SourceFile(_) => None, |
265 | }; | 291 | }; |
266 | res.insert(file_id, range); | 292 | match range { |
267 | SearchScope::new(res) | 293 | Some(range) => SearchScope::file_range(FileRange { file_id, range }), |
294 | None => SearchScope::single_file(file_id), | ||
295 | } | ||
268 | } | 296 | } |
269 | 297 | ||
270 | 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> { |