1 //! The core of the module-level name resolution algorithm.
3 //! `DefCollector::collect` contains the fixed-point iteration loop which
4 //! resolves imports and expands macros.
7 builtin_derive::find_builtin_derive,
8 builtin_macro::find_builtin_macro,
9 name::{name, AsName, Name},
10 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
12 use ra_cfg::CfgOptions;
13 use ra_db::{CrateId, FileId};
15 use rustc_hash::FxHashMap;
16 use test_utils::tested_by;
22 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
23 raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, Resolution, ResolveMode,
25 path::{ModPath, PathKind},
27 AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
28 LocalImportId, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc,
29 TypeAliasLoc, UnionLoc,
32 pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
33 let crate_graph = db.crate_graph();
35 // populate external prelude
36 for dep in crate_graph.dependencies(def_map.krate) {
37 let dep_def_map = db.crate_def_map(dep.crate_id);
38 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
39 def_map.extern_prelude.insert(
41 ModuleId { krate: dep.crate_id, local_id: dep_def_map.root }.into(),
44 // look for the prelude
45 // If the dependency defines a prelude, we overwrite an already defined
46 // prelude. This is necessary to import the "std" prelude if a crate
47 // depends on both "core" and "std".
48 let dep_def_map = db.crate_def_map(dep.crate_id);
49 if dep_def_map.prelude.is_some() {
50 def_map.prelude = dep_def_map.prelude;
54 let cfg_options = crate_graph.cfg_options(def_map.krate);
56 let mut collector = DefCollector {
59 glob_imports: FxHashMap::default(),
60 unresolved_imports: Vec::new(),
61 resolved_imports: Vec::new(),
63 unexpanded_macros: Vec::new(),
64 unexpanded_attribute_macros: Vec::new(),
65 mod_dirs: FxHashMap::default(),
72 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
73 enum PartialResolvedImport {
74 /// None of any namespaces is resolved
76 /// One of namespaces is resolved
78 /// All namespaces are resolved, OR it is came from other crate
82 impl PartialResolvedImport {
83 fn namespaces(&self) -> PerNs {
85 PartialResolvedImport::Unresolved => PerNs::none(),
86 PartialResolvedImport::Indeterminate(ns) => *ns,
87 PartialResolvedImport::Resolved(ns) => *ns,
92 #[derive(Clone, Debug, Eq, PartialEq)]
93 struct ImportDirective {
94 module_id: LocalModuleId,
95 import_id: LocalImportId,
96 import: raw::ImportData,
97 status: PartialResolvedImport,
100 #[derive(Clone, Debug, Eq, PartialEq)]
101 struct MacroDirective {
102 module_id: LocalModuleId,
103 ast_id: AstId<ast::MacroCall>,
105 legacy: Option<MacroCallId>,
108 /// Walks the tree of module recursively
109 struct DefCollector<'a, DB> {
111 def_map: CrateDefMap,
112 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>,
113 unresolved_imports: Vec<ImportDirective>,
114 resolved_imports: Vec<ImportDirective>,
115 unexpanded_macros: Vec<MacroDirective>,
116 unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, ModPath)>,
117 mod_dirs: FxHashMap<LocalModuleId, ModDir>,
118 cfg_options: &'a CfgOptions,
121 impl<DB> DefCollector<'_, DB>
125 fn collect(&mut self) {
126 let crate_graph = self.db.crate_graph();
127 let file_id = crate_graph.crate_root(self.def_map.krate);
128 let raw_items = self.db.raw_items(file_id.into());
129 let module_id = self.def_map.root;
130 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
132 def_collector: &mut *self,
134 file_id: file_id.into(),
135 raw_items: &raw_items,
136 mod_dir: ModDir::root(),
138 .collect(raw_items.items());
140 // main name resolution fixed-point loop.
143 self.db.check_canceled();
144 self.resolve_imports();
146 match self.resolve_macros() {
147 ReachedFixedPoint::Yes => break,
148 ReachedFixedPoint::No => i += 1,
151 log::error!("name resolution is stuck");
156 // Resolve all indeterminate resolved imports again
157 // As some of the macros will expand newly import shadowing partial resolved imports
158 // FIXME: We maybe could skip this, if we handle the Indetermine imports in `resolve_imports`
160 let partial_resolved = self.resolved_imports.iter().filter_map(|directive| {
161 if let PartialResolvedImport::Indeterminate(_) = directive.status {
162 let mut directive = directive.clone();
163 directive.status = PartialResolvedImport::Unresolved;
169 self.unresolved_imports.extend(partial_resolved);
170 self.resolve_imports();
172 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
173 // show unresolved imports in completion, etc
174 for directive in unresolved_imports {
175 self.record_resolved_import(&directive)
179 /// Define a macro with `macro_rules`.
181 /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`,
182 /// then it is also defined in the root module scope.
183 /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition.
185 /// It is surprising that the macro will never be in the current module scope.
186 /// These code fails with "unresolved import/macro",
187 /// ```rust,compile_fail
188 /// mod m { macro_rules! foo { () => {} } }
189 /// use m::foo as bar;
192 /// ```rust,compile_fail
193 /// macro_rules! foo { () => {} }
198 /// Well, this code compiles, because the plain path `foo` in `use` is searched
199 /// in the legacy textual scope only.
201 /// macro_rules! foo { () => {} }
206 module_id: LocalModuleId,
212 self.define_legacy_macro(module_id, name.clone(), macro_);
215 // In Rust, `#[macro_export]` macros are unconditionally visible at the
216 // crate root, even if the parent modules is **not** visible.
221 &[(name, Resolution { def: PerNs::macros(macro_), import: None })],
226 /// Define a legacy textual scoped macro in module
228 /// We use a map `legacy_macros` to store all legacy textual scoped macros visable per module.
229 /// It will clone all macros from parent legacy scope, whose definition is prior to
230 /// the definition of current module.
231 /// And also, `macro_use` on a module will import all legacy macros visable inside to
232 /// current legacy scope, with possible shadowing.
233 fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, macro_: MacroDefId) {
235 self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_);
238 /// Import macros from `#[macro_use] extern crate`.
239 fn import_macros_from_extern_crate(
241 current_module_id: LocalModuleId,
242 import: &raw::ImportData,
245 "importing macros from extern crate: {:?} ({:?})",
247 self.def_map.edition,
250 let res = self.def_map.resolve_name_in_extern_prelude(
254 .expect("extern crate should have been desugared to one-element path"),
257 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
258 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
259 self.import_all_macros_exported(current_module_id, m.krate);
263 /// Import all exported macros from another crate
265 /// Exported macros are just all macros in the root module scope.
266 /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
267 /// created by `use` in the root module, ignoring the visibility of `use`.
268 fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
269 let def_map = self.db.crate_def_map(krate);
270 for (name, def) in def_map[def_map.root].scope.macros() {
271 // `macro_use` only bring things into legacy scope.
272 self.define_legacy_macro(current_module_id, name.clone(), def);
276 /// Import resolution
278 /// This is a fix point algorithm. We resolve imports until no forward
279 /// progress in resolving imports is made
280 fn resolve_imports(&mut self) {
281 let mut n_previous_unresolved = self.unresolved_imports.len() + 1;
283 while self.unresolved_imports.len() < n_previous_unresolved {
284 n_previous_unresolved = self.unresolved_imports.len();
285 let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
286 for mut directive in imports {
287 directive.status = self.resolve_import(directive.module_id, &directive.import);
289 match directive.status {
290 PartialResolvedImport::Indeterminate(_) => {
291 self.record_resolved_import(&directive);
292 // FIXME: For avoid performance regression,
293 // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved)
294 self.resolved_imports.push(directive)
296 PartialResolvedImport::Resolved(_) => {
297 self.record_resolved_import(&directive);
298 self.resolved_imports.push(directive)
300 PartialResolvedImport::Unresolved => {
301 self.unresolved_imports.push(directive);
310 module_id: LocalModuleId,
311 import: &raw::ImportData,
312 ) -> PartialResolvedImport {
313 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
314 if import.is_extern_crate {
315 let res = self.def_map.resolve_name_in_extern_prelude(
319 .expect("extern crate should have been desugared to one-element path"),
321 PartialResolvedImport::Resolved(res)
323 let res = self.def_map.resolve_path_fp_with_macro(
328 BuiltinShadowMode::Module,
331 let def = res.resolved_def;
332 if res.reached_fixedpoint == ReachedFixedPoint::No {
333 return PartialResolvedImport::Unresolved;
336 if let Some(krate) = res.krate {
337 if krate != self.def_map.krate {
338 return PartialResolvedImport::Resolved(def);
342 // Check whether all namespace is resolved
343 if def.take_types().is_some()
344 && def.take_values().is_some()
345 && def.take_macros().is_some()
347 PartialResolvedImport::Resolved(def)
349 PartialResolvedImport::Indeterminate(def)
354 fn record_resolved_import(&mut self, directive: &ImportDirective) {
355 let module_id = directive.module_id;
356 let import_id = directive.import_id;
357 let import = &directive.import;
358 let def = directive.status.namespaces();
361 log::debug!("glob import: {:?}", import);
362 match def.take_types() {
363 Some(ModuleDefId::ModuleId(m)) => {
364 if import.is_prelude {
365 tested_by!(std_prelude);
366 self.def_map.prelude = Some(m);
367 } else if m.krate != self.def_map.krate {
368 tested_by!(glob_across_crates);
369 // glob import from other crate => we can just import everything once
370 let item_map = self.db.crate_def_map(m.krate);
371 let scope = &item_map[m.local_id].scope;
373 // Module scoped macros is included
377 .map(|(name, res)| (name.clone(), res.clone()))
378 .collect::<Vec<_>>();
380 self.update(module_id, Some(import_id), &items);
382 // glob import from same crate => we do an initial
383 // import, and then need to propagate any further
385 let scope = &self.def_map[m.local_id].scope;
387 // Module scoped macros is included
391 .map(|(name, res)| (name.clone(), res.clone()))
392 .collect::<Vec<_>>();
394 self.update(module_id, Some(import_id), &items);
395 // record the glob import in case we add further items
396 let glob = self.glob_imports.entry(m.local_id).or_default();
397 if !glob.iter().any(|it| *it == (module_id, import_id)) {
398 glob.push((module_id, import_id));
402 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
403 tested_by!(glob_enum);
404 // glob import from enum => just import all the variants
405 let enum_data = self.db.enum_data(e);
406 let resolutions = enum_data
409 .map(|(local_id, variant_data)| {
410 let name = variant_data.name.clone();
411 let variant = EnumVariantId { parent: e, local_id };
412 let res = Resolution {
413 def: PerNs::both(variant.into(), variant.into()),
414 import: Some(import_id),
418 .collect::<Vec<_>>();
419 self.update(module_id, Some(import_id), &resolutions);
422 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
425 log::debug!("glob import {:?} didn't resolve as type", import);
429 match import.path.segments.last() {
430 Some(last_segment) => {
431 let name = import.alias.clone().unwrap_or_else(|| last_segment.clone());
432 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
434 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
435 if import.is_extern_crate && module_id == self.def_map.root {
436 if let Some(def) = def.take_types() {
437 self.def_map.extern_prelude.insert(name.clone(), def);
441 let resolution = Resolution { def, import: Some(import_id) };
442 self.update(module_id, Some(import_id), &[(name, resolution)]);
444 None => tested_by!(bogus_paths),
451 module_id: LocalModuleId,
452 import: Option<LocalImportId>,
453 resolutions: &[(Name, Resolution)],
455 self.update_recursive(module_id, import, resolutions, 0)
460 module_id: LocalModuleId,
461 import: Option<LocalImportId>,
462 resolutions: &[(Name, Resolution)],
466 // prevent stack overflows (but this shouldn't be possible)
467 panic!("infinite recursion in glob imports!");
469 let module_items = &mut self.def_map.modules[module_id].scope;
470 let mut changed = false;
471 for (name, res) in resolutions {
472 let existing = module_items.items.entry(name.clone()).or_default();
474 if existing.def.types.is_none() && res.def.types.is_some() {
475 existing.def.types = res.def.types;
476 existing.import = import.or(res.import);
479 if existing.def.values.is_none() && res.def.values.is_some() {
480 existing.def.values = res.def.values;
481 existing.import = import.or(res.import);
484 if existing.def.macros.is_none() && res.def.macros.is_some() {
485 existing.def.macros = res.def.macros;
486 existing.import = import.or(res.import);
490 if existing.def.is_none()
492 && existing.import.is_none()
493 && res.import.is_some()
495 existing.import = res.import;
502 let glob_imports = self
506 .flat_map(|v| v.iter())
508 .collect::<Vec<_>>();
509 for (glob_importing_module, glob_import) in glob_imports {
510 // We pass the glob import so that the tracked import in those modules is that glob import
511 self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1);
515 fn resolve_macros(&mut self) -> ReachedFixedPoint {
516 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
517 let mut attribute_macros =
518 std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new());
519 let mut resolved = Vec::new();
520 let mut res = ReachedFixedPoint::Yes;
521 macros.retain(|directive| {
522 if let Some(call_id) = directive.legacy {
523 res = ReachedFixedPoint::No;
524 resolved.push((directive.module_id, call_id));
528 let resolved_res = self.def_map.resolve_path_fp_with_macro(
533 BuiltinShadowMode::Module,
536 if let Some(def) = resolved_res.resolved_def.take_macros() {
537 let call_id = def.as_call_id(self.db, MacroCallKind::FnLike(directive.ast_id));
538 resolved.push((directive.module_id, call_id));
539 res = ReachedFixedPoint::No;
545 attribute_macros.retain(|(module_id, ast_id, path)| {
546 let resolved_res = self.resolve_attribute_macro(path);
548 if let Some(def) = resolved_res {
549 let call_id = def.as_call_id(self.db, MacroCallKind::Attr(*ast_id));
550 resolved.push((*module_id, call_id));
551 res = ReachedFixedPoint::No;
558 self.unexpanded_macros = macros;
559 self.unexpanded_attribute_macros = attribute_macros;
561 for (module_id, macro_call_id) in resolved {
562 self.collect_macro_expansion(module_id, macro_call_id);
568 fn resolve_attribute_macro(&self, path: &ModPath) -> Option<MacroDefId> {
569 // FIXME this is currently super hacky, just enough to support the
571 if let Some(name) = path.as_ident() {
572 // FIXME this should actually be handled with the normal name
573 // resolution; the std lib defines built-in stubs for the derives,
574 // but these are new-style `macro`s, which we don't support yet
575 if let Some(def_id) = find_builtin_derive(name) {
582 fn collect_macro_expansion(&mut self, module_id: LocalModuleId, macro_call_id: MacroCallId) {
583 let file_id: HirFileId = macro_call_id.as_file();
584 let raw_items = self.db.raw_items(file_id);
585 let mod_dir = self.mod_dirs[&module_id].clone();
587 def_collector: &mut *self,
590 raw_items: &raw_items,
593 .collect(raw_items.items());
596 fn finish(self) -> CrateDefMap {
601 /// Walks a single module, populating defs, imports and macros
602 struct ModCollector<'a, D> {
604 module_id: LocalModuleId,
606 raw_items: &'a raw::RawItems,
610 impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
614 fn collect(&mut self, items: &[raw::RawItem]) {
615 // Note: don't assert that inserted value is fresh: it's simply not true
617 self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
619 // Prelude module is always considered to be `#[macro_use]`.
620 if let Some(prelude_module) = self.def_collector.def_map.prelude {
621 if prelude_module.krate != self.def_collector.def_map.krate {
622 tested_by!(prelude_is_macro_use);
623 self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
627 // This should be processed eagerly instead of deferred to resolving.
628 // `#[macro_use] extern crate` is hoisted to imports macros before collecting
631 if self.is_cfg_enabled(&item.attrs) {
632 if let raw::RawItemKind::Import(import_id) = item.kind {
633 let import = self.raw_items[import_id].clone();
634 if import.is_extern_crate && import.is_macro_use {
635 self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
642 if self.is_cfg_enabled(&item.attrs) {
644 raw::RawItemKind::Module(m) => {
645 self.collect_module(&self.raw_items[m], &item.attrs)
647 raw::RawItemKind::Import(import_id) => {
648 self.def_collector.unresolved_imports.push(ImportDirective {
649 module_id: self.module_id,
651 import: self.raw_items[import_id].clone(),
652 status: PartialResolvedImport::Unresolved,
655 raw::RawItemKind::Def(def) => {
656 self.define_def(&self.raw_items[def], &item.attrs)
658 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
659 raw::RawItemKind::Impl(imp) => {
660 let module = ModuleId {
661 krate: self.def_collector.def_map.krate,
662 local_id: self.module_id,
664 let container = ContainerId::ModuleId(module);
665 let ast_id = self.raw_items[imp].ast_id;
667 ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
668 .intern(self.def_collector.db);
669 self.def_collector.def_map.modules[self.module_id].impls.push(impl_id)
676 fn collect_module(&mut self, module: &raw::ModuleData, attrs: &Attrs) {
677 let path_attr = attrs.by_key("path").string_value();
678 let is_macro_use = attrs.by_key("macro_use").exists();
680 // inline module, just recurse
681 raw::ModuleData::Definition { name, items, ast_id } => {
683 self.push_child_module(name.clone(), AstId::new(self.file_id, *ast_id), None);
686 def_collector: &mut *self.def_collector,
688 file_id: self.file_id,
689 raw_items: self.raw_items,
690 mod_dir: self.mod_dir.descend_into_definition(name, path_attr),
694 self.import_all_legacy_macros(module_id);
697 // out of line module, resolve, parse and recurse
698 raw::ModuleData::Declaration { name, ast_id } => {
699 let ast_id = AstId::new(self.file_id, *ast_id);
700 match self.mod_dir.resolve_declaration(
701 self.def_collector.db,
706 Ok((file_id, mod_dir)) => {
707 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id));
708 let raw_items = self.def_collector.db.raw_items(file_id.into());
710 def_collector: &mut *self.def_collector,
712 file_id: file_id.into(),
713 raw_items: &raw_items,
716 .collect(raw_items.items());
718 self.import_all_legacy_macros(module_id);
721 Err(candidate) => self.def_collector.def_map.diagnostics.push(
722 DefDiagnostic::UnresolvedModule {
723 module: self.module_id,
733 fn push_child_module(
736 declaration: AstId<ast::Module>,
737 definition: Option<FileId>,
739 let modules = &mut self.def_collector.def_map.modules;
740 let res = modules.alloc(ModuleData::default());
741 modules[res].parent = Some(self.module_id);
742 modules[res].origin = ModuleOrigin::not_sure_file(definition, declaration);
743 modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone();
744 modules[self.module_id].children.insert(name.clone(), res);
745 let resolution = Resolution {
747 ModuleId { krate: self.def_collector.def_map.krate, local_id: res }.into(),
751 self.def_collector.update(self.module_id, None, &[(name, resolution)]);
755 fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) {
756 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
757 // FIXME: check attrs to see if this is an attribute macro invocation;
758 // in which case we don't add the invocation, just a single attribute
761 self.collect_derives(attrs, def);
763 let name = def.name.clone();
764 let container = ContainerId::ModuleId(module);
765 let def: PerNs = match def.kind {
766 raw::DefKind::Function(ast_id) => {
767 let def = FunctionLoc {
768 container: container.into(),
769 ast_id: AstId::new(self.file_id, ast_id),
771 .intern(self.def_collector.db);
773 PerNs::values(def.into())
775 raw::DefKind::Struct(ast_id) => {
776 let def = StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
777 .intern(self.def_collector.db);
778 PerNs::both(def.into(), def.into())
780 raw::DefKind::Union(ast_id) => {
781 let def = UnionLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
782 .intern(self.def_collector.db);
783 PerNs::both(def.into(), def.into())
785 raw::DefKind::Enum(ast_id) => {
786 let def = EnumLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
787 .intern(self.def_collector.db);
788 PerNs::types(def.into())
790 raw::DefKind::Const(ast_id) => {
792 container: container.into(),
793 ast_id: AstId::new(self.file_id, ast_id),
795 .intern(self.def_collector.db);
797 PerNs::values(def.into())
799 raw::DefKind::Static(ast_id) => {
800 let def = StaticLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
801 .intern(self.def_collector.db);
803 PerNs::values(def.into())
805 raw::DefKind::Trait(ast_id) => {
806 let def = TraitLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
807 .intern(self.def_collector.db);
809 PerNs::types(def.into())
811 raw::DefKind::TypeAlias(ast_id) => {
812 let def = TypeAliasLoc {
813 container: container.into(),
814 ast_id: AstId::new(self.file_id, ast_id),
816 .intern(self.def_collector.db);
818 PerNs::types(def.into())
821 let resolution = Resolution { def, import: None };
822 self.def_collector.update(self.module_id, None, &[(name, resolution)])
825 fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) {
826 for derive_subtree in attrs.by_key("derive").tt_values() {
827 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
828 for tt in &derive_subtree.token_trees {
829 let ident = match &tt {
830 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident,
831 tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok
832 _ => continue, // anything else would be an error (which we currently ignore)
834 let path = ModPath::from_tt_ident(ident);
836 let ast_id = AstId::new(self.file_id, def.kind.ast_id());
837 self.def_collector.unexpanded_attribute_macros.push((self.module_id, ast_id, path));
842 fn collect_macro(&mut self, mac: &raw::MacroData) {
843 let ast_id = AstId::new(self.file_id, mac.ast_id);
845 // Case 0: builtin macros
847 if let Some(name) = &mac.name {
848 let krate = self.def_collector.def_map.krate;
849 if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) {
850 self.def_collector.define_macro(
861 // Case 1: macro rules, define a macro in crate-global mutable scope
862 if is_macro_rules(&mac.path) {
863 if let Some(name) = &mac.name {
864 let macro_id = MacroDefId {
865 ast_id: Some(ast_id),
866 krate: Some(self.def_collector.def_map.krate),
867 kind: MacroDefKind::Declarative,
869 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
874 // Case 2: try to resolve in legacy scope and expand macro_rules
875 if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
876 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
879 macro_def.as_call_id(self.def_collector.db, MacroCallKind::FnLike(ast_id));
881 self.def_collector.unexpanded_macros.push(MacroDirective {
882 module_id: self.module_id,
883 path: mac.path.clone(),
885 legacy: Some(macro_call_id),
891 // Case 3: resolve in module scope, expand during name resolution.
892 // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
893 let mut path = mac.path.clone();
895 path.kind = PathKind::Super(0);
898 self.def_collector.unexpanded_macros.push(MacroDirective {
899 module_id: self.module_id,
906 fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
907 let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone();
908 for (name, macro_) in macros {
909 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
913 fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
914 // FIXME: handle cfg_attr :-)
918 .all(|tt| self.def_collector.cfg_options.is_cfg_enabled(tt) != Some(false))
922 fn is_macro_rules(path: &ModPath) -> bool {
923 path.as_ident() == Some(&name![macro_rules])
928 use crate::{db::DefDatabase, test_db::TestDB};
930 use ra_db::{fixture::WithFixture, SourceDatabase};
934 fn do_collect_defs(db: &impl DefDatabase, def_map: CrateDefMap) -> CrateDefMap {
935 let mut collector = DefCollector {
938 glob_imports: FxHashMap::default(),
939 unresolved_imports: Vec::new(),
940 resolved_imports: Vec::new(),
941 unexpanded_macros: Vec::new(),
942 unexpanded_attribute_macros: Vec::new(),
943 mod_dirs: FxHashMap::default(),
944 cfg_options: &CfgOptions::default(),
950 fn do_resolve(code: &str) -> CrateDefMap {
951 let (db, _file_id) = TestDB::with_single_file(&code);
952 let krate = db.test_crate();
955 let edition = db.crate_graph().edition(krate);
956 let mut modules: Arena<LocalModuleId, ModuleData> = Arena::default();
957 let root = modules.alloc(ModuleData::default());
961 extern_prelude: FxHashMap::default(),
965 diagnostics: Vec::new(),
968 do_collect_defs(&db, def_map)
972 fn test_macro_expand_will_stop() {
976 ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); }