]> git.lizzy.rs Git - rust.git/commitdiff
Move CrateDefMap to hir_def
authorAleksey Kladov <aleksey.kladov@gmail.com>
Thu, 31 Oct 2019 15:45:10 +0000 (18:45 +0300)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Sun, 3 Nov 2019 15:04:06 +0000 (18:04 +0300)
25 files changed:
crates/ra_hir/src/code_model.rs
crates/ra_hir/src/code_model/src.rs
crates/ra_hir/src/db.rs
crates/ra_hir/src/diagnostics.rs
crates/ra_hir/src/from_id.rs [new file with mode: 0644]
crates/ra_hir/src/from_source.rs
crates/ra_hir/src/lib.rs
crates/ra_hir/src/nameres.rs
crates/ra_hir/src/nameres/collector.rs [deleted file]
crates/ra_hir/src/nameres/per_ns.rs [deleted file]
crates/ra_hir/src/nameres/tests.rs
crates/ra_hir/src/nameres/tests/globs.rs
crates/ra_hir/src/nameres/tests/incremental.rs
crates/ra_hir/src/nameres/tests/macros.rs
crates/ra_hir/src/resolve.rs
crates/ra_hir/src/source_binder.rs
crates/ra_hir/src/ty/tests.rs
crates/ra_hir_def/src/adt.rs
crates/ra_hir_def/src/db.rs
crates/ra_hir_def/src/diagnostics.rs [new file with mode: 0644]
crates/ra_hir_def/src/lib.rs
crates/ra_hir_def/src/nameres.rs
crates/ra_hir_def/src/nameres/collector.rs [new file with mode: 0644]
crates/ra_hir_def/src/nameres/per_ns.rs [new file with mode: 0644]
crates/ra_ide_api/src/completion/complete_path.rs

index 5b78bdfef389e99b1df5c23f36525e45ebf9f824..f03b59217fe0e0c8c306b75d5548c4c61296b91d 100644 (file)
@@ -9,7 +9,7 @@
     adt::VariantData,
     builtin_type::BuiltinType,
     type_ref::{Mutability, TypeRef},
-    CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId,
+    CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId,
 };
 use hir_expand::{
     diagnostics::DiagnosticSink,
         TypeAliasId,
     },
     impl_block::ImplBlock,
-    nameres::{ImportId, ModuleScope, Namespace},
+    nameres::{ImportId, Namespace},
     resolve::{Resolver, Scope, TypeNs},
     traits::TraitData,
     ty::{InferenceResult, TraitRef},
-    Either, HasSource, Name, Ty,
+    Either, HasSource, Name, ScopeDef, Ty,
 };
 
 /// hir::Crate describes a single crate. It's the main interface with which
@@ -66,7 +66,7 @@ pub fn dependencies(self, db: &impl DefDatabase) -> Vec<CrateDependency> {
     }
 
     pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> {
-        let module_id = db.crate_def_map(self).root();
+        let module_id = db.crate_def_map(self.crate_id).root();
         Some(Module::new(self, module_id))
     }
 
