]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/nameres.rs
parameters.split_last()
[rust.git] / crates / hir_def / src / nameres.rs
index 542f190a11b932d1ca6561dee5132cdcf0388510..ca4255c58193f9b407b543448107789a906b3ccd 100644 (file)
@@ -1,14 +1,14 @@
 //! This module implements import-resolution/macro expansion algorithm.
 //!
-//! The result of this module is `CrateDefMap`: a data structure which contains:
+//! The result of this module is `DefMap`: a data structure which contains:
 //!
 //!   * a tree of modules for the crate
 //!   * for each module, a set of items visible in the module (directly declared
 //!     or imported)
 //!
-//! Note that `CrateDefMap` contains fully macro expanded code.
+//! Note that `DefMap` contains fully macro expanded code.
 //!
-//! Computing `CrateDefMap` can be partitioned into several logically
+//! Computing `DefMap` can be partitioned into several logically
 //! independent "phases". The phases are mutually recursive though, there's no
 //! strict ordering.
 //!
 //! path and, upon success, we run macro expansion and "collect module" phase on
 //! the result
 
+pub mod attr_resolution;
+pub mod diagnostics;
 mod collector;
 mod mod_resolution;
 mod path_resolution;
+mod proc_macro;
 
 #[cfg(test)]
 mod tests;
-mod proc_macro;
 
 use std::sync::Arc;
 
 use base_db::{CrateId, Edition, FileId};
-use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile, MacroDefId};
+use hir_expand::{name::Name, InFile, MacroDefId};
 use la_arena::Arena;
 use profile::Count;
 use rustc_hash::FxHashMap;
 use stdx::format_to;
-use syntax::ast;
+use syntax::{ast, SmolStr};
 
 use crate::{
     db::DefDatabase,
     item_scope::{BuiltinShadowMode, ItemScope},
+    item_tree::TreeId,
     nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
     path::ModPath,
     per_ns::PerNs,
+    visibility::Visibility,
     AstId, BlockId, BlockLoc, LocalModuleId, ModuleDefId, ModuleId,
 };
 
@@ -101,10 +105,16 @@ pub struct DefMap {
     /// Side table with additional proc. macro info, for use by name resolution in downstream
     /// crates.
     ///
-    /// (the primary purpose is to resolve derive helpers)
+    /// (the primary purpose is to resolve derive helpers and fetch a proc-macros name)
     exported_proc_macros: FxHashMap<MacroDefId, ProcMacroDef>,
 
+    /// Custom attributes registered with `#![register_attr]`.
+    registered_attrs: Vec<SmolStr>,
+    /// Custom tool modules registered with `#![register_tool]`.
+    registered_tools: Vec<SmolStr>,
+
     edition: Edition,
+    recursion_limit: Option<u32>,
     diagnostics: Vec<DefDiagnostic>,
 }
 
@@ -144,14 +154,8 @@ pub enum ModuleOrigin {
     },
 }
 
