aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/nameres
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-12-23 14:35:31 +0000
committerSeivan Heidari <[email protected]>2019-12-23 14:35:31 +0000
commitb21d9337d9200e2cfdc90b386591c72c302dc03e (patch)
treef81f5c08f821115cee26fa4d3ceaae88c7807fd5 /crates/ra_hir_def/src/nameres
parent18a0937585b836ec5ed054b9ae48e0156ab6d9ef (diff)
parentce07a2daa9e53aa86a769f8641b14c2878444fbc (diff)
Merge branch 'master' into feature/themes
Diffstat (limited to 'crates/ra_hir_def/src/nameres')
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs637
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs105
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs105
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs53
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs21
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs4
-rw-r--r--crates/ra_hir_def/src/nameres/tests/macros.rs24
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs4
8 files changed, 515 insertions, 438 deletions
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index fd8245113..b9f40d3dd 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -4,14 +4,15 @@
4//! resolves imports and expands macros. 4//! resolves imports and expands macros.
5 5
6use hir_expand::{ 6use hir_expand::{
7 builtin_derive::find_builtin_derive,
7 builtin_macro::find_builtin_macro, 8 builtin_macro::find_builtin_macro,
8 name::{self, AsName, Name}, 9 name::{name, AsName, Name},
9 HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind, 10 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
10}; 11};
11use ra_cfg::CfgOptions; 12use ra_cfg::CfgOptions;
12use ra_db::{CrateId, FileId}; 13use ra_db::{CrateId, FileId};
13use ra_syntax::ast; 14use ra_syntax::ast;
14use rustc_hash::{FxHashMap, FxHashSet}; 15use rustc_hash::FxHashMap;
15use test_utils::tested_by; 16use test_utils::tested_by;
16 17
17use crate::{ 18use crate::{
@@ -19,13 +20,12 @@ use crate::{
19 db::DefDatabase, 20 db::DefDatabase,
20 nameres::{ 21 nameres::{
21 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, 22 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
22 raw, CrateDefMap, ModuleData, Resolution, ResolveMode, 23 raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
23 }, 24 },
24 path::{Path, PathKind}, 25 path::{ModPath, PathKind},
25 per_ns::PerNs, 26 per_ns::PerNs,
26 AdtId, AstId, AstItemDef, ConstLoc, ContainerId, EnumId, EnumVariantId, FunctionLoc, ImplId, 27 AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
27 Intern, LocalImportId, LocalModuleId, LocationCtx, ModuleDefId, ModuleId, StaticLoc, StructId, 28 LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
28 TraitId, TypeAliasLoc, UnionId,
29}; 29};
30 30
31pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 31pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
@@ -57,68 +57,63 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
57 def_map, 57 def_map,
58 glob_imports: FxHashMap::default(), 58 glob_imports: FxHashMap::default(),
59 unresolved_imports: Vec::new(), 59 unresolved_imports: Vec::new(),
60 resolved_imports: Vec::new(),
61
60 unexpanded_macros: Vec::new(), 62 unexpanded_macros: Vec::new(),
63 unexpanded_attribute_macros: Vec::new(),
61 mod_dirs: FxHashMap::default(), 64 mod_dirs: FxHashMap::default(),
62 macro_stack_monitor: MacroStackMonitor::default(),
63 poison_macros: FxHashSet::default(),
64 cfg_options, 65 cfg_options,
65 }; 66 };
66 collector.collect(); 67 collector.collect();
67 collector.finish() 68 collector.finish()
68} 69}
69 70
70#[derive(Default)] 71#[derive(Copy, Clone, Debug, Eq, PartialEq)]
71struct MacroStackMonitor { 72enum PartialResolvedImport {
72 counts: FxHashMap<MacroDefId, u32>, 73 /// None of any namespaces is resolved
73 74 Unresolved,
74 /// Mainly use for test 75 /// One of namespaces is resolved
75 validator: Option<Box<dyn Fn(u32) -> bool>>, 76 Indeterminate(PerNs),
77 /// All namespaces are resolved, OR it is came from other crate
78 Resolved(PerNs),
76} 79}
77 80
78impl MacroStackMonitor { 81impl PartialResolvedImport {
79 fn increase(&mut self, macro_def_id: MacroDefId) { 82 fn namespaces(&self) -> PerNs {
80 *self.counts.entry(macro_def_id).or_default() += 1; 83 match self {
81 } 84 PartialResolvedImport::Unresolved => PerNs::none(),
82 85 PartialResolvedImport::Indeterminate(ns) => *ns,
83 fn decrease(&mut self, macro_def_id: MacroDefId) { 86 PartialResolvedImport::Resolved(ns) => *ns,
84 *self.counts.entry(macro_def_id).or_default() -= 1; 87 }
85 } 88 }
89}
86 90
87 fn is_poison(&self, macro_def_id: MacroDefId) -> bool { 91#[derive(Clone, Debug, Eq, PartialEq)]
88 let cur = *self.counts.get(&macro_def_id).unwrap_or(&0); 92struct ImportDirective {
93 module_id: LocalModuleId,
94 import_id: raw::Import,
95 import: raw::ImportData,
96 status: PartialResolvedImport,
97}
89 98
90 if let Some(validator) = &self.validator { 99#[derive(Clone, Debug, Eq, PartialEq)]
91 validator(cur) 100struct MacroDirective {
92 } else { 101 module_id: LocalModuleId,
93 cur > 100 102 ast_id: AstId<ast::MacroCall>,
94 } 103 path: ModPath,
95 } 104 legacy: Option<MacroCallId>,
96} 105}
97 106
98/// Walks the tree of module recursively 107/// Walks the tree of module recursively
99struct DefCollector<'a, DB> { 108struct DefCollector<'a, DB> {
100 db: &'a DB, 109 db: &'a DB,
101 def_map: CrateDefMap, 110 def_map: CrateDefMap,
102 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>, 111 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, raw::Import)>>,
103 unresolved_imports: Vec<(LocalModuleId, LocalImportId, raw::ImportData)>, 112 unresolved_imports: Vec<ImportDirective>,
104 unexpanded_macros: Vec<(LocalModuleId, AstId<ast::MacroCall>, Path)>, 113 resolved_imports: Vec<ImportDirective>,
114 unexpanded_macros: Vec<MacroDirective>,
115 unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, ModPath)>,
105 mod_dirs: FxHashMap<LocalModuleId, ModDir>, 116 mod_dirs: FxHashMap<LocalModuleId, ModDir>,
106
107 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
108 /// To prevent stack overflow, we add a deep counter here for prevent that.
109 macro_stack_monitor: MacroStackMonitor,
110 /// Some macros are not well-behavior, which leads to infinite loop
111 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
112 /// We mark it down and skip it in collector
113 ///
114 /// FIXME:
115 /// Right now it only handle a poison macro in a single crate,
116 /// such that if other crate try to call that macro,
117 /// the whole process will do again until it became poisoned in that crate.
118 /// We should handle this macro set globally
119 /// However, do we want to put it as a global variable?
120 poison_macros: FxHashSet<MacroDefId>,
121
122 cfg_options: &'a CfgOptions, 117 cfg_options: &'a CfgOptions,
123} 118}
124 119
@@ -131,7 +126,7 @@ where
131 let file_id = crate_graph.crate_root(self.def_map.krate); 126 let file_id = crate_graph.crate_root(self.def_map.krate);
132 let raw_items = self.db.raw_items(file_id.into()); 127 let raw_items = self.db.raw_items(file_id.into());
133 let module_id = self.def_map.root; 128 let module_id = self.def_map.root;
134 self.def_map.modules[module_id].definition = Some(file_id); 129 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
135 ModCollector { 130 ModCollector {
136 def_collector: &mut *self, 131 def_collector: &mut *self,
137 module_id, 132 module_id,
@@ -145,9 +140,11 @@ where
145 let mut i = 0; 140 let mut i = 0;
146 loop { 141 loop {
147 self.db.check_canceled(); 142 self.db.check_canceled();
148 match (self.resolve_imports(), self.resolve_macros()) { 143 self.resolve_imports();
149 (ReachedFixedPoint::Yes, ReachedFixedPoint::Yes) => break, 144
150 _ => i += 1, 145 match self.resolve_macros() {
146 ReachedFixedPoint::Yes => break,
147 ReachedFixedPoint::No => i += 1,
151 } 148 }
152 if i == 1000 { 149 if i == 1000 {
153 log::error!("name resolution is stuck"); 150 log::error!("name resolution is stuck");
@@ -155,10 +152,26 @@ where
155 } 152 }
156 } 153 }
157 154
155 // Resolve all indeterminate resolved imports again
156 // As some of the macros will expand newly import shadowing partial resolved imports
157 // FIXME: We maybe could skip this, if we handle the Indetermine imports in `resolve_imports`
158 // correctly
159 let partial_resolved = self.resolved_imports.iter().filter_map(|directive| {
160 if let PartialResolvedImport::Indeterminate(_) = directive.status {
161 let mut directive = directive.clone();
162 directive.status = PartialResolvedImport::Unresolved;
163 Some(directive)
164 } else {
165 None
166 }
167 });
168 self.unresolved_imports.extend(partial_resolved);
169 self.resolve_imports();
170
158 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 171 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
159 // show unresolved imports in completion, etc 172 // show unresolved imports in completion, etc
160 for (module_id, import, import_data) in unresolved_imports { 173 for directive in unresolved_imports {
161 self.record_resolved_import(module_id, PerNs::none(), import, &import_data) 174 self.record_resolved_import(&directive)
162 } 175 }
163 } 176 }
164 177
@@ -201,24 +214,20 @@ where
201 // In Rust, `#[macro_export]` macros are unconditionally visible at the 214 // In Rust, `#[macro_export]` macros are unconditionally visible at the
202 // crate root, even if the parent modules is **not** visible. 215 // crate root, even if the parent modules is **not** visible.
203 if export { 216 if export {
204 self.update( 217 self.update(self.def_map.root, &[(name, PerNs::macros(macro_))]);
205 self.def_map.root,
206 None,
207 &[(name, Resolution { def: PerNs::macros(macro_), import: None })],
208 );
209 } 218 }
210 } 219 }
211 220
212 /// Define a legacy textual scoped macro in module 221 /// Define a legacy textual scoped macro in module
213 /// 222 ///
214 /// We use a map `legacy_macros` to store all legacy textual scoped macros visable per module. 223 /// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module.
215 /// It will clone all macros from parent legacy scope, whose definition is prior to 224 /// It will clone all macros from parent legacy scope, whose definition is prior to
216 /// the definition of current module. 225 /// the definition of current module.
217 /// And also, `macro_use` on a module will import all legacy macros visable inside to 226 /// And also, `macro_use` on a module will import all legacy macros visible inside to
218 /// current legacy scope, with possible shadowing. 227 /// current legacy scope, with possible shadowing.
219 fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, macro_: MacroDefId) { 228 fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroDefId) {
220 // Always shadowing 229 // Always shadowing
221 self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_); 230 self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
222 } 231 }
223 232
224 /// Import macros from `#[macro_use] extern crate`. 233 /// Import macros from `#[macro_use] extern crate`.
@@ -259,31 +268,43 @@ where
259 } 268 }
260 } 269 }
261 270
262 fn resolve_imports(&mut self) -> ReachedFixedPoint { 271 /// Import resolution
263 let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 272 ///
264 let mut resolved = Vec::new(); 273 /// This is a fix point algorithm. We resolve imports until no forward
265 imports.retain(|(module_id, import, import_data)| { 274 /// progress in resolving imports is made
266 let (def, fp) = self.resolve_import(*module_id, import_data); 275 fn resolve_imports(&mut self) {
267 if fp == ReachedFixedPoint::Yes { 276 let mut n_previous_unresolved = self.unresolved_imports.len() + 1;
268 resolved.push((*module_id, def, *import, import_data.clone())) 277
278 while self.unresolved_imports.len() < n_previous_unresolved {
279 n_previous_unresolved = self.unresolved_imports.len();
280 let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
281 for mut directive in imports {
282 directive.status = self.resolve_import(directive.module_id, &directive.import);
283
284 match directive.status {
285 PartialResolvedImport::Indeterminate(_) => {
286 self.record_resolved_import(&directive);
287 // FIXME: For avoid performance regression,
288 // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved)
289 self.resolved_imports.push(directive)
290 }
291 PartialResolvedImport::Resolved(_) => {
292 self.record_resolved_import(&directive);
293 self.resolved_imports.push(directive)
294 }
295 PartialResolvedImport::Unresolved => {
296 self.unresolved_imports.push(directive);
297 }
298 }
269 } 299 }
270 fp == ReachedFixedPoint::No
271 });
272 self.unresolved_imports = imports;
273 // Resolves imports, filling-in module scopes
274 let result =
275 if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No };
276 for (module_id, def, import, import_data) in resolved {
277 self.record_resolved_import(module_id, def, import, &import_data)
278 } 300 }
279 result
280 } 301 }
281 302
282 fn resolve_import( 303 fn resolve_import(
283 &self, 304 &self,
284 module_id: LocalModuleId, 305 module_id: LocalModuleId,
285 import: &raw::ImportData, 306 import: &raw::ImportData,
286 ) -> (PerNs, ReachedFixedPoint) { 307 ) -> PartialResolvedImport {
287 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 308 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
288 if import.is_extern_crate { 309 if import.is_extern_crate {
289 let res = self.def_map.resolve_name_in_extern_prelude( 310 let res = self.def_map.resolve_name_in_extern_prelude(
@@ -292,26 +313,45 @@ where
292 .as_ident() 313 .as_ident()
293 .expect("extern crate should have been desugared to one-element path"), 314 .expect("extern crate should have been desugared to one-element path"),
294 ); 315 );
295 (res, ReachedFixedPoint::Yes) 316 PartialResolvedImport::Resolved(res)
296 } else { 317 } else {
297 let res = self.def_map.resolve_path_fp_with_macro( 318 let res = self.def_map.resolve_path_fp_with_macro(
298 self.db, 319 self.db,
299 ResolveMode::Import, 320 ResolveMode::Import,
300 module_id, 321 module_id,
301 &import.path, 322 &import.path,
323 BuiltinShadowMode::Module,
302 ); 324 );
303 325
304 (res.resolved_def, res.reached_fixedpoint) 326 let def = res.resolved_def;
327 if res.reached_fixedpoint == ReachedFixedPoint::No {
328 return PartialResolvedImport::Unresolved;
329 }
330
331 if let Some(krate) = res.krate {
332 if krate != self.def_map.krate {
333 return PartialResolvedImport::Resolved(def);
334 }
335 }
336
337 // Check whether all namespace is resolved
338 if def.take_types().is_some()
339 && def.take_values().is_some()
340 && def.take_macros().is_some()
341 {
342 PartialResolvedImport::Resolved(def)
343 } else {
344 PartialResolvedImport::Indeterminate(def)
345 }
305 } 346 }
306 } 347 }
307 348
308 fn record_resolved_import( 349 fn record_resolved_import(&mut self, directive: &ImportDirective) {
309 &mut self, 350 let module_id = directive.module_id;
310 module_id: LocalModuleId, 351 let import_id = directive.import_id;
311 def: PerNs, 352 let import = &directive.import;
312 import_id: LocalImportId, 353 let def = directive.status.namespaces();
313 import: &raw::ImportData, 354
314 ) {
315 if import.is_glob { 355 if import.is_glob {
316 log::debug!("glob import: {:?}", import); 356 log::debug!("glob import: {:?}", import);
317 match def.take_types() { 357 match def.take_types() {
@@ -326,13 +366,9 @@ where
326 let scope = &item_map[m.local_id].scope; 366 let scope = &item_map[m.local_id].scope;
327 367
328 // Module scoped macros is included 368 // Module scoped macros is included
329 let items = scope 369 let items = scope.collect_resolutions();
330 .items
331 .iter()
332 .map(|(name, res)| (name.clone(), res.clone()))
333 .collect::<Vec<_>>();
334 370
335 self.update(module_id, Some(import_id), &items); 371 self.update(module_id, &items);
336 } else { 372 } else {
337 // glob import from same crate => we do an initial 373 // glob import from same crate => we do an initial
338 // import, and then need to propagate any further 374 // import, and then need to propagate any further
@@ -340,18 +376,14 @@ where
340 let scope = &self.def_map[m.local_id].scope; 376 let scope = &self.def_map[m.local_id].scope;
341 377
342 // Module scoped macros is included 378 // Module scoped macros is included
343 let items = scope 379 let items = scope.collect_resolutions();
344 .items
345 .iter()
346 .map(|(name, res)| (name.clone(), res.clone()))
347 .collect::<Vec<_>>();
348 380
349 self.update(module_id, Some(import_id), &items); 381 self.update(module_id, &items);
350 // record the glob import in case we add further items 382 // record the glob import in case we add further items
351 self.glob_imports 383 let glob = self.glob_imports.entry(m.local_id).or_default();
352 .entry(m.local_id) 384 if !glob.iter().any(|it| *it == (module_id, import_id)) {
353 .or_default() 385 glob.push((module_id, import_id));
354 .push((module_id, import_id)); 386 }
355 } 387 }
356 } 388 }
357 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { 389 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
@@ -361,17 +393,14 @@ where
361 let resolutions = enum_data 393 let resolutions = enum_data
362 .variants 394 .variants
363 .iter() 395 .iter()
364 .filter_map(|(local_id, variant_data)| { 396 .map(|(local_id, variant_data)| {
365 let name = variant_data.name.clone(); 397 let name = variant_data.name.clone();
366 let variant = EnumVariantId { parent: e, local_id }; 398 let variant = EnumVariantId { parent: e, local_id };
367 let res = Resolution { 399 let res = PerNs::both(variant.into(), variant.into());
368 def: PerNs::both(variant.into(), variant.into()), 400 (name, res)
369 import: Some(import_id),
370 };
371 Some((name, res))
372 }) 401 })
373 .collect::<Vec<_>>(); 402 .collect::<Vec<_>>();
374 self.update(module_id, Some(import_id), &resolutions); 403 self.update(module_id, &resolutions);
375 } 404 }
376 Some(d) => { 405 Some(d) => {
377 log::debug!("glob import {:?} from non-module/enum {:?}", import, d); 406 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -383,7 +412,7 @@ where
383 } else { 412 } else {
384 match import.path.segments.last() { 413 match import.path.segments.last() {
385 Some(last_segment) => { 414 Some(last_segment) => {
386 let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone()); 415 let name = import.alias.clone().unwrap_or_else(|| last_segment.clone());
387 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); 416 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
388 417
389 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 418 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
@@ -393,62 +422,31 @@ where
393 } 422 }
394 } 423 }
395 424
396 let resolution = Resolution { def, import: Some(import_id) }; 425 self.update(module_id, &[(name, def)]);
397 self.update(module_id, Some(import_id), &[(name, resolution)]);
398 } 426 }
399 None => tested_by!(bogus_paths), 427 None => tested_by!(bogus_paths),
400 } 428 }
401 } 429 }
402 } 430 }
403 431
404 fn update( 432 fn update(&mut self, module_id: LocalModuleId, resolutions: &[(Name, PerNs)]) {
405 &mut self, 433 self.update_recursive(module_id, resolutions, 0)
406 module_id: LocalModuleId,
407 import: Option<LocalImportId>,
408 resolutions: &[(Name, Resolution)],
409 ) {
410 self.update_recursive(module_id, import, resolutions, 0)
411 } 434 }
412 435
413 fn update_recursive( 436 fn update_recursive(
414 &mut self, 437 &mut self,
415 module_id: LocalModuleId, 438 module_id: LocalModuleId,
416 import: Option<LocalImportId>, 439 resolutions: &[(Name, PerNs)],
417 resolutions: &[(Name, Resolution)],
418 depth: usize, 440 depth: usize,
419 ) { 441 ) {
420 if depth > 100 { 442 if depth > 100 {
421 // prevent stack overflows (but this shouldn't be possible) 443 // prevent stack overflows (but this shouldn't be possible)
422 panic!("infinite recursion in glob imports!"); 444 panic!("infinite recursion in glob imports!");
423 } 445 }
424 let module_items = &mut self.def_map.modules[module_id].scope; 446 let scope = &mut self.def_map.modules[module_id].scope;
425 let mut changed = false; 447 let mut changed = false;
426 for (name, res) in resolutions { 448 for (name, res) in resolutions {
427 let existing = module_items.items.entry(name.clone()).or_default(); 449 changed |= scope.push_res(name.clone(), *res);
428
429 if existing.def.types.is_none() && res.def.types.is_some() {
430 existing.def.types = res.def.types;
431 existing.import = import.or(res.import);
432 changed = true;
433 }
434 if existing.def.values.is_none() && res.def.values.is_some() {
435 existing.def.values = res.def.values;
436 existing.import = import.or(res.import);
437 changed = true;
438 }
439 if existing.def.macros.is_none() && res.def.macros.is_some() {
440 existing.def.macros = res.def.macros;
441 existing.import = import.or(res.import);
442 changed = true;
443 }
444
445 if existing.def.is_none()
446 && res.def.is_none()
447 && existing.import.is_none()
448 && res.import.is_some()
449 {
450 existing.import = res.import;
451 }
452 } 450 }
453 451
454 if !changed { 452 if !changed {
@@ -461,27 +459,48 @@ where
461 .flat_map(|v| v.iter()) 459 .flat_map(|v| v.iter())
462 .cloned() 460 .cloned()
463 .collect::<Vec<_>>(); 461 .collect::<Vec<_>>();
464 for (glob_importing_module, glob_import) in glob_imports { 462 for (glob_importing_module, _glob_import) in glob_imports {
465 // We pass the glob import so that the tracked import in those modules is that glob import 463 // We pass the glob import so that the tracked import in those modules is that glob import
466 self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1); 464 self.update_recursive(glob_importing_module, resolutions, depth + 1);
467 } 465 }
468 } 466 }
469 467
470 fn resolve_macros(&mut self) -> ReachedFixedPoint { 468 fn resolve_macros(&mut self) -> ReachedFixedPoint {
471 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 469 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
470 let mut attribute_macros =
471 std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new());
472 let mut resolved = Vec::new(); 472 let mut resolved = Vec::new();
473 let mut res = ReachedFixedPoint::Yes; 473 let mut res = ReachedFixedPoint::Yes;
474 macros.retain(|(module_id, ast_id, path)| { 474 macros.retain(|directive| {
475 if let Some(call_id) = directive.legacy {
476 res = ReachedFixedPoint::No;
477 resolved.push((directive.module_id, call_id));
478 return false;
479 }
480
475 let resolved_res = self.def_map.resolve_path_fp_with_macro( 481 let resolved_res = self.def_map.resolve_path_fp_with_macro(
476 self.db, 482 self.db,
477 ResolveMode::Other, 483 ResolveMode::Other,
478 *module_id, 484 directive.module_id,
479 path, 485 &directive.path,
486 BuiltinShadowMode::Module,
480 ); 487 );
481 488
482 if let Some(def) = resolved_res.resolved_def.take_macros() { 489 if let Some(def) = resolved_res.resolved_def.take_macros() {
483 let call_id = def.as_call_id(self.db, *ast_id); 490 let call_id = def.as_call_id(self.db, MacroCallKind::FnLike(directive.ast_id));
484 resolved.push((*module_id, call_id, def)); 491 resolved.push((directive.module_id, call_id));
492 res = ReachedFixedPoint::No;
493 return false;
494 }
495
496 true
497 });
498 attribute_macros.retain(|(module_id, ast_id, path)| {
499 let resolved_res = self.resolve_attribute_macro(path);
500
501 if let Some(def) = resolved_res {
502 let call_id = def.as_call_id(self.db, MacroCallKind::Attr(*ast_id));
503 resolved.push((*module_id, call_id));
485 res = ReachedFixedPoint::No; 504 res = ReachedFixedPoint::No;
486 return false; 505 return false;
487 } 506 }
@@ -490,44 +509,41 @@ where
490 }); 509 });
491 510
492 self.unexpanded_macros = macros; 511 self.unexpanded_macros = macros;
512 self.unexpanded_attribute_macros = attribute_macros;
493 513
494 for (module_id, macro_call_id, macro_def_id) in resolved { 514 for (module_id, macro_call_id) in resolved {
495 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id); 515 self.collect_macro_expansion(module_id, macro_call_id);
496 } 516 }
497 517
498 res 518 res
499 } 519 }
500 520
501 fn collect_macro_expansion( 521 fn resolve_attribute_macro(&self, path: &ModPath) -> Option<MacroDefId> {
502 &mut self, 522 // FIXME this is currently super hacky, just enough to support the
503 module_id: LocalModuleId, 523 // built-in derives
504 macro_call_id: MacroCallId, 524 if let Some(name) = path.as_ident() {
505 macro_def_id: MacroDefId, 525 // FIXME this should actually be handled with the normal name
506 ) { 526 // resolution; the std lib defines built-in stubs for the derives,
507 if self.poison_macros.contains(&macro_def_id) { 527 // but these are new-style `macro`s, which we don't support yet
508 return; 528 if let Some(def_id) = find_builtin_derive(name) {
509 } 529 return Some(def_id);
510
511 self.macro_stack_monitor.increase(macro_def_id);
512
513 if !self.macro_stack_monitor.is_poison(macro_def_id) {
514 let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items);
515 let raw_items = self.db.raw_items(file_id);
516 let mod_dir = self.mod_dirs[&module_id].clone();
517 ModCollector {
518 def_collector: &mut *self,
519 file_id,
520 module_id,
521 raw_items: &raw_items,
522 mod_dir,
523 } 530 }
524 .collect(raw_items.items());
525 } else {
526 log::error!("Too deep macro expansion: {:?}", macro_call_id);
527 self.poison_macros.insert(macro_def_id);
528 } 531 }
532 None
533 }
529 534
530 self.macro_stack_monitor.decrease(macro_def_id); 535 fn collect_macro_expansion(&mut self, module_id: LocalModuleId, macro_call_id: MacroCallId) {
536 let file_id: HirFileId = macro_call_id.as_file();
537 let raw_items = self.db.raw_items(file_id);
538 let mod_dir = self.mod_dirs[&module_id].clone();
539 ModCollector {
540 def_collector: &mut *self,
541 file_id,
542 module_id,
543 raw_items: &raw_items,
544 mod_dir,
545 }
546 .collect(raw_items.items());
531 } 547 }
532 548
533 fn finish(self) -> CrateDefMap { 549 fn finish(self) -> CrateDefMap {
@@ -581,20 +597,31 @@ where
581 raw::RawItemKind::Module(m) => { 597 raw::RawItemKind::Module(m) => {
582 self.collect_module(&self.raw_items[m], &item.attrs) 598 self.collect_module(&self.raw_items[m], &item.attrs)
583 } 599 }
584 raw::RawItemKind::Import(import_id) => self 600 raw::RawItemKind::Import(import_id) => {
585 .def_collector 601 self.def_collector.unresolved_imports.push(ImportDirective {
586 .unresolved_imports 602 module_id: self.module_id,
587 .push((self.module_id, import_id, self.raw_items[import_id].clone())), 603 import_id,
588 raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), 604 import: self.raw_items[import_id].clone(),
605 status: PartialResolvedImport::Unresolved,
606 })
607 }
608 raw::RawItemKind::Def(def) => {
609 self.define_def(&self.raw_items[def], &item.attrs)
610 }
589 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), 611 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
590 raw::RawItemKind::Impl(imp) => { 612 raw::RawItemKind::Impl(imp) => {
591 let module = ModuleId { 613 let module = ModuleId {
592 krate: self.def_collector.def_map.krate, 614 krate: self.def_collector.def_map.krate,
593 local_id: self.module_id, 615 local_id: self.module_id,
594 }; 616 };
595 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); 617 let container = ContainerId::ModuleId(module);
596 let imp_id = ImplId::from_ast_id(ctx, self.raw_items[imp].ast_id); 618 let ast_id = self.raw_items[imp].ast_id;
597 self.def_collector.def_map.modules[self.module_id].impls.push(imp_id) 619 let impl_id =
620 ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
621 .intern(self.def_collector.db);
622 self.def_collector.def_map.modules[self.module_id]
623 .scope
624 .define_impl(impl_id)
598 } 625 }
599 } 626 }
600 } 627 }
@@ -667,72 +694,91 @@ where
667 let modules = &mut self.def_collector.def_map.modules; 694 let modules = &mut self.def_collector.def_map.modules;
668 let res = modules.alloc(ModuleData::default()); 695 let res = modules.alloc(ModuleData::default());
669 modules[res].parent = Some(self.module_id); 696 modules[res].parent = Some(self.module_id);
670 modules[res].declaration = Some(declaration); 697 modules[res].origin = ModuleOrigin::not_sure_file(definition, declaration);
671 modules[res].definition = definition; 698 for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() {
672 modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); 699 modules[res].scope.define_legacy_macro(name, mac)
700 }
673 modules[self.module_id].children.insert(name.clone(), res); 701 modules[self.module_id].children.insert(name.clone(), res);
674 let resolution = Resolution { 702 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res };
675 def: PerNs::types( 703 let def: ModuleDefId = module.into();
676 ModuleId { krate: self.def_collector.def_map.krate, local_id: res }.into(), 704 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
677 ), 705 self.def_collector.update(self.module_id, &[(name, def.into())]);
678 import: None,
679 };
680 self.def_collector.update(self.module_id, None, &[(name, resolution)]);
681 res 706 res
682 } 707 }
683 708
684 fn define_def(&mut self, def: &raw::DefData) { 709 fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) {
685 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; 710 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
686 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); 711 // FIXME: check attrs to see if this is an attribute macro invocation;
712 // in which case we don't add the invocation, just a single attribute
713 // macro invocation
687 714
688 let name = def.name.clone(); 715 self.collect_derives(attrs, def);
689 let def: PerNs = match def.kind {
690 raw::DefKind::Function(ast_id) => {
691 let def = FunctionLoc {
692 container: ContainerId::ModuleId(module),
693 ast_id: AstId::new(self.file_id, ast_id),
694 }
695 .intern(self.def_collector.db);
696 716
697 PerNs::values(def.into()) 717 let name = def.name.clone();
718 let container = ContainerId::ModuleId(module);
719 let def: ModuleDefId = match def.kind {
720 raw::DefKind::Function(ast_id) => FunctionLoc {
721 container: container.into(),
722 ast_id: AstId::new(self.file_id, ast_id),
698 } 723 }
724 .intern(self.def_collector.db)
725 .into(),
699 raw::DefKind::Struct(ast_id) => { 726 raw::DefKind::Struct(ast_id) => {
700 let id = StructId::from_ast_id(ctx, ast_id).into(); 727 StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
701 PerNs::both(id, id) 728 .intern(self.def_collector.db)
729 .into()
702 } 730 }
703 raw::DefKind::Union(ast_id) => { 731 raw::DefKind::Union(ast_id) => {
704 let id = UnionId::from_ast_id(ctx, ast_id).into(); 732 UnionLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
705 PerNs::both(id, id) 733 .intern(self.def_collector.db)
734 .into()
735 }
736 raw::DefKind::Enum(ast_id) => {
737 EnumLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
738 .intern(self.def_collector.db)
739 .into()
706 } 740 }
707 raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()),
708 raw::DefKind::Const(ast_id) => { 741 raw::DefKind::Const(ast_id) => {
709 let def = ConstLoc { 742 ConstLoc { container: container.into(), ast_id: AstId::new(self.file_id, ast_id) }
710 container: ContainerId::ModuleId(module), 743 .intern(self.def_collector.db)
711 ast_id: AstId::new(self.file_id, ast_id), 744 .into()
712 }
713 .intern(self.def_collector.db);
714
715 PerNs::values(def.into())
716 } 745 }
717 raw::DefKind::Static(ast_id) => { 746 raw::DefKind::Static(ast_id) => {
718 let def = StaticLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) } 747 StaticLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
719 .intern(self.def_collector.db); 748 .intern(self.def_collector.db)
720 749 .into()
721 PerNs::values(def.into())
722 } 750 }
723 raw::DefKind::Trait(ast_id) => PerNs::types(TraitId::from_ast_id(ctx, ast_id).into()), 751 raw::DefKind::Trait(ast_id) => {
724 raw::DefKind::TypeAlias(ast_id) => { 752 TraitLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
725 let def = TypeAliasLoc { 753 .intern(self.def_collector.db)
726 container: ContainerId::ModuleId(module), 754 .into()
727 ast_id: AstId::new(self.file_id, ast_id),
728 }
729 .intern(self.def_collector.db);
730
731 PerNs::types(def.into())
732 } 755 }
756 raw::DefKind::TypeAlias(ast_id) => TypeAliasLoc {
757 container: container.into(),
758 ast_id: AstId::new(self.file_id, ast_id),
759 }
760 .intern(self.def_collector.db)
761 .into(),
733 }; 762 };
734 let resolution = Resolution { def, import: None }; 763 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
735 self.def_collector.update(self.module_id, None, &[(name, resolution)]) 764 self.def_collector.update(self.module_id, &[(name, def.into())])
765 }
766
767 fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) {
768 for derive_subtree in attrs.by_key("derive").tt_values() {
769 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
770 for tt in &derive_subtree.token_trees {
771 let ident = match &tt {
772 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident,
773 tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok
774 _ => continue, // anything else would be an error (which we currently ignore)
775 };
776 let path = ModPath::from_tt_ident(ident);
777
778 let ast_id = AstId::new(self.file_id, def.kind.ast_id());
779 self.def_collector.unexpanded_attribute_macros.push((self.module_id, ast_id, path));
780 }
781 }
736 } 782 }
737 783
738 fn collect_macro(&mut self, mac: &raw::MacroData) { 784 fn collect_macro(&mut self, mac: &raw::MacroData) {
@@ -758,8 +804,8 @@ where
758 if is_macro_rules(&mac.path) { 804 if is_macro_rules(&mac.path) {
759 if let Some(name) = &mac.name { 805 if let Some(name) = &mac.name {
760 let macro_id = MacroDefId { 806 let macro_id = MacroDefId {
761 ast_id, 807 ast_id: Some(ast_id),
762 krate: self.def_collector.def_map.krate, 808 krate: Some(self.def_collector.def_map.krate),
763 kind: MacroDefKind::Declarative, 809 kind: MacroDefKind::Declarative,
764 }; 810 };
765 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); 811 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
@@ -767,14 +813,20 @@ where
767 return; 813 return;
768 } 814 }
769 815
770 // Case 2: try to resolve in legacy scope and expand macro_rules, triggering 816 // Case 2: try to resolve in legacy scope and expand macro_rules
771 // recursive item collection.
772 if let Some(macro_def) = mac.path.as_ident().and_then(|name| { 817 if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
773 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) 818 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
774 }) { 819 }) {
775 let macro_call_id = macro_def.as_call_id(self.def_collector.db, ast_id); 820 let macro_call_id =
821 macro_def.as_call_id(self.def_collector.db, MacroCallKind::FnLike(ast_id));
822
823 self.def_collector.unexpanded_macros.push(MacroDirective {
824 module_id: self.module_id,
825 path: mac.path.clone(),
826 ast_id,
827 legacy: Some(macro_call_id),
828 });
776 829
777 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def);
778 return; 830 return;
779 } 831 }
780 832
@@ -782,13 +834,19 @@ where
782 // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only. 834 // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
783 let mut path = mac.path.clone(); 835 let mut path = mac.path.clone();
784 if path.is_ident() { 836 if path.is_ident() {
785 path.kind = PathKind::Self_; 837 path.kind = PathKind::Super(0);
786 } 838 }
787 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path)); 839
840 self.def_collector.unexpanded_macros.push(MacroDirective {
841 module_id: self.module_id,
842 path,
843 ast_id,
844 legacy: None,
845 });
788 } 846 }
789 847
790 fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { 848 fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
791 let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); 849 let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros();
792 for (name, macro_) in macros { 850 for (name, macro_) in macros {
793 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); 851 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
794 } 852 }
@@ -803,45 +861,35 @@ where
803 } 861 }
804} 862}
805 863
806fn is_macro_rules(path: &Path) -> bool { 864fn is_macro_rules(path: &ModPath) -> bool {
807 path.as_ident() == Some(&name::MACRO_RULES) 865 path.as_ident() == Some(&name![macro_rules])
808} 866}
809 867
810#[cfg(test)] 868#[cfg(test)]
811mod tests { 869mod tests {
870 use crate::{db::DefDatabase, test_db::TestDB};
812 use ra_arena::Arena; 871 use ra_arena::Arena;
813 use ra_db::{fixture::WithFixture, SourceDatabase}; 872 use ra_db::{fixture::WithFixture, SourceDatabase};
814 use rustc_hash::FxHashSet;
815
816 use crate::{db::DefDatabase, test_db::TestDB};
817 873
818 use super::*; 874 use super::*;
819 875
820 fn do_collect_defs( 876 fn do_collect_defs(db: &impl DefDatabase, def_map: CrateDefMap) -> CrateDefMap {
821 db: &impl DefDatabase,
822 def_map: CrateDefMap,
823 monitor: MacroStackMonitor,
824 ) -> (CrateDefMap, FxHashSet<MacroDefId>) {
825 let mut collector = DefCollector { 877 let mut collector = DefCollector {
826 db, 878 db,
827 def_map, 879 def_map,
828 glob_imports: FxHashMap::default(), 880 glob_imports: FxHashMap::default(),
829 unresolved_imports: Vec::new(), 881 unresolved_imports: Vec::new(),
882 resolved_imports: Vec::new(),
830 unexpanded_macros: Vec::new(), 883 unexpanded_macros: Vec::new(),
884 unexpanded_attribute_macros: Vec::new(),
831 mod_dirs: FxHashMap::default(), 885 mod_dirs: FxHashMap::default(),
832 macro_stack_monitor: monitor,
833 poison_macros: FxHashSet::default(),
834 cfg_options: &CfgOptions::default(), 886 cfg_options: &CfgOptions::default(),
835 }; 887 };
836 collector.collect(); 888 collector.collect();
837 (collector.def_map, collector.poison_macros) 889 collector.def_map
838 } 890 }
839 891
840 fn do_limited_resolve( 892 fn do_resolve(code: &str) -> CrateDefMap {
841 code: &str,
842 limit: u32,
843 poison_limit: u32,
844 ) -> (CrateDefMap, FxHashSet<MacroDefId>) {
845 let (db, _file_id) = TestDB::with_single_file(&code); 893 let (db, _file_id) = TestDB::with_single_file(&code);
846 let krate = db.test_crate(); 894 let krate = db.test_crate();
847 895
@@ -859,59 +907,18 @@ mod tests {
859 diagnostics: Vec::new(), 907 diagnostics: Vec::new(),
860 } 908 }
861 }; 909 };
862 910 do_collect_defs(&db, def_map)
863 let mut monitor = MacroStackMonitor::default();
864 monitor.validator = Some(Box::new(move |count| {
865 assert!(count < limit);
866 count >= poison_limit
867 }));
868
869 do_collect_defs(&db, def_map, monitor)
870 } 911 }
871 912
872 #[test] 913 #[test]
873 fn test_macro_expand_limit_width() { 914 fn test_macro_expand_will_stop() {
874 do_limited_resolve( 915 do_resolve(
875 r#" 916 r#"
876 macro_rules! foo { 917 macro_rules! foo {
877 ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); } 918 ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); }
878 } 919 }
879foo!(KABOOM); 920foo!(KABOOM);
880 "#, 921 "#,
881 16,
882 1000,
883 ); 922 );
884 } 923 }
885
886 #[test]
887 fn test_macro_expand_poisoned() {
888 let (_, poison_macros) = do_limited_resolve(
889 r#"
890 macro_rules! foo {
891 ($ty:ty) => { foo!($ty); }
892 }
893foo!(KABOOM);
894 "#,
895 100,
896 16,
897 );
898
899 assert_eq!(poison_macros.len(), 1);
900 }
901
902 #[test]
903 fn test_macro_expand_normal() {
904 let (_, poison_macros) = do_limited_resolve(
905 r#"
906 macro_rules! foo {
907 ($ident:ident) => { struct $ident {} }
908 }
909foo!(Bar);
910 "#,
911 16,
912 16,
913 );
914
915 assert_eq!(poison_macros.len(), 0);
916 }
917} 924}
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index b72c55bd1..695014c7b 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -10,16 +10,18 @@
10//! 10//!
11//! `ReachedFixedPoint` signals about this. 11//! `ReachedFixedPoint` signals about this.
12 12
13use std::iter::successors;
14
13use hir_expand::name::Name; 15use hir_expand::name::Name;
14use ra_db::Edition; 16use ra_db::Edition;
15use test_utils::tested_by; 17use test_utils::tested_by;
16 18
17use crate::{ 19use crate::{
18 db::DefDatabase, 20 db::DefDatabase,
19 nameres::CrateDefMap, 21 nameres::{BuiltinShadowMode, CrateDefMap},
20 path::{Path, PathKind}, 22 path::{ModPath, PathKind},
21 per_ns::PerNs, 23 per_ns::PerNs,
22 AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, 24 AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
23}; 25};
24 26
25#[derive(Debug, Clone, Copy, PartialEq, Eq)] 27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -39,19 +41,21 @@ pub(super) struct ResolvePathResult {
39 pub(super) resolved_def: PerNs, 41 pub(super) resolved_def: PerNs,
40 pub(super) segment_index: Option<usize>, 42 pub(super) segment_index: Option<usize>,
41 pub(super) reached_fixedpoint: ReachedFixedPoint, 43 pub(super) reached_fixedpoint: ReachedFixedPoint,
44 pub(super) krate: Option<CrateId>,
42} 45}
43 46
44impl ResolvePathResult { 47impl ResolvePathResult {
45 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { 48 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
46 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) 49 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None)
47 } 50 }
48 51
49 fn with( 52 fn with(
50 resolved_def: PerNs, 53 resolved_def: PerNs,
51 reached_fixedpoint: ReachedFixedPoint, 54 reached_fixedpoint: ReachedFixedPoint,
52 segment_index: Option<usize>, 55 segment_index: Option<usize>,
56 krate: Option<CrateId>,
53 ) -> ResolvePathResult { 57 ) -> ResolvePathResult {
54 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } 58 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index, krate }
55 } 59 }
56} 60}
57 61
@@ -67,8 +71,18 @@ impl CrateDefMap {
67 db: &impl DefDatabase, 71 db: &impl DefDatabase,
68 mode: ResolveMode, 72 mode: ResolveMode,
69 original_module: LocalModuleId, 73 original_module: LocalModuleId,
70 path: &Path, 74 path: &ModPath,
75 shadow: BuiltinShadowMode,
71 ) -> ResolvePathResult { 76 ) -> ResolvePathResult {
77 // if it is not the last segment, we prefer the module to the builtin
78 let prefer_module = |index| {
79 if index == path.segments.len() - 1 {
80 shadow
81 } else {
82 BuiltinShadowMode::Module
83 }
84 };
85
72 let mut segments = path.segments.iter().enumerate(); 86 let mut segments = path.segments.iter().enumerate();
73 let mut curr_per_ns: PerNs = match path.kind { 87 let mut curr_per_ns: PerNs = match path.kind {
74 PathKind::DollarCrate(krate) => { 88 PathKind::DollarCrate(krate) => {
@@ -85,9 +99,6 @@ impl CrateDefMap {
85 PathKind::Crate => { 99 PathKind::Crate => {
86 PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into()) 100 PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into())
87 } 101 }
88 PathKind::Self_ => {
89 PerNs::types(ModuleId { krate: self.krate, local_id: original_module }.into())
90 }
91 // plain import or absolute path in 2015: crate-relative with 102 // plain import or absolute path in 2015: crate-relative with
92 // fallback to extern prelude (with the simplification in 103 // fallback to extern prelude (with the simplification in
93 // rust-lang/rust#57745) 104 // rust-lang/rust#57745)
@@ -96,24 +107,26 @@ impl CrateDefMap {
96 if self.edition == Edition::Edition2015 107 if self.edition == Edition::Edition2015
97 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => 108 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
98 { 109 {
99 let segment = match segments.next() { 110 let (idx, segment) = match segments.next() {
100 Some((_, segment)) => segment, 111 Some((idx, segment)) => (idx, segment),
101 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 112 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
102 }; 113 };
103 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 114 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
104 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) 115 self.resolve_name_in_crate_root_or_extern_prelude(&segment, prefer_module(idx))
105 } 116 }
106 PathKind::Plain => { 117 PathKind::Plain => {
107 let segment = match segments.next() { 118 let (idx, segment) = match segments.next() {
108 Some((_, segment)) => segment, 119 Some((idx, segment)) => (idx, segment),
109 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 120 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
110 }; 121 };
111 log::debug!("resolving {:?} in module", segment); 122 log::debug!("resolving {:?} in module", segment);
112 self.resolve_name_in_module(db, original_module, &segment.name) 123 self.resolve_name_in_module(db, original_module, &segment, prefer_module(idx))
113 } 124 }
114 PathKind::Super => { 125 PathKind::Super(lvl) => {
115 if let Some(p) = self.modules[original_module].parent { 126 let m = successors(Some(original_module), |m| self.modules[*m].parent)
116 PerNs::types(ModuleId { krate: self.krate, local_id: p }.into()) 127 .nth(lvl as usize);
128 if let Some(local_id) = m {
129 PerNs::types(ModuleId { krate: self.krate, local_id }.into())
117 } else { 130 } else {
118 log::debug!("super path in root module"); 131 log::debug!("super path in root module");
119 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 132 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -125,18 +138,13 @@ impl CrateDefMap {
125 Some((_, segment)) => segment, 138 Some((_, segment)) => segment,
126 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 139 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
127 }; 140 };
128 if let Some(def) = self.extern_prelude.get(&segment.name) { 141 if let Some(def) = self.extern_prelude.get(&segment) {
129 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 142 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
130 PerNs::types(*def) 143 PerNs::types(*def)
131 } else { 144 } else {
132 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude 145 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
133 } 146 }
134 } 147 }
135 PathKind::Type(_) => {
136 // This is handled in `infer::infer_path_expr`
137 // The result returned here does not matter
138 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
139 }
140 }; 148 };
141 149
142 for (i, segment) in segments { 150 for (i, segment) in segments {
@@ -156,32 +164,29 @@ impl CrateDefMap {
156 curr_per_ns = match curr { 164 curr_per_ns = match curr {
157 ModuleDefId::ModuleId(module) => { 165 ModuleDefId::ModuleId(module) => {
158 if module.krate != self.krate { 166 if module.krate != self.krate {
159 let path = 167 let path = ModPath {
160 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; 168 segments: path.segments[i..].to_vec(),
169 kind: PathKind::Super(0),
170 };
161 log::debug!("resolving {:?} in other crate", path); 171 log::debug!("resolving {:?} in other crate", path);
162 let defp_map = db.crate_def_map(module.krate); 172 let defp_map = db.crate_def_map(module.krate);
163 let (def, s) = defp_map.resolve_path(db, module.local_id, &path); 173 let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
164 return ResolvePathResult::with( 174 return ResolvePathResult::with(
165 def, 175 def,
166 ReachedFixedPoint::Yes, 176 ReachedFixedPoint::Yes,
167 s.map(|s| s + i), 177 s.map(|s| s + i),
178 Some(module.krate),
168 ); 179 );
169 } 180 }
170 181
171 // Since it is a qualified path here, it should not contains legacy macros 182 // Since it is a qualified path here, it should not contains legacy macros
172 match self[module.local_id].scope.get(&segment.name) { 183 self[module.local_id].scope.get(&segment, prefer_module(i))
173 Some(res) => res.def,
174 _ => {
175 log::debug!("path segment {:?} not found", segment.name);
176 return ResolvePathResult::empty(ReachedFixedPoint::No);
177 }
178 }
179 } 184 }
180 ModuleDefId::AdtId(AdtId::EnumId(e)) => { 185 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
181 // enum variant 186 // enum variant
182 tested_by!(can_import_enum_variant); 187 tested_by!(can_import_enum_variant);
183 let enum_data = db.enum_data(e); 188 let enum_data = db.enum_data(e);
184 match enum_data.variant(&segment.name) { 189 match enum_data.variant(&segment) {
185 Some(local_id) => { 190 Some(local_id) => {
186 let variant = EnumVariantId { parent: e, local_id }; 191 let variant = EnumVariantId { parent: e, local_id };
187 PerNs::both(variant.into(), variant.into()) 192 PerNs::both(variant.into(), variant.into())
@@ -191,6 +196,7 @@ impl CrateDefMap {
191 PerNs::types(e.into()), 196 PerNs::types(e.into()),
192 ReachedFixedPoint::Yes, 197 ReachedFixedPoint::Yes,
193 Some(i), 198 Some(i),
199 Some(self.krate),
194 ); 200 );
195 } 201 }
196 } 202 }
@@ -200,7 +206,7 @@ impl CrateDefMap {
200 // (`Struct::method`), or some other kind of associated item 206 // (`Struct::method`), or some other kind of associated item
201 log::debug!( 207 log::debug!(
202 "path segment {:?} resolved to non-module {:?}, but is not last", 208 "path segment {:?} resolved to non-module {:?}, but is not last",
203 segment.name, 209 segment,
204 curr, 210 curr,
205 ); 211 );
206 212
@@ -208,11 +214,13 @@ impl CrateDefMap {
208 PerNs::types(s), 214 PerNs::types(s),
209 ReachedFixedPoint::Yes, 215 ReachedFixedPoint::Yes,
210 Some(i), 216 Some(i),
217 Some(self.krate),
211 ); 218 );
212 } 219 }
213 }; 220 };
214 } 221 }
215 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) 222
223 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate))
216 } 224 }
217 225
218 fn resolve_name_in_module( 226 fn resolve_name_in_module(
@@ -220,6 +228,7 @@ impl CrateDefMap {
220 db: &impl DefDatabase, 228 db: &impl DefDatabase,
221 module: LocalModuleId, 229 module: LocalModuleId,
222 name: &Name, 230 name: &Name,
231 shadow: BuiltinShadowMode,
223 ) -> PerNs { 232 ) -> PerNs {
224 // Resolve in: 233 // Resolve in:
225 // - legacy scope of macro 234 // - legacy scope of macro
@@ -228,23 +237,31 @@ impl CrateDefMap {
228 // - std prelude 237 // - std prelude
229 let from_legacy_macro = 238 let from_legacy_macro =
230 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); 239 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
231 let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def); 240 let from_scope = self[module].scope.get(name, shadow);
232 let from_extern_prelude = 241 let from_extern_prelude =
233 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 242 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
234 let from_prelude = self.resolve_in_prelude(db, name); 243 let from_prelude = self.resolve_in_prelude(db, name, shadow);
235 244
236 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) 245 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
237 } 246 }
238 247
239 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { 248 fn resolve_name_in_crate_root_or_extern_prelude(
240 let from_crate_root = 249 &self,
241 self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def); 250 name: &Name,
251 shadow: BuiltinShadowMode,
252 ) -> PerNs {
253 let from_crate_root = self[self.root].scope.get(name, shadow);
242 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 254 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
243 255
244 from_crate_root.or(from_extern_prelude) 256 from_crate_root.or(from_extern_prelude)
245 } 257 }
246 258
247 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs { 259 fn resolve_in_prelude(
260 &self,
261 db: &impl DefDatabase,
262 name: &Name,
263 shadow: BuiltinShadowMode,
264 ) -> PerNs {
248 if let Some(prelude) = self.prelude { 265 if let Some(prelude) = self.prelude {
249 let keep; 266 let keep;
250 let def_map = if prelude.krate == self.krate { 267 let def_map = if prelude.krate == self.krate {
@@ -254,7 +271,7 @@ impl CrateDefMap {
254 keep = db.crate_def_map(prelude.krate); 271 keep = db.crate_def_map(prelude.krate);
255 &keep 272 &keep
256 }; 273 };
257 def_map[prelude.local_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) 274 def_map[prelude.local_id].scope.get(name, shadow)
258 } else { 275 } else {
259 PerNs::none() 276 PerNs::none()
260 } 277 }
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 6eb106094..73dc08745 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -10,21 +10,18 @@ use std::{ops::Index, sync::Arc};
10use hir_expand::{ 10use hir_expand::{
11 ast_id_map::AstIdMap, 11 ast_id_map::AstIdMap,
12 db::AstDatabase, 12 db::AstDatabase,
13 either::Either,
14 hygiene::Hygiene, 13 hygiene::Hygiene,
15 name::{AsName, Name}, 14 name::{AsName, Name},
16}; 15};
17use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 16use ra_arena::{impl_arena_id, Arena, RawId};
17use ra_prof::profile;
18use ra_syntax::{ 18use ra_syntax::{
19 ast::{self, AttrsOwner, NameOwner}, 19 ast::{self, AttrsOwner, NameOwner},
20 AstNode, AstPtr, 20 AstNode,
21}; 21};
22use test_utils::tested_by; 22use test_utils::tested_by;
23 23
24use crate::{ 24use crate::{attr::Attrs, db::DefDatabase, path::ModPath, FileAstId, HirFileId, InFile};
25 attr::Attrs, db::DefDatabase, path::Path, trace::Trace, FileAstId, HirFileId, LocalImportId,
26 Source,
27};
28 25
29/// `RawItems` is a set of top-level items in a file (except for impls). 26/// `RawItems` is a set of top-level items in a file (except for impls).
30/// 27///
@@ -33,7 +30,7 @@ use crate::{
33#[derive(Debug, Default, PartialEq, Eq)] 30#[derive(Debug, Default, PartialEq, Eq)]
34pub struct RawItems { 31pub struct RawItems {
35 modules: Arena<Module, ModuleData>, 32 modules: Arena<Module, ModuleData>,
36 imports: Arena<LocalImportId, ImportData>, 33 imports: Arena<Import, ImportData>,
37 defs: Arena<Def, DefData>, 34 defs: Arena<Def, DefData>,
38 macros: Arena<Macro, MacroData>, 35 macros: Arena<Macro, MacroData>,
39 impls: Arena<Impl, ImplData>, 36 impls: Arena<Impl, ImplData>,
@@ -41,35 +38,15 @@ pub struct RawItems {
41 items: Vec<RawItem>, 38 items: Vec<RawItem>,
42} 39}
43 40
44#[derive(Debug, Default, PartialEq, Eq)]
45pub struct ImportSourceMap {
46 map: ArenaMap<LocalImportId, ImportSourcePtr>,
47}
48
49type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>;
50
51impl ImportSourceMap {
52 pub fn get(&self, import: LocalImportId) -> ImportSourcePtr {
53 self.map[import].clone()
54 }
55}
56
57impl RawItems { 41impl RawItems {
58 pub(crate) fn raw_items_query( 42 pub(crate) fn raw_items_query(
59 db: &(impl DefDatabase + AstDatabase), 43 db: &(impl DefDatabase + AstDatabase),
60 file_id: HirFileId, 44 file_id: HirFileId,
61 ) -> Arc<RawItems> { 45 ) -> Arc<RawItems> {
62 db.raw_items_with_source_map(file_id).0 46 let _p = profile("raw_items_query");
63 }
64
65 pub(crate) fn raw_items_with_source_map_query(
66 db: &(impl DefDatabase + AstDatabase),
67 file_id: HirFileId,
68 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
69 let mut collector = RawItemsCollector { 47 let mut collector = RawItemsCollector {
70 raw_items: RawItems::default(), 48 raw_items: RawItems::default(),
71 source_ast_id_map: db.ast_id_map(file_id), 49 source_ast_id_map: db.ast_id_map(file_id),
72 imports: Trace::new(),
73 file_id, 50 file_id,
74 hygiene: Hygiene::new(db, file_id), 51 hygiene: Hygiene::new(db, file_id),
75 }; 52 };
@@ -80,11 +57,8 @@ impl RawItems {
80 collector.process_module(None, item_list); 57 collector.process_module(None, item_list);
81 } 58 }
82 } 59 }
83 let mut raw_items = collector.raw_items; 60 let raw_items = collector.raw_items;
84 let (arena, map) = collector.imports.into_arena_and_map(); 61 Arc::new(raw_items)
85 raw_items.imports = arena;
86 let source_map = ImportSourceMap { map };
87 (Arc::new(raw_items), Arc::new(source_map))
88 } 62 }
89 63
90 pub(super) fn items(&self) -> &[RawItem] { 64 pub(super) fn items(&self) -> &[RawItem] {
@@ -99,9 +73,9 @@ impl Index<Module> for RawItems {
99 } 73 }
100} 74}
101 75
102impl Index<LocalImportId> for RawItems { 76impl Index<Import> for RawItems {
103 type Output = ImportData; 77 type Output = ImportData;
104 fn index(&self, idx: LocalImportId) -> &ImportData { 78 fn index(&self, idx: Import) -> &ImportData {
105 &self.imports[idx] 79 &self.imports[idx]
106 } 80 }
107} 81}
@@ -136,7 +110,7 @@ pub(super) struct RawItem {
136#[derive(Debug, PartialEq, Eq, Clone, Copy)] 110#[derive(Debug, PartialEq, Eq, Clone, Copy)]
137pub(super) enum RawItemKind { 111pub(super) enum RawItemKind {
138 Module(Module), 112 Module(Module),
139 Import(LocalImportId), 113 Import(Import),
140 Def(Def), 114 Def(Def),
141 Macro(Macro), 115 Macro(Macro),
142 Impl(Impl), 116 Impl(Impl),
@@ -152,9 +126,13 @@ pub(super) enum ModuleData {
152 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, 126 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
153} 127}
154 128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
130pub(crate) struct Import(RawId);
131impl_arena_id!(Import);
132
155#[derive(Debug, Clone, PartialEq, Eq)] 133#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct ImportData { 134pub struct ImportData {
157 pub(super) path: Path, 135 pub(super) path: ModPath,
158 pub(super) alias: Option<Name>, 136 pub(super) alias: Option<Name>,
159 pub(super) is_glob: bool, 137 pub(super) is_glob: bool,
160 pub(super) is_prelude: bool, 138 pub(super) is_prelude: bool,
@@ -184,6 +162,21 @@ pub(super) enum DefKind {
184 TypeAlias(FileAstId<ast::TypeAliasDef>), 162 TypeAlias(FileAstId<ast::TypeAliasDef>),
185} 163}
186 164
165impl DefKind {
166 pub fn ast_id(&self) -> FileAstId<ast::ModuleItem> {
167 match self {
168 DefKind::Function(it) => it.upcast(),
169 DefKind::Struct(it) => it.upcast(),
170 DefKind::Union(it) => it.upcast(),
171 DefKind::Enum(it) => it.upcast(),
172 DefKind::Const(it) => it.upcast(),
173 DefKind::Static(it) => it.upcast(),
174 DefKind::Trait(it) => it.upcast(),
175 DefKind::TypeAlias(it) => it.upcast(),
176 }
177 }
178}
179
187#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 180#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
188pub(super) struct Macro(RawId); 181pub(super) struct Macro(RawId);
189impl_arena_id!(Macro); 182impl_arena_id!(Macro);
@@ -191,7 +184,7 @@ impl_arena_id!(Macro);
191#[derive(Debug, PartialEq, Eq)] 184#[derive(Debug, PartialEq, Eq)]
192pub(super) struct MacroData { 185pub(super) struct MacroData {
193 pub(super) ast_id: FileAstId<ast::MacroCall>, 186 pub(super) ast_id: FileAstId<ast::MacroCall>,
194 pub(super) path: Path, 187 pub(super) path: ModPath,
195 pub(super) name: Option<Name>, 188 pub(super) name: Option<Name>,
196 pub(super) export: bool, 189 pub(super) export: bool,
197 pub(super) builtin: bool, 190 pub(super) builtin: bool,
@@ -208,7 +201,6 @@ pub(super) struct ImplData {
208 201
209struct RawItemsCollector { 202struct RawItemsCollector {
210 raw_items: RawItems, 203 raw_items: RawItems,
211 imports: Trace<LocalImportId, ImportData, ImportSourcePtr>,
212 source_ast_id_map: Arc<AstIdMap>, 204 source_ast_id_map: Arc<AstIdMap>,
213 file_id: HirFileId, 205 file_id: HirFileId,
214 hygiene: Hygiene, 206 hygiene: Hygiene,
@@ -312,10 +304,10 @@ impl RawItemsCollector {
312 let attrs = self.parse_attrs(&use_item); 304 let attrs = self.parse_attrs(&use_item);
313 305
314 let mut buf = Vec::new(); 306 let mut buf = Vec::new();
315 Path::expand_use_item( 307 ModPath::expand_use_item(
316 Source { value: use_item, file_id: self.file_id }, 308 InFile { value: use_item, file_id: self.file_id },
317 &self.hygiene, 309 &self.hygiene,
318 |path, use_tree, is_glob, alias| { 310 |path, _use_tree, is_glob, alias| {
319 let import_data = ImportData { 311 let import_data = ImportData {
320 path, 312 path,
321 alias, 313 alias,
@@ -324,11 +316,11 @@ impl RawItemsCollector {
324 is_extern_crate: false, 316 is_extern_crate: false,
325 is_macro_use: false, 317 is_macro_use: false,
326 }; 318 };
327 buf.push((import_data, Either::A(AstPtr::new(use_tree)))); 319 buf.push(import_data);
328 }, 320 },
329 ); 321 );
330 for (import_data, ptr) in buf { 322 for import_data in buf {
331 self.push_import(current_module, attrs.clone(), import_data, ptr); 323 self.push_import(current_module, attrs.clone(), import_data);
332 } 324 }
333 } 325 }
334 326
@@ -338,7 +330,7 @@ impl RawItemsCollector {
338 extern_crate: ast::ExternCrateItem, 330 extern_crate: ast::ExternCrateItem,
339 ) { 331 ) {
340 if let Some(name_ref) = extern_crate.name_ref() { 332 if let Some(name_ref) = extern_crate.name_ref() {
341 let path = Path::from_name_ref(&name_ref); 333 let path = ModPath::from_name_ref(&name_ref);
342 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); 334 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
343 let attrs = self.parse_attrs(&extern_crate); 335 let attrs = self.parse_attrs(&extern_crate);
344 // FIXME: cfg_attr 336 // FIXME: cfg_attr
@@ -351,18 +343,13 @@ impl RawItemsCollector {
351 is_extern_crate: true, 343 is_extern_crate: true,
352 is_macro_use, 344 is_macro_use,
353 }; 345 };
354 self.push_import( 346 self.push_import(current_module, attrs, import_data);
355 current_module,
356 attrs,
357 import_data,
358 Either::B(AstPtr::new(&extern_crate)),
359 );
360 } 347 }
361 } 348 }
362 349
363 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { 350 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
364 let attrs = self.parse_attrs(&m); 351 let attrs = self.parse_attrs(&m);
365 let path = match m.path().and_then(|path| Path::from_src(path, &self.hygiene)) { 352 let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) {
366 Some(it) => it, 353 Some(it) => it,
367 _ => return, 354 _ => return,
368 }; 355 };
@@ -387,14 +374,8 @@ impl RawItemsCollector {
387 self.push_item(current_module, attrs, RawItemKind::Impl(imp)) 374 self.push_item(current_module, attrs, RawItemKind::Impl(imp))
388 } 375 }
389 376
390 fn push_import( 377 fn push_import(&mut self, current_module: Option<Module>, attrs: Attrs, data: ImportData) {
391 &mut self, 378 let import = self.raw_items.imports.alloc(data);
392 current_module: Option<Module>,
393 attrs: Attrs,
394 data: ImportData,
395 source: ImportSourcePtr,
396 ) {
397 let import = self.imports.alloc(|| source, || data);
398 self.push_item(current_module, attrs, RawItemKind::Import(import)) 379 self.push_item(current_module, attrs, RawItemKind::Import(import))
399 } 380 }
400 381
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 87fcd617c..ff474b53b 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -32,27 +32,22 @@ fn render_crate_def_map(map: &CrateDefMap) -> String {
32 *buf += path; 32 *buf += path;
33 *buf += "\n"; 33 *buf += "\n";
34 34
35 let mut entries = map.modules[module] 35 let mut entries = map.modules[module].scope.collect_resolutions();
36 .scope 36 entries.sort_by_key(|(name, _)| name.clone());
37 .items 37
38 .iter() 38 for (name, def) in entries {
39 .map(|(name, res)| (name, res.def))
40 .collect::<Vec<_>>();
41 entries.sort_by_key(|(name, _)| *name);
42
43 for (name, res) in entries {
44 *buf += &format!("{}:", name); 39 *buf += &format!("{}:", name);
45 40
46 if res.types.is_some() { 41 if def.types.is_some() {
47 *buf += " t"; 42 *buf += " t";
48 } 43 }
49 if res.values.is_some() { 44 if def.values.is_some() {
50 *buf += " v"; 45 *buf += " v";
51 } 46 }
52 if res.macros.is_some() { 47 if def.macros.is_some() {
53 *buf += " m"; 48 *buf += " m";
54 } 49 }
55 if res.is_none() { 50 if def.is_none() {
56 *buf += " _"; 51 *buf += " _";
57 } 52 }
58 53
@@ -558,3 +553,35 @@ fn cfg_test() {
558 ⋮Foo: t v 553 ⋮Foo: t v
559 "###); 554 "###);
560} 555}
556
557#[test]
558fn infer_multiple_namespace() {
559 let map = def_map(
560 r#"
561//- /main.rs
562mod a {
563 pub type T = ();
564 pub use crate::b::*;
565}
566
567use crate::a::T;
568
569mod b {
570 pub const T: () = ();
571}
572"#,
573 );
574
575 assert_snapshot!(map, @r###"
576 ⋮crate
577 ⋮T: t v
578 ⋮a: t
579 ⋮b: t
580
581 ⋮crate::b
582 ⋮T: v
583
584 ⋮crate::a
585 ⋮T: t v
586"###);
587}
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs
index 5b03fe365..5e24cb94d 100644
--- a/crates/ra_hir_def/src/nameres/tests/globs.rs
+++ b/crates/ra_hir_def/src/nameres/tests/globs.rs
@@ -112,3 +112,24 @@ fn glob_enum() {
112 "### 112 "###
113 ); 113 );
114} 114}
115
116#[test]
117fn glob_enum_group() {
118 covers!(glob_enum_group);
119 let map = def_map(
120 "
121 //- /lib.rs
122 enum Foo {
123 Bar, Baz
124 }
125 use self::Foo::{*};
126 ",
127 );
128 assert_snapshot!(map, @r###"
129 ⋮crate
130 ⋮Bar: t v
131 ⋮Baz: t v
132 ⋮Foo: t
133 "###
134 );
135}
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs
index 903a22771..ef2e9435c 100644
--- a/crates/ra_hir_def/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs
@@ -116,7 +116,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
116 let events = db.log_executed(|| { 116 let events = db.log_executed(|| {
117 let crate_def_map = db.crate_def_map(krate); 117 let crate_def_map = db.crate_def_map(krate);
118 let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); 118 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
119 assert_eq!(module_data.scope.items.len(), 1); 119 assert_eq!(module_data.scope.collect_resolutions().len(), 1);
120 }); 120 });
121 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 121 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
122 } 122 }
@@ -126,7 +126,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
126 let events = db.log_executed(|| { 126 let events = db.log_executed(|| {
127 let crate_def_map = db.crate_def_map(krate); 127 let crate_def_map = db.crate_def_map(krate);
128 let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); 128 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
129 assert_eq!(module_data.scope.items.len(), 1); 129 assert_eq!(module_data.scope.collect_resolutions().len(), 1);
130 }); 130 });
131 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 131 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
132 } 132 }
diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs
index 704065633..d104f5993 100644
--- a/crates/ra_hir_def/src/nameres/tests/macros.rs
+++ b/crates/ra_hir_def/src/nameres/tests/macros.rs
@@ -600,3 +600,27 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() {
600 ⋮bar: t v 600 ⋮bar: t v
601 "###); 601 "###);
602} 602}
603
604#[test]
605fn expand_derive() {
606 let map = compute_crate_def_map(
607 "
608 //- /main.rs
609 #[derive(Clone)]
610 struct Foo;
611 ",
612 );
613 assert_eq!(map.modules[map.root].scope.impls().len(), 1);
614}
615
616#[test]
617fn expand_multiple_derive() {
618 let map = compute_crate_def_map(
619 "
620 //- /main.rs
621 #[derive(Copy, Clone)]
622 struct Foo;
623 ",
624 );
625 assert_eq!(map.modules[map.root].scope.impls().len(), 2);
626}
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
index e11530062..e800cc68e 100644
--- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
@@ -668,7 +668,7 @@ fn unresolved_module_diagnostics() {
668 module: LocalModuleId( 668 module: LocalModuleId(
669 0, 669 0,
670 ), 670 ),
671 declaration: AstId { 671 declaration: InFile {
672 file_id: HirFileId( 672 file_id: HirFileId(
673 FileId( 673 FileId(
674 FileId( 674 FileId(
@@ -676,7 +676,7 @@ fn unresolved_module_diagnostics() {
676 ), 676 ),
677 ), 677 ),
678 ), 678 ),
679 file_ast_id: FileAstId { 679 value: FileAstId {
680 raw: ErasedFileAstId( 680 raw: ErasedFileAstId(
681 1, 681 1,
682 ), 682 ),