@@ -120,7 +120,7 @@ pub(crate) fn new(krate: Crate, crate_module_id: CrateModuleId) -> Module {
 
     /// Name of this module.
     pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
-        let def_map = db.crate_def_map(self.krate());
+        let def_map = db.crate_def_map(self.id.krate);
         let parent = def_map[self.id.module_id].parent?;
         def_map[parent].children.iter().find_map(|(name, module_id)| {
             if *module_id == self.id.module_id {
@@ -151,20 +151,20 @@ pub fn krate(self) -> Crate {
     /// might be missing `krate`. This can happen if a module's file is not included
     /// in the module tree of any target in `Cargo.toml`.
     pub fn crate_root(self, db: &impl DefDatabase) -> Module {
-        let def_map = db.crate_def_map(self.krate());
+        let def_map = db.crate_def_map(self.id.krate);
         self.with_module_id(def_map.root())
     }
 
     /// Finds a child module with the specified name.
     pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option<Module> {
-        let def_map = db.crate_def_map(self.krate());
+        let def_map = db.crate_def_map(self.id.krate);
         let child_id = def_map[self.id.module_id].children.get(name)?;
         Some(self.with_module_id(*child_id))
     }
 
     /// Iterates over all child modules.
     pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> {
-        let def_map = db.crate_def_map(self.krate());
+        let def_map = db.crate_def_map(self.id.krate);
         let children = def_map[self.id.module_id]
             .children
             .iter()
@@ -175,7 +175,7 @@ pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> {
 
     /// Finds a parent module.
     pub fn parent(self, db: &impl DefDatabase) -> Option<Module> {
-        let def_map = db.crate_def_map(self.krate());
+        let def_map = db.crate_def_map(self.id.krate);
         let parent_id = def_map[self.id.module_id].parent?;
         Some(self.with_module_id(parent_id))
     }
@@ -191,12 +191,16 @@ pub fn path_to_root(self, db: &impl HirDatabase) -> Vec<Module> {
     }
 
     /// Returns a `ModuleScope`: a set of items, visible in this module.
-    pub fn scope(self, db: &impl HirDatabase) -> ModuleScope {
-        db.crate_def_map(self.krate())[self.id.module_id].scope.clone()
+    pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option<ImportId>)> {
+        db.crate_def_map(self.id.krate)[self.id.module_id]
+            .scope
+            .entries()
+            .map(|(name, res)| (name.clone(), res.def.into(), res.import))
+            .collect()
     }
 
     pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
-        db.crate_def_map(self.krate()).add_diagnostics(db, self.id.module_id, sink);
+        db.crate_def_map(self.id.krate).add_diagnostics(db, self.id.module_id, sink);
         for decl in self.declarations(db) {
             match decl {
                 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
@@ -220,12 +224,12 @@ pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
     }
 
     pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver {
-        let def_map = db.crate_def_map(self.krate());
+        let def_map = db.crate_def_map(self.id.krate);
         Resolver::default().push_module_scope(def_map, self.id.module_id)
     }
 
     pub fn declarations(self, db: &impl DefDatabase) -> Vec<ModuleDef> {
-        let def_map = db.crate_def_map(self.krate());
+        let def_map = db.crate_def_map(self.id.krate);
         def_map[self.id.module_id]
             .scope
             .entries()
@@ -233,6 +237,7 @@ pub fn declarations(self, db: &impl DefDatabase) -> Vec<ModuleDef> {
             .flat_map(|per_ns| {
                 per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter())
             })
+            .map(ModuleDef::from)
             .collect()
     }
 
@@ -336,12 +341,12 @@ pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver {
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Union {
-    pub(crate) id: StructId,
+    pub(crate) id: UnionId,
 }
 
 impl Union {
     pub fn name(self, db: &impl DefDatabase) -> Option<Name> {
-        db.struct_data(self.id).name.clone()
+        db.union_data(self.id).name.clone()
     }
 
     pub fn module(self, db: &impl HirDatabase) -> Module {
index bd0c3c226aa474ebe284668c2251343bc832ee8e..6d116ee75c908f25391304922e7dd6dfac936ae4 100644 (file)
@@ -22,7 +22,7 @@ pub trait HasSource {
 impl Module {
     /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
     pub fn definition_source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ModuleSource> {
-        let def_map = db.crate_def_map(self.krate());
+        let def_map = db.crate_def_map(self.id.krate);
         let decl_id = def_map[self.id.module_id].declaration;
         let file_id = def_map[self.id.module_id].definition;
         let ast = ModuleSource::new(db, file_id, decl_id);
@@ -36,7 +36,7 @@ pub fn declaration_source(
         self,
         db: &(impl DefDatabase + AstDatabase),
     ) -> Option<Source<ast::Module>> {
-        let def_map = db.crate_def_map(self.krate());
+        let def_map = db.crate_def_map(self.id.krate);
         let decl = def_map[self.id.module_id].declaration?;
         let ast = decl.to_node(db);
         Some(Source { file_id: decl.file_id(), ast })
index 89ca4e39f0af9fa09933fbb6850f12f802bdb833..f45804c7ce902b35bbf58607ce4469bb7d7ed7a7 100644 (file)
@@ -11,7 +11,7 @@
     ids,
     impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks},
     lang_item::{LangItemTarget, LangItems},
-    nameres::{CrateDefMap, Namespace},
+    nameres::Namespace,
     traits::TraitData,
     ty::{
         method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate,
@@ -23,8 +23,8 @@
 };
 
 pub use hir_def::db::{
-    DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase, InternDatabaseStorage,
-    RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery,
+    CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase,
+    InternDatabaseStorage, RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery,
 };
 pub use hir_expand::db::{
     AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
@@ -41,9 +41,6 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
     #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)]
     fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex;
 
-    #[salsa::invoke(CrateDefMap::crate_def_map_query)]
-    fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
-
     #[salsa::invoke(ModuleImplBlocks::impls_in_module_with_source_map_query)]
     fn impls_in_module_with_source_map(
         &self,
index a33af8f467534346c52b17ad7f9facd21d30cb46..1751e7be33a28a4a709d462847112bb0625dda9f 100644 (file)
@@ -3,10 +3,10 @@
 use std::any::Any;
 
 use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
-use relative_path::RelativePathBuf;
 
 use crate::{db::AstDatabase, HirFileId, Name, Source};
 
+pub use hir_def::diagnostics::UnresolvedModule;
 pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
 
 #[derive(Debug)]
@@ -29,25 +29,6 @@ fn as_any(&self) -> &(dyn Any + Send + 'static) {
     }
 }
 
-#[derive(Debug)]
-pub struct UnresolvedModule {
-    pub file: HirFileId,
-    pub decl: AstPtr<ast::Module>,
-    pub candidate: RelativePathBuf,
-}
-
-impl Diagnostic for UnresolvedModule {
-    fn message(&self) -> String {
-        "unresolved module".to_string()
-    }
-    fn source(&self) -> Source<SyntaxNodePtr> {
-        Source { file_id: self.file, ast: self.decl.into() }
-    }
-    fn as_any(&self) -> &(dyn Any + Send + 'static) {
-        self
-    }
-}
-
 #[derive(Debug)]
 pub struct MissingFields {
     pub file: HirFileId,
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs
new file mode 100644 (file)
index 0000000..c08203b
--- /dev/null
@@ -0,0 +1,58 @@
+use hir_def::{AdtId, EnumVariantId, ModuleDefId};
+
+use crate::{Adt, EnumVariant, ModuleDef};
+
+macro_rules! from_id {
+    ($(($id:path, $ty:path)),*) => {$(
+        impl From<$id> for $ty {
+            fn from(id: $id) -> $ty {
+                $ty { id }
+            }
+        }
+    )*}
+}
+
+from_id![
+    (hir_def::ModuleId, crate::Module),
+    (hir_def::StructId, crate::Struct),
+    (hir_def::UnionId, crate::Union),
+    (hir_def::EnumId, crate::Enum),
+    (hir_def::TypeAliasId, crate::TypeAlias),
+    (hir_def::TraitId, crate::Trait),
+    (hir_def::StaticId, crate::Static),
+    (hir_def::ConstId, crate::Const),
+    (hir_def::FunctionId, crate::Function),
+    (hir_expand::MacroDefId, crate::MacroDef)
+];
+
+impl From<AdtId> for Adt {
+    fn from(id: AdtId) -> Self {
+        match id {
+            AdtId::StructId(it) => Adt::Struct(it.into()),
+            AdtId::UnionId(it) => Adt::Union(it.into()),
+            AdtId::EnumId(it) => Adt::Enum(it.into()),
+        }
+    }
+}
+
+impl From<EnumVariantId> for EnumVariant {
+    fn from(id: EnumVariantId) -> Self {
+        EnumVariant { parent: id.parent.into(), id: id.local_id }
+    }
+}
+
+impl From<ModuleDefId> for ModuleDef {
+    fn from(id: ModuleDefId) -> Self {
+        match id {
+            ModuleDefId::ModuleId(it) => ModuleDef::Module(it.into()),
+            ModuleDefId::FunctionId(it) => ModuleDef::Function(it.into()),
+            ModuleDefId::AdtId(it) => ModuleDef::Adt(it.into()),
+            ModuleDefId::EnumVariantId(it) => ModuleDef::EnumVariant(it.into()),
+            ModuleDefId::ConstId(it) => ModuleDef::Const(it.into()),
+            ModuleDefId::StaticId(it) => ModuleDef::Static(it.into()),
+            ModuleDefId::TraitId(it) => ModuleDef::Trait(it.into()),
+            ModuleDefId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()),
+            ModuleDefId::BuiltinType(it) => ModuleDef::BuiltinType(it),
+        }
+    }
+}
index a9de0145538b630aa3dc93fdc7345fb8b19e0089..9899bdbbce26af5ccc65ccacfcc3691cef3dd639 100644 (file)
@@ -149,14 +149,20 @@ pub fn from_definition(
             ModuleSource::SourceFile(_) => None,
         };
 
-        db.relevant_crates(src.file_id.original_file(db))
-            .iter()
-            .map(|&crate_id| Crate { crate_id })
-            .find_map(|krate| {
-                let def_map = db.crate_def_map(krate);
-                let module_id = def_map.find_module_by_source(src.file_id, decl_id)?;
-                Some(Module::new(krate, module_id))
-            })
+        db.relevant_crates(src.file_id.original_file(db)).iter().find_map(|&crate_id| {
+            let def_map = db.crate_def_map(crate_id);
+
+            let (module_id, _module_data) =
+                def_map.modules.iter().find(|(_module_id, module_data)| {
+                    if decl_id.is_some() {
+                        module_data.declaration == decl_id
+                    } else {
+                        module_data.definition.map(|it| it.into()) == Some(src.file_id)
+                    }
+                })?;
+
+            Some(Module::new(Crate { crate_id }, module_id))
+        })
     }
 }
 
index 0ba17e5710d307e31d43d068fa4fe5313d2a3fe1..52bad22284b96963b6051de3050e5583b3ff1589 100644 (file)
@@ -47,6 +47,7 @@ fn from(it: $sv) -> $e {
 pub mod diagnostics;
 mod util;
 
+mod from_id;
 mod code_model;
 
 pub mod from_source;
index 32a6ab47495fb372efe32c3bed2fe698a8db4995..bb775cfc9d22e24866b3a8ac329d816c7fb8e4cf 100644 (file)
 //! path and, upon success, we run macro expansion and "collect module" phase
 //! on the result
 
-mod per_ns;
-mod collector;
 #[cfg(test)]
 mod tests;
 
-use std::sync::Arc;
-
-use hir_def::{builtin_type::BuiltinType, CrateModuleId};
-use hir_expand::diagnostics::DiagnosticSink;
-use once_cell::sync::Lazy;
-use ra_arena::Arena;
-use ra_db::{Edition, FileId};
-use ra_prof::profile;
-use ra_syntax::ast;
-use rustc_hash::{FxHashMap, FxHashSet};
-use test_utils::tested_by;
-
-use crate::{
-    db::{AstDatabase, DefDatabase},
-    ids::MacroDefId,
-    nameres::diagnostics::DefDiagnostic,
-    Adt, AstId, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait,
+pub use hir_def::nameres::{
+    per_ns::{Namespace, PerNs},
+    raw::ImportId,
 };
-
-pub use self::per_ns::{Namespace, PerNs};
-
-pub use hir_def::nameres::raw::ImportId;
-
-/// Contains all top-level defs from a macro-expanded crate
-#[derive(Debug, PartialEq, Eq)]
-pub struct CrateDefMap {
-    krate: Crate,
-    edition: Edition,
-    /// The prelude module for this crate. This either comes from an import
-    /// marked with the `prelude_import` attribute, or (in the normal case) from
-    /// a dependency (`std` or `core`).
-    prelude: Option<Module>,
-    extern_prelude: FxHashMap<Name, ModuleDef>,
-    root: CrateModuleId,
-    modules: Arena<CrateModuleId, ModuleData>,
-
-    /// Some macros are not well-behavior, which leads to infinite loop
-    /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
-    /// We mark it down and skip it in collector
-    ///
-    /// FIXME:
-    /// Right now it only handle a poison macro in a single crate,
-    /// such that if other crate try to call that macro,
-    /// the whole process will do again until it became poisoned in that crate.
-    /// We should handle this macro set globally
-    /// However, do we want to put it as a global variable?
-    poison_macros: FxHashSet<MacroDefId>,
-
-    diagnostics: Vec<DefDiagnostic>,
-}
-
-impl std::ops::Index<CrateModuleId> for CrateDefMap {
-    type Output = ModuleData;
-    fn index(&self, id: CrateModuleId) -> &ModuleData {
-        &self.modules[id]
-    }
-}
-
-#[derive(Default, Debug, PartialEq, Eq)]
-pub struct ModuleData {
-    pub(crate) parent: Option<CrateModuleId>,
-    pub(crate) children: FxHashMap<Name, CrateModuleId>,
-    pub(crate) scope: ModuleScope,
-    /// None for root
-    pub(crate) declaration: Option<AstId<ast::Module>>,
-    /// None for inline modules.
-    ///
-    /// Note that non-inline modules, by definition, live inside non-macro file.
-    pub(crate) definition: Option<FileId>,
-}
-
-#[derive(Debug, Default, PartialEq, Eq, Clone)]
-pub struct ModuleScope {
-    items: FxHashMap<Name, Resolution>,
-    /// Macros visable in current module in legacy textual scope
-    ///
-    /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
-    /// If it yields no result, then it turns to module scoped `macros`.
-    /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
-    /// and only normal scoped `macros` will be searched in.
-    ///
-    /// Note that this automatically inherit macros defined textually before the definition of module itself.
-    ///
-    /// Module scoped macros will be inserted into `items` instead of here.
-    // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
-    // be all resolved to the last one defined if shadowing happens.
-    legacy_macros: FxHashMap<Name, MacroDef>,
-}
-
-static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
-    BuiltinType::ALL
-        .iter()
-        .map(|(name, ty)| {
-            (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None })
-        })
-        .collect()
-});
-
-/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
-/// Other methods will only resolve values, types and module scoped macros only.
-impl ModuleScope {
-    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
-        //FIXME: shadowing
-        self.items.iter().chain(BUILTIN_SCOPE.iter())
-    }
-
-    /// Iterate over all module scoped macros
-    pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a {
-        self.items
-            .iter()
-            .filter_map(|(name, res)| res.def.get_macros().map(|macro_| (name, macro_)))
-    }
-
-    /// Iterate over all legacy textual scoped macros visable at the end of the module
-    pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDef)> + 'a {
-        self.legacy_macros.iter().map(|(name, def)| (name, *def))
-    }
-
-    /// Get a name from current module scope, legacy macros are not included
-    pub fn get(&self, name: &Name) -> Option<&Resolution> {
-        self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name))
-    }
-
-    pub fn traits<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a {
-        self.items.values().filter_map(|r| match r.def.take_types() {
-            Some(ModuleDef::Trait(t)) => Some(t),
-            _ => None,
-        })
-    }
-
-    fn get_legacy_macro(&self, name: &Name) -> Option<MacroDef> {
-        self.legacy_macros.get(name).copied()
-    }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Default)]
-pub struct Resolution {
-    /// None for unresolved
-    pub def: PerNs,
-    /// ident by which this is imported into local scope.
-    pub import: Option<ImportId>,
-}
-
-impl Resolution {
-    pub(crate) fn from_macro(macro_: MacroDef) -> Self {
-        Resolution { def: PerNs::macros(macro_), import: None }
-    }
-}
-
-#[derive(Debug, Clone)]
-struct ResolvePathResult {
-    resolved_def: PerNs,
-    segment_index: Option<usize>,
-    reached_fixedpoint: ReachedFixedPoint,
-}
-
-impl ResolvePathResult {
-    fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
-        ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
-    }
-
-    fn with(
-        resolved_def: PerNs,
-        reached_fixedpoint: ReachedFixedPoint,
-        segment_index: Option<usize>,
-    ) -> ResolvePathResult {
-        ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum ResolveMode {
-    Import,
-    Other,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum ReachedFixedPoint {
-    Yes,
-    No,
-}
-
-impl CrateDefMap {
-    pub(crate) fn crate_def_map_query(
-        // Note that this doesn't have `+ AstDatabase`!
-        // This gurantess that `CrateDefMap` is stable across reparses.
-        db: &impl DefDatabase,
-        krate: Crate,
-    ) -> Arc<CrateDefMap> {
-        let _p = profile("crate_def_map_query");
-        let def_map = {
-            let edition = krate.edition(db);
-            let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
-            let root = modules.alloc(ModuleData::default());
-            CrateDefMap {
-                krate,
-                edition,
-                extern_prelude: FxHashMap::default(),
-                prelude: None,
-                root,
-                modules,
-                poison_macros: FxHashSet::default(),
-                diagnostics: Vec::new(),
-            }
-        };
-        let def_map = collector::collect_defs(db, def_map);
-        Arc::new(def_map)
-    }
-
-    pub(crate) fn krate(&self) -> Crate {
-        self.krate
-    }
-
-    pub(crate) fn root(&self) -> CrateModuleId {
-        self.root
-    }
-
-    pub(crate) fn prelude(&self) -> Option<Module> {
-        self.prelude
-    }
-
-    pub(crate) fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDef> {
-        &self.extern_prelude
-    }
-
-    pub(crate) fn add_diagnostics(
-        &self,
-        db: &(impl DefDatabase + AstDatabase),
-        module: CrateModuleId,
-        sink: &mut DiagnosticSink,
-    ) {
-        self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
-    }
-
-    pub(crate) fn find_module_by_source(
-        &self,
-        file_id: HirFileId,
-        decl_id: Option<AstId<ast::Module>>,
-    ) -> Option<CrateModuleId> {
-        let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| {
-            if decl_id.is_some() {
-                module_data.declaration == decl_id
-            } else {
-                module_data.definition.map(|it| it.into()) == Some(file_id)
-            }
-        })?;
-        Some(module_id)
-    }
-
-    pub(crate) fn resolve_path(
-        &self,
-        db: &impl DefDatabase,
-        original_module: CrateModuleId,
-        path: &Path,
-    ) -> (PerNs, Option<usize>) {
-        let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
-        (res.resolved_def, res.segment_index)
-    }
-
-    // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
-    // the result.
-    fn resolve_path_fp_with_macro(
-        &self,
-        db: &impl DefDatabase,
-        mode: ResolveMode,
-        original_module: CrateModuleId,
-        path: &Path,
-    ) -> ResolvePathResult {
-        let mut segments = path.segments.iter().enumerate();
-        let mut curr_per_ns: PerNs = match path.kind {
-            PathKind::DollarCrate(crate_id) => {
-                let krate = Crate { crate_id };
-                if krate == self.krate {
-                    tested_by!(macro_dollar_crate_self);
-                    PerNs::types(Module::new(self.krate, self.root).into())
-                } else {
-                    match krate.root_module(db) {
-                        Some(module) => {
-                            tested_by!(macro_dollar_crate_other);
-                            PerNs::types(module.into())
-                        }
-                        None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
-                    }
-                }
-            }
-            PathKind::Crate => PerNs::types(Module::new(self.krate, self.root).into()),
-            PathKind::Self_ => PerNs::types(Module::new(self.krate, original_module).into()),
-            // plain import or absolute path in 2015: crate-relative with
-            // fallback to extern prelude (with the simplification in
-            // rust-lang/rust#57745)
-            // FIXME there must be a nicer way to write this condition
-            PathKind::Plain | PathKind::Abs
-                if self.edition == Edition::Edition2015
-                    && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
-            {
-                let segment = match segments.next() {
-                    Some((_, segment)) => segment,
-                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
-                };
-                log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
-                self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
-            }
-            PathKind::Plain => {
-                let segment = match segments.next() {
-                    Some((_, segment)) => segment,
-                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
-                };
-                log::debug!("resolving {:?} in module", segment);
-                self.resolve_name_in_module(db, original_module, &segment.name)
-            }
-            PathKind::Super => {
-                if let Some(p) = self.modules[original_module].parent {
-                    PerNs::types(Module::new(self.krate, p).into())
-                } else {
-                    log::debug!("super path in root module");
-                    return ResolvePathResult::empty(ReachedFixedPoint::Yes);
-                }
-            }
-            PathKind::Abs => {
-                // 2018-style absolute path -- only extern prelude
-                let segment = match segments.next() {
-                    Some((_, segment)) => segment,
-                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
-                };
-                if let Some(def) = self.extern_prelude.get(&segment.name) {
-                    log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
-                    PerNs::types(*def)
-                } else {
-                    return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
-                }
-            }
-            PathKind::Type(_) => {
-                // This is handled in `infer::infer_path_expr`
-                // The result returned here does not matter
-                return ResolvePathResult::empty(ReachedFixedPoint::Yes);
-            }
-        };
-
-        for (i, segment) in segments {
-            let curr = match curr_per_ns.take_types() {
-                Some(r) => r,
-                None => {
-                    // we still have path segments left, but the path so far
-                    // didn't resolve in the types namespace => no resolution
-                    // (don't break here because `curr_per_ns` might contain
-                    // something in the value namespace, and it would be wrong
-                    // to return that)
-                    return ResolvePathResult::empty(ReachedFixedPoint::No);
-                }
-            };
-            // resolve segment in curr
-
-            curr_per_ns = match curr {
-                ModuleDef::Module(module) => {
-                    if module.krate() != self.krate {
-                        let path =
-                            Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
-                        log::debug!("resolving {:?} in other crate", path);
-                        let defp_map = db.crate_def_map(module.krate());
-                        let (def, s) = defp_map.resolve_path(db, module.id.module_id, &path);
-                        return ResolvePathResult::with(
-                            def,
-                            ReachedFixedPoint::Yes,
-                            s.map(|s| s + i),
-                        );
-                    }
-
-                    // Since it is a qualified path here, it should not contains legacy macros
-                    match self[module.id.module_id].scope.get(&segment.name) {
-                        Some(res) => res.def,
-                        _ => {
-                            log::debug!("path segment {:?} not found", segment.name);
-                            return ResolvePathResult::empty(ReachedFixedPoint::No);
-                        }
-                    }
-                }
-                ModuleDef::Adt(Adt::Enum(e)) => {
-                    // enum variant
-                    tested_by!(can_import_enum_variant);
-                    match e.variant(db, &segment.name) {
-                        Some(variant) => PerNs::both(variant.into(), variant.into()),
-                        None => {
-                            return ResolvePathResult::with(
-                                PerNs::types(e.into()),
-                                ReachedFixedPoint::Yes,
-                                Some(i),
-                            );
-                        }
-                    }
-                }
-                s => {
-                    // could be an inherent method call in UFCS form
-                    // (`Struct::method`), or some other kind of associated item
-                    log::debug!(
-                        "path segment {:?} resolved to non-module {:?}, but is not last",
-                        segment.name,
-                        curr,
-                    );
-
-                    return ResolvePathResult::with(
-                        PerNs::types(s),
-                        ReachedFixedPoint::Yes,
-                        Some(i),
-                    );
-                }
-            };
-        }
-        ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
-    }
-
-    fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
-        let from_crate_root =
-            self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
-        let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
-
-        from_crate_root.or(from_extern_prelude)
-    }
-
-    pub(crate) fn resolve_name_in_module(
-        &self,
-        db: &impl DefDatabase,
-        module: CrateModuleId,
-        name: &Name,
-    ) -> PerNs {
-        // Resolve in:
-        //  - legacy scope of macro
-        //  - current module / scope
-        //  - extern prelude
-        //  - std prelude
-        let from_legacy_macro =
-            self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
-        let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
-        let from_extern_prelude =
-            self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
-        let from_prelude = self.resolve_in_prelude(db, name);
-
-        from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
-    }
-
-    fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
-        self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
-    }
-
-    fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs {
-        if let Some(prelude) = self.prelude {
-            let keep;
-            let def_map = if prelude.krate() == self.krate {
-                self
-            } else {
-                // Extend lifetime
-                keep = db.crate_def_map(prelude.krate());
-                &keep
-            };
-            def_map[prelude.id.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
-        } else {
-            PerNs::none()
-        }
-    }
-}
-
-mod diagnostics {
-    use hir_expand::diagnostics::DiagnosticSink;
-    use ra_syntax::{ast, AstPtr};
-    use relative_path::RelativePathBuf;
-
-    use crate::{
-        db::{AstDatabase, DefDatabase},
-        diagnostics::UnresolvedModule,
-        nameres::CrateModuleId,
-        AstId,
-    };
-
-    #[derive(Debug, PartialEq, Eq)]
-    pub(super) enum DefDiagnostic {
-        UnresolvedModule {
-            module: CrateModuleId,
-            declaration: AstId<ast::Module>,
-            candidate: RelativePathBuf,
-        },
-    }
-
-    impl DefDiagnostic {
-        pub(super) fn add_to(
-            &self,
-            db: &(impl DefDatabase + AstDatabase),
-            target_module: CrateModuleId,
-            sink: &mut DiagnosticSink,
-        ) {
-            match self {
-                DefDiagnostic::UnresolvedModule { module, declaration, candidate } => {
-                    if *module != target_module {
-                        return;
-                    }
-                    let decl = declaration.to_node(db);
-                    sink.push(UnresolvedModule {
-                        file: declaration.file_id(),
-                        decl: AstPtr::new(&decl),
-                        candidate: candidate.clone(),
-                    })
-                }
-            }
-        }
-    }
-}
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
deleted file mode 100644 (file)
index ee0a4c9..0000000
+++ /dev/null
@@ -1,837 +0,0 @@
-//! FIXME: write short doc here
-
-use hir_def::{
-    attr::Attr,
-    nameres::{mod_resolution::ModDir, raw},
-};
-use hir_expand::name;
-use ra_cfg::CfgOptions;
-use ra_db::FileId;
-use ra_syntax::{ast, SmolStr};
-use rustc_hash::FxHashMap;
-use test_utils::tested_by;
-
-use crate::{
-    db::DefDatabase,
-    ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind},
-    nameres::{
-        diagnostics::DefDiagnostic, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef,
-        PerNs, ReachedFixedPoint, Resolution, ResolveMode,
-    },
-    Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static,
-    Struct, Trait, TypeAlias, Union,
-};
-
-pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
-    // populate external prelude
-    for dep in def_map.krate.dependencies(db) {
-        log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
-        if let Some(module) = dep.krate.root_module(db) {
-            def_map.extern_prelude.insert(dep.name.clone(), module.into());
-        }
-        // look for the prelude
-        if def_map.prelude.is_none() {
-            let map = db.crate_def_map(dep.krate);
-            if map.prelude.is_some() {
-                def_map.prelude = map.prelude;
-            }
-        }
-    }
-
-    let crate_graph = db.crate_graph();
-    let cfg_options = crate_graph.cfg_options(def_map.krate().crate_id());
-
-    let mut collector = DefCollector {
-        db,
-        def_map,
-        glob_imports: FxHashMap::default(),
-        unresolved_imports: Vec::new(),
-        unexpanded_macros: Vec::new(),
-        mod_dirs: FxHashMap::default(),
-        macro_stack_monitor: MacroStackMonitor::default(),
-        cfg_options,
-    };
-    collector.collect();
-    collector.finish()
-}
-
-#[derive(Default)]
-struct MacroStackMonitor {
-    counts: FxHashMap<MacroDefId, u32>,
-
-    /// Mainly use for test
-    validator: Option<Box<dyn Fn(u32) -> bool>>,
-}
-
-impl MacroStackMonitor {
-    fn increase(&mut self, macro_def_id: MacroDefId) {
-        *self.counts.entry(macro_def_id).or_default() += 1;
-    }
-
-    fn decrease(&mut self, macro_def_id: MacroDefId) {
-        *self.counts.entry(macro_def_id).or_default() -= 1;
-    }
-
-    fn is_poison(&self, macro_def_id: MacroDefId) -> bool {
-        let cur = *self.counts.get(&macro_def_id).unwrap_or(&0);
-
-        if let Some(validator) = &self.validator {
-            validator(cur)
-        } else {
-            cur > 100
-        }
-    }
-}
-
-/// Walks the tree of module recursively
-struct DefCollector<'a, DB> {
-    db: &'a DB,
-    def_map: CrateDefMap,
-    glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
-    unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
-    unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>,
-    mod_dirs: FxHashMap<CrateModuleId, ModDir>,
-
-    /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
-    /// To prevent stack overflow, we add a deep counter here for prevent that.
-    macro_stack_monitor: MacroStackMonitor,
-
-    cfg_options: &'a CfgOptions,
-}
-
-impl<DB> DefCollector<'_, DB>
-where
-    DB: DefDatabase,
-{
-    fn collect(&mut self) {
-        let crate_graph = self.db.crate_graph();
-        let file_id = crate_graph.crate_root(self.def_map.krate.crate_id());
-        let raw_items = self.db.raw_items(file_id.into());
-        let module_id = self.def_map.root;
-        self.def_map.modules[module_id].definition = Some(file_id);
-        ModCollector {
-            def_collector: &mut *self,
-            module_id,
-            file_id: file_id.into(),
-            raw_items: &raw_items,
-            mod_dir: ModDir::root(),
-        }
-        .collect(raw_items.items());
-
-        // main name resolution fixed-point loop.
-        let mut i = 0;
-        loop {
-            self.db.check_canceled();
-            match (self.resolve_imports(), self.resolve_macros()) {
-                (ReachedFixedPoint::Yes, ReachedFixedPoint::Yes) => break,
-                _ => i += 1,
-            }
-            if i == 1000 {
-                log::error!("name resolution is stuck");
-                break;
-            }
-        }
-
-        let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
-        // show unresolved imports in completion, etc
-        for (module_id, import, import_data) in unresolved_imports {
-            self.record_resolved_import(module_id, PerNs::none(), import, &import_data)
-        }
-    }
-
-    /// Define a macro with `macro_rules`.
-    ///
-    /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`,
-    /// then it is also defined in the root module scope.
-    /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition.
-    ///
-    /// It is surprising that the macro will never be in the current module scope.
-    /// These code fails with "unresolved import/macro",
-    /// ```rust,compile_fail
-    /// mod m { macro_rules! foo { () => {} } }
-    /// use m::foo as bar;
-    /// ```
-    ///
-    /// ```rust,compile_fail
-    /// macro_rules! foo { () => {} }
-    /// self::foo!();
-    /// crate::foo!();
-    /// ```
-    ///
-    /// Well, this code compiles, bacause the plain path `foo` in `use` is searched
-    /// in the legacy textual scope only.
-    /// ```rust
-    /// macro_rules! foo { () => {} }
-    /// use foo as bar;
-    /// ```
-    fn define_macro(
-        &mut self,
-        module_id: CrateModuleId,
-        name: Name,
-        macro_: MacroDef,
-        export: bool,
-    ) {
-        // Textual scoping
-        self.define_legacy_macro(module_id, name.clone(), macro_);
-
-        // Module scoping
-        // In Rust, `#[macro_export]` macros are unconditionally visible at the
-        // crate root, even if the parent modules is **not** visible.
-        if export {
-            self.update(self.def_map.root, None, &[(name, Resolution::from_macro(macro_))]);
-        }
-    }
-
-    /// Define a legacy textual scoped macro in module
-    ///
-    /// We use a map `legacy_macros` to store all legacy textual scoped macros visable per module.
-    /// It will clone all macros from parent legacy scope, whose definition is prior to
-    /// the definition of current module.
-    /// And also, `macro_use` on a module will import all legacy macros visable inside to
-    /// current legacy scope, with possible shadowing.
-    fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDef) {
-        // Always shadowing
-        self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_);
-    }
-
-    /// Import macros from `#[macro_use] extern crate`.
-    fn import_macros_from_extern_crate(
-        &mut self,
-        current_module_id: CrateModuleId,
-        import: &raw::ImportData,
-    ) {
-        log::debug!(
-            "importing macros from extern crate: {:?} ({:?})",
-            import,
-            self.def_map.edition,
-        );
-
-        let res = self.def_map.resolve_name_in_extern_prelude(
-            &import
-                .path
-                .as_ident()
-                .expect("extern crate should have been desugared to one-element path"),
-        );
-
-        if let Some(ModuleDef::Module(m)) = res.take_types() {
-            tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
-            self.import_all_macros_exported(current_module_id, m.krate());
-        }
-    }
-
-    /// Import all exported macros from another crate
-    ///
-    /// Exported macros are just all macros in the root module scope.
-    /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
-    /// created by `use` in the root module, ignoring the visibility of `use`.
-    fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: Crate) {
-        let def_map = self.db.crate_def_map(krate);
-        for (name, def) in def_map[def_map.root].scope.macros() {
-            // `macro_use` only bring things into legacy scope.
-            self.define_legacy_macro(current_module_id, name.clone(), def);
-        }
-    }
-
-    fn resolve_imports(&mut self) -> ReachedFixedPoint {
-        let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
-        let mut resolved = Vec::new();
-        imports.retain(|(module_id, import, import_data)| {
-            let (def, fp) = self.resolve_import(*module_id, import_data);
-            if fp == ReachedFixedPoint::Yes {
-                resolved.push((*module_id, def, *import, import_data.clone()))
-            }
-            fp == ReachedFixedPoint::No
-        });
-        self.unresolved_imports = imports;
-        // Resolves imports, filling-in module scopes
-        let result =
-            if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No };
-        for (module_id, def, import, import_data) in resolved {
-            self.record_resolved_import(module_id, def, import, &import_data)
-        }
-        result
-    }
-
-    fn resolve_import(
-        &self,
-        module_id: CrateModuleId,
-        import: &raw::ImportData,
-    ) -> (PerNs, ReachedFixedPoint) {
-        log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
-        if import.is_extern_crate {
-            let res = self.def_map.resolve_name_in_extern_prelude(
-                &import
-                    .path
-                    .as_ident()
-                    .expect("extern crate should have been desugared to one-element path"),
-            );
-            (res, ReachedFixedPoint::Yes)
-        } else {
-            let res = self.def_map.resolve_path_fp_with_macro(
-                self.db,
-                ResolveMode::Import,
-                module_id,
-                &import.path,
-            );
-
-            (res.resolved_def, res.reached_fixedpoint)
-        }
-    }
-
-    fn record_resolved_import(
-        &mut self,
-        module_id: CrateModuleId,
-        def: PerNs,
-        import_id: raw::ImportId,
-        import: &raw::ImportData,
-    ) {
-        if import.is_glob {
-            log::debug!("glob import: {:?}", import);
-            match def.take_types() {
-                Some(ModuleDef::Module(m)) => {
-                    if import.is_prelude {
-                        tested_by!(std_prelude);
-                        self.def_map.prelude = Some(m);
-                    } else if m.krate() != self.def_map.krate {
-                        tested_by!(glob_across_crates);
-                        // glob import from other crate => we can just import everything once
-                        let item_map = self.db.crate_def_map(m.krate());
-                        let scope = &item_map[m.id.module_id].scope;
-
-                        // Module scoped macros is included
-                        let items = scope
-                            .items
-                            .iter()
-                            .map(|(name, res)| (name.clone(), res.clone()))
-                            .collect::<Vec<_>>();
-
-                        self.update(module_id, Some(import_id), &items);
-                    } else {
-                        // glob import from same crate => we do an initial
-                        // import, and then need to propagate any further
-                        // additions
-                        let scope = &self.def_map[m.id.module_id].scope;
-
-                        // Module scoped macros is included
-                        let items = scope
-                            .items
-                            .iter()
-                            .map(|(name, res)| (name.clone(), res.clone()))
-                            .collect::<Vec<_>>();
-
-                        self.update(module_id, Some(import_id), &items);
-                        // record the glob import in case we add further items
-                        self.glob_imports
-                            .entry(m.id.module_id)
-                            .or_default()
-                            .push((module_id, import_id));
-                    }
-                }
-                Some(ModuleDef::Adt(Adt::Enum(e))) => {
-                    tested_by!(glob_enum);
-                    // glob import from enum => just import all the variants
-                    let variants = e.variants(self.db);
-                    let resolutions = variants
-                        .into_iter()
-                        .filter_map(|variant| {
-                            let res = Resolution {
-                                def: PerNs::both(variant.into(), variant.into()),
-                                import: Some(import_id),
-                            };
-                            let name = variant.name(self.db)?;
-                            Some((name, res))
-                        })
-                        .collect::<Vec<_>>();
-                    self.update(module_id, Some(import_id), &resolutions);
-                }
-                Some(d) => {
-                    log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
-                }
-                None => {
-                    log::debug!("glob import {:?} didn't resolve as type", import);
-                }
-            }
-        } else {
-            match import.path.segments.last() {
-                Some(last_segment) => {
-                    let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone());
-                    log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
-
-                    // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
-                    if import.is_extern_crate && module_id == self.def_map.root {
-                        if let Some(def) = def.take_types() {
-                            self.def_map.extern_prelude.insert(name.clone(), def);
-                        }
-                    }
-
-                    let resolution = Resolution { def, import: Some(import_id) };
-                    self.update(module_id, Some(import_id), &[(name, resolution)]);
-                }
-                None => tested_by!(bogus_paths),
-            }
-        }
-    }
-
-    fn update(
-        &mut self,
-        module_id: CrateModuleId,
-        import: Option<raw::ImportId>,
-        resolutions: &[(Name, Resolution)],
-    ) {
-        self.update_recursive(module_id, import, resolutions, 0)
-    }
-
-    fn update_recursive(
-        &mut self,
-        module_id: CrateModuleId,
-        import: Option<raw::ImportId>,
-        resolutions: &[(Name, Resolution)],
-        depth: usize,
-    ) {
-        if depth > 100 {
-            // prevent stack overflows (but this shouldn't be possible)
-            panic!("infinite recursion in glob imports!");
-        }
-        let module_items = &mut self.def_map.modules[module_id].scope;
-        let mut changed = false;
-        for (name, res) in resolutions {
-            let existing = module_items.items.entry(name.clone()).or_default();
-
-            if existing.def.types.is_none() && res.def.types.is_some() {
-                existing.def.types = res.def.types;
-                existing.import = import.or(res.import);
-                changed = true;
-            }
-            if existing.def.values.is_none() && res.def.values.is_some() {
-                existing.def.values = res.def.values;
-                existing.import = import.or(res.import);
-                changed = true;
-            }
-            if existing.def.macros.is_none() && res.def.macros.is_some() {
-                existing.def.macros = res.def.macros;
-                existing.import = import.or(res.import);
-                changed = true;
-            }
-
-            if existing.def.is_none()
-                && res.def.is_none()
-                && existing.import.is_none()
-                && res.import.is_some()
-            {
-                existing.import = res.import;
-            }
-        }
-
-        if !changed {
-            return;
-        }
-        let glob_imports = self
-            .glob_imports
-            .get(&module_id)
-            .into_iter()
-            .flat_map(|v| v.iter())
-            .cloned()
-            .collect::<Vec<_>>();
-        for (glob_importing_module, glob_import) in glob_imports {
-            // We pass the glob import so that the tracked import in those modules is that glob import
-            self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1);
-        }
-    }
-
-    fn resolve_macros(&mut self) -> ReachedFixedPoint {
-        let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
-        let mut resolved = Vec::new();
-        let mut res = ReachedFixedPoint::Yes;
-        macros.retain(|(module_id, ast_id, path)| {
-            let resolved_res = self.def_map.resolve_path_fp_with_macro(
-                self.db,
-                ResolveMode::Other,
-                *module_id,
-                path,
-            );
-
-            if let Some(def) = resolved_res.resolved_def.get_macros() {
-                let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id: *ast_id });
-                resolved.push((*module_id, call_id, def.id));
-                res = ReachedFixedPoint::No;
-                return false;
-            }
-
-            true
-        });
-
-        self.unexpanded_macros = macros;
-
-        for (module_id, macro_call_id, macro_def_id) in resolved {
-            self.collect_macro_expansion(module_id, macro_call_id, macro_def_id);
-        }
-
-        res
-    }
-
-    fn collect_macro_expansion(
-        &mut self,
-        module_id: CrateModuleId,
-        macro_call_id: MacroCallId,
-        macro_def_id: MacroDefId,
-    ) {
-        if self.def_map.poison_macros.contains(&macro_def_id) {
-            return;
-        }
-
-        self.macro_stack_monitor.increase(macro_def_id);
-
-        if !self.macro_stack_monitor.is_poison(macro_def_id) {
-            let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items);
-            let raw_items = self.db.raw_items(file_id);
-            let mod_dir = self.mod_dirs[&module_id].clone();
-            ModCollector {
-                def_collector: &mut *self,
-                file_id,
-                module_id,
-                raw_items: &raw_items,
-                mod_dir,
-            }
-            .collect(raw_items.items());
-        } else {
-            log::error!("Too deep macro expansion: {:?}", macro_call_id);
-            self.def_map.poison_macros.insert(macro_def_id);
-        }
-
-        self.macro_stack_monitor.decrease(macro_def_id);
-    }
-
-    fn finish(self) -> CrateDefMap {
-        self.def_map
-    }
-}
-
-/// Walks a single module, populating defs, imports and macros
-struct ModCollector<'a, D> {
-    def_collector: D,
-    module_id: CrateModuleId,
-    file_id: HirFileId,
-    raw_items: &'a raw::RawItems,
-    mod_dir: ModDir,
-}
-
-impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
-where
-    DB: DefDatabase,
-{
-    fn collect(&mut self, items: &[raw::RawItem]) {
-        // Note: don't assert that inserted value is fresh: it's simply not true
-        // for macros.
-        self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
-
-        // Prelude module is always considered to be `#[macro_use]`.
-        if let Some(prelude_module) = self.def_collector.def_map.prelude {
-            if prelude_module.krate() != self.def_collector.def_map.krate {
-                tested_by!(prelude_is_macro_use);
-                self.def_collector
-                    .import_all_macros_exported(self.module_id, prelude_module.krate());
-            }
-        }
-
-        // This should be processed eagerly instead of deferred to resolving.
-        // `#[macro_use] extern crate` is hoisted to imports macros before collecting
-        // any other items.
-        for item in items {
-            if self.is_cfg_enabled(item.attrs()) {
-                if let raw::RawItemKind::Import(import_id) = item.kind {
-                    let import = self.raw_items[import_id].clone();
-                    if import.is_extern_crate && import.is_macro_use {
-                        self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
-                    }
-                }
-            }
-        }
-
-        for item in items {
-            if self.is_cfg_enabled(item.attrs()) {
-                match item.kind {
-                    raw::RawItemKind::Module(m) => {
-                        self.collect_module(&self.raw_items[m], item.attrs())
-                    }
-                    raw::RawItemKind::Import(import_id) => self
-                        .def_collector
-                        .unresolved_imports
-                        .push((self.module_id, import_id, self.raw_items[import_id].clone())),
-                    raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]),
-                    raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
-                }
-            }
-        }
-    }
-
-    fn collect_module(&mut self, module: &raw::ModuleData, attrs: &[Attr]) {
-        let path_attr = self.path_attr(attrs);
-        let is_macro_use = self.is_macro_use(attrs);
-        match module {
-            // inline module, just recurse
-            raw::ModuleData::Definition { name, items, ast_id } => {
-                let module_id =
-                    self.push_child_module(name.clone(), AstId::new(self.file_id, *ast_id), None);
-
-                ModCollector {
-                    def_collector: &mut *self.def_collector,
-                    module_id,
-                    file_id: self.file_id,
-                    raw_items: self.raw_items,
-                    mod_dir: self.mod_dir.descend_into_definition(name, path_attr),
-                }
-                .collect(&*items);
-                if is_macro_use {
-                    self.import_all_legacy_macros(module_id);
-                }
-            }
-            // out of line module, resolve, parse and recurse
-            raw::ModuleData::Declaration { name, ast_id } => {
-                let ast_id = AstId::new(self.file_id, *ast_id);
-                match self.mod_dir.resolve_declaration(
-                    self.def_collector.db,
-                    self.file_id,
-                    name,
-                    path_attr,
-                ) {
-                    Ok((file_id, mod_dir)) => {
-                        let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id));
-                        let raw_items = self.def_collector.db.raw_items(file_id.into());
-                        ModCollector {
-                            def_collector: &mut *self.def_collector,
-                            module_id,
-                            file_id: file_id.into(),
-                            raw_items: &raw_items,
-                            mod_dir,
-                        }
-                        .collect(raw_items.items());
-                        if is_macro_use {
-                            self.import_all_legacy_macros(module_id);
-                        }
-                    }
-                    Err(candidate) => self.def_collector.def_map.diagnostics.push(
-                        DefDiagnostic::UnresolvedModule {
-                            module: self.module_id,
-                            declaration: ast_id,
-                            candidate,
-                        },
-                    ),
-                };
-            }
-        }
-    }
-
-    fn push_child_module(
-        &mut self,
-        name: Name,
-        declaration: AstId<ast::Module>,
-        definition: Option<FileId>,
-    ) -> CrateModuleId {
-        let modules = &mut self.def_collector.def_map.modules;
-        let res = modules.alloc(ModuleData::default());
-        modules[res].parent = Some(self.module_id);
-        modules[res].declaration = Some(declaration);
-        modules[res].definition = definition;
-        modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone();
-        modules[self.module_id].children.insert(name.clone(), res);
-        let resolution = Resolution {
-            def: PerNs::types(Module::new(self.def_collector.def_map.krate, res).into()),
-            import: None,
-        };
-        self.def_collector.update(self.module_id, None, &[(name, resolution)]);
-        res
-    }
-
-    fn define_def(&mut self, def: &raw::DefData) {
-        let module = Module::new(self.def_collector.def_map.krate, self.module_id);
-        let ctx = LocationCtx::new(self.def_collector.db, module.id, self.file_id);
-
-        macro_rules! def {
-            ($kind:ident, $ast_id:ident) => {
-                $kind { id: AstItemDef::from_ast_id(ctx, $ast_id) }.into()
-            };
-        }
-        let name = def.name.clone();
-        let def: PerNs = match def.kind {
-            raw::DefKind::Function(ast_id) => PerNs::values(def!(Function, ast_id)),
-            raw::DefKind::Struct(ast_id) => {
-                let s = def!(Struct, ast_id);
-                PerNs::both(s, s)
-            }
-            raw::DefKind::Union(ast_id) => {
-                let s = def!(Union, ast_id);
-                PerNs::both(s, s)
-            }
-            raw::DefKind::Enum(ast_id) => PerNs::types(def!(Enum, ast_id)),
-            raw::DefKind::Const(ast_id) => PerNs::values(def!(Const, ast_id)),
-            raw::DefKind::Static(ast_id) => PerNs::values(def!(Static, ast_id)),
-            raw::DefKind::Trait(ast_id) => PerNs::types(def!(Trait, ast_id)),
-            raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)),
-        };
-        let resolution = Resolution { def, import: None };
-        self.def_collector.update(self.module_id, None, &[(name, resolution)])
-    }
-
-    fn collect_macro(&mut self, mac: &raw::MacroData) {
-        let ast_id = AstId::new(self.file_id, mac.ast_id);
-
-        // Case 1: macro rules, define a macro in crate-global mutable scope
-        if is_macro_rules(&mac.path) {
-            if let Some(name) = &mac.name {
-                let macro_id =
-                    MacroDefId { ast_id, krate: self.def_collector.def_map.krate.crate_id };
-                let macro_ = MacroDef { id: macro_id };
-                self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export);
-            }
-            return;
-        }
-
-        // Case 2: try to resolve in legacy scope and expand macro_rules, triggering
-        // recursive item collection.
-        if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
-            self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
-        }) {
-            let def = macro_def.id;
-            let macro_call_id = self.def_collector.db.intern_macro(MacroCallLoc { def, ast_id });
-
-            self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def);
-            return;
-        }
-
-        // Case 3: resolve in module scope, expand during name resolution.
-        // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
-        let mut path = mac.path.clone();
-        if path.is_ident() {
-            path.kind = PathKind::Self_;
-        }
-        self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path));
-    }
-
-    fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) {
-        let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone();
-        for (name, macro_) in macros {
-            self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
-        }
-    }
-
-    fn is_cfg_enabled(&self, attrs: &[Attr]) -> bool {
-        attrs.iter().all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false))
-    }
-
-    fn path_attr<'a>(&self, attrs: &'a [Attr]) -> Option<&'a SmolStr> {
-        attrs.iter().find_map(|attr| attr.as_path())
-    }
-
-    fn is_macro_use<'a>(&self, attrs: &'a [Attr]) -> bool {
-        attrs.iter().any(|attr| attr.is_simple_atom("macro_use"))
-    }
-}
-
-fn is_macro_rules(path: &Path) -> bool {
-    path.as_ident() == Some(&name::MACRO_RULES)
-}
-
-#[cfg(test)]
-mod tests {
-    use ra_db::SourceDatabase;
-
-    use super::*;
-    use crate::{db::DefDatabase, mock::MockDatabase, Crate};
-    use ra_arena::Arena;
-    use rustc_hash::FxHashSet;
-
-    fn do_collect_defs(
-        db: &impl DefDatabase,
-        def_map: CrateDefMap,
-        monitor: MacroStackMonitor,
-    ) -> CrateDefMap {
-        let mut collector = DefCollector {
-            db,
-            def_map,
-            glob_imports: FxHashMap::default(),
-            unresolved_imports: Vec::new(),
-            unexpanded_macros: Vec::new(),
-            mod_dirs: FxHashMap::default(),
-            macro_stack_monitor: monitor,
-            cfg_options: &CfgOptions::default(),
-        };
-        collector.collect();
-        collector.finish()
-    }
-
-    fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap {
-        let (db, _source_root, _) = MockDatabase::with_single_file(&code);
-        let crate_id = db.crate_graph().iter().next().unwrap();
-        let krate = Crate { crate_id };
-
-        let def_map = {
-            let edition = krate.edition(&db);
-            let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
-            let root = modules.alloc(ModuleData::default());
-            CrateDefMap {
-                krate,
-                edition,
-                extern_prelude: FxHashMap::default(),
-                prelude: None,
-                root,
-                modules,
-                poison_macros: FxHashSet::default(),
-                diagnostics: Vec::new(),
-            }
-        };
-
-        let mut monitor = MacroStackMonitor::default();
-        monitor.validator = Some(Box::new(move |count| {
-            assert!(count < limit);
-            count >= poison_limit
-        }));
-
-        do_collect_defs(&db, def_map, monitor)
-    }
-
-    #[test]
-    fn test_macro_expand_limit_width() {
-        do_limited_resolve(
-            r#"
-        macro_rules! foo {
-            ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); }
-        }
-foo!(KABOOM);
-        "#,
-            16,
-            1000,
-        );
-    }
-
-    #[test]
-    fn test_macro_expand_poisoned() {
-        let def = do_limited_resolve(
-            r#"
-        macro_rules! foo {
-            ($ty:ty) => { foo!($ty); }
-        }
-foo!(KABOOM);
-        "#,
-            100,
-            16,
-        );
-
-        assert_eq!(def.poison_macros.len(), 1);
-    }
-
-    #[test]
-    fn test_macro_expand_normal() {
-        let def = do_limited_resolve(
-            r#"
-        macro_rules! foo {
-            ($ident:ident) => { struct $ident {} }
-        }
-foo!(Bar);
-        "#,
-            16,
-            16,
-        );
-
-        assert_eq!(def.poison_macros.len(), 0);
-    }
-}
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs
deleted file mode 100644 (file)
index 0da6789..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-//! FIXME: write short doc here
-
-use crate::{MacroDef, ModuleDef};
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum Namespace {
-    Types,
-    Values,
-    // Note that only type inference uses this enum, and it doesn't care about macros.
-    // Macro,
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct PerNs {
-    pub types: Option<ModuleDef>,
-    pub values: Option<ModuleDef>,
-    /// Since macros has different type, many methods simply ignore it.
-    /// We can only use special method like `get_macros` to access it.
-    pub macros: Option<MacroDef>,
-}
-
-impl Default for PerNs {
-    fn default() -> Self {
-        PerNs { types: None, values: None, macros: None }
-    }
-}
-
-impl PerNs {
-    pub fn none() -> PerNs {
-        PerNs { types: None, values: None, macros: None }
-    }
-
-    pub fn values(t: ModuleDef) -> PerNs {
-        PerNs { types: None, values: Some(t), macros: None }
-    }
-
-    pub fn types(t: ModuleDef) -> PerNs {
-        PerNs { types: Some(t), values: None, macros: None }
-    }
-
-    pub fn both(types: ModuleDef, values: ModuleDef) -> PerNs {
-        PerNs { types: Some(types), values: Some(values), macros: None }
-    }
-
-    pub fn macros(macro_: MacroDef) -> PerNs {
-        PerNs { types: None, values: None, macros: Some(macro_) }
-    }
-
-    pub fn is_none(&self) -> bool {
-        self.types.is_none() && self.values.is_none() && self.macros.is_none()
-    }
-
-    pub fn is_all(&self) -> bool {
-        self.types.is_some() && self.values.is_some() && self.macros.is_some()
-    }
-
-    pub fn take_types(self) -> Option<ModuleDef> {
-        self.types
-    }
-
-    pub fn take_values(self) -> Option<ModuleDef> {
-        self.values
-    }
-
-    pub fn get_macros(&self) -> Option<MacroDef> {
-        self.macros
-    }
-
-    pub fn only_macros(&self) -> PerNs {
-        PerNs { types: None, values: None, macros: self.macros }
-    }
-
-    pub fn or(self, other: PerNs) -> PerNs {
-        PerNs {
-            types: self.types.or(other.types),
-            values: self.values.or(other.values),
-            macros: self.macros.or(other.macros),
-        }
-    }
-}
index 8c6b40aaf2a0dfbbec6afa3382d664958d058442..02db91a86245a42eba6dc000252f34e79d636203 100644 (file)
@@ -6,30 +6,25 @@
 
 use std::sync::Arc;
 
+use hir_def::{db::DefDatabase2, nameres::*, CrateModuleId};
 use insta::assert_snapshot;
 use ra_db::SourceDatabase;
-use test_utils::covers;
+// use test_utils::covers;
 
-use crate::{
-    mock::{CrateGraphFixture, MockDatabase},
-    Crate,
-};
-
-use super::*;
+use crate::mock::{CrateGraphFixture, MockDatabase};
 
 fn compute_crate_def_map(fixture: &str, graph: Option<CrateGraphFixture>) -> Arc<CrateDefMap> {
     let mut db = MockDatabase::with_files(fixture);
     if let Some(graph) = graph {
         db.set_crate_graph_from_fixture(graph);
     }
-    let crate_id = db.crate_graph().iter().next().unwrap();
-    let krate = Crate { crate_id };
+    let krate = db.crate_graph().iter().next().unwrap();
     db.crate_def_map(krate)
 }
 
 fn render_crate_def_map(map: &CrateDefMap) -> String {
     let mut buf = String::new();
-    go(&mut buf, map, "\ncrate", map.root);
+    go(&mut buf, map, "\ncrate", map.root());
     return buf.trim().to_string();
 
     fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: CrateModuleId) {
@@ -118,7 +113,7 @@ enum E { V }
 
 #[test]
 fn bogus_paths() {
-    covers!(bogus_paths);
+    // covers!(bogus_paths);
     let map = def_map(
         "
         //- /lib.rs
@@ -233,7 +228,7 @@ fn re_exports() {
 
 #[test]
 fn std_prelude() {
-    covers!(std_prelude);
+    // covers!(std_prelude);
     let map = def_map_with_crate_graph(
         "
         //- /main.rs
@@ -261,7 +256,7 @@ fn std_prelude() {
 
 #[test]
 fn can_import_enum_variant() {
-    covers!(can_import_enum_variant);
+    // covers!(can_import_enum_variant);
     let map = def_map(
         "
         //- /lib.rs
index 7ac22b47b80809e22ca5614cacf0f23de386cb63..b3e4d8d9454eda66003a970ce42e228f92d0bff1 100644 (file)
@@ -75,7 +75,7 @@ fn glob_2() {
 
 #[test]
 fn glob_across_crates() {
-    covers!(glob_across_crates);
+    // covers!(glob_across_crates);
     let map = def_map_with_crate_graph(
         "
         //- /main.rs
@@ -98,7 +98,7 @@ fn glob_across_crates() {
 
 #[test]
 fn glob_enum() {
-    covers!(glob_enum);
+    // covers!(glob_enum);
     let map = def_map(
         "
         //- /lib.rs
index af9c39760268c5f5e35f301f7fe1282b4192688f..723ece7b0210a0d9335bc28293d0c9e6b33bd237 100644 (file)
@@ -1,13 +1,12 @@
-use super::*;
-
 use std::sync::Arc;
 
 use ra_db::{SourceDatabase, SourceDatabaseExt};
 
+use super::*;
+
 fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) {
     let (mut db, pos) = MockDatabase::with_position(initial);
-    let crate_id = db.crate_graph().iter().next().unwrap();
-    let krate = Crate { crate_id };
+    let krate = db.crate_graph().iter().next().unwrap();
     {
         let events = db.log_executed(|| {
             db.crate_def_map(krate);
index 4f52ad2c543ad5a3b790b50cafeb940949598e83..78bb0eb0ddde648b30b420e13cc92e8abf45d098 100644 (file)
@@ -187,7 +187,7 @@ macro_rules! bar {
 
 #[test]
 fn macro_rules_from_other_crates_are_visible_with_macro_use() {
-    covers!(macro_rules_from_other_crates_are_visible_with_macro_use);
+    // covers!(macro_rules_from_other_crates_are_visible_with_macro_use);
     let map = def_map_with_crate_graph(
         "
         //- /main.rs
@@ -241,7 +241,7 @@ macro_rules! structs_priv {
 
 #[test]
 fn prelude_is_macro_use() {
-    covers!(prelude_is_macro_use);
+    // covers!(prelude_is_macro_use);
     let map = def_map_with_crate_graph(
         "
         //- /main.rs
@@ -531,8 +531,8 @@ macro_rules! bar {
 
 #[test]
 fn macro_dollar_crate_is_correct_in_item() {
-    covers!(macro_dollar_crate_self);
-    covers!(macro_dollar_crate_other);
+    // covers!(macro_dollar_crate_self);
+    // covers!(macro_dollar_crate_other);
     let map = def_map_with_crate_graph(
         "
         //- /main.rs
@@ -594,7 +594,7 @@ macro_rules! not_current2 {
 
 #[test]
 fn macro_dollar_crate_is_correct_in_indirect_deps() {
-    covers!(macro_dollar_crate_other);
+    // covers!(macro_dollar_crate_other);
     // From std
     let map = def_map_with_crate_graph(
         r#"
index 75b24d386f16af06f04b4e3b899b25a2c9b5f808..3e3f8c252e2e57ed1fe66937d25ddc0445d3de6f 100644 (file)
@@ -3,8 +3,9 @@
 
 use hir_def::{
     builtin_type::BuiltinType,
+    nameres::CrateDefMap,
     path::{Path, PathKind},
-    CrateModuleId,
+    AdtId, CrateModuleId, ModuleDefId,
 };
 use hir_expand::name::{self, Name};
 use rustc_hash::FxHashSet;
@@ -18,7 +19,7 @@
     },
     generics::GenericParams,
     impl_block::ImplBlock,
-    nameres::{CrateDefMap, PerNs},
+    nameres::PerNs,
     Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, Trait, TypeAlias,
 };
 
@@ -90,7 +91,7 @@ impl Resolver {
     pub(crate) fn resolve_known_trait(&self, db: &impl HirDatabase, path: &Path) -> Option<Trait> {
         let res = self.resolve_module_path(db, path).take_types()?;
         match res {
-            ModuleDef::Trait(it) => Some(it),
+            ModuleDefId::TraitId(it) => Some(it.into()),
             _ => None,
         }
     }
@@ -103,7 +104,7 @@ pub(crate) fn resolve_known_struct(
     ) -> Option<Struct> {
         let res = self.resolve_module_path(db, path).take_types()?;
         match res {
-            ModuleDef::Adt(Adt::Struct(it)) => Some(it),
+            ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it.into()),
             _ => None,
         }
     }
@@ -112,7 +113,7 @@ pub(crate) fn resolve_known_struct(
     pub(crate) fn resolve_known_enum(&self, db: &impl HirDatabase, path: &Path) -> Option<Enum> {
         let res = self.resolve_module_path(db, path).take_types()?;
         match res {
-            ModuleDef::Adt(Adt::Enum(it)) => Some(it),
+            ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it.into()),
             _ => None,
         }
     }
@@ -166,18 +167,18 @@ pub(crate) fn resolve_path_in_type_ns(
                 Scope::ModuleScope(m) => {
                     let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
                     let res = match module_def.take_types()? {
-                        ModuleDef::Adt(it) => TypeNs::Adt(it),
-                        ModuleDef::EnumVariant(it) => TypeNs::EnumVariant(it),
+                        ModuleDefId::AdtId(it) => TypeNs::Adt(it.into()),
+                        ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariant(it.into()),
 
-                        ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it),
-                        ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it),
+                        ModuleDefId::TypeAliasId(it) => TypeNs::TypeAlias(it.into()),
+                        ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
 
-                        ModuleDef::Trait(it) => TypeNs::Trait(it),
+                        ModuleDefId::TraitId(it) => TypeNs::Trait(it.into()),
 
-                        ModuleDef::Function(_)
-                        | ModuleDef::Const(_)
-                        | ModuleDef::Static(_)
-                        | ModuleDef::Module(_) => return None,
+                        ModuleDefId::FunctionId(_)
+                        | ModuleDefId::ConstId(_)
+                        | ModuleDefId::StaticId(_)
+                        | ModuleDefId::ModuleId(_) => return None,
                     };
                     return Some((res, idx));
                 }
@@ -261,33 +262,35 @@ pub(crate) fn resolve_path_in_value_ns<'p>(
                     return match idx {
                         None => {
                             let value = match module_def.take_values()? {
-                                ModuleDef::Function(it) => ValueNs::Function(it),
-                                ModuleDef::Adt(Adt::Struct(it)) => ValueNs::Struct(it),
-                                ModuleDef::EnumVariant(it) => ValueNs::EnumVariant(it),
-                                ModuleDef::Const(it) => ValueNs::Const(it),
-                                ModuleDef::Static(it) => ValueNs::Static(it),
-
-                                ModuleDef::Adt(Adt::Enum(_))
-                                | ModuleDef::Adt(Adt::Union(_))
-                                | ModuleDef::Trait(_)
-                                | ModuleDef::TypeAlias(_)
-                                | ModuleDef::BuiltinType(_)
-                                | ModuleDef::Module(_) => return None,
+                                ModuleDefId::FunctionId(it) => ValueNs::Function(it.into()),
+                                ModuleDefId::AdtId(AdtId::StructId(it)) => {
+                                    ValueNs::Struct(it.into())
+                                }
+                                ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariant(it.into()),
+                                ModuleDefId::ConstId(it) => ValueNs::Const(it.into()),
+                                ModuleDefId::StaticId(it) => ValueNs::Static(it.into()),
+
+                                ModuleDefId::AdtId(AdtId::EnumId(_))
+                                | ModuleDefId::AdtId(AdtId::UnionId(_))
+                                | ModuleDefId::TraitId(_)
+                                | ModuleDefId::TypeAliasId(_)
+                                | ModuleDefId::BuiltinType(_)
+                                | ModuleDefId::ModuleId(_) => return None,
                             };
                             Some(ResolveValueResult::ValueNs(value))
                         }
                         Some(idx) => {
                             let ty = match module_def.take_types()? {
-                                ModuleDef::Adt(it) => TypeNs::Adt(it),
-                                ModuleDef::Trait(it) => TypeNs::Trait(it),
-                                ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it),
-                                ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it),
-
-                                ModuleDef::Module(_)
-                                | ModuleDef::Function(_)
-                                | ModuleDef::EnumVariant(_)
-                                | ModuleDef::Const(_)
-                                | ModuleDef::Static(_) => return None,
+                                ModuleDefId::AdtId(it) => TypeNs::Adt(it.into()),
+                                ModuleDefId::TraitId(it) => TypeNs::Trait(it.into()),
+                                ModuleDefId::TypeAliasId(it) => TypeNs::TypeAlias(it.into()),
+                                ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
+
+                                ModuleDefId::ModuleId(_)
+                                | ModuleDefId::FunctionId(_)
+                                | ModuleDefId::EnumVariantId(_)
+                                | ModuleDefId::ConstId(_)
+                                | ModuleDefId::StaticId(_) => return None,
                             };
                             Some(ResolveValueResult::Partial(ty, idx))
                         }
@@ -315,7 +318,7 @@ pub(crate) fn resolve_path_as_macro(
         path: &Path,
     ) -> Option<MacroDef> {
         let (item_map, module) = self.module()?;
-        item_map.resolve_path(db, module, path).0.get_macros()
+        item_map.resolve_path(db, module, path).0.get_macros().map(MacroDef::from)
     }
 
     pub(crate) fn process_all_names(
@@ -333,10 +336,11 @@ pub(crate) fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<Trait>
         for scope in &self.scopes {
             if let Scope::ModuleScope(m) = scope {
                 if let Some(prelude) = m.crate_def_map.prelude() {
-                    let prelude_def_map = db.crate_def_map(prelude.krate());
-                    traits.extend(prelude_def_map[prelude.id.module_id].scope.traits());
+                    let prelude_def_map = db.crate_def_map(prelude.krate);
+                    traits
+                        .extend(prelude_def_map[prelude.module_id].scope.traits().map(Trait::from));
                 }
-                traits.extend(m.crate_def_map[m.module_id].scope.traits());
+                traits.extend(m.crate_def_map[m.module_id].scope.traits().map(Trait::from));
             }
         }
         traits
@@ -351,7 +355,7 @@ fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
     }
 
     pub(crate) fn krate(&self) -> Option<Crate> {
-        self.module().map(|t| t.0.krate())
+        self.module().map(|t| Crate { crate_id: t.0.krate() })
     }
 
     pub(crate) fn where_predicates_in_scope<'a>(
@@ -420,8 +424,10 @@ impl From<PerNs> for ScopeDef {
     fn from(def: PerNs) -> Self {
         def.take_types()
             .or_else(|| def.take_values())
-            .map(ScopeDef::ModuleDef)
-            .or_else(|| def.get_macros().map(ScopeDef::MacroDef))
+            .map(|module_def_id| ScopeDef::ModuleDef(module_def_id.into()))
+            .or_else(|| {
+                def.get_macros().map(|macro_def_id| ScopeDef::MacroDef(macro_def_id.into()))
+            })
             .unwrap_or(ScopeDef::Unknown)
     }
 }
@@ -441,18 +447,16 @@ fn process_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, ScopeDef)
                     f(name.clone(), res.def.into());
                 });
                 m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
-                    f(name.clone(), ScopeDef::MacroDef(macro_));
+                    f(name.clone(), ScopeDef::MacroDef(macro_.into()));
                 });
-                m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| {
-                    f(name.clone(), ScopeDef::ModuleDef(*def));
+                m.crate_def_map.extern_prelude().iter().for_each(|(name, &def)| {
+                    f(name.clone(), ScopeDef::ModuleDef(def.into()));
                 });
                 if let Some(prelude) = m.crate_def_map.prelude() {
-                    let prelude_def_map = db.crate_def_map(prelude.krate());
-                    prelude_def_map[prelude.id.module_id].scope.entries().for_each(
-                        |(name, res)| {
-                            f(name.clone(), res.def.into());
-                        },
-                    );
+                    let prelude_def_map = db.crate_def_map(prelude.krate);
+                    prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| {
+                        f(name.clone(), res.def.into());
+                    });
                 }
             }
             Scope::GenericParams(gp) => {
index a4ca59bba1b4c1eb912d3924d469d64d7395f40d..66cb4b357f886f6fbc9578b17a6126bb34b6ffd6 100644 (file)
@@ -253,8 +253,11 @@ pub fn resolve_hir_path(
             Some(res)
         });
 
-        let items =
-            self.resolver.resolve_module_path(db, &path).take_types().map(PathResolution::Def);
+        let items = self
+            .resolver
+            .resolve_module_path(db, &path)
+            .take_types()
+            .map(|it| PathResolution::Def(it.into()));
         types.or(values).or(items).or_else(|| {
             self.resolver.resolve_path_as_macro(db, &path).map(|def| PathResolution::Macro(def))
         })
index bfef48b1613a5a29c3a1ebaa043a52098e487337..f271557377d0dcc5a39e00fbaf45588babbad423 100644 (file)
@@ -3403,7 +3403,7 @@ trait Trait { fn foo(self) -> u128 {} }
 
 #[test]
 fn infer_macro_with_dollar_crate_is_correct_in_expr() {
-    covers!(macro_dollar_crate_other);
+    // covers!(macro_dollar_crate_other);
     let (mut db, pos) = MockDatabase::with_position(
         r#"
 //- /main.rs
index 22bd469f0a31a9789c28ec28223521e888ef1afc..8f41e55d26f9ab9e6bd88b6c7b5a6ff03d5bacea 100644 (file)
@@ -8,7 +8,7 @@
 
 use crate::{
     db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId,
-    LocalStructFieldId, StructId,
+    LocalStructFieldId, StructId, UnionId,
 };
 
 /// Note that we use `StructData` for unions as well!
@@ -56,6 +56,13 @@ pub(crate) fn struct_data_query(db: &impl DefDatabase2, struct_: StructId) -> Ar
         let variant_data = Arc::new(variant_data);
         Arc::new(StructData { name, variant_data })
     }
+    pub(crate) fn union_data_query(db: &impl DefDatabase2, struct_: UnionId) -> Arc<StructData> {
+        let src = struct_.source(db);
+        let name = src.ast.name().map(|n| n.as_name());
+        let variant_data = VariantData::new(src.ast.kind());
+        let variant_data = Arc::new(variant_data);
+        Arc::new(StructData { name, variant_data })
+    }
 }
 
 impl EnumData {
@@ -74,6 +81,11 @@ pub(crate) fn enum_data_query(db: &impl DefDatabase2, e: EnumId) -> Arc<EnumData
             .collect();
         Arc::new(EnumData { name, variants })
     }
+
+    pub(crate) fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
+        let (id, _) = self.variants.iter().find(|(_id, data)| data.name.as_ref() == Some(name))?;
+        Some(id)
+    }
 }
 
 impl VariantData {
index f6027013f2a8e451ec978a4dc424ebb89c2b6fe5..a42348101b487a97988f150490bfc42555b1b272 100644 (file)
@@ -2,13 +2,16 @@
 use std::sync::Arc;
 
 use hir_expand::{db::AstDatabase, HirFileId};
-use ra_db::{salsa, SourceDatabase};
+use ra_db::{salsa, CrateId, SourceDatabase};
 use ra_syntax::ast;
 
 use crate::{
     adt::{EnumData, StructData},
-    nameres::raw::{ImportSourceMap, RawItems},
-    EnumId, StructId,
+    nameres::{
+        raw::{ImportSourceMap, RawItems},
+        CrateDefMap,
+    },
+    EnumId, StructId, UnionId,
 };
 
 #[salsa::query_group(InternDatabaseStorage)]
@@ -42,9 +45,15 @@ fn raw_items_with_source_map(
     #[salsa::invoke(RawItems::raw_items_query)]
     fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
 
+    #[salsa::invoke(CrateDefMap::crate_def_map_query)]
+    fn crate_def_map(&self, krate: CrateId) -> Arc<CrateDefMap>;
+
     #[salsa::invoke(StructData::struct_data_query)]
     fn struct_data(&self, s: StructId) -> Arc<StructData>;
 
+    #[salsa::invoke(StructData::union_data_query)]
+    fn union_data(&self, s: UnionId) -> Arc<StructData>;
+
     #[salsa::invoke(EnumData::enum_data_query)]
     fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
 }
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs
new file mode 100644 (file)
index 0000000..637184c
--- /dev/null
@@ -0,0 +1,26 @@
+use std::any::Any;
+
+use hir_expand::diagnostics::Diagnostic;
+use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
+use relative_path::RelativePathBuf;
+
+use hir_expand::{HirFileId, Source};
+
+#[derive(Debug)]
+pub struct UnresolvedModule {
+    pub file: HirFileId,
+    pub decl: AstPtr<ast::Module>,
+    pub candidate: RelativePathBuf,
+}
+
+impl Diagnostic for UnresolvedModule {
+    fn message(&self) -> String {
+        "unresolved module".to_string()
+    }
+    fn source(&self) -> Source<SyntaxNodePtr> {
+        Source { file_id: self.file, ast: self.decl.into() }
+    }
+    fn as_any(&self) -> &(dyn Any + Send + 'static) {
+        self
+    }
+}
index 6d66f481d3f81de2bccebdda7612ca5cec044ed2..42e080a72e94a7dcc6b7b17483eebfb4ab2d4670 100644 (file)
@@ -13,6 +13,7 @@
 pub mod type_ref;
 pub mod builtin_type;
 pub mod adt;
+pub mod diagnostics;
 
 // FIXME: this should be private
 pub mod nameres;
@@ -237,8 +238,8 @@ fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> {
 // FIXME: rename to `VariantId`, only enums can ave variants
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct EnumVariantId {
-    parent: EnumId,
-    local_id: LocalEnumVariantId,
+    pub parent: EnumId,
+    pub local_id: LocalEnumVariantId,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
index 11ba8a7770d9f2af71ab311a9747fc5ee52494b7..db59344aa380b9fe21fd7954c8674f322b0b5461 100644 (file)
@@ -2,4 +2,492 @@
 
 // FIXME: review privacy of submodules
 pub mod raw;
+pub mod per_ns;
+pub mod collector;
 pub mod mod_resolution;
+
+use std::sync::Arc;
+
+use hir_expand::{diagnostics::DiagnosticSink, name::Name, MacroDefId};
+use once_cell::sync::Lazy;
+use ra_arena::Arena;
+use ra_db::{CrateId, Edition, FileId};
+use ra_prof::profile;
+use ra_syntax::ast;
+use rustc_hash::{FxHashMap, FxHashSet};
+// use test_utils::tested_by;
+
+use crate::{
+    builtin_type::BuiltinType,
+    db::DefDatabase2,
+    nameres::{diagnostics::DefDiagnostic, per_ns::PerNs, raw::ImportId},
+    path::{Path, PathKind},
+    AdtId, AstId, CrateModuleId, EnumVariantId, ModuleDefId, ModuleId, TraitId,
+};
+
+/// Contains all top-level defs from a macro-expanded crate
+#[derive(Debug, PartialEq, Eq)]
+pub struct CrateDefMap {
+    krate: CrateId,
+    edition: Edition,
+    /// The prelude module for this crate. This either comes from an import
+    /// marked with the `prelude_import` attribute, or (in the normal case) from
+    /// a dependency (`std` or `core`).
+    prelude: Option<ModuleId>,
+    extern_prelude: FxHashMap<Name, ModuleDefId>,
+    root: CrateModuleId,
+    pub modules: Arena<CrateModuleId, ModuleData>,
+
+    /// Some macros are not well-behavior, which leads to infinite loop
+    /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
+    /// We mark it down and skip it in collector
+    ///
+    /// FIXME:
+    /// Right now it only handle a poison macro in a single crate,
+    /// such that if other crate try to call that macro,
+    /// the whole process will do again until it became poisoned in that crate.
+    /// We should handle this macro set globally
+    /// However, do we want to put it as a global variable?
+    poison_macros: FxHashSet<MacroDefId>,
+
+    diagnostics: Vec<DefDiagnostic>,
+}
+
+impl std::ops::Index<CrateModuleId> for CrateDefMap {
+    type Output = ModuleData;
+    fn index(&self, id: CrateModuleId) -> &ModuleData {
+        &self.modules[id]
+    }
+}
+
+#[derive(Default, Debug, PartialEq, Eq)]
+pub struct ModuleData {
+    pub parent: Option<CrateModuleId>,
+    pub children: FxHashMap<Name, CrateModuleId>,
+    pub scope: ModuleScope,
+    /// None for root
+    pub declaration: Option<AstId<ast::Module>>,
+    /// None for inline modules.
+    ///
+    /// Note that non-inline modules, by definition, live inside non-macro file.
+    pub definition: Option<FileId>,
+}
+
+#[derive(Debug, Default, PartialEq, Eq, Clone)]
+pub struct ModuleScope {
+    pub items: FxHashMap<Name, Resolution>,
+    /// Macros visable in current module in legacy textual scope
+    ///
+    /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
+    /// If it yields no result, then it turns to module scoped `macros`.
+    /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
+    /// and only normal scoped `macros` will be searched in.
+    ///
+    /// Note that this automatically inherit macros defined textually before the definition of module itself.
+    ///
+    /// Module scoped macros will be inserted into `items` instead of here.
+    // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
+    // be all resolved to the last one defined if shadowing happens.
+    legacy_macros: FxHashMap<Name, MacroDefId>,
+}
+
+static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
+    BuiltinType::ALL
+        .iter()
+        .map(|(name, ty)| {
+            (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None })
+        })
+        .collect()
+});
+
+/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
+/// Other methods will only resolve values, types and module scoped macros only.
+impl ModuleScope {
+    pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
+        //FIXME: shadowing
+        self.items.iter().chain(BUILTIN_SCOPE.iter())
+    }
+
+    /// Iterate over all module scoped macros
+    pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
+        self.items
+            .iter()
+            .filter_map(|(name, res)| res.def.get_macros().map(|macro_| (name, macro_)))
+    }
+
+    /// Iterate over all legacy textual scoped macros visable at the end of the module
+    pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
+        self.legacy_macros.iter().map(|(name, def)| (name, *def))
+    }
+
+    /// Get a name from current module scope, legacy macros are not included
+    pub fn get(&self, name: &Name) -> Option<&Resolution> {
+        self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name))
+    }
+
+    pub fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
+        self.items.values().filter_map(|r| match r.def.take_types() {
+            Some(ModuleDefId::TraitId(t)) => Some(t),
+            _ => None,
+        })
+    }
+
+    fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
+        self.legacy_macros.get(name).copied()
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Default)]
+pub struct Resolution {
+    /// None for unresolved
+    pub def: PerNs,
+    /// ident by which this is imported into local scope.
+    pub import: Option<ImportId>,
+}
+
+impl Resolution {
+    pub(crate) fn from_macro(macro_: MacroDefId) -> Self {
+        Resolution { def: PerNs::macros(macro_), import: None }
+    }
+}
+
+#[derive(Debug, Clone)]
+struct ResolvePathResult {
+    resolved_def: PerNs,
+    segment_index: Option<usize>,
+    reached_fixedpoint: ReachedFixedPoint,
+}
+
+impl ResolvePathResult {
+    fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
+        ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
+    }
+
+    fn with(
+        resolved_def: PerNs,
+        reached_fixedpoint: ReachedFixedPoint,
+        segment_index: Option<usize>,
+    ) -> ResolvePathResult {
+        ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum ResolveMode {
+    Import,
+    Other,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum ReachedFixedPoint {
+    Yes,
+    No,
+}
+
+impl CrateDefMap {
+    pub(crate) fn crate_def_map_query(
+        // Note that this doesn't have `+ AstDatabase`!
+        // This gurantess that `CrateDefMap` is stable across reparses.
+        db: &impl DefDatabase2,
+        krate: CrateId,
+    ) -> Arc<CrateDefMap> {
+        let _p = profile("crate_def_map_query");
+        let def_map = {
+            let crate_graph = db.crate_graph();
+            let edition = crate_graph.edition(krate);
+            let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
+            let root = modules.alloc(ModuleData::default());
+            CrateDefMap {
+                krate,
+                edition,
+                extern_prelude: FxHashMap::default(),
+                prelude: None,
+                root,
+                modules,
+                poison_macros: FxHashSet::default(),
+                diagnostics: Vec::new(),
+            }
+        };
+        let def_map = collector::collect_defs(db, def_map);
+        Arc::new(def_map)
+    }
+
+    pub fn krate(&self) -> CrateId {
+        self.krate
+    }
+
+    pub fn root(&self) -> CrateModuleId {
+        self.root
+    }
+
+    pub fn prelude(&self) -> Option<ModuleId> {
+        self.prelude
+    }
+
+    pub fn extern_prelude(&self) -> &FxHashMap<Name, ModuleDefId> {
+        &self.extern_prelude
+    }
+
+    pub fn add_diagnostics(
+        &self,
+        db: &impl DefDatabase2,
+        module: CrateModuleId,
+        sink: &mut DiagnosticSink,
+    ) {
+        self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
+    }
+
+    pub fn resolve_path(
+        &self,
+        db: &impl DefDatabase2,
+        original_module: CrateModuleId,
+        path: &Path,
+    ) -> (PerNs, Option<usize>) {
+        let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
+        (res.resolved_def, res.segment_index)
+    }
+
+    // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
+    // the result.
+    fn resolve_path_fp_with_macro(
+        &self,
+        db: &impl DefDatabase2,
+        mode: ResolveMode,
+        original_module: CrateModuleId,
+        path: &Path,
+    ) -> ResolvePathResult {
+        let mut segments = path.segments.iter().enumerate();
+        let mut curr_per_ns: PerNs = match path.kind {
+            PathKind::DollarCrate(krate) => {
+                if krate == self.krate {
+                    // tested_by!(macro_dollar_crate_self);
+                    PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
+                } else {
+                    let def_map = db.crate_def_map(krate);
+                    let module = ModuleId { krate, module_id: def_map.root };
+                    // tested_by!(macro_dollar_crate_other);
+                    PerNs::types(module.into())
+                }
+            }
+            PathKind::Crate => {
+                PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
+            }
+            PathKind::Self_ => {
+                PerNs::types(ModuleId { krate: self.krate, module_id: original_module }.into())
+            }
+            // plain import or absolute path in 2015: crate-relative with
+            // fallback to extern prelude (with the simplification in
+            // rust-lang/rust#57745)
+            // FIXME there must be a nicer way to write this condition
+            PathKind::Plain | PathKind::Abs
+                if self.edition == Edition::Edition2015
+                    && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
+            {
+                let segment = match segments.next() {
+                    Some((_, segment)) => segment,
+                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
+                };
+                log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
+                self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
+            }
+            PathKind::Plain => {
+                let segment = match segments.next() {
+                    Some((_, segment)) => segment,
+                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
+                };
+                log::debug!("resolving {:?} in module", segment);
+                self.resolve_name_in_module(db, original_module, &segment.name)
+            }
+            PathKind::Super => {
+                if let Some(p) = self.modules[original_module].parent {
+                    PerNs::types(ModuleId { krate: self.krate, module_id: p }.into())
+                } else {
+                    log::debug!("super path in root module");
+                    return ResolvePathResult::empty(ReachedFixedPoint::Yes);
+                }
+            }
+            PathKind::Abs => {
+                // 2018-style absolute path -- only extern prelude
+                let segment = match segments.next() {
+                    Some((_, segment)) => segment,
+                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
+                };
+                if let Some(def) = self.extern_prelude.get(&segment.name) {
+                    log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
+                    PerNs::types(*def)
+                } else {
+                    return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
+                }
+            }
+            PathKind::Type(_) => {
+                // This is handled in `infer::infer_path_expr`
+                // The result returned here does not matter
+                return ResolvePathResult::empty(ReachedFixedPoint::Yes);
+            }
+        };
+
+        for (i, segment) in segments {
+            let curr = match curr_per_ns.take_types() {
+                Some(r) => r,
+                None => {
+                    // we still have path segments left, but the path so far
+                    // didn't resolve in the types namespace => no resolution
+                    // (don't break here because `curr_per_ns` might contain
+                    // something in the value namespace, and it would be wrong
+                    // to return that)
+                    return ResolvePathResult::empty(ReachedFixedPoint::No);
+                }
+            };
+            // resolve segment in curr
+
+            curr_per_ns = match curr {
+                ModuleDefId::ModuleId(module) => {
+                    if module.krate != self.krate {
+                        let path =
+                            Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
+                        log::debug!("resolving {:?} in other crate", path);
+                        let defp_map = db.crate_def_map(module.krate);
+                        let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
+                        return ResolvePathResult::with(
+                            def,
+                            ReachedFixedPoint::Yes,
+                            s.map(|s| s + i),
+                        );
+                    }
+
+                    // Since it is a qualified path here, it should not contains legacy macros
+                    match self[module.module_id].scope.get(&segment.name) {
+                        Some(res) => res.def,
+                        _ => {
+                            log::debug!("path segment {:?} not found", segment.name);
+                            return ResolvePathResult::empty(ReachedFixedPoint::No);
+                        }
+                    }
+                }
+                ModuleDefId::AdtId(AdtId::EnumId(e)) => {
+                    // enum variant
+                    // tested_by!(can_import_enum_variant);
+                    let enum_data = db.enum_data(e);
+                    match enum_data.variant(&segment.name) {
+                        Some(local_id) => {
+                            let variant = EnumVariantId { parent: e, local_id };
+                            PerNs::both(variant.into(), variant.into())
+                        }
+                        None => {
+                            return ResolvePathResult::with(
+                                PerNs::types(e.into()),
+                                ReachedFixedPoint::Yes,
+                                Some(i),
+                            );
+                        }
+                    }
+                }
+                s => {
+                    // could be an inherent method call in UFCS form
+                    // (`Struct::method`), or some other kind of associated item
+                    log::debug!(
+                        "path segment {:?} resolved to non-module {:?}, but is not last",
+                        segment.name,
+                        curr,
+                    );
+
+                    return ResolvePathResult::with(
+                        PerNs::types(s),
+                        ReachedFixedPoint::Yes,
+                        Some(i),
+                    );
+                }
+            };
+        }
+        ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
+    }
+
+    fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
+        let from_crate_root =
+            self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
+        let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
+
+        from_crate_root.or(from_extern_prelude)
+    }
+
+    pub(crate) fn resolve_name_in_module(
+        &self,
+        db: &impl DefDatabase2,
+        module: CrateModuleId,
+        name: &Name,
+    ) -> PerNs {
+        // Resolve in:
+        //  - legacy scope of macro
+        //  - current module / scope
+        //  - extern prelude
+        //  - std prelude
+        let from_legacy_macro =
+            self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
+        let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
+        let from_extern_prelude =
+            self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
+        let from_prelude = self.resolve_in_prelude(db, name);
+
+        from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
+    }
+
+    fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
+        self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
+    }
+
+    fn resolve_in_prelude(&self, db: &impl DefDatabase2, name: &Name) -> PerNs {
+        if let Some(prelude) = self.prelude {
+            let keep;
+            let def_map = if prelude.krate == self.krate {
+                self
+            } else {
+                // Extend lifetime
+                keep = db.crate_def_map(prelude.krate);
+                &keep
+            };
+            def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
+        } else {
+            PerNs::none()
+        }
+    }
+}
+
+mod diagnostics {
+    use hir_expand::diagnostics::DiagnosticSink;
+    use ra_syntax::{ast, AstPtr};
+    use relative_path::RelativePathBuf;
+
+    use crate::{db::DefDatabase2, diagnostics::UnresolvedModule, nameres::CrateModuleId, AstId};
+
+    #[derive(Debug, PartialEq, Eq)]
+    pub(super) enum DefDiagnostic {
+        UnresolvedModule {
+            module: CrateModuleId,
+            declaration: AstId<ast::Module>,
+            candidate: RelativePathBuf,
+        },
+    }
+
+    impl DefDiagnostic {
+        pub(super) fn add_to(
+            &self,
+            db: &impl DefDatabase2,
+            target_module: CrateModuleId,
+            sink: &mut DiagnosticSink,
+        ) {
+            match self {
+                DefDiagnostic::UnresolvedModule { module, declaration, candidate } => {
+                    if *module != target_module {
+                        return;
+                    }
+                    let decl = declaration.to_node(db);
+                    sink.push(UnresolvedModule {
+                        file: declaration.file_id(),
+                        decl: AstPtr::new(&decl),
+                        candidate: candidate.clone(),
+                    })
+                }
+            }
+        }
+    }
+}
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
new file mode 100644 (file)
index 0000000..8a96d3d
--- /dev/null
@@ -0,0 +1,845 @@
+//! FIXME: write short doc here
+
+use hir_expand::{
+    name::{self, AsName, Name},
+    HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind,
+};
+use ra_cfg::CfgOptions;
+use ra_db::{CrateId, FileId};
+use ra_syntax::{ast, SmolStr};
+use rustc_hash::FxHashMap;
+// use test_utils::tested_by;
+
+use crate::{
+    attr::Attr,
+    db::DefDatabase2,
+    nameres::{
+        diagnostics::DefDiagnostic, mod_resolution::ModDir, per_ns::PerNs, raw, CrateDefMap,
+        ModuleData, ReachedFixedPoint, Resolution, ResolveMode,
+    },
+    path::{Path, PathKind},
+    AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId,
+    LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId,
+};
+
+pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> CrateDefMap {
+    let crate_graph = db.crate_graph();
+
+    // populate external prelude
+    for dep in crate_graph.dependencies(def_map.krate) {
+        let dep_def_map = db.crate_def_map(dep.crate_id);
+        log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
+        def_map.extern_prelude.insert(
+            dep.as_name(),
+            ModuleId { krate: dep.crate_id, module_id: dep_def_map.root }.into(),
+        );
+
+        // look for the prelude
+        if def_map.prelude.is_none() {
+            let map = db.crate_def_map(dep.crate_id);
+            if map.prelude.is_some() {
+                def_map.prelude = map.prelude;
+            }
+        }
+    }
+
+    let cfg_options = crate_graph.cfg_options(def_map.krate);
+
+    let mut collector = DefCollector {
+        db,
+        def_map,
+        glob_imports: FxHashMap::default(),
+        unresolved_imports: Vec::new(),
+        unexpanded_macros: Vec::new(),
+        mod_dirs: FxHashMap::default(),
+        macro_stack_monitor: MacroStackMonitor::default(),
+        cfg_options,
+    };
+    collector.collect();
+    collector.finish()
+}
+
+#[derive(Default)]
+struct MacroStackMonitor {
+    counts: FxHashMap<MacroDefId, u32>,
+
+    /// Mainly use for test
+    validator: Option<Box<dyn Fn(u32) -> bool>>,
+}
+
+impl MacroStackMonitor {
+    fn increase(&mut self, macro_def_id: MacroDefId) {
+        *self.counts.entry(macro_def_id).or_default() += 1;
+    }
+
+    fn decrease(&mut self, macro_def_id: MacroDefId) {
+        *self.counts.entry(macro_def_id).or_default() -= 1;
+    }
+
+    fn is_poison(&self, macro_def_id: MacroDefId) -> bool {
+        let cur = *self.counts.get(&macro_def_id).unwrap_or(&0);
+
+        if let Some(validator) = &self.validator {
+            validator(cur)
+        } else {
+            cur > 100
+        }
+    }
+}
+
+/// Walks the tree of module recursively
+struct DefCollector<'a, DB> {
+    db: &'a DB,
+    def_map: CrateDefMap,
+    glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
+    unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
+    unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>,
+    mod_dirs: FxHashMap<CrateModuleId, ModDir>,
+
+    /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
+    /// To prevent stack overflow, we add a deep counter here for prevent that.
+    macro_stack_monitor: MacroStackMonitor,
+
+    cfg_options: &'a CfgOptions,
+}
+
+impl<DB> DefCollector<'_, DB>
+where
+    DB: DefDatabase2,
+{
+    fn collect(&mut self) {
+        let crate_graph = self.db.crate_graph();
+        let file_id = crate_graph.crate_root(self.def_map.krate);
+        let raw_items = self.db.raw_items(file_id.into());
+        let module_id = self.def_map.root;
+        self.def_map.modules[module_id].definition = Some(file_id);
+        ModCollector {
+            def_collector: &mut *self,
+            module_id,
+            file_id: file_id.into(),
+            raw_items: &raw_items,
+            mod_dir: ModDir::root(),
+        }
+        .collect(raw_items.items());
+
+        // main name resolution fixed-point loop.
+        let mut i = 0;
+        loop {
+            self.db.check_canceled();
+            match (self.resolve_imports(), self.resolve_macros()) {
+                (ReachedFixedPoint::Yes, ReachedFixedPoint::Yes) => break,
+                _ => i += 1,
+            }
+            if i == 1000 {
+                log::error!("name resolution is stuck");
+                break;
+            }
+        }
+
+        let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
+        // show unresolved imports in completion, etc
+        for (module_id, import, import_data) in unresolved_imports {
+            self.record_resolved_import(module_id, PerNs::none(), import, &import_data)
+        }
+    }
+
+    /// Define a macro with `macro_rules`.
+    ///
+    /// It will define the macro in legacy textual scope, and if it has `#[macro_export]`,
+    /// then it is also defined in the root module scope.
+    /// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition.
+    ///
+    /// It is surprising that the macro will never be in the current module scope.
+    /// These code fails with "unresolved import/macro",
+    /// ```rust,compile_fail
+    /// mod m { macro_rules! foo { () => {} } }
+    /// use m::foo as bar;
+    /// ```
+    ///
+    /// ```rust,compile_fail
+    /// macro_rules! foo { () => {} }
+    /// self::foo!();
+    /// crate::foo!();
+    /// ```
+    ///
+    /// Well, this code compiles, bacause the plain path `foo` in `use` is searched
+    /// in the legacy textual scope only.
+    /// ```rust
+    /// macro_rules! foo { () => {} }
+    /// use foo as bar;
+    /// ```
+    fn define_macro(
+        &mut self,
+        module_id: CrateModuleId,
+        name: Name,
+        macro_: MacroDefId,
+        export: bool,
+    ) {
+        // Textual scoping
+        self.define_legacy_macro(module_id, name.clone(), macro_);
+
+        // Module scoping
+        // In Rust, `#[macro_export]` macros are unconditionally visible at the
+        // crate root, even if the parent modules is **not** visible.
+        if export {
+            self.update(self.def_map.root, None, &[(name, Resolution::from_macro(macro_))]);
+        }
+    }
+
+    /// Define a legacy textual scoped macro in module
+    ///
+    /// We use a map `legacy_macros` to store all legacy textual scoped macros visable per module.
+    /// It will clone all macros from parent legacy scope, whose definition is prior to
+    /// the definition of current module.
+    /// And also, `macro_use` on a module will import all legacy macros visable inside to
+    /// current legacy scope, with possible shadowing.
+    fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDefId) {
+        // Always shadowing
+        self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_);
+    }
+
+    /// Import macros from `#[macro_use] extern crate`.
+    fn import_macros_from_extern_crate(
+        &mut self,
+        current_module_id: CrateModuleId,
+        import: &raw::ImportData,
+    ) {
+        log::debug!(
+            "importing macros from extern crate: {:?} ({:?})",
+            import,
+            self.def_map.edition,
+        );
+
+        let res = self.def_map.resolve_name_in_extern_prelude(
+            &import
+                .path
+                .as_ident()
+                .expect("extern crate should have been desugared to one-element path"),
+        );
+
+        if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
+            // tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
+            self.import_all_macros_exported(current_module_id, m.krate);
+        }
+    }
+
+    /// Import all exported macros from another crate
+    ///
+    /// Exported macros are just all macros in the root module scope.
+    /// Note that it contains not only all `#[macro_export]` macros, but also all aliases
+    /// created by `use` in the root module, ignoring the visibility of `use`.
+    fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: CrateId) {
+        let def_map = self.db.crate_def_map(krate);
+        for (name, def) in def_map[def_map.root].scope.macros() {
+            // `macro_use` only bring things into legacy scope.
+            self.define_legacy_macro(current_module_id, name.clone(), def);
+        }
+    }
+
+    fn resolve_imports(&mut self) -> ReachedFixedPoint {
+        let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
+        let mut resolved = Vec::new();
+        imports.retain(|(module_id, import, import_data)| {
+            let (def, fp) = self.resolve_import(*module_id, import_data);
+            if fp == ReachedFixedPoint::Yes {
+                resolved.push((*module_id, def, *import, import_data.clone()))
+            }
+            fp == ReachedFixedPoint::No
+        });
+        self.unresolved_imports = imports;
+        // Resolves imports, filling-in module scopes
+        let result =
+            if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No };
+        for (module_id, def, import, import_data) in resolved {
+            self.record_resolved_import(module_id, def, import, &import_data)
+        }
+        result
+    }
+
+    fn resolve_import(
+        &self,
+        module_id: CrateModuleId,
+        import: &raw::ImportData,
+    ) -> (PerNs, ReachedFixedPoint) {
+        log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
+        if import.is_extern_crate {
+            let res = self.def_map.resolve_name_in_extern_prelude(
+                &import
+                    .path
+                    .as_ident()
+                    .expect("extern crate should have been desugared to one-element path"),
+            );
+            (res, ReachedFixedPoint::Yes)
+        } else {
+            let res = self.def_map.resolve_path_fp_with_macro(
+                self.db,
+                ResolveMode::Import,
+                module_id,
+                &import.path,
+            );
+
+            (res.resolved_def, res.reached_fixedpoint)
+        }
+    }
+
+    fn record_resolved_import(
+        &mut self,
+        module_id: CrateModuleId,
+        def: PerNs,
+        import_id: raw::ImportId,
+        import: &raw::ImportData,
+    ) {
+        if import.is_glob {
+            log::debug!("glob import: {:?}", import);
+            match def.take_types() {
+                Some(ModuleDefId::ModuleId(m)) => {
+                    if import.is_prelude {
+                        // tested_by!(std_prelude);
+                        self.def_map.prelude = Some(m);
+                    } else if m.krate != self.def_map.krate {
+                        // tested_by!(glob_across_crates);
+                        // glob import from other crate => we can just import everything once
+                        let item_map = self.db.crate_def_map(m.krate);
+                        let scope = &item_map[m.module_id].scope;
+
+                        // Module scoped macros is included
+                        let items = scope
+                            .items
+                            .iter()
+                            .map(|(name, res)| (name.clone(), res.clone()))
+                            .collect::<Vec<_>>();
+
+                        self.update(module_id, Some(import_id), &items);
+                    } else {
+                        // glob import from same crate => we do an initial
+                        // import, and then need to propagate any further
+                        // additions
+                        let scope = &self.def_map[m.module_id].scope;
+
+                        // Module scoped macros is included
+                        let items = scope
+                            .items
+                            .iter()
+                            .map(|(name, res)| (name.clone(), res.clone()))
+                            .collect::<Vec<_>>();
+
+                        self.update(module_id, Some(import_id), &items);
+                        // record the glob import in case we add further items
+                        self.glob_imports
+                            .entry(m.module_id)
+                            .or_default()
+                            .push((module_id, import_id));
+                    }
+                }
+                Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
+                    // tested_by!(glob_enum);
+                    // glob import from enum => just import all the variants
+                    let enum_data = self.db.enum_data(e);
+                    let resolutions = enum_data
+                        .variants
+                        .iter()
+                        .filter_map(|(local_id, variant_data)| {
+                            let name = variant_data.name.clone()?;
+                            let variant = EnumVariantId { parent: e, local_id };
+                            let res = Resolution {
+                                def: PerNs::both(variant.into(), variant.into()),
+                                import: Some(import_id),
+                            };
+                            Some((name, res))
+                        })
+                        .collect::<Vec<_>>();
+                    self.update(module_id, Some(import_id), &resolutions);
+                }
+                Some(d) => {
+                    log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
+                }
+                None => {
+                    log::debug!("glob import {:?} didn't resolve as type", import);
+                }
+            }
+        } else {
+            match import.path.segments.last() {
+                Some(last_segment) => {
+                    let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone());
+                    log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
+
+                    // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
+                    if import.is_extern_crate && module_id == self.def_map.root {
+                        if let Some(def) = def.take_types() {
+                            self.def_map.extern_prelude.insert(name.clone(), def);
+                        }
+                    }
+
+                    let resolution = Resolution { def, import: Some(import_id) };
+                    self.update(module_id, Some(import_id), &[(name, resolution)]);
+                }
+                // tested_by!(bogus_paths),
+                None => (),
+            }
+        }
+    }
+
+    fn update(
+        &mut self,
+        module_id: CrateModuleId,
+        import: Option<raw::ImportId>,
+        resolutions: &[(Name, Resolution)],
+    ) {
+        self.update_recursive(module_id, import, resolutions, 0)
+    }
+
+    fn update_recursive(
+        &mut self,
+        module_id: CrateModuleId,
+        import: Option<raw::ImportId>,
+        resolutions: &[(Name, Resolution)],
+        depth: usize,
+    ) {
+        if depth > 100 {
+            // prevent stack overflows (but this shouldn't be possible)
+            panic!("infinite recursion in glob imports!");
+        }
+        let module_items = &mut self.def_map.modules[module_id].scope;
+        let mut changed = false;
+        for (name, res) in resolutions {
+            let existing = module_items.items.entry(name.clone()).or_default();
+
+            if existing.def.types.is_none() && res.def.types.is_some() {
+                existing.def.types = res.def.types;
+                existing.import = import.or(res.import);
+                changed = true;
+            }
+            if existing.def.values.is_none() && res.def.values.is_some() {
+                existing.def.values = res.def.values;
+                existing.import = import.or(res.import);
+                changed = true;
+            }
+            if existing.def.macros.is_none() && res.def.macros.is_some() {
+                existing.def.macros = res.def.macros;
+                existing.import = import.or(res.import);
+                changed = true;
+            }
+
+            if existing.def.is_none()
+                && res.def.is_none()
+                && existing.import.is_none()
+                && res.import.is_some()
+            {
+                existing.import = res.import;
+            }
+        }
+
+        if !changed {
+            return;
+        }
+        let glob_imports = self
+            .glob_imports
+            .get(&module_id)
+            .into_iter()
+            .flat_map(|v| v.iter())
+            .cloned()
+            .collect::<Vec<_>>();
+        for (glob_importing_module, glob_import) in glob_imports {
+            // We pass the glob import so that the tracked import in those modules is that glob import
+            self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1);
+        }
+    }
+
+    fn resolve_macros(&mut self) -> ReachedFixedPoint {
+        let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
+        let mut resolved = Vec::new();
+        let mut res = ReachedFixedPoint::Yes;
+        macros.retain(|(module_id, ast_id, path)| {
+            let resolved_res = self.def_map.resolve_path_fp_with_macro(
+                self.db,
+                ResolveMode::Other,
+                *module_id,
+                path,
+            );
+
+            if let Some(def) = resolved_res.resolved_def.get_macros() {
+                let call_id = self.db.intern_macro(MacroCallLoc { def, ast_id: *ast_id });
+                resolved.push((*module_id, call_id, def));
+                res = ReachedFixedPoint::No;
+                return false;
+            }
+
+            true
+        });
+
+        self.unexpanded_macros = macros;
+
+        for (module_id, macro_call_id, macro_def_id) in resolved {
+            self.collect_macro_expansion(module_id, macro_call_id, macro_def_id);
+        }
+
+        res
+    }
+
+    fn collect_macro_expansion(
+        &mut self,
+        module_id: CrateModuleId,
+        macro_call_id: MacroCallId,
+        macro_def_id: MacroDefId,
+    ) {
+        if self.def_map.poison_macros.contains(&macro_def_id) {
+            return;
+        }
+
+        self.macro_stack_monitor.increase(macro_def_id);
+
+        if !self.macro_stack_monitor.is_poison(macro_def_id) {
+            let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items);
+            let raw_items = self.db.raw_items(file_id);
+            let mod_dir = self.mod_dirs[&module_id].clone();
+            ModCollector {
+                def_collector: &mut *self,
+                file_id,
+                module_id,
+                raw_items: &raw_items,
+                mod_dir,
+            }
+            .collect(raw_items.items());
+        } else {
+            log::error!("Too deep macro expansion: {:?}", macro_call_id);
+            self.def_map.poison_macros.insert(macro_def_id);
+        }
+
+        self.macro_stack_monitor.decrease(macro_def_id);
+    }
+
+    fn finish(self) -> CrateDefMap {
+        self.def_map
+    }
+}
+
+/// Walks a single module, populating defs, imports and macros
+struct ModCollector<'a, D> {
+    def_collector: D,
+    module_id: CrateModuleId,
+    file_id: HirFileId,
+    raw_items: &'a raw::RawItems,
+    mod_dir: ModDir,
+}
+
+impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
+where
+    DB: DefDatabase2,
+{
+    fn collect(&mut self, items: &[raw::RawItem]) {
+        // Note: don't assert that inserted value is fresh: it's simply not true
+        // for macros.
+        self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
+
+        // Prelude module is always considered to be `#[macro_use]`.
+        if let Some(prelude_module) = self.def_collector.def_map.prelude {
+            if prelude_module.krate != self.def_collector.def_map.krate {
+                // tested_by!(prelude_is_macro_use);
+                self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
+            }
+        }
+
+        // This should be processed eagerly instead of deferred to resolving.
+        // `#[macro_use] extern crate` is hoisted to imports macros before collecting
+        // any other items.
+        for item in items {
+            if self.is_cfg_enabled(item.attrs()) {
+                if let raw::RawItemKind::Import(import_id) = item.kind {
+                    let import = self.raw_items[import_id].clone();
+                    if import.is_extern_crate && import.is_macro_use {
+                        self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
+                    }
+                }
+            }
+        }
+
+        for item in items {
+            if self.is_cfg_enabled(item.attrs()) {
+                match item.kind {
+                    raw::RawItemKind::Module(m) => {
+                        self.collect_module(&self.raw_items[m], item.attrs())
+                    }
+                    raw::RawItemKind::Import(import_id) => self
+                        .def_collector
+                        .unresolved_imports
+                        .push((self.module_id, import_id, self.raw_items[import_id].clone())),
+                    raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]),
+                    raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
+                }
+            }
+        }
+    }
+
+    fn collect_module(&mut self, module: &raw::ModuleData, attrs: &[Attr]) {
+        let path_attr = self.path_attr(attrs);
+        let is_macro_use = self.is_macro_use(attrs);
+        match module {
+            // inline module, just recurse
+            raw::ModuleData::Definition { name, items, ast_id } => {
+                let module_id =
+                    self.push_child_module(name.clone(), AstId::new(self.file_id, *ast_id), None);
+
+                ModCollector {
+                    def_collector: &mut *self.def_collector,
+                    module_id,
+                    file_id: self.file_id,
+                    raw_items: self.raw_items,
+                    mod_dir: self.mod_dir.descend_into_definition(name, path_attr),
+                }
+                .collect(&*items);
+                if is_macro_use {
+                    self.import_all_legacy_macros(module_id);
+                }
+            }
+            // out of line module, resolve, parse and recurse
+            raw::ModuleData::Declaration { name, ast_id } => {
+                let ast_id = AstId::new(self.file_id, *ast_id);
+                match self.mod_dir.resolve_declaration(
+                    self.def_collector.db,
+                    self.file_id,
+                    name,
+                    path_attr,
+                ) {
+                    Ok((file_id, mod_dir)) => {
+                        let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id));
+                        let raw_items = self.def_collector.db.raw_items(file_id.into());
+                        ModCollector {
+                            def_collector: &mut *self.def_collector,
+                            module_id,
+                            file_id: file_id.into(),
+                            raw_items: &raw_items,
+                            mod_dir,
+                        }
+                        .collect(raw_items.items());
+                        if is_macro_use {
+                            self.import_all_legacy_macros(module_id);
+                        }
+                    }
+                    Err(candidate) => self.def_collector.def_map.diagnostics.push(
+                        DefDiagnostic::UnresolvedModule {
+                            module: self.module_id,
+                            declaration: ast_id,
+                            candidate,
+                        },
+                    ),
+                };
+            }
+        }
+    }
+
+    fn push_child_module(
+        &mut self,
+        name: Name,
+        declaration: AstId<ast::Module>,
+        definition: Option<FileId>,
+    ) -> CrateModuleId {
+        let modules = &mut self.def_collector.def_map.modules;
+        let res = modules.alloc(ModuleData::default());
+        modules[res].parent = Some(self.module_id);
+        modules[res].declaration = Some(declaration);
+        modules[res].definition = definition;
+        modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone();
+        modules[self.module_id].children.insert(name.clone(), res);
+        let resolution = Resolution {
+            def: PerNs::types(
+                ModuleId { krate: self.def_collector.def_map.krate, module_id: res }.into(),
+            ),
+            import: None,
+        };
+        self.def_collector.update(self.module_id, None, &[(name, resolution)]);
+        res
+    }
+
+    fn define_def(&mut self, def: &raw::DefData) {
+        let module =
+            ModuleId { krate: self.def_collector.def_map.krate, module_id: self.module_id };
+        let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id);
+
+        let name = def.name.clone();
+        let def: PerNs = match def.kind {
+            raw::DefKind::Function(ast_id) => {
+                PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into())
+            }
+            raw::DefKind::Struct(ast_id) => {
+                let s = StructId::from_ast_id(ctx, ast_id).into();
+                PerNs::both(s, s)
+            }
+            raw::DefKind::Union(ast_id) => {
+                let s = UnionId::from_ast_id(ctx, ast_id).into();
+                PerNs::both(s, s)
+            }
+            raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()),
+            raw::DefKind::Const(ast_id) => PerNs::values(ConstId::from_ast_id(ctx, ast_id).into()),
+            raw::DefKind::Static(ast_id) => {
+                PerNs::values(StaticId::from_ast_id(ctx, ast_id).into())
+            }
+            raw::DefKind::Trait(ast_id) => PerNs::types(TraitId::from_ast_id(ctx, ast_id).into()),
+            raw::DefKind::TypeAlias(ast_id) => {
+                PerNs::types(TypeAliasId::from_ast_id(ctx, ast_id).into())
+            }
+        };
+        let resolution = Resolution { def, import: None };
+        self.def_collector.update(self.module_id, None, &[(name, resolution)])
+    }
+
+    fn collect_macro(&mut self, mac: &raw::MacroData) {
+        let ast_id = AstId::new(self.file_id, mac.ast_id);
+
+        // Case 1: macro rules, define a macro in crate-global mutable scope
+        if is_macro_rules(&mac.path) {
+            if let Some(name) = &mac.name {
+                let macro_id = MacroDefId { ast_id, krate: self.def_collector.def_map.krate };
+                self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
+            }
+            return;
+        }
+
+        // Case 2: try to resolve in legacy scope and expand macro_rules, triggering
+        // recursive item collection.
+        if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
+            self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
+        }) {
+            let macro_call_id =
+                self.def_collector.db.intern_macro(MacroCallLoc { def: macro_def, ast_id });
+
+            self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def);
+            return;
+        }
+
+        // Case 3: resolve in module scope, expand during name resolution.
+        // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
+        let mut path = mac.path.clone();
+        if path.is_ident() {
+            path.kind = PathKind::Self_;
+        }
+        self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path));
+    }
+
+    fn import_all_legacy_macros(&mut self, module_id: CrateModuleId) {
+        let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone();
+        for (name, macro_) in macros {
+            self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
+        }
+    }
+
+    fn is_cfg_enabled(&self, attrs: &[Attr]) -> bool {
+        attrs.iter().all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false))
+    }
+
+    fn path_attr<'a>(&self, attrs: &'a [Attr]) -> Option<&'a SmolStr> {
+        attrs.iter().find_map(|attr| attr.as_path())
+    }
+
+    fn is_macro_use<'a>(&self, attrs: &'a [Attr]) -> bool {
+        attrs.iter().any(|attr| attr.is_simple_atom("macro_use"))
+    }
+}
+
+fn is_macro_rules(path: &Path) -> bool {
+    path.as_ident() == Some(&name::MACRO_RULES)
+}
+
+#[cfg(never)]
+mod tests {
+    use ra_db::SourceDatabase;
+
+    use super::*;
+    use crate::{db::DefDatabase, mock::MockDatabase, Crate};
+    use ra_arena::Arena;
+    use rustc_hash::FxHashSet;
+
+    fn do_collect_defs(
+        db: &impl DefDatabase,
+        def_map: CrateDefMap,
+        monitor: MacroStackMonitor,
+    ) -> CrateDefMap {
+        let mut collector = DefCollector {
+            db,
+            def_map,
+            glob_imports: FxHashMap::default(),
+            unresolved_imports: Vec::new(),
+            unexpanded_macros: Vec::new(),
+            mod_dirs: FxHashMap::default(),
+            macro_stack_monitor: monitor,
+            cfg_options: &CfgOptions::default(),
+        };
+        collector.collect();
+        collector.finish()
+    }
+
+    fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap {
+        let (db, _source_root, _) = MockDatabase::with_single_file(&code);
+        let crate_id = db.crate_graph().iter().next().unwrap();
+        let krate = Crate { crate_id };
+
+        let def_map = {
+            let edition = krate.edition(&db);
+            let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default();
+            let root = modules.alloc(ModuleData::default());
+            CrateDefMap {
+                krate,
+                edition,
+                extern_prelude: FxHashMap::default(),
+                prelude: None,
+                root,
+                modules,
+                poison_macros: FxHashSet::default(),
+                diagnostics: Vec::new(),
+            }
+        };
+
+        let mut monitor = MacroStackMonitor::default();
+        monitor.validator = Some(Box::new(move |count| {
+            assert!(count < limit);
+            count >= poison_limit
+        }));
+
+        do_collect_defs(&db, def_map, monitor)
+    }
+
+    #[test]
+    fn test_macro_expand_limit_width() {
+        do_limited_resolve(
+            r#"
+        macro_rules! foo {
+            ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); }
+        }
+foo!(KABOOM);
+        "#,
+            16,
+            1000,
+        );
+    }
+
+    #[test]
+    fn test_macro_expand_poisoned() {
+        let def = do_limited_resolve(
+            r#"
+        macro_rules! foo {
+            ($ty:ty) => { foo!($ty); }
+        }
+foo!(KABOOM);
+        "#,
+            100,
+            16,
+        );
+
+        assert_eq!(def.poison_macros.len(), 1);
+    }
+
+    #[test]
+    fn test_macro_expand_normal() {
+        let def = do_limited_resolve(
+            r#"
+        macro_rules! foo {
+            ($ident:ident) => { struct $ident {} }
+        }
+foo!(Bar);
+        "#,
+            16,
+            16,
+        );
+
+        assert_eq!(def.poison_macros.len(), 0);
+    }
+}
diff --git a/crates/ra_hir_def/src/nameres/per_ns.rs b/crates/ra_hir_def/src/nameres/per_ns.rs
new file mode 100644 (file)
index 0000000..298b0b0
--- /dev/null
@@ -0,0 +1,82 @@
+//! FIXME: write short doc here
+
+use hir_expand::MacroDefId;
+
+use crate::ModuleDefId;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum Namespace {
+    Types,
+    Values,
+    // Note that only type inference uses this enum, and it doesn't care about macros.
+    // Macro,
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct PerNs {
+    pub types: Option<ModuleDefId>,
+    pub values: Option<ModuleDefId>,
+    /// Since macros has different type, many methods simply ignore it.
+    /// We can only use special method like `get_macros` to access it.
+    pub macros: Option<MacroDefId>,
+}
+
+impl Default for PerNs {
+    fn default() -> Self {
+        PerNs { types: None, values: None, macros: None }
+    }
+}
+
+impl PerNs {
+    pub fn none() -> PerNs {
+        PerNs { types: None, values: None, macros: None }
+    }
+
+    pub fn values(t: ModuleDefId) -> PerNs {
+        PerNs { types: None, values: Some(t), macros: None }
+    }
+
+    pub fn types(t: ModuleDefId) -> PerNs {
+        PerNs { types: Some(t), values: None, macros: None }
+    }
+
+    pub fn both(types: ModuleDefId, values: ModuleDefId) -> PerNs {
+        PerNs { types: Some(types), values: Some(values), macros: None }
+    }
+
+    pub fn macros(macro_: MacroDefId) -> PerNs {
+        PerNs { types: None, values: None, macros: Some(macro_) }
+    }
+
+    pub fn is_none(&self) -> bool {
+        self.types.is_none() && self.values.is_none() && self.macros.is_none()
+    }
+
+    pub fn is_all(&self) -> bool {
+        self.types.is_some() && self.values.is_some() && self.macros.is_some()
+    }
+
+    pub fn take_types(self) -> Option<ModuleDefId> {
+        self.types
+    }
+
+    pub fn take_values(self) -> Option<ModuleDefId> {
+        self.values
+    }
+
+    pub fn get_macros(&self) -> Option<MacroDefId> {
+        self.macros
+    }
+
+    pub fn only_macros(&self) -> PerNs {
+        PerNs { types: None, values: None, macros: self.macros }
+    }
+
+    pub fn or(self, other: PerNs) -> PerNs {
+        PerNs {
+            types: self.types.or(other.types),
+            values: self.values.or(other.values),
+            macros: self.macros.or(other.macros),
+        }
+    }
+}
index 9ac9768afb203e35c762fa63a3a01976d37195b9..09ca401794eae55df799242dbcac4e5f113273ec 100644 (file)
@@ -18,15 +18,15 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
     match def {
         hir::ModuleDef::Module(module) => {
             let module_scope = module.scope(ctx.db);
-            for (name, res) in module_scope.entries() {
-                if let Some(hir::ModuleDef::BuiltinType(..)) = res.def.take_types() {
+            for (name, def, import) in module_scope {
+                if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def {
                     if ctx.use_item_syntax.is_some() {
                         tested_by!(dont_complete_primitive_in_use);
                         continue;
                     }
                 }
                 if Some(module) == ctx.module {
-                    if let Some(import) = res.import {
+                    if let Some(import) = import {
                         if let Either::A(use_tree) = module.import_source(ctx.db, import) {
                             if use_tree.syntax().text_range().contains_inclusive(ctx.offset) {
                                 // for `use self::foo<|>`, don't suggest `foo` as a completion
@@ -36,7 +36,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
                         }
                     }
                 }
-                acc.add_resolution(ctx, name.to_string(), &res.def.into());
+                acc.add_resolution(ctx, name.to_string(), &def);
             }
         }
         hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => {