aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/nameres/collector.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/nameres/collector.rs')
-rw-r--r--crates/hir_def/src/nameres/collector.rs1279
1 files changed, 1279 insertions, 0 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
new file mode 100644
index 000000000..3e99c8773
--- /dev/null
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -0,0 +1,1279 @@
1//! The core of the module-level name resolution algorithm.
2//!
3//! `DefCollector::collect` contains the fixed-point iteration loop which
4//! resolves imports and expands macros.
5
6use base_db::{CrateId, FileId, ProcMacroId};
7use cfg::CfgOptions;
8use hir_expand::{
9 ast_id_map::FileAstId,
10 builtin_derive::find_builtin_derive,
11 builtin_macro::find_builtin_macro,
12 name::{name, AsName, Name},
13 proc_macro::ProcMacroExpander,
14 HirFileId, MacroCallId, MacroDefId, MacroDefKind,
15};
16use rustc_hash::FxHashMap;
17use syntax::ast;
18use test_utils::mark;
19
20use crate::{
21 attr::Attrs,
22 db::DefDatabase,
23 item_scope::{ImportType, PerNsGlobImports},
24 item_tree::{
25 self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, Mod, ModItem, ModKind, StructDefKind,
26 },
27 nameres::{
28 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
29 BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
30 },
31 path::{ImportAlias, ModPath, PathKind},
32 per_ns::PerNs,
33 visibility::{RawVisibility, Visibility},
34 AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId,
35 FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc,
36 TraitLoc, TypeAliasLoc, UnionLoc,
37};
38
39const GLOB_RECURSION_LIMIT: usize = 100;
40const EXPANSION_DEPTH_LIMIT: usize = 128;
41const FIXED_POINT_LIMIT: usize = 8192;
42
43pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
44 let crate_graph = db.crate_graph();
45
46 // populate external prelude
47 for dep in &crate_graph[def_map.krate].dependencies {
48 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
49 let dep_def_map = db.crate_def_map(dep.crate_id);
50 def_map.extern_prelude.insert(
51 dep.as_name(),
52 ModuleId { krate: dep.crate_id, local_id: dep_def_map.root }.into(),
53 );
54
55 // look for the prelude
56 // If the dependency defines a prelude, we overwrite an already defined
57 // prelude. This is necessary to import the "std" prelude if a crate
58 // depends on both "core" and "std".
59 if dep_def_map.prelude.is_some() {
60 def_map.prelude = dep_def_map.prelude;
61 }
62 }
63
64 let cfg_options = &crate_graph[def_map.krate].cfg_options;
65 let proc_macros = &crate_graph[def_map.krate].proc_macro;
66 let proc_macros = proc_macros
67 .iter()
68 .enumerate()
69 .map(|(idx, it)| {
70 // FIXME: a hacky way to create a Name from string.
71 let name = tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() };
72 (name.as_name(), ProcMacroExpander::new(def_map.krate, ProcMacroId(idx as u32)))
73 })
74 .collect();
75
76 let mut collector = DefCollector {
77 db,
78 def_map,
79 glob_imports: FxHashMap::default(),
80 unresolved_imports: Vec::new(),
81 resolved_imports: Vec::new(),
82
83 unexpanded_macros: Vec::new(),
84 unexpanded_attribute_macros: Vec::new(),
85 mod_dirs: FxHashMap::default(),
86 cfg_options,
87 proc_macros,
88 from_glob_import: Default::default(),
89 };
90 collector.collect();
91 collector.finish()
92}
93
94#[derive(Copy, Clone, Debug, Eq, PartialEq)]
95enum PartialResolvedImport {
96 /// None of any namespaces is resolved
97 Unresolved,
98 /// One of namespaces is resolved
99 Indeterminate(PerNs),
100 /// All namespaces are resolved, OR it is came from other crate
101 Resolved(PerNs),
102}
103
104impl PartialResolvedImport {
105 fn namespaces(&self) -> PerNs {
106 match self {
107 PartialResolvedImport::Unresolved => PerNs::none(),
108 PartialResolvedImport::Indeterminate(ns) => *ns,
109 PartialResolvedImport::Resolved(ns) => *ns,
110 }
111 }
112}
113
114#[derive(Clone, Debug, Eq, PartialEq)]
115struct Import {
116 pub path: ModPath,
117 pub alias: Option<ImportAlias>,
118 pub visibility: RawVisibility,
119 pub is_glob: bool,
120 pub is_prelude: bool,
121 pub is_extern_crate: bool,
122 pub is_macro_use: bool,
123}
124
125impl Import {
126 fn from_use(tree: &ItemTree, id: FileItemTreeId<item_tree::Import>) -> Self {
127 let it = &tree[id];
128 let visibility = &tree[it.visibility];
129 Self {
130 path: it.path.clone(),
131 alias: it.alias.clone(),
132 visibility: visibility.clone(),
133 is_glob: it.is_glob,
134 is_prelude: it.is_prelude,
135 is_extern_crate: false,
136 is_macro_use: false,
137 }
138 }
139
140 fn from_extern_crate(tree: &ItemTree, id: FileItemTreeId<item_tree::ExternCrate>) -> Self {
141 let it = &tree[id];
142 let visibility = &tree[it.visibility];
143 Self {
144 path: it.path.clone(),
145 alias: it.alias.clone(),
146 visibility: visibility.clone(),
147 is_glob: false,
148 is_prelude: false,
149 is_extern_crate: true,
150 is_macro_use: it.is_macro_use,
151 }
152 }
153}
154
155#[derive(Clone, Debug, Eq, PartialEq)]
156struct ImportDirective {
157 module_id: LocalModuleId,
158 import: Import,
159 status: PartialResolvedImport,
160}
161
162#[derive(Clone, Debug, Eq, PartialEq)]
163struct MacroDirective {
164 module_id: LocalModuleId,
165 ast_id: AstIdWithPath<ast::MacroCall>,
166 legacy: Option<MacroCallId>,
167 depth: usize,
168}
169
170#[derive(Clone, Debug, Eq, PartialEq)]
171struct DeriveDirective {
172 module_id: LocalModuleId,
173 ast_id: AstIdWithPath<ast::Item>,
174}
175
176struct DefData<'a> {
177 id: ModuleDefId,
178 name: &'a Name,
179 visibility: &'a RawVisibility,
180 has_constructor: bool,
181}
182
183/// Walks the tree of module recursively
184struct DefCollector<'a> {
185 db: &'a dyn DefDatabase,
186 def_map: CrateDefMap,
187 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>,
188 unresolved_imports: Vec<ImportDirective>,
189 resolved_imports: Vec<ImportDirective>,
190 unexpanded_macros: Vec<MacroDirective>,
191 unexpanded_attribute_macros: Vec<DeriveDirective>,
192 mod_dirs: FxHashMap<LocalModuleId, ModDir>,
193 cfg_options: &'a CfgOptions,
194 proc_macros: Vec<(Name, ProcMacroExpander)>,
195 from_glob_import: PerNsGlobImports,
196}
197
198impl DefCollector<'_> {
199 fn collect(&mut self) {
200 let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
201 let item_tree = self.db.item_tree(file_id.into());
202 let module_id = self.def_map.root;
203 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
204 ModCollector {
205 def_collector: &mut *self,
206 macro_depth: 0,
207 module_id,
208 file_id: file_id.into(),
209 item_tree: &item_tree,
210 mod_dir: ModDir::root(),
211 }
212 .collect(item_tree.top_level_items());
213
214 // main name resolution fixed-point loop.
215 let mut i = 0;
216 loop {
217 self.db.check_canceled();
218 self.resolve_imports();
219
220 match self.resolve_macros() {
221 ReachedFixedPoint::Yes => break,
222 ReachedFixedPoint::No => i += 1,
223 }
224 if i == FIXED_POINT_LIMIT {
225 log::error!("name resolution is stuck");
226 break;
227 }
228 }
229
230 // Resolve all indeterminate resolved imports again
231 // As some of the macros will expand newly import shadowing partial resolved imports
232 // FIXME: We maybe could skip this, if we handle the Indetermine imports in `resolve_imports`
233 // correctly
234 let partial_resolved = self.resolved_imports.iter().filter_map(|directive| {
235 if let PartialResolvedImport::Indeterminate(_) = directive.status {
236 let mut directive = directive.clone();
237 directive.status = PartialResolvedImport::Unresolved;
238 Some(directive)
239 } else {
240 None
241 }
242 });
243 self.unresolved_imports.extend(partial_resolved);
244 self.resolve_imports();
245
246 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
247 // show unresolved imports in completion, etc
248 for directive in unresolved_imports {
249 self.record_resolved_import(&directive)
250 }
251
252 // Record proc-macros
253 self.collect_proc_macro();
254 }
255
256 fn collect_proc_macro(&mut self) {
257 let proc_macros = std::mem::take(&mut self.proc_macros);
258 for (name, expander) in proc_macros {
259 let krate = self.def_map.krate;
260
261 let macro_id = MacroDefId {
262 ast_id: None,
263 krate: Some(krate),
264 kind: MacroDefKind::CustomDerive(expander),
265 local_inner: false,
266 };
267
268 self.define_proc_macro(name.clone(), macro_id);
269 }
270 }
271
272 /// Define a macro with `macro_rules`.
273 ///
274 /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`,
275 /// then it is also defined in the root module scope.
276 /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition.
277 ///
278 /// It is surprising that the macro will never be in the current module scope.
279 /// These code fails with "unresolved import/macro",
280 /// ```rust,compile_fail
281 /// mod m { macro_rules! foo { () => {} } }
282 /// use m::foo as bar;
283 /// ```
284 ///
285 /// ```rust,compile_fail
286 /// macro_rules! foo { () => {} }
287 /// self::foo!();
288 /// crate::foo!();
289 /// ```
290 ///
291 /// Well, this code compiles, because the plain path `foo` in `use` is searched
292 /// in the legacy textual scope only.
293 /// ```rust
294 /// macro_rules! foo { () => {} }
295 /// use foo as bar;
296 /// ```
297 fn define_macro(
298 &mut self,
299 module_id: LocalModuleId,
300 name: Name,
301 macro_: MacroDefId,
302 export: bool,
303 ) {
304 // Textual scoping
305 self.define_legacy_macro(module_id, name.clone(), macro_);
306
307 // Module scoping
308 // In Rust, `#[macro_export]` macros are unconditionally visible at the
309 // crate root, even if the parent modules is **not** visible.
310 if export {
311 self.update(
312 self.def_map.root,
313 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
314 Visibility::Public,
315 ImportType::Named,
316 );
317 }
318 }
319
320 /// Define a legacy textual scoped macro in module
321 ///
322 /// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module.
323 /// It will clone all macros from parent legacy scope, whose definition is prior to
324 /// the definition of current module.
325 /// And also, `macro_use` on a module will import all legacy macros visible inside to
326 /// current legacy scope, with possible shadowing.
327 fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroDefId) {
328 // Always shadowing
329 self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
330 }
331
332 /// Define a proc macro
333 ///
334 /// A proc macro is similar to normal macro scope, but it would not visiable in legacy textual scoped.
335 /// And unconditionally exported.
336 fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) {
337 self.update(
338 self.def_map.root,
339 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
340 Visibility::Public,
341 ImportType::Named,
342 );
343 }
344
345 /// Import macros from `#[macro_use] extern crate`.
346 fn import_macros_from_extern_crate(
347 &mut self,
348 current_module_id: LocalModuleId,
349 import: &item_tree::ExternCrate,
350 ) {
351 log::debug!(
352 "importing macros from extern crate: {:?} ({:?})",
353 import,
354 self.def_map.edition,
355 );
356
357 let res = self.def_map.resolve_name_in_extern_prelude(
358 &import
359 .path
360 .as_ident()
361 .expect("extern crate should have been desugared to one-element path"),
362 );
363
364 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
365 mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
366 self.import_all_macros_exported(current_module_id, m.krate);
367 }
368 }
369
370 /// Import all exported macros from another crate
371 ///
372 /// Exported macros are just all macros in the root module scope.
373 /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
374 /// created by `use` in the root module, ignoring the visibility of `use`.
375 fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
376 let def_map = self.db.crate_def_map(krate);
377 for (name, def) in def_map[def_map.root].scope.macros() {
378 // `macro_use` only bring things into legacy scope.
379 self.define_legacy_macro(current_module_id, name.clone(), def);
380 }
381 }
382
383 /// Import resolution
384 ///
385 /// This is a fix point algorithm. We resolve imports until no forward
386 /// progress in resolving imports is made
387 fn resolve_imports(&mut self) {
388 let mut n_previous_unresolved = self.unresolved_imports.len() + 1;
389
390 while self.unresolved_imports.len() < n_previous_unresolved {
391 n_previous_unresolved = self.unresolved_imports.len();
392 let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
393 for mut directive in imports {
394 directive.status = self.resolve_import(directive.module_id, &directive.import);
395 match directive.status {
396 PartialResolvedImport::Indeterminate(_) => {
397 self.record_resolved_import(&directive);
398 // FIXME: For avoid performance regression,
399 // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved)
400 self.resolved_imports.push(directive)
401 }
402 PartialResolvedImport::Resolved(_) => {
403 self.record_resolved_import(&directive);
404 self.resolved_imports.push(directive)
405 }
406 PartialResolvedImport::Unresolved => {
407 self.unresolved_imports.push(directive);
408 }
409 }
410 }
411 }
412 }
413
414 fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
415 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
416 if import.is_extern_crate {
417 let res = self.def_map.resolve_name_in_extern_prelude(
418 &import
419 .path
420 .as_ident()
421 .expect("extern crate should have been desugared to one-element path"),
422 );
423 PartialResolvedImport::Resolved(res)
424 } else {
425 let res = self.def_map.resolve_path_fp_with_macro(
426 self.db,
427 ResolveMode::Import,
428 module_id,
429 &import.path,
430 BuiltinShadowMode::Module,
431 );
432
433 let def = res.resolved_def;
434 if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
435 return PartialResolvedImport::Unresolved;
436 }
437
438 if let Some(krate) = res.krate {
439 if krate != self.def_map.krate {
440 return PartialResolvedImport::Resolved(def);
441 }
442 }
443
444 // Check whether all namespace is resolved
445 if def.take_types().is_some()
446 && def.take_values().is_some()
447 && def.take_macros().is_some()
448 {
449 PartialResolvedImport::Resolved(def)
450 } else {
451 PartialResolvedImport::Indeterminate(def)
452 }
453 }
454 }
455
456 fn record_resolved_import(&mut self, directive: &ImportDirective) {
457 let module_id = directive.module_id;
458 let import = &directive.import;
459 let def = directive.status.namespaces();
460 let vis = self
461 .def_map
462 .resolve_visibility(self.db, module_id, &directive.import.visibility)
463 .unwrap_or(Visibility::Public);
464
465 if import.is_glob {
466 log::debug!("glob import: {:?}", import);
467 match def.take_types() {
468 Some(ModuleDefId::ModuleId(m)) => {
469 if import.is_prelude {
470 mark::hit!(std_prelude);
471 self.def_map.prelude = Some(m);
472 } else if m.krate != self.def_map.krate {
473 mark::hit!(glob_across_crates);
474 // glob import from other crate => we can just import everything once
475 let item_map = self.db.crate_def_map(m.krate);
476 let scope = &item_map[m.local_id].scope;
477
478 // Module scoped macros is included
479 let items = scope
480 .resolutions()
481 // only keep visible names...
482 .map(|(n, res)| {
483 (n, res.filter_visibility(|v| v.is_visible_from_other_crate()))
484 })
485 .filter(|(_, res)| !res.is_none())
486 .collect::<Vec<_>>();
487
488 self.update(module_id, &items, vis, ImportType::Glob);
489 } else {
490 // glob import from same crate => we do an initial
491 // import, and then need to propagate any further
492 // additions
493 let scope = &self.def_map[m.local_id].scope;
494
495 // Module scoped macros is included
496 let items = scope
497 .resolutions()
498 // only keep visible names...
499 .map(|(n, res)| {
500 (
501 n,
502 res.filter_visibility(|v| {
503 v.is_visible_from_def_map(&self.def_map, module_id)
504 }),
505 )
506 })
507 .filter(|(_, res)| !res.is_none())
508 .collect::<Vec<_>>();
509
510 self.update(module_id, &items, vis, ImportType::Glob);
511 // record the glob import in case we add further items
512 let glob = self.glob_imports.entry(m.local_id).or_default();
513 if !glob.iter().any(|(mid, _)| *mid == module_id) {
514 glob.push((module_id, vis));
515 }
516 }
517 }
518 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
519 mark::hit!(glob_enum);
520 // glob import from enum => just import all the variants
521
522 // XXX: urgh, so this works by accident! Here, we look at
523 // the enum data, and, in theory, this might require us to
524 // look back at the crate_def_map, creating a cycle. For
525 // example, `enum E { crate::some_macro!(); }`. Luckely, the
526 // only kind of macro that is allowed inside enum is a
527 // `cfg_macro`, and we don't need to run name resolution for
528 // it, but this is sheer luck!
529 let enum_data = self.db.enum_data(e);
530 let resolutions = enum_data
531 .variants
532 .iter()
533 .map(|(local_id, variant_data)| {
534 let name = variant_data.name.clone();
535 let variant = EnumVariantId { parent: e, local_id };
536 let res = PerNs::both(variant.into(), variant.into(), vis);
537 (Some(name), res)
538 })
539 .collect::<Vec<_>>();
540 self.update(module_id, &resolutions, vis, ImportType::Glob);
541 }
542 Some(d) => {
543 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
544 }
545 None => {
546 log::debug!("glob import {:?} didn't resolve as type", import);
547 }
548 }
549 } else {
550 match import.path.segments.last() {
551 Some(last_segment) => {
552 let name = match &import.alias {
553 Some(ImportAlias::Alias(name)) => Some(name.clone()),
554 Some(ImportAlias::Underscore) => None,
555 None => Some(last_segment.clone()),
556 };
557 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
558
559 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
560 if import.is_extern_crate && module_id == self.def_map.root {
561 if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) {
562 self.def_map.extern_prelude.insert(name.clone(), def);
563 }
564 }
565
566 self.update(module_id, &[(name, def)], vis, ImportType::Named);
567 }
568 None => mark::hit!(bogus_paths),
569 }
570 }
571 }
572
573 fn update(
574 &mut self,
575 module_id: LocalModuleId,
576 resolutions: &[(Option<Name>, PerNs)],
577 vis: Visibility,
578 import_type: ImportType,
579 ) {
580 self.db.check_canceled();
581 self.update_recursive(module_id, resolutions, vis, import_type, 0)
582 }
583
584 fn update_recursive(
585 &mut self,
586 module_id: LocalModuleId,
587 resolutions: &[(Option<Name>, PerNs)],
588 // All resolutions are imported with this visibility; the visibilies in
589 // the `PerNs` values are ignored and overwritten
590 vis: Visibility,
591 import_type: ImportType,
592 depth: usize,
593 ) {
594 if depth > GLOB_RECURSION_LIMIT {
595 // prevent stack overflows (but this shouldn't be possible)
596 panic!("infinite recursion in glob imports!");
597 }
598 let mut changed = false;
599
600 for (name, res) in resolutions {
601 match name {
602 Some(name) => {
603 let scope = &mut self.def_map.modules[module_id].scope;
604 changed |= scope.push_res_with_import(
605 &mut self.from_glob_import,
606 (module_id, name.clone()),
607 res.with_visibility(vis),
608 import_type,
609 );
610 }
611 None => {
612 let tr = match res.take_types() {
613 Some(ModuleDefId::TraitId(tr)) => tr,
614 Some(other) => {
615 log::debug!("non-trait `_` import of {:?}", other);
616 continue;
617 }
618 None => continue,
619 };
620 let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr);
621 let should_update = match old_vis {
622 None => true,
623 Some(old_vis) => {
624 let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
625 panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr);
626 });
627
628 if max_vis == old_vis {
629 false
630 } else {
631 mark::hit!(upgrade_underscore_visibility);
632 true
633 }
634 }
635 };
636
637 if should_update {
638 changed = true;
639 self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
640 }
641 }
642 }
643 }
644
645 if !changed {
646 return;
647 }
648 let glob_imports = self
649 .glob_imports
650 .get(&module_id)
651 .into_iter()
652 .flat_map(|v| v.iter())
653 .filter(|(glob_importing_module, _)| {
654 // we know all resolutions have the same visibility (`vis`), so we
655 // just need to check that once
656 vis.is_visible_from_def_map(&self.def_map, *glob_importing_module)
657 })
658 .cloned()
659 .collect::<Vec<_>>();
660
661 for (glob_importing_module, glob_import_vis) in glob_imports {
662 self.update_recursive(
663 glob_importing_module,
664 resolutions,
665 glob_import_vis,
666 ImportType::Glob,
667 depth + 1,
668 );
669 }
670 }
671
672 fn resolve_macros(&mut self) -> ReachedFixedPoint {
673 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
674 let mut attribute_macros =
675 std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new());
676 let mut resolved = Vec::new();
677 let mut res = ReachedFixedPoint::Yes;
678 macros.retain(|directive| {
679 if let Some(call_id) = directive.legacy {
680 res = ReachedFixedPoint::No;
681 resolved.push((directive.module_id, call_id, directive.depth));
682 return false;
683 }
684
685 if let Some(call_id) =
686 directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
687 let resolved_res = self.def_map.resolve_path_fp_with_macro(
688 self.db,
689 ResolveMode::Other,
690 directive.module_id,
691 &path,
692 BuiltinShadowMode::Module,
693 );
694 resolved_res.resolved_def.take_macros()
695 })
696 {
697 resolved.push((directive.module_id, call_id, directive.depth));
698 res = ReachedFixedPoint::No;
699 return false;
700 }
701
702 true
703 });
704 attribute_macros.retain(|directive| {
705 if let Some(call_id) =
706 directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| {
707 self.resolve_attribute_macro(&directive, &path)
708 })
709 {
710 resolved.push((directive.module_id, call_id, 0));
711 res = ReachedFixedPoint::No;
712 return false;
713 }
714
715 true
716 });
717
718 self.unexpanded_macros = macros;
719 self.unexpanded_attribute_macros = attribute_macros;
720
721 for (module_id, macro_call_id, depth) in resolved {
722 self.collect_macro_expansion(module_id, macro_call_id, depth);
723 }
724
725 res
726 }
727
728 fn resolve_attribute_macro(
729 &self,
730 directive: &DeriveDirective,
731 path: &ModPath,
732 ) -> Option<MacroDefId> {
733 if let Some(name) = path.as_ident() {
734 // FIXME this should actually be handled with the normal name
735 // resolution; the std lib defines built-in stubs for the derives,
736 // but these are new-style `macro`s, which we don't support yet
737 if let Some(def_id) = find_builtin_derive(name) {
738 return Some(def_id);
739 }
740 }
741 let resolved_res = self.def_map.resolve_path_fp_with_macro(
742 self.db,
743 ResolveMode::Other,
744 directive.module_id,
745 &path,
746 BuiltinShadowMode::Module,
747 );
748
749 resolved_res.resolved_def.take_macros()
750 }
751
752 fn collect_macro_expansion(
753 &mut self,
754 module_id: LocalModuleId,
755 macro_call_id: MacroCallId,
756 depth: usize,
757 ) {
758 if depth > EXPANSION_DEPTH_LIMIT {
759 mark::hit!(macro_expansion_overflow);
760 log::warn!("macro expansion is too deep");
761 return;
762 }
763 let file_id: HirFileId = macro_call_id.as_file();
764 let item_tree = self.db.item_tree(file_id);
765 let mod_dir = self.mod_dirs[&module_id].clone();
766 ModCollector {
767 def_collector: &mut *self,
768 macro_depth: depth,
769 file_id,
770 module_id,
771 item_tree: &item_tree,
772 mod_dir,
773 }
774 .collect(item_tree.top_level_items());
775 }
776
777 fn finish(self) -> CrateDefMap {
778 self.def_map
779 }
780}
781
782/// Walks a single module, populating defs, imports and macros
783struct ModCollector<'a, 'b> {
784 def_collector: &'a mut DefCollector<'b>,
785 macro_depth: usize,
786 module_id: LocalModuleId,
787 file_id: HirFileId,
788 item_tree: &'a ItemTree,
789 mod_dir: ModDir,
790}
791
792impl ModCollector<'_, '_> {
793 fn collect(&mut self, items: &[ModItem]) {
794 // Note: don't assert that inserted value is fresh: it's simply not true
795 // for macros.
796 self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
797
798 // Prelude module is always considered to be `#[macro_use]`.
799 if let Some(prelude_module) = self.def_collector.def_map.prelude {
800 if prelude_module.krate != self.def_collector.def_map.krate {
801 mark::hit!(prelude_is_macro_use);
802 self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
803 }
804 }
805
806 // This should be processed eagerly instead of deferred to resolving.
807 // `#[macro_use] extern crate` is hoisted to imports macros before collecting
808 // any other items.
809 for item in items {
810 if self.is_cfg_enabled(self.item_tree.attrs((*item).into())) {
811 if let ModItem::ExternCrate(id) = item {
812 let import = self.item_tree[*id].clone();
813 if import.is_macro_use {
814 self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
815 }
816 }
817 }
818 }
819
820 for &item in items {
821 let attrs = self.item_tree.attrs(item.into());
822 if self.is_cfg_enabled(attrs) {
823 let module =
824 ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
825 let container = ContainerId::ModuleId(module);
826
827 let mut def = None;
828 match item {
829 ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs),
830 ModItem::Import(import_id) => {
831 self.def_collector.unresolved_imports.push(ImportDirective {
832 module_id: self.module_id,
833 import: Import::from_use(&self.item_tree, import_id),
834 status: PartialResolvedImport::Unresolved,
835 })
836 }
837 ModItem::ExternCrate(import_id) => {
838 self.def_collector.unresolved_imports.push(ImportDirective {
839 module_id: self.module_id,
840 import: Import::from_extern_crate(&self.item_tree, import_id),
841 status: PartialResolvedImport::Unresolved,
842 })
843 }
844 ModItem::MacroCall(mac) => self.collect_macro(&self.item_tree[mac]),
845 ModItem::Impl(imp) => {
846 let module = ModuleId {
847 krate: self.def_collector.def_map.krate,
848 local_id: self.module_id,
849 };
850 let container = ContainerId::ModuleId(module);
851 let impl_id = ImplLoc { container, id: ItemTreeId::new(self.file_id, imp) }
852 .intern(self.def_collector.db);
853 self.def_collector.def_map.modules[self.module_id]
854 .scope
855 .define_impl(impl_id)
856 }
857 ModItem::Function(id) => {
858 let func = &self.item_tree[id];
859 def = Some(DefData {
860 id: FunctionLoc {
861 container: container.into(),
862 id: ItemTreeId::new(self.file_id, id),
863 }
864 .intern(self.def_collector.db)
865 .into(),
866 name: &func.name,
867 visibility: &self.item_tree[func.visibility],
868 has_constructor: false,
869 });
870 }
871 ModItem::Struct(id) => {
872 let it = &self.item_tree[id];
873
874 // FIXME: check attrs to see if this is an attribute macro invocation;
875 // in which case we don't add the invocation, just a single attribute
876 // macro invocation
877 self.collect_derives(attrs, it.ast_id.upcast());
878
879 def = Some(DefData {
880 id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) }
881 .intern(self.def_collector.db)
882 .into(),
883 name: &it.name,
884 visibility: &self.item_tree[it.visibility],
885 has_constructor: it.kind != StructDefKind::Record,
886 });
887 }
888 ModItem::Union(id) => {
889 let it = &self.item_tree[id];
890
891 // FIXME: check attrs to see if this is an attribute macro invocation;
892 // in which case we don't add the invocation, just a single attribute
893 // macro invocation
894 self.collect_derives(attrs, it.ast_id.upcast());
895
896 def = Some(DefData {
897 id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) }
898 .intern(self.def_collector.db)
899 .into(),
900 name: &it.name,
901 visibility: &self.item_tree[it.visibility],
902 has_constructor: false,
903 });
904 }
905 ModItem::Enum(id) => {
906 let it = &self.item_tree[id];
907
908 // FIXME: check attrs to see if this is an attribute macro invocation;
909 // in which case we don't add the invocation, just a single attribute
910 // macro invocation
911 self.collect_derives(attrs, it.ast_id.upcast());
912
913 def = Some(DefData {
914 id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) }
915 .intern(self.def_collector.db)
916 .into(),
917 name: &it.name,
918 visibility: &self.item_tree[it.visibility],
919 has_constructor: false,
920 });
921 }
922 ModItem::Const(id) => {
923 let it = &self.item_tree[id];
924
925 if let Some(name) = &it.name {
926 def = Some(DefData {
927 id: ConstLoc {
928 container: container.into(),
929 id: ItemTreeId::new(self.file_id, id),
930 }
931 .intern(self.def_collector.db)
932 .into(),
933 name,
934 visibility: &self.item_tree[it.visibility],
935 has_constructor: false,
936 });
937 }
938 }
939 ModItem::Static(id) => {
940 let it = &self.item_tree[id];
941
942 def = Some(DefData {
943 id: StaticLoc { container, id: ItemTreeId::new(self.file_id, id) }
944 .intern(self.def_collector.db)
945 .into(),
946 name: &it.name,
947 visibility: &self.item_tree[it.visibility],
948 has_constructor: false,
949 });
950 }
951 ModItem::Trait(id) => {
952 let it = &self.item_tree[id];
953
954 def = Some(DefData {
955 id: TraitLoc { container, id: ItemTreeId::new(self.file_id, id) }
956 .intern(self.def_collector.db)
957 .into(),
958 name: &it.name,
959 visibility: &self.item_tree[it.visibility],
960 has_constructor: false,
961 });
962 }
963 ModItem::TypeAlias(id) => {
964 let it = &self.item_tree[id];
965
966 def = Some(DefData {
967 id: TypeAliasLoc {
968 container: container.into(),
969 id: ItemTreeId::new(self.file_id, id),
970 }
971 .intern(self.def_collector.db)
972 .into(),
973 name: &it.name,
974 visibility: &self.item_tree[it.visibility],
975 has_constructor: false,
976 });
977 }
978 }
979
980 if let Some(DefData { id, name, visibility, has_constructor }) = def {
981 self.def_collector.def_map.modules[self.module_id].scope.define_def(id);
982 let vis = self
983 .def_collector
984 .def_map
985 .resolve_visibility(self.def_collector.db, self.module_id, visibility)
986 .unwrap_or(Visibility::Public);
987 self.def_collector.update(
988 self.module_id,
989 &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
990 vis,
991 ImportType::Named,
992 )
993 }
994 }
995 }
996 }
997
998 fn collect_module(&mut self, module: &Mod, attrs: &Attrs) {
999 let path_attr = attrs.by_key("path").string_value();
1000 let is_macro_use = attrs.by_key("macro_use").exists();
1001 match &module.kind {
1002 // inline module, just recurse
1003 ModKind::Inline { items } => {
1004 let module_id = self.push_child_module(
1005 module.name.clone(),
1006 AstId::new(self.file_id, module.ast_id),
1007 None,
1008 &self.item_tree[module.visibility],
1009 );
1010
1011 ModCollector {
1012 def_collector: &mut *self.def_collector,
1013 macro_depth: self.macro_depth,
1014 module_id,
1015 file_id: self.file_id,
1016 item_tree: self.item_tree,
1017 mod_dir: self.mod_dir.descend_into_definition(&module.name, path_attr),
1018 }
1019 .collect(&*items);
1020 if is_macro_use {
1021 self.import_all_legacy_macros(module_id);
1022 }
1023 }
1024 // out of line module, resolve, parse and recurse
1025 ModKind::Outline {} => {
1026 let ast_id = AstId::new(self.file_id, module.ast_id);
1027 match self.mod_dir.resolve_declaration(
1028 self.def_collector.db,
1029 self.file_id,
1030 &module.name,
1031 path_attr,
1032 ) {
1033 Ok((file_id, is_mod_rs, mod_dir)) => {
1034 let module_id = self.push_child_module(
1035 module.name.clone(),
1036 ast_id,
1037 Some((file_id, is_mod_rs)),
1038 &self.item_tree[module.visibility],
1039 );
1040 let item_tree = self.def_collector.db.item_tree(file_id.into());
1041 ModCollector {
1042 def_collector: &mut *self.def_collector,
1043 macro_depth: self.macro_depth,
1044 module_id,
1045 file_id: file_id.into(),
1046 item_tree: &item_tree,
1047 mod_dir,
1048 }
1049 .collect(item_tree.top_level_items());
1050 if is_macro_use {
1051 self.import_all_legacy_macros(module_id);
1052 }
1053 }
1054 Err(candidate) => self.def_collector.def_map.diagnostics.push(
1055 DefDiagnostic::UnresolvedModule {
1056 module: self.module_id,
1057 declaration: ast_id,
1058 candidate,
1059 },
1060 ),
1061 };
1062 }
1063 }
1064 }
1065
1066 fn push_child_module(
1067 &mut self,
1068 name: Name,
1069 declaration: AstId<ast::Module>,
1070 definition: Option<(FileId, bool)>,
1071 visibility: &crate::visibility::RawVisibility,
1072 ) -> LocalModuleId {
1073 let vis = self
1074 .def_collector
1075 .def_map
1076 .resolve_visibility(self.def_collector.db, self.module_id, visibility)
1077 .unwrap_or(Visibility::Public);
1078 let modules = &mut self.def_collector.def_map.modules;
1079 let res = modules.alloc(ModuleData::default());
1080 modules[res].parent = Some(self.module_id);
1081 modules[res].origin = match definition {
1082 None => ModuleOrigin::Inline { definition: declaration },
1083 Some((definition, is_mod_rs)) => {
1084 ModuleOrigin::File { declaration, definition, is_mod_rs }
1085 }
1086 };
1087 for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() {
1088 modules[res].scope.define_legacy_macro(name, mac)
1089 }
1090 modules[self.module_id].children.insert(name.clone(), res);
1091 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res };
1092 let def: ModuleDefId = module.into();
1093 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
1094 self.def_collector.update(
1095 self.module_id,
1096 &[(Some(name), PerNs::from_def(def, vis, false))],
1097 vis,
1098 ImportType::Named,
1099 );
1100 res
1101 }
1102
1103 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) {
1104 for derive_subtree in attrs.by_key("derive").tt_values() {
1105 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
1106 for tt in &derive_subtree.token_trees {
1107 let ident = match &tt {
1108 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident,
1109 tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok
1110 _ => continue, // anything else would be an error (which we currently ignore)
1111 };
1112 let path = ModPath::from_tt_ident(ident);
1113
1114 let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
1115 self.def_collector
1116 .unexpanded_attribute_macros
1117 .push(DeriveDirective { module_id: self.module_id, ast_id });
1118 }
1119 }
1120 }
1121
1122 fn collect_macro(&mut self, mac: &MacroCall) {
1123 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
1124
1125 // Case 0: builtin macros
1126 if mac.is_builtin {
1127 if let Some(name) = &mac.name {
1128 let krate = self.def_collector.def_map.krate;
1129 if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) {
1130 self.def_collector.define_macro(
1131 self.module_id,
1132 name.clone(),
1133 macro_id,
1134 mac.is_export,
1135 );
1136 return;
1137 }
1138 }
1139 }
1140
1141 // Case 1: macro rules, define a macro in crate-global mutable scope
1142 if is_macro_rules(&mac.path) {
1143 if let Some(name) = &mac.name {
1144 let macro_id = MacroDefId {
1145 ast_id: Some(ast_id.ast_id),
1146 krate: Some(self.def_collector.def_map.krate),
1147 kind: MacroDefKind::Declarative,
1148 local_inner: mac.is_local_inner,
1149 };
1150 self.def_collector.define_macro(
1151 self.module_id,
1152 name.clone(),
1153 macro_id,
1154 mac.is_export,
1155 );
1156 }
1157 return;
1158 }
1159
1160 // Case 2: try to resolve in legacy scope and expand macro_rules
1161 if let Some(macro_call_id) =
1162 ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| {
1163 path.as_ident().and_then(|name| {
1164 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
1165 })
1166 })
1167 {
1168 self.def_collector.unexpanded_macros.push(MacroDirective {
1169 module_id: self.module_id,
1170 ast_id,
1171 legacy: Some(macro_call_id),
1172 depth: self.macro_depth + 1,
1173 });
1174
1175 return;
1176 }
1177
1178 // Case 3: resolve in module scope, expand during name resolution.
1179 // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
1180 if ast_id.path.is_ident() {
1181 ast_id.path.kind = PathKind::Super(0);
1182 }
1183
1184 self.def_collector.unexpanded_macros.push(MacroDirective {
1185 module_id: self.module_id,
1186 ast_id,
1187 legacy: None,
1188 depth: self.macro_depth + 1,
1189 });
1190 }
1191
1192 fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
1193 let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros();
1194 for (name, macro_) in macros {
1195 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
1196 }
1197 }
1198
1199 fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
1200 attrs.is_cfg_enabled(self.def_collector.cfg_options)
1201 }
1202}
1203
1204fn is_macro_rules(path: &ModPath) -> bool {
1205 path.as_ident() == Some(&name![macro_rules])
1206}
1207
1208#[cfg(test)]
1209mod tests {
1210 use crate::{db::DefDatabase, test_db::TestDB};
1211 use arena::Arena;
1212 use base_db::{fixture::WithFixture, SourceDatabase};
1213
1214 use super::*;
1215
1216 fn do_collect_defs(db: &dyn DefDatabase, def_map: CrateDefMap) -> CrateDefMap {
1217 let mut collector = DefCollector {
1218 db,
1219 def_map,
1220 glob_imports: FxHashMap::default(),
1221 unresolved_imports: Vec::new(),
1222 resolved_imports: Vec::new(),
1223 unexpanded_macros: Vec::new(),
1224 unexpanded_attribute_macros: Vec::new(),
1225 mod_dirs: FxHashMap::default(),
1226 cfg_options: &CfgOptions::default(),
1227 proc_macros: Default::default(),
1228 from_glob_import: Default::default(),
1229 };
1230 collector.collect();
1231 collector.def_map
1232 }
1233
1234 fn do_resolve(code: &str) -> CrateDefMap {
1235 let (db, _file_id) = TestDB::with_single_file(&code);
1236 let krate = db.test_crate();
1237
1238 let def_map = {
1239 let edition = db.crate_graph()[krate].edition;
1240 let mut modules: Arena<ModuleData> = Arena::default();
1241 let root = modules.alloc(ModuleData::default());
1242 CrateDefMap {
1243 krate,
1244 edition,
1245 extern_prelude: FxHashMap::default(),
1246 prelude: None,
1247 root,
1248 modules,
1249 diagnostics: Vec::new(),
1250 }
1251 };
1252 do_collect_defs(&db, def_map)
1253 }
1254
1255 #[test]
1256 fn test_macro_expand_will_stop_1() {
1257 do_resolve(
1258 r#"
1259 macro_rules! foo {
1260 ($($ty:ty)*) => { foo!($($ty)*); }
1261 }
1262 foo!(KABOOM);
1263 "#,
1264 );
1265 }
1266
1267 #[ignore] // this test does succeed, but takes quite a while :/
1268 #[test]
1269 fn test_macro_expand_will_stop_2() {
1270 do_resolve(
1271 r#"
1272 macro_rules! foo {
1273 ($($ty:ty)*) => { foo!($($ty)* $($ty)*); }
1274 }
1275 foo!(KABOOM);
1276 "#,
1277 );
1278 }
1279}