aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/nameres/collector.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/nameres/collector.rs')
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs637
1 files changed, 322 insertions, 315 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}