-impl Default for ModuleOrigin {
-    fn default() -> Self {
-        ModuleOrigin::CrateRoot { definition: FileId(0) }
-    }
-}
-
 impl ModuleOrigin {
-    fn declaration(&self) -> Option<AstId<ast::Module>> {
+    pub fn declaration(&self) -> Option<AstId<ast::Module>> {
         match self {
             ModuleOrigin::File { declaration: module, .. }
             | ModuleOrigin::Inline { definition: module, .. } => Some(*module),
@@ -195,14 +199,16 @@ fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
     }
 }
 
-#[derive(Default, Debug, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq)]
 pub struct ModuleData {
+    /// Where does this module come from?
+    pub origin: ModuleOrigin,
+    /// Declared visibility of this module.
+    pub visibility: Visibility,
+
     pub parent: Option<LocalModuleId>,
     pub children: FxHashMap<Name, LocalModuleId>,
     pub scope: ItemScope,
-
-    /// Where does this module come from?
-    pub origin: ModuleOrigin,
 }
 
 impl DefMap {
@@ -210,9 +216,18 @@ pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<D
         let _p = profile::span("crate_def_map_query").detail(|| {
             db.crate_graph()[krate].display_name.as_deref().unwrap_or_default().to_string()
         });
-        let edition = db.crate_graph()[krate].edition;
-        let def_map = DefMap::empty(krate, edition);
-        let def_map = collector::collect_defs(db, def_map, None);
+
+        let crate_graph = db.crate_graph();
+
+        let edition = crate_graph[krate].edition;
+        let origin = ModuleOrigin::CrateRoot { definition: crate_graph[krate].root_file_id };
+        let def_map = DefMap::empty(krate, edition, origin);
+        let def_map = collector::collect_defs(
+            db,
+            def_map,
+            TreeId::new(crate_graph[krate].root_file_id.into(), None),
+        );
+
         Arc::new(def_map)
     }
 
@@ -222,47 +237,54 @@ pub(crate) fn block_def_map_query(
     ) -> Option<Arc<DefMap>> {
         let block: BlockLoc = db.lookup_intern_block(block_id);
 
-        let item_tree = db.file_item_tree(block.ast_id.file_id);
-        if item_tree.inner_items_of_block(block.ast_id.value).is_empty() {
+        let tree_id = TreeId::new(block.ast_id.file_id, Some(block_id));
+        let item_tree = tree_id.item_tree(db);
+        if item_tree.top_level_items().is_empty() {
             return None;
         }
 
         let block_info = BlockInfo { block: block_id, parent: block.module };
 
         let parent_map = block.module.def_map(db);
-        let mut def_map = DefMap::empty(block.module.krate, parent_map.edition);
+        let mut def_map = DefMap::empty(
+            block.module.krate,
+            parent_map.edition,
+            ModuleOrigin::BlockExpr { block: block.ast_id },
+        );
         def_map.block = Some(block_info);
 
-        let def_map = collector::collect_defs(db, def_map, Some(block.ast_id));
+        let def_map = collector::collect_defs(db, def_map, tree_id);
         Some(Arc::new(def_map))
     }
 
-    fn empty(krate: CrateId, edition: Edition) -> DefMap {
+    fn empty(krate: CrateId, edition: Edition, root_module_origin: ModuleOrigin) -> DefMap {
         let mut modules: Arena<ModuleData> = Arena::default();
-        let root = modules.alloc(ModuleData::default());
+
+        let local_id = LocalModuleId::from_raw(la_arena::RawIdx::from(0));
+        // NB: we use `None` as block here, which would be wrong for implicit
+        // modules declared by blocks with items. At the moment, we don't use
+        // this visibility for anything outside IDE, so that's probably OK.
+        let visibility = Visibility::Module(ModuleId { krate, local_id, block: None });
+        let root = modules.alloc(ModuleData::new(root_module_origin, visibility));
+        assert_eq!(local_id, root);
+
         DefMap {
             _c: Count::new(),
             block: None,
             krate,
             edition,
+            recursion_limit: None,
             extern_prelude: FxHashMap::default(),
             exported_proc_macros: FxHashMap::default(),
             prelude: None,
             root,
             modules,
+            registered_attrs: Vec::new(),
+            registered_tools: Vec::new(),
             diagnostics: Vec::new(),
         }
     }
 
-    pub fn add_diagnostics(
-        &self,
-        db: &dyn DefDatabase,
-        module: LocalModuleId,
-        sink: &mut DiagnosticSink,
-    ) {
-        self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
-    }
-
     pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ {
         self.modules
             .iter()
@@ -273,7 +295,15 @@ pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalMod
     pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
         self.modules.iter()
     }
-
+    pub fn exported_proc_macros(&self) -> impl Iterator<Item = (MacroDefId, Name)> + '_ {
+        self.exported_proc_macros.iter().map(|(id, def)| (*id, def.name.clone()))
+    }
+    pub fn registered_tools(&self) -> &[SmolStr] {
+        &self.registered_tools
+    }
+    pub fn registered_attrs(&self) -> &[SmolStr] {
+        &self.registered_attrs
+    }
     pub fn root(&self) -> LocalModuleId {
         self.root
     }
@@ -375,10 +405,7 @@ pub fn parent(&self) -> Option<ModuleId> {
     pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
         match &self[local_mod].parent {
             Some(parent) => Some(self.module_id(*parent)),
-            None => match &self.block {
-                Some(block) => Some(block.parent),
-                None => None,
-            },
+            None => self.block.as_ref().map(|block| block.parent),
         }
     }
 
@@ -410,6 +437,20 @@ fn go(buf: &mut String, map: &DefMap, path: &str, module: LocalModuleId) {
         }
     }
 
+    pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String {
+        let mut buf = String::new();
+        let mut arc;
+        let mut current_map = self;
+        while let Some(block) = &current_map.block {
+            format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
+            arc = block.parent.def_map(db);
+            current_map = &*arc;
+        }
+
+        format_to!(buf, "crate scope\n");
+        buf
+    }
+
     fn shrink_to_fit(&mut self) {
         // Exhaustive match to require handling new fields.
         let Self {
@@ -418,8 +459,11 @@ fn shrink_to_fit(&mut self) {
             extern_prelude,
             diagnostics,
             modules,
+            registered_attrs,
+            registered_tools,
             block: _,
             edition: _,
+            recursion_limit: _,
             krate: _,
             prelude: _,
             root: _,
@@ -429,14 +473,35 @@ fn shrink_to_fit(&mut self) {
         exported_proc_macros.shrink_to_fit();
         diagnostics.shrink_to_fit();
         modules.shrink_to_fit();
+        registered_attrs.shrink_to_fit();
+        registered_tools.shrink_to_fit();
         for (_, module) in modules.iter_mut() {
             module.children.shrink_to_fit();
             module.scope.shrink_to_fit();
         }
     }
+
+    /// Get a reference to the def map's diagnostics.
+    pub fn diagnostics(&self) -> &[DefDiagnostic] {
+        self.diagnostics.as_slice()
+    }
+
+    pub fn recursion_limit(&self) -> Option<u32> {
+        self.recursion_limit
+    }
 }
 
 impl ModuleData {
+    pub(crate) fn new(origin: ModuleOrigin, visibility: Visibility) -> Self {
+        ModuleData {
+            origin,
+            visibility,
+            parent: None,
+            children: FxHashMap::default(),
+            scope: ItemScope::default(),
+        }
+    }
+
     /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
     pub fn definition_source(&self, db: &dyn DefDatabase) -> InFile<ModuleSource> {
         self.origin.definition_source(db)
@@ -457,235 +522,3 @@ pub enum ModuleSource {
     Module(ast::Module),
     BlockExpr(ast::BlockExpr),
 }
-
-mod diagnostics {
-    use cfg::{CfgExpr, CfgOptions};
-    use hir_expand::diagnostics::DiagnosticSink;
-    use hir_expand::hygiene::Hygiene;
-    use hir_expand::{InFile, MacroCallKind};
-    use syntax::ast::AttrsOwner;
-    use syntax::{ast, AstNode, AstPtr, SyntaxKind, SyntaxNodePtr};
-
-    use crate::path::ModPath;
-    use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId};
-
-    #[derive(Debug, PartialEq, Eq)]
-    enum DiagnosticKind {
-        UnresolvedModule { declaration: AstId<ast::Module>, candidate: String },
-
-        UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
-
-        UnresolvedImport { ast: AstId<ast::Use>, index: usize },
-
-        UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions },
-
-        UnresolvedProcMacro { ast: MacroCallKind },
-
-        UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
-
-        MacroError { ast: MacroCallKind, message: String },
-    }
-
-    #[derive(Debug, PartialEq, Eq)]
-    pub(super) struct DefDiagnostic {
-        in_module: LocalModuleId,
-        kind: DiagnosticKind,
-    }
-
-    impl DefDiagnostic {
-        pub(super) fn unresolved_module(
-            container: LocalModuleId,
-            declaration: AstId<ast::Module>,
-            candidate: String,
-        ) -> Self {
-            Self {
-                in_module: container,
-                kind: DiagnosticKind::UnresolvedModule { declaration, candidate },
-            }
-        }
-
-        pub(super) fn unresolved_extern_crate(
-            container: LocalModuleId,
-            declaration: AstId<ast::ExternCrate>,
-        ) -> Self {
-            Self {
-                in_module: container,
-                kind: DiagnosticKind::UnresolvedExternCrate { ast: declaration },
-            }
-        }
-
-        pub(super) fn unresolved_import(
-            container: LocalModuleId,
-            ast: AstId<ast::Use>,
-            index: usize,
-        ) -> Self {
-            Self { in_module: container, kind: DiagnosticKind::UnresolvedImport { ast, index } }
-        }
-
-        pub(super) fn unconfigured_code(
-            container: LocalModuleId,
-            ast: AstId<ast::Item>,
-            cfg: CfgExpr,
-            opts: CfgOptions,
-        ) -> Self {
-            Self { in_module: container, kind: DiagnosticKind::UnconfiguredCode { ast, cfg, opts } }
-        }
-
-        pub(super) fn unresolved_proc_macro(container: LocalModuleId, ast: MacroCallKind) -> Self {
-            Self { in_module: container, kind: DiagnosticKind::UnresolvedProcMacro { ast } }
-        }
-
-        pub(super) fn macro_error(
-            container: LocalModuleId,
-            ast: MacroCallKind,
-            message: String,
-        ) -> Self {
-            Self { in_module: container, kind: DiagnosticKind::MacroError { ast, message } }
-        }
-
-        pub(super) fn unresolved_macro_call(
-            container: LocalModuleId,
-            ast: AstId<ast::MacroCall>,
-            path: ModPath,
-        ) -> Self {
-            Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast, path } }
-        }
-
-        pub(super) fn add_to(
-            &self,
-            db: &dyn DefDatabase,
-            target_module: LocalModuleId,
-            sink: &mut DiagnosticSink,
-        ) {
-            if self.in_module != target_module {
-                return;
-            }
-
-            match &self.kind {
-                DiagnosticKind::UnresolvedModule { declaration, candidate } => {
-                    let decl = declaration.to_node(db.upcast());
-                    sink.push(UnresolvedModule {
-                        file: declaration.file_id,
-                        decl: AstPtr::new(&decl),
-                        candidate: candidate.clone(),
-                    })
-                }
-
-                DiagnosticKind::UnresolvedExternCrate { ast } => {
-                    let item = ast.to_node(db.upcast());
-                    sink.push(UnresolvedExternCrate {
-                        file: ast.file_id,
-                        item: AstPtr::new(&item),
-                    });
-                }
-
-                DiagnosticKind::UnresolvedImport { ast, index } => {
-                    let use_item = ast.to_node(db.upcast());
-                    let hygiene = Hygiene::new(db.upcast(), ast.file_id);
-                    let mut cur = 0;
-                    let mut tree = None;
-                    ModPath::expand_use_item(
-                        InFile::new(ast.file_id, use_item),
-                        &hygiene,
-                        |_mod_path, use_tree, _is_glob, _alias| {
-                            if cur == *index {
-                                tree = Some(use_tree.clone());
-                            }
-
-                            cur += 1;
-                        },
-                    );
-
-                    if let Some(tree) = tree {
-                        sink.push(UnresolvedImport { file: ast.file_id, node: AstPtr::new(&tree) });
-                    }
-                }
-
-                DiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
-                    let item = ast.to_node(db.upcast());
-                    sink.push(InactiveCode {
-                        file: ast.file_id,
-                        node: AstPtr::new(&item).into(),
-                        cfg: cfg.clone(),
-                        opts: opts.clone(),
-                    });
-                }
-
-                DiagnosticKind::UnresolvedProcMacro { ast } => {
-                    let mut precise_location = None;
-                    let (file, ast, name) = match ast {
-                        MacroCallKind::FnLike { ast_id } => {
-                            let node = ast_id.to_node(db.upcast());
-                            (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
-                        }
-                        MacroCallKind::Derive { ast_id, derive_name, .. } => {
-                            let node = ast_id.to_node(db.upcast());
-
-                            // Compute the precise location of the macro name's token in the derive
-                            // list.
-                            // FIXME: This does not handle paths to the macro, but neither does the
-                            // rest of r-a.
-                            let derive_attrs =
-                                node.attrs().filter_map(|attr| match attr.as_simple_call() {
-                                    Some((name, args)) if name == "derive" => Some(args),
-                                    _ => None,
-                                });
-                            'outer: for attr in derive_attrs {
-                                let tokens =
-                                    attr.syntax().children_with_tokens().filter_map(|elem| {
-                                        match elem {
-                                            syntax::NodeOrToken::Node(_) => None,
-                                            syntax::NodeOrToken::Token(tok) => Some(tok),
-                                        }
-                                    });
-                                for token in tokens {
-                                    if token.kind() == SyntaxKind::IDENT
-                                        && token.text() == derive_name.as_str()
-                                    {
-                                        precise_location = Some(token.text_range());
-                                        break 'outer;
-                                    }
-                                }
-                            }
-
-                            (
-                                ast_id.file_id,
-                                SyntaxNodePtr::from(AstPtr::new(&node)),
-                                Some(derive_name.clone()),
-                            )
-                        }
-                    };
-                    sink.push(UnresolvedProcMacro {
-                        file,
-                        node: ast,
-                        precise_location,
-                        macro_name: name,
-                    });
-                }
-
-                DiagnosticKind::UnresolvedMacroCall { ast, path } => {
-                    let node = ast.to_node(db.upcast());
-                    sink.push(UnresolvedMacroCall {
-                        file: ast.file_id,
-                        node: AstPtr::new(&node),
-                        path: path.clone(),
-                    });
-                }
-
-                DiagnosticKind::MacroError { ast, message } => {
-                    let (file, ast) = match ast {
-                        MacroCallKind::FnLike { ast_id, .. } => {
-                            let node = ast_id.to_node(db.upcast());
-                            (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
-                        }
-                        MacroCallKind::Derive { ast_id, .. } => {
-                            let node = ast_id.to_node(db.upcast());
-                            (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
-                        }
-                    };
-                    sink.push(MacroError { file, node: ast, message: message.clone() });
-                }
-            }
-        }
-    }
-}