aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/nameres')
-rw-r--r--crates/ra_hir/src/nameres/collector.rs187
-rw-r--r--crates/ra_hir/src/nameres/tests.rs17
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs40
3 files changed, 184 insertions, 60 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 621236551..ba7ea0017 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -1,17 +1,18 @@
1use arrayvec::ArrayVec; 1use arrayvec::ArrayVec;
2use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
3use either::Either;
3use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
4use test_utils::tested_by; 5use test_utils::tested_by;
5use ra_db::FileId; 6use ra_db::FileId;
6use ra_syntax::ast; 7use ra_syntax::ast;
7 8
8use crate::{ 9use crate::{
9 Function, Module, Struct, Union, Enum, Const, Static, Trait, TypeAlias, 10 Function, Module, Struct, Union, Enum, Const, Static, Trait, TypeAlias, MacroDef,
10 DefDatabase, HirFileId, Name, Path, 11 DefDatabase, HirFileId, Name, Path,
11 KnownName, 12 KnownName,
12 nameres::{ 13 nameres::{
13 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, 14 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode,
14 CrateDefMap, CrateModuleId, ModuleData, 15 CrateDefMap, CrateModuleId, ModuleData, ItemOrMacro,
15 diagnostics::DefDiagnostic, 16 diagnostics::DefDiagnostic,
16 raw, 17 raw,
17 }, 18 },
@@ -124,13 +125,21 @@ where
124 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 125 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
125 // show unresolved imports in completion, etc 126 // show unresolved imports in completion, etc
126 for (module_id, import, import_data) in unresolved_imports { 127 for (module_id, import, import_data) in unresolved_imports {
127 self.record_resolved_import(module_id, PerNs::none(), import, &import_data) 128 self.record_resolved_import(
129 module_id,
130 Either::Left(PerNs::none()),
131 import,
132 &import_data,
133 )
128 } 134 }
129 } 135 }
130 136
131 fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) { 137 fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) {
132 if export { 138 if export {
133 self.def_map.public_macros.insert(name.clone(), macro_id); 139 self.def_map.public_macros.insert(name.clone(), macro_id);
140
141 let def = Either::Right(MacroDef { id: macro_id });
142 self.update(self.def_map.root, None, &[(name.clone(), def)]);
134 } else { 143 } else {
135 self.def_map.local_macros.insert(name.clone(), macro_id); 144 self.def_map.local_macros.insert(name.clone(), macro_id);
136 } 145 }
@@ -161,7 +170,7 @@ where
161 &self, 170 &self,
162 module_id: CrateModuleId, 171 module_id: CrateModuleId,
163 import: &raw::ImportData, 172 import: &raw::ImportData,
164 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { 173 ) -> (ItemOrMacro, ReachedFixedPoint) {
165 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 174 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
166 if import.is_extern_crate { 175 if import.is_extern_crate {
167 let res = self.def_map.resolve_name_in_extern_prelude( 176 let res = self.def_map.resolve_name_in_extern_prelude(
@@ -170,10 +179,14 @@ where
170 .as_ident() 179 .as_ident()
171 .expect("extern crate should have been desugared to one-element path"), 180 .expect("extern crate should have been desugared to one-element path"),
172 ); 181 );
173 (res, ReachedFixedPoint::Yes) 182 (Either::Left(res), ReachedFixedPoint::Yes)
174 } else { 183 } else {
175 let res = 184 let res = self.def_map.resolve_path_fp_with_macro(
176 self.def_map.resolve_path_fp(self.db, ResolveMode::Import, module_id, &import.path); 185 self.db,
186 ResolveMode::Import,
187 module_id,
188 &import.path,
189 );
177 190
178 (res.resolved_def, res.reached_fixedpoint) 191 (res.resolved_def, res.reached_fixedpoint)
179 } 192 }
@@ -182,13 +195,13 @@ where
182 fn record_resolved_import( 195 fn record_resolved_import(
183 &mut self, 196 &mut self,
184 module_id: CrateModuleId, 197 module_id: CrateModuleId,
185 def: PerNs<ModuleDef>, 198 def: ItemOrMacro,
186 import_id: raw::ImportId, 199 import_id: raw::ImportId,
187 import: &raw::ImportData, 200 import: &raw::ImportData,
188 ) { 201 ) {
189 if import.is_glob { 202 if import.is_glob {
190 log::debug!("glob import: {:?}", import); 203 log::debug!("glob import: {:?}", import);
191 match def.take_types() { 204 match def.left().and_then(|item| item.take_types()) {
192 Some(ModuleDef::Module(m)) => { 205 Some(ModuleDef::Module(m)) => {
193 if import.is_prelude { 206 if import.is_prelude {
194 tested_by!(std_prelude); 207 tested_by!(std_prelude);
@@ -201,9 +214,14 @@ where
201 let items = scope 214 let items = scope
202 .items 215 .items
203 .iter() 216 .iter()
204 .map(|(name, res)| (name.clone(), res.clone())) 217 .map(|(name, res)| (name.clone(), Either::Left(res.clone())));
205 .collect::<Vec<_>>(); 218 let macros = scope
206 self.update(module_id, Some(import_id), &items); 219 .macros
220 .iter()
221 .map(|(name, res)| (name.clone(), Either::Right(res.clone())));
222
223 let all = items.chain(macros).collect::<Vec<_>>();
224 self.update(module_id, Some(import_id), &all);
207 } else { 225 } else {
208 // glob import from same crate => we do an initial 226 // glob import from same crate => we do an initial
209 // import, and then need to propagate any further 227 // import, and then need to propagate any further
@@ -212,9 +230,15 @@ where
212 let items = scope 230 let items = scope
213 .items 231 .items
214 .iter() 232 .iter()
215 .map(|(name, res)| (name.clone(), res.clone())) 233 .map(|(name, res)| (name.clone(), Either::Left(res.clone())));
216 .collect::<Vec<_>>(); 234 let macros = scope
217 self.update(module_id, Some(import_id), &items); 235 .macros
236 .iter()
237 .map(|(name, res)| (name.clone(), Either::Right(res.clone())));
238
239 let all = items.chain(macros).collect::<Vec<_>>();
240
241 self.update(module_id, Some(import_id), &all);
218 // record the glob import in case we add further items 242 // record the glob import in case we add further items
219 self.glob_imports 243 self.glob_imports
220 .entry(m.module_id) 244 .entry(m.module_id)
@@ -234,7 +258,7 @@ where
234 import: Some(import_id), 258 import: Some(import_id),
235 }; 259 };
236 let name = variant.name(self.db)?; 260 let name = variant.name(self.db)?;
237 Some((name, res)) 261 Some((name, Either::Left(res)))
238 }) 262 })
239 .collect::<Vec<_>>(); 263 .collect::<Vec<_>>();
240 self.update(module_id, Some(import_id), &resolutions); 264 self.update(module_id, Some(import_id), &resolutions);
@@ -254,11 +278,18 @@ where
254 278
255 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 279 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
256 if import.is_extern_crate && module_id == self.def_map.root { 280 if import.is_extern_crate && module_id == self.def_map.root {
257 if let Some(def) = def.take_types() { 281 if let Some(def) = def.left().and_then(|item| item.take_types()) {
258 self.def_map.extern_prelude.insert(name.clone(), def); 282 self.def_map.extern_prelude.insert(name.clone(), def);
259 } 283 }
260 } 284 }
261 let resolution = Resolution { def, import: Some(import_id) }; 285
286 let resolution = match def {
287 Either::Left(item) => {
288 Either::Left(Resolution { def: item, import: Some(import_id) })
289 }
290 Either::Right(macro_) => Either::Right(macro_),
291 };
292
262 self.update(module_id, Some(import_id), &[(name, resolution)]); 293 self.update(module_id, Some(import_id), &[(name, resolution)]);
263 } 294 }
264 None => tested_by!(bogus_paths), 295 None => tested_by!(bogus_paths),
@@ -270,7 +301,7 @@ where
270 &mut self, 301 &mut self,
271 module_id: CrateModuleId, 302 module_id: CrateModuleId,
272 import: Option<raw::ImportId>, 303 import: Option<raw::ImportId>,
273 resolutions: &[(Name, Resolution)], 304 resolutions: &[(Name, Either<Resolution, MacroDef>)],
274 ) { 305 ) {
275 self.update_recursive(module_id, import, resolutions, 0) 306 self.update_recursive(module_id, import, resolutions, 0)
276 } 307 }
@@ -279,7 +310,7 @@ where
279 &mut self, 310 &mut self,
280 module_id: CrateModuleId, 311 module_id: CrateModuleId,
281 import: Option<raw::ImportId>, 312 import: Option<raw::ImportId>,
282 resolutions: &[(Name, Resolution)], 313 resolutions: &[(Name, Either<Resolution, MacroDef>)],
283 depth: usize, 314 depth: usize,
284 ) { 315 ) {
285 if depth > 100 { 316 if depth > 100 {
@@ -289,25 +320,38 @@ where
289 let module_items = &mut self.def_map.modules[module_id].scope; 320 let module_items = &mut self.def_map.modules[module_id].scope;
290 let mut changed = false; 321 let mut changed = false;
291 for (name, res) in resolutions { 322 for (name, res) in resolutions {
292 let existing = module_items.items.entry(name.clone()).or_default(); 323 match res {
293 if existing.def.types.is_none() && res.def.types.is_some() { 324 // item
294 existing.def.types = res.def.types; 325 Either::Left(res) => {
295 existing.import = import.or(res.import); 326 let existing = module_items.items.entry(name.clone()).or_default();
296 changed = true; 327
297 } 328 if existing.def.types.is_none() && res.def.types.is_some() {
298 if existing.def.values.is_none() && res.def.values.is_some() { 329 existing.def.types = res.def.types;
299 existing.def.values = res.def.values; 330 existing.import = import.or(res.import);
300 existing.import = import.or(res.import); 331 changed = true;
301 changed = true; 332 }
302 } 333 if existing.def.values.is_none() && res.def.values.is_some() {
303 if existing.def.is_none() 334 existing.def.values = res.def.values;
304 && res.def.is_none() 335 existing.import = import.or(res.import);
305 && existing.import.is_none() 336 changed = true;
306 && res.import.is_some() 337 }
307 { 338
308 existing.import = res.import; 339 if existing.def.is_none()
340 && res.def.is_none()
341 && existing.import.is_none()
342 && res.import.is_some()
343 {
344 existing.import = res.import;
345 }
346 }
347 // macro
348 Either::Right(res) => {
349 // Always shadowing
350 module_items.macros.insert(name.clone(), *res);
351 }
309 } 352 }
310 } 353 }
354
311 if !changed { 355 if !changed {
312 return; 356 return;
313 } 357 }
@@ -324,37 +368,64 @@ where
324 } 368 }
325 } 369 }
326 370
327 // XXX: this is just a pile of hacks now, because `PerNs` does not handle
328 // macro namespace.
329 fn resolve_macros(&mut self) -> ReachedFixedPoint { 371 fn resolve_macros(&mut self) -> ReachedFixedPoint {
330 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 372 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
331 let mut resolved = Vec::new(); 373 let mut resolved = Vec::new();
332 let mut res = ReachedFixedPoint::Yes; 374 let mut res = ReachedFixedPoint::Yes;
333 macros.retain(|(module_id, ast_id, path)| { 375 macros.retain(|(module_id, ast_id, path)| {
334 if path.segments.len() != 2 { 376 let resolved_res = self.def_map.resolve_path_fp_with_macro(
335 return true; 377 self.db,
378 ResolveMode::Other,
379 *module_id,
380 path,
381 );
382
383 if let Some(def) = resolved_res.resolved_def.right() {
384 let call_id = MacroCallLoc { def: def.id, ast_id: *ast_id }.id(self.db);
385 resolved.push((*module_id, call_id, def.id));
386 res = ReachedFixedPoint::No;
387 return false;
336 } 388 }
337 let crate_name = &path.segments[0].name; 389
338 let krate = match self.def_map.resolve_name_in_extern_prelude(crate_name).take_types() { 390 if resolved_res.reached_fixedpoint != ReachedFixedPoint::Yes {
339 Some(ModuleDef::Module(m)) => m.krate(self.db), 391 let crate_name = &path.segments[0].name;
340 _ => return true, 392
341 }; 393 // FIXME:
342 let krate = match krate { 394 // $crate are not handled in resolver right now
343 Some(it) => it, 395 if crate_name.to_string() == "$crate" {
344 _ => return true, 396 return true;
345 }; 397 }
346 res = ReachedFixedPoint::No; 398
347 let def_map = self.db.crate_def_map(krate); 399 // FIXME:
348 if let Some(macro_id) = def_map.public_macros.get(&path.segments[1].name).cloned() { 400 // Currently `#[cfg(test)]` are ignored and cargo-metadata do not insert
349 let call_id = MacroCallLoc { def: macro_id, ast_id: *ast_id }.id(self.db); 401 // dev-dependencies of dependencies. For example,
350 resolved.push((*module_id, call_id, macro_id)); 402 // if we depend on parking lot, and parking lot has a dev-dependency on lazy_static.
403 // Then `lazy_static` wil not included in `CrateGraph`
404 // We can fix that by proper handling `cfg(test)`.
405 //
406 // So right now we set the fixpoint to No only if its crate is in CrateGraph
407 // See issue #1282 for details
408 let krate =
409 match self.def_map.resolve_name_in_extern_prelude(crate_name).take_types() {
410 Some(ModuleDef::Module(m)) => m.krate(self.db),
411 _ => return true,
412 };
413 if krate.is_none() {
414 return true;
415 }
416
417 res = resolved_res.reached_fixedpoint;
351 } 418 }
352 false 419
420 true
353 }); 421 });
354 422
423 self.unexpanded_macros = macros;
424
355 for (module_id, macro_call_id, macro_def_id) in resolved { 425 for (module_id, macro_call_id, macro_def_id) in resolved {
356 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id); 426 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id);
357 } 427 }
428
358 res 429 res
359 } 430 }
360 431
@@ -475,7 +546,7 @@ where
475 ), 546 ),
476 import: None, 547 import: None,
477 }; 548 };
478 self.def_collector.update(self.module_id, None, &[(name, resolution)]); 549 self.def_collector.update(self.module_id, None, &[(name, Either::Left(resolution))]);
479 res 550 res
480 } 551 }
481 552
@@ -506,7 +577,7 @@ where
506 raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), 577 raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)),
507 }; 578 };
508 let resolution = Resolution { def, import: None }; 579 let resolution = Resolution { def, import: None };
509 self.def_collector.update(self.module_id, None, &[(name, resolution)]) 580 self.def_collector.update(self.module_id, None, &[(name, Either::Left(resolution))])
510 } 581 }
511 582
512 fn collect_macro(&mut self, mac: &raw::MacroData) { 583 fn collect_macro(&mut self, mac: &raw::MacroData) {
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 14c8ee50b..ffb627c02 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -7,6 +7,7 @@ use std::sync::Arc;
7use ra_db::SourceDatabase; 7use ra_db::SourceDatabase;
8use test_utils::covers; 8use test_utils::covers;
9use insta::assert_snapshot_matches; 9use insta::assert_snapshot_matches;
10use either::Either;
10 11
11use crate::{ 12use crate::{
12 Crate, 13 Crate,
@@ -35,10 +36,22 @@ fn render_crate_def_map(map: &CrateDefMap) -> String {
35 *buf += path; 36 *buf += path;
36 *buf += "\n"; 37 *buf += "\n";
37 38
38 let mut entries = map.modules[module].scope.items.iter().collect::<Vec<_>>(); 39 let items =
40 map.modules[module].scope.items.iter().map(|(name, it)| (name, Either::Left(it)));
41 let macros =
42 map.modules[module].scope.macros.iter().map(|(name, m)| (name, Either::Right(m)));
43 let mut entries = items.chain(macros).collect::<Vec<_>>();
44
39 entries.sort_by_key(|(name, _)| *name); 45 entries.sort_by_key(|(name, _)| *name);
40 for (name, res) in entries { 46 for (name, res) in entries {
41 *buf += &format!("{}: {}\n", name, dump_resolution(res)) 47 match res {
48 Either::Left(it) => {
49 *buf += &format!("{}: {}\n", name, dump_resolution(it));
50 }
51 Either::Right(_) => {
52 *buf += &format!("{}: m\n", name);
53 }
54 }
42 } 55 }
43 for (name, child) in map.modules[module].children.iter() { 56 for (name, child) in map.modules[module].children.iter() {
44 let path = path.to_string() + &format!("::{}", name); 57 let path = path.to_string() + &format!("::{}", name);
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index f7ca380ad..42241aeff 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -92,3 +92,43 @@ fn macro_rules_from_other_crates_are_visible() {
92 ⋮bar: t 92 ⋮bar: t
93 "###); 93 "###);
94} 94}
95
96#[test]
97fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
98 let map = def_map_with_crate_graph(
99 "
100 //- /main.rs
101 macro_rules! baz {
102 () => {
103 use foo::bar;
104 }
105 }
106
107 foo!();
108 bar!();
109 baz!();
110
111 //- /lib.rs
112 #[macro_export]
113 macro_rules! foo {
114 () => {
115 struct Foo { field: u32 }
116 }
117 }
118 #[macro_export]
119 macro_rules! bar {
120 () => {
121 use foo::foo;
122 }
123 }
124 ",
125 crate_graph! {
126 "main": ("/main.rs", ["foo"]),
127 "foo": ("/lib.rs", []),
128 },
129 );
130 assert_snapshot_matches!(map, @r###"crate
131Foo: t v
132bar: m
133foo: m"###);
134}