2019-11-24 15:05:12 +00:00
|
|
|
//! The core of the module-level name resolution algorithm.
|
|
|
|
//!
|
|
|
|
//! `DefCollector::collect` contains the fixed-point iteration loop which
|
|
|
|
//! resolves imports and expands macros.
|
2019-09-30 08:58:53 +00:00
|
|
|
|
2020-09-17 13:28:23 +00:00
|
|
|
use std::iter;
|
|
|
|
|
2021-06-01 11:39:19 +00:00
|
|
|
use base_db::{CrateId, Edition, FileId, ProcMacroId};
|
2020-10-22 17:19:18 +00:00
|
|
|
use cfg::{CfgExpr, CfgOptions};
|
2019-10-31 15:45:10 +00:00
|
|
|
use hir_expand::{
|
2020-06-15 17:16:14 +00:00
|
|
|
ast_id_map::FileAstId,
|
2019-12-05 14:10:33 +00:00
|
|
|
builtin_derive::find_builtin_derive,
|
2019-11-10 03:03:24 +00:00
|
|
|
builtin_macro::find_builtin_macro,
|
2021-06-01 11:39:19 +00:00
|
|
|
name::{name, AsName, Name},
|
2020-03-18 09:47:59 +00:00
|
|
|
proc_macro::ProcMacroExpander,
|
2021-05-10 14:35:06 +00:00
|
|
|
FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
|
2019-10-31 07:31:29 +00:00
|
|
|
};
|
2020-11-26 19:09:54 +00:00
|
|
|
use hir_expand::{InFile, MacroCallLoc};
|
2021-05-22 00:30:03 +00:00
|
|
|
use itertools::Itertools;
|
2021-05-25 23:01:58 +00:00
|
|
|
use la_arena::Idx;
|
2020-09-18 14:43:50 +00:00
|
|
|
use rustc_hash::{FxHashMap, FxHashSet};
|
2020-08-12 16:26:51 +00:00
|
|
|
use syntax::ast;
|
2019-03-02 20:59:04 +00:00
|
|
|
|
|
|
|
use crate::{
|
2021-05-20 18:40:02 +00:00
|
|
|
attr::{Attr, AttrId, AttrInput, Attrs},
|
2021-05-31 11:37:11 +00:00
|
|
|
attr_macro_as_call_id, builtin_attr,
|
2019-11-23 11:44:43 +00:00
|
|
|
db::DefDatabase,
|
2021-03-19 13:23:13 +00:00
|
|
|
derive_macro_as_call_id,
|
2021-04-03 18:56:53 +00:00
|
|
|
intern::Interned,
|
2020-06-26 01:34:39 +00:00
|
|
|
item_scope::{ImportType, PerNsGlobImports},
|
2020-12-15 14:37:37 +00:00
|
|
|
item_tree::{
|
2021-05-21 19:08:06 +00:00
|
|
|
self, Fields, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod,
|
|
|
|
ModItem, ModKind,
|
2020-12-15 14:37:37 +00:00
|
|
|
},
|
2021-02-28 11:12:11 +00:00
|
|
|
macro_call_as_call_id,
|
2019-03-23 17:41:59 +00:00
|
|
|
nameres::{
|
internal: move diagnostics to hir
The idea here is to eventually get rid of `dyn Diagnostic` and
`DiagnosticSink` infrastructure altogether, and just have a `enum
hir::Diagnostic` instead.
The problem with `dyn Diagnostic` is that it is defined in the lowest
level of the stack (hir_expand), but is used by the highest level (ide).
As a first step, we free hir_expand and hir_def from `dyn Diagnostic`
and kick the can up to `hir_ty`, as an intermediate state. The plan is
then to move DiagnosticSink similarly to the hir crate, and, as final
third step, remove its usage from the ide.
One currently unsolved problem is testing. You can notice that the test
which checks precise diagnostic ranges, unresolved_import_in_use_tree,
was moved to the ide layer. Logically, only IDE should have the infra to
render a specific range.
At the same time, the range is determined with the data produced in
hir_def and hir crates, so this layering is rather unfortunate. Working
on hir_def shouldn't require compiling `ide` for testing.
2021-05-23 20:31:59 +00:00
|
|
|
diagnostics::DefDiagnostic,
|
|
|
|
mod_resolution::ModDir,
|
|
|
|
path_resolution::ReachedFixedPoint,
|
|
|
|
proc_macro::{ProcMacroDef, ProcMacroKind},
|
2021-01-18 19:18:05 +00:00
|
|
|
BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
|
2019-03-23 17:41:59 +00:00
|
|
|
},
|
2020-02-02 13:04:06 +00:00
|
|
|
path::{ImportAlias, ModPath, PathKind},
|
2019-11-23 13:53:16 +00:00
|
|
|
per_ns::PerNs,
|
2020-06-15 17:16:14 +00:00
|
|
|
visibility::{RawVisibility, Visibility},
|
2021-03-09 18:09:02 +00:00
|
|
|
AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
|
|
|
|
LocalModuleId, ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
|
|
|
|
UnresolvedMacro,
|
2019-03-02 20:59:04 +00:00
|
|
|
};
|
|
|
|
|
2020-07-15 13:52:32 +00:00
|
|
|
const GLOB_RECURSION_LIMIT: usize = 100;
|
|
|
|
const EXPANSION_DEPTH_LIMIT: usize = 128;
|
|
|
|
const FIXED_POINT_LIMIT: usize = 8192;
|
|
|
|
|
2021-01-21 14:22:17 +00:00
|
|
|
pub(super) fn collect_defs(
|
|
|
|
db: &dyn DefDatabase,
|
|
|
|
mut def_map: DefMap,
|
2021-01-28 18:33:00 +00:00
|
|
|
block: Option<AstId<ast::BlockExpr>>,
|
2021-01-21 14:22:17 +00:00
|
|
|
) -> DefMap {
|
2019-10-31 15:45:10 +00:00
|
|
|
let crate_graph = db.crate_graph();
|
|
|
|
|
2021-04-02 17:00:26 +00:00
|
|
|
if block.is_none() {
|
|
|
|
// populate external prelude
|
|
|
|
for dep in &crate_graph[def_map.krate].dependencies {
|
|
|
|
log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
|
|
|
|
let dep_def_map = db.crate_def_map(dep.crate_id);
|
|
|
|
def_map
|
|
|
|
.extern_prelude
|
|
|
|
.insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into());
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-09 10:14:51 +00:00
|
|
|
let cfg_options = &crate_graph[def_map.krate].cfg_options;
|
2020-03-18 12:56:46 +00:00
|
|
|
let proc_macros = &crate_graph[def_map.krate].proc_macro;
|
|
|
|
let proc_macros = proc_macros
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(idx, it)| {
|
|
|
|
// FIXME: a hacky way to create a Name from string.
|
2020-03-26 16:41:44 +00:00
|
|
|
let name = tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() };
|
|
|
|
(name.as_name(), ProcMacroExpander::new(def_map.krate, ProcMacroId(idx as u32)))
|
2020-03-18 12:56:46 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2019-09-29 22:52:15 +00:00
|
|
|
|
2019-03-02 20:59:04 +00:00
|
|
|
let mut collector = DefCollector {
|
|
|
|
db,
|
2019-03-13 13:04:28 +00:00
|
|
|
def_map,
|
|
|
|
glob_imports: FxHashMap::default(),
|
2019-03-02 20:59:04 +00:00
|
|
|
unresolved_imports: Vec::new(),
|
2019-12-07 11:20:41 +00:00
|
|
|
resolved_imports: Vec::new(),
|
|
|
|
|
2021-05-20 11:12:29 +00:00
|
|
|
unresolved_macros: Vec::new(),
|
2019-10-10 11:45:05 +00:00
|
|
|
mod_dirs: FxHashMap::default(),
|
2019-09-29 22:52:15 +00:00
|
|
|
cfg_options,
|
2020-03-18 12:56:46 +00:00
|
|
|
proc_macros,
|
2020-09-18 15:50:04 +00:00
|
|
|
exports_proc_macros: false,
|
2020-06-26 01:34:39 +00:00
|
|
|
from_glob_import: Default::default(),
|
2021-05-20 18:18:53 +00:00
|
|
|
skip_attrs: Default::default(),
|
2021-05-20 17:56:04 +00:00
|
|
|
derive_helpers_in_scope: Default::default(),
|
2021-05-20 18:40:02 +00:00
|
|
|
registered_attrs: Default::default(),
|
|
|
|
registered_tools: Default::default(),
|
2019-03-02 20:59:04 +00:00
|
|
|
};
|
2021-01-21 14:22:17 +00:00
|
|
|
match block {
|
|
|
|
Some(block) => {
|
|
|
|
collector.seed_with_inner(block);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
collector.seed_with_top_level();
|
|
|
|
}
|
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
collector.collect();
|
2021-04-03 21:45:27 +00:00
|
|
|
let mut def_map = collector.finish();
|
|
|
|
def_map.shrink_to_fit();
|
|
|
|
def_map
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2019-12-07 11:20:41 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
|
|
enum PartialResolvedImport {
|
|
|
|
/// None of any namespaces is resolved
|
|
|
|
Unresolved,
|
|
|
|
/// One of namespaces is resolved
|
|
|
|
Indeterminate(PerNs),
|
|
|
|
/// All namespaces are resolved, OR it is came from other crate
|
|
|
|
Resolved(PerNs),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialResolvedImport {
|
|
|
|
fn namespaces(&self) -> PerNs {
|
|
|
|
match self {
|
|
|
|
PartialResolvedImport::Unresolved => PerNs::none(),
|
|
|
|
PartialResolvedImport::Indeterminate(ns) => *ns,
|
|
|
|
PartialResolvedImport::Resolved(ns) => *ns,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-16 13:47:58 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
enum ImportSource {
|
2021-05-25 23:01:58 +00:00
|
|
|
Import { id: ItemTreeId<item_tree::Import>, use_tree: Idx<ast::UseTree> },
|
2020-09-16 13:47:58 +00:00
|
|
|
ExternCrate(ItemTreeId<item_tree::ExternCrate>),
|
|
|
|
}
|
|
|
|
|
2020-06-22 13:07:06 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
struct Import {
|
2021-04-03 18:56:53 +00:00
|
|
|
path: Interned<ModPath>,
|
2020-11-02 12:13:32 +00:00
|
|
|
alias: Option<ImportAlias>,
|
|
|
|
visibility: RawVisibility,
|
|
|
|
is_glob: bool,
|
|
|
|
is_prelude: bool,
|
|
|
|
is_extern_crate: bool,
|
|
|
|
is_macro_use: bool,
|
2020-09-16 13:47:58 +00:00
|
|
|
source: ImportSource,
|
2020-06-22 13:07:06 +00:00
|
|
|
}
|
|
|
|
|
2020-06-24 13:36:18 +00:00
|
|
|
impl Import {
|
2020-12-18 19:37:26 +00:00
|
|
|
fn from_use(
|
|
|
|
db: &dyn DefDatabase,
|
|
|
|
krate: CrateId,
|
|
|
|
tree: &ItemTree,
|
|
|
|
id: ItemTreeId<item_tree::Import>,
|
2021-05-25 23:01:58 +00:00
|
|
|
) -> Vec<Self> {
|
2020-09-16 13:47:58 +00:00
|
|
|
let it = &tree[id.value];
|
2020-12-18 19:37:26 +00:00
|
|
|
let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
|
2020-06-24 13:36:18 +00:00
|
|
|
let visibility = &tree[it.visibility];
|
2021-05-25 23:01:58 +00:00
|
|
|
let is_prelude = attrs.by_key("prelude_import").exists();
|
|
|
|
|
|
|
|
let mut res = Vec::new();
|
|
|
|
it.use_tree.expand(|idx, path, is_glob, alias| {
|
|
|
|
res.push(Self {
|
|
|
|
path: Interned::new(path), // FIXME this makes little sense
|
|
|
|
alias,
|
|
|
|
visibility: visibility.clone(),
|
|
|
|
is_glob,
|
|
|
|
is_prelude,
|
|
|
|
is_extern_crate: false,
|
|
|
|
is_macro_use: false,
|
|
|
|
source: ImportSource::Import { id, use_tree: idx },
|
|
|
|
});
|
|
|
|
});
|
|
|
|
res
|
2020-06-22 13:07:06 +00:00
|
|
|
}
|
|
|
|
|
2020-12-18 19:37:26 +00:00
|
|
|
fn from_extern_crate(
|
|
|
|
db: &dyn DefDatabase,
|
|
|
|
krate: CrateId,
|
|
|
|
tree: &ItemTree,
|
|
|
|
id: ItemTreeId<item_tree::ExternCrate>,
|
|
|
|
) -> Self {
|
2020-09-16 13:47:58 +00:00
|
|
|
let it = &tree[id.value];
|
2020-12-18 19:37:26 +00:00
|
|
|
let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
|
2020-06-24 13:36:18 +00:00
|
|
|
let visibility = &tree[it.visibility];
|
2020-06-22 13:07:06 +00:00
|
|
|
Self {
|
2021-04-03 18:56:53 +00:00
|
|
|
path: Interned::new(ModPath::from_segments(
|
|
|
|
PathKind::Plain,
|
|
|
|
iter::once(it.name.clone()),
|
|
|
|
)),
|
2020-06-24 13:36:18 +00:00
|
|
|
alias: it.alias.clone(),
|
|
|
|
visibility: visibility.clone(),
|
2020-06-22 13:07:06 +00:00
|
|
|
is_glob: false,
|
|
|
|
is_prelude: false,
|
|
|
|
is_extern_crate: true,
|
2020-12-18 19:37:26 +00:00
|
|
|
is_macro_use: attrs.by_key("macro_use").exists(),
|
2020-09-16 13:47:58 +00:00
|
|
|
source: ImportSource::ExternCrate(id),
|
2020-06-22 13:07:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-07 11:20:41 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
struct ImportDirective {
|
|
|
|
module_id: LocalModuleId,
|
2020-06-12 21:24:26 +00:00
|
|
|
import: Import,
|
2019-12-07 11:20:41 +00:00
|
|
|
status: PartialResolvedImport,
|
|
|
|
}
|
|
|
|
|
2019-12-08 12:33:42 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
struct MacroDirective {
|
|
|
|
module_id: LocalModuleId,
|
2020-03-13 12:57:44 +00:00
|
|
|
depth: usize,
|
2021-03-23 16:23:10 +00:00
|
|
|
kind: MacroDirectiveKind,
|
2019-12-08 12:33:42 +00:00
|
|
|
}
|
|
|
|
|
2020-02-17 04:57:24 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2021-03-23 16:23:10 +00:00
|
|
|
enum MacroDirectiveKind {
|
2021-05-08 23:36:06 +00:00
|
|
|
FnLike { ast_id: AstIdWithPath<ast::MacroCall>, fragment: FragmentKind },
|
2021-04-09 11:38:01 +00:00
|
|
|
Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
|
2021-05-31 11:37:11 +00:00
|
|
|
Attr { ast_id: AstIdWithPath<ast::Item>, attr: Attr, mod_item: ModItem },
|
2020-02-17 04:57:24 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 17:16:14 +00:00
|
|
|
struct DefData<'a> {
|
|
|
|
id: ModuleDefId,
|
|
|
|
name: &'a Name,
|
|
|
|
visibility: &'a RawVisibility,
|
|
|
|
has_constructor: bool,
|
|
|
|
}
|
|
|
|
|
2019-03-02 20:59:04 +00:00
|
|
|
/// Walks the tree of module recursively
|
2020-03-13 15:05:46 +00:00
|
|
|
struct DefCollector<'a> {
|
|
|
|
db: &'a dyn DefDatabase,
|
2021-01-18 19:18:05 +00:00
|
|
|
def_map: DefMap,
|
2019-12-26 15:00:10 +00:00
|
|
|
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>,
|
2019-12-07 11:20:41 +00:00
|
|
|
unresolved_imports: Vec<ImportDirective>,
|
|
|
|
resolved_imports: Vec<ImportDirective>,
|
2021-05-20 11:12:29 +00:00
|
|
|
unresolved_macros: Vec<MacroDirective>,
|
2019-11-23 13:49:53 +00:00
|
|
|
mod_dirs: FxHashMap<LocalModuleId, ModDir>,
|
2019-09-29 22:52:15 +00:00
|
|
|
cfg_options: &'a CfgOptions,
|
2020-09-28 11:02:28 +00:00
|
|
|
/// List of procedural macros defined by this crate. This is read from the dynamic library
|
|
|
|
/// built by the build system, and is the list of proc. macros we can actually expand. It is
|
|
|
|
/// empty when proc. macro support is disabled (in which case we still do name resolution for
|
|
|
|
/// them).
|
2020-03-25 12:14:22 +00:00
|
|
|
proc_macros: Vec<(Name, ProcMacroExpander)>,
|
2020-09-18 15:50:04 +00:00
|
|
|
exports_proc_macros: bool,
|
2020-06-26 01:34:39 +00:00
|
|
|
from_glob_import: PerNsGlobImports,
|
2021-05-20 17:56:04 +00:00
|
|
|
/// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute.
|
|
|
|
/// This map is used to skip all attributes up to and including the one that failed to resolve,
|
|
|
|
/// in order to not expand them twice.
|
|
|
|
///
|
|
|
|
/// This also stores the attributes to skip when we resolve derive helpers and non-macro
|
|
|
|
/// non-builtin attributes in general.
|
2021-05-20 18:18:53 +00:00
|
|
|
skip_attrs: FxHashMap<InFile<ModItem>, AttrId>,
|
2021-05-19 21:35:09 +00:00
|
|
|
/// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
|
|
|
|
/// attributes.
|
|
|
|
derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<Name>>,
|
2021-05-20 18:40:02 +00:00
|
|
|
/// Custom attributes registered with `#![register_attr]`.
|
|
|
|
registered_attrs: Vec<String>,
|
|
|
|
/// Custom tool modules registered with `#![register_tool]`.
|
|
|
|
registered_tools: Vec<String>,
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2020-03-13 15:05:46 +00:00
|
|
|
impl DefCollector<'_> {
|
2021-01-21 14:22:17 +00:00
|
|
|
fn seed_with_top_level(&mut self) {
|
2020-03-09 10:11:59 +00:00
|
|
|
let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
|
2021-03-13 01:24:26 +00:00
|
|
|
let item_tree = self.db.file_item_tree(file_id.into());
|
2019-03-02 20:59:04 +00:00
|
|
|
let module_id = self.def_map.root;
|
2019-12-05 13:33:29 +00:00
|
|
|
self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
|
2021-05-20 18:40:02 +00:00
|
|
|
|
|
|
|
let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
|
|
|
|
if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) {
|
2021-06-01 11:39:19 +00:00
|
|
|
self.inject_prelude(&attrs);
|
|
|
|
|
2021-05-20 18:40:02 +00:00
|
|
|
// Process other crate-level attributes.
|
|
|
|
for attr in &*attrs {
|
|
|
|
let attr_name = match attr.path.as_ident() {
|
|
|
|
Some(name) => name,
|
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
|
|
|
|
let registered_name = if *attr_name == hir_expand::name![register_attr]
|
|
|
|
|| *attr_name == hir_expand::name![register_tool]
|
|
|
|
{
|
2021-05-24 22:50:19 +00:00
|
|
|
match attr.input.as_deref() {
|
2021-05-20 18:40:02 +00:00
|
|
|
Some(AttrInput::TokenTree(subtree)) => match &*subtree.token_trees {
|
|
|
|
[tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(),
|
|
|
|
_ => continue,
|
|
|
|
},
|
|
|
|
_ => continue,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
if *attr_name == hir_expand::name![register_attr] {
|
|
|
|
self.registered_attrs.push(registered_name.to_string());
|
|
|
|
cov_mark::hit!(register_attr);
|
|
|
|
} else {
|
|
|
|
self.registered_tools.push(registered_name.to_string());
|
|
|
|
cov_mark::hit!(register_tool);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-17 23:23:46 +00:00
|
|
|
ModCollector {
|
|
|
|
def_collector: &mut *self,
|
|
|
|
macro_depth: 0,
|
|
|
|
module_id,
|
|
|
|
file_id: file_id.into(),
|
|
|
|
item_tree: &item_tree,
|
|
|
|
mod_dir: ModDir::root(),
|
|
|
|
}
|
|
|
|
.collect(item_tree.top_level_items());
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2021-01-21 14:22:17 +00:00
|
|
|
}
|
|
|
|
|
2021-01-28 18:33:00 +00:00
|
|
|
fn seed_with_inner(&mut self, block: AstId<ast::BlockExpr>) {
|
2021-03-13 01:24:26 +00:00
|
|
|
let item_tree = self.db.file_item_tree(block.file_id);
|
2021-01-21 14:22:17 +00:00
|
|
|
let module_id = self.def_map.root;
|
2021-01-28 18:33:00 +00:00
|
|
|
self.def_map.modules[module_id].origin = ModuleOrigin::BlockExpr { block };
|
2021-01-21 14:22:17 +00:00
|
|
|
if item_tree
|
|
|
|
.top_level_attrs(self.db, self.def_map.krate)
|
|
|
|
.cfg()
|
|
|
|
.map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false))
|
|
|
|
{
|
|
|
|
ModCollector {
|
|
|
|
def_collector: &mut *self,
|
|
|
|
macro_depth: 0,
|
|
|
|
module_id,
|
2021-01-28 18:33:00 +00:00
|
|
|
file_id: block.file_id,
|
2021-01-21 14:22:17 +00:00
|
|
|
item_tree: &item_tree,
|
|
|
|
mod_dir: ModDir::root(),
|
|
|
|
}
|
2021-01-28 18:33:00 +00:00
|
|
|
.collect(item_tree.inner_items_of_block(block.value));
|
2021-01-21 14:22:17 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
|
2021-01-21 14:22:17 +00:00
|
|
|
fn collect(&mut self) {
|
2019-03-02 20:59:04 +00:00
|
|
|
// main name resolution fixed-point loop.
|
|
|
|
let mut i = 0;
|
2021-05-19 16:56:00 +00:00
|
|
|
'outer: loop {
|
|
|
|
loop {
|
2021-05-17 17:07:10 +00:00
|
|
|
self.db.unwind_if_cancelled();
|
2021-05-19 16:56:00 +00:00
|
|
|
loop {
|
|
|
|
if self.resolve_imports() == ReachedFixedPoint::Yes {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if self.resolve_macros() == ReachedFixedPoint::Yes {
|
|
|
|
break;
|
|
|
|
}
|
2019-12-07 11:20:41 +00:00
|
|
|
|
2021-05-19 16:56:00 +00:00
|
|
|
i += 1;
|
|
|
|
if i == FIXED_POINT_LIMIT {
|
|
|
|
log::error!("name resolution is stuck");
|
|
|
|
break 'outer;
|
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2021-05-19 16:56:00 +00:00
|
|
|
|
2021-05-20 17:56:04 +00:00
|
|
|
if self.reseed_with_unresolved_attribute() == ReachedFixedPoint::Yes {
|
2019-03-02 20:59:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-03-14 08:53:40 +00:00
|
|
|
|
2019-12-07 11:20:41 +00:00
|
|
|
// Resolve all indeterminate resolved imports again
|
|
|
|
// As some of the macros will expand newly import shadowing partial resolved imports
|
2021-01-08 14:46:48 +00:00
|
|
|
// FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports`
|
2019-12-07 11:20:41 +00:00
|
|
|
// correctly
|
|
|
|
let partial_resolved = self.resolved_imports.iter().filter_map(|directive| {
|
|
|
|
if let PartialResolvedImport::Indeterminate(_) = directive.status {
|
|
|
|
let mut directive = directive.clone();
|
|
|
|
directive.status = PartialResolvedImport::Unresolved;
|
|
|
|
Some(directive)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
});
|
|
|
|
self.unresolved_imports.extend(partial_resolved);
|
|
|
|
self.resolve_imports();
|
|
|
|
|
2019-03-14 08:53:40 +00:00
|
|
|
let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
|
|
|
|
// show unresolved imports in completion, etc
|
2020-09-16 13:47:58 +00:00
|
|
|
for directive in &unresolved_imports {
|
|
|
|
self.record_resolved_import(directive)
|
2019-03-14 08:53:40 +00:00
|
|
|
}
|
2020-09-16 13:47:58 +00:00
|
|
|
self.unresolved_imports = unresolved_imports;
|
2020-09-18 15:50:04 +00:00
|
|
|
|
|
|
|
// FIXME: This condition should instead check if this is a `proc-macro` type crate.
|
|
|
|
if self.exports_proc_macros {
|
|
|
|
// A crate exporting procedural macros is not allowed to export anything else.
|
|
|
|
//
|
|
|
|
// Additionally, while the proc macro entry points must be `pub`, they are not publicly
|
|
|
|
// exported in type/value namespace. This function reduces the visibility of all items
|
|
|
|
// in the crate root that aren't proc macros.
|
|
|
|
let root = self.def_map.root;
|
2021-01-25 14:21:33 +00:00
|
|
|
let module_id = self.def_map.module_id(root);
|
2020-09-18 15:50:04 +00:00
|
|
|
let root = &mut self.def_map.modules[root];
|
2021-01-25 14:21:33 +00:00
|
|
|
root.scope.censor_non_proc_macros(module_id);
|
2020-09-18 15:50:04 +00:00
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2021-05-19 13:17:57 +00:00
|
|
|
/// When the fixed-point loop reaches a stable state, we might still have some unresolved
|
2021-05-20 17:56:04 +00:00
|
|
|
/// attributes (or unexpanded attribute proc macros) left over. This takes one of them, and
|
|
|
|
/// feeds the item it's applied to back into name resolution.
|
2021-05-19 13:17:57 +00:00
|
|
|
///
|
|
|
|
/// This effectively ignores the fact that the macro is there and just treats the items as
|
|
|
|
/// normal code.
|
|
|
|
///
|
|
|
|
/// This improves UX when proc macros are turned off or don't work, and replicates the behavior
|
|
|
|
/// before we supported proc. attribute macros.
|
2021-05-20 17:56:04 +00:00
|
|
|
fn reseed_with_unresolved_attribute(&mut self) -> ReachedFixedPoint {
|
2021-05-19 19:05:58 +00:00
|
|
|
cov_mark::hit!(unresolved_attribute_fallback);
|
|
|
|
|
2021-05-20 17:56:04 +00:00
|
|
|
let mut unresolved_macros = std::mem::replace(&mut self.unresolved_macros, Vec::new());
|
|
|
|
let pos = unresolved_macros.iter().position(|directive| {
|
|
|
|
if let MacroDirectiveKind::Attr { ast_id, mod_item, attr } = &directive.kind {
|
2021-05-31 11:37:11 +00:00
|
|
|
self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id);
|
2021-05-19 13:17:57 +00:00
|
|
|
|
2021-05-20 18:08:39 +00:00
|
|
|
let file_id = ast_id.ast_id.file_id;
|
2021-05-19 13:17:57 +00:00
|
|
|
let item_tree = self.db.file_item_tree(file_id);
|
|
|
|
let mod_dir = self.mod_dirs[&directive.module_id].clone();
|
|
|
|
ModCollector {
|
|
|
|
def_collector: &mut *self,
|
|
|
|
macro_depth: directive.depth,
|
|
|
|
module_id: directive.module_id,
|
|
|
|
file_id,
|
|
|
|
item_tree: &item_tree,
|
|
|
|
mod_dir,
|
|
|
|
}
|
|
|
|
.collect(&[*mod_item]);
|
2021-05-20 17:56:04 +00:00
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
2021-05-19 13:17:57 +00:00
|
|
|
}
|
2021-05-20 17:56:04 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
if let Some(pos) = pos {
|
|
|
|
unresolved_macros.remove(pos);
|
2021-05-19 13:17:57 +00:00
|
|
|
}
|
2021-05-19 19:05:58 +00:00
|
|
|
|
|
|
|
// The collection above might add new unresolved macros (eg. derives), so merge the lists.
|
2021-05-20 11:12:29 +00:00
|
|
|
self.unresolved_macros.extend(unresolved_macros);
|
2021-05-19 13:17:57 +00:00
|
|
|
|
2021-05-20 17:56:04 +00:00
|
|
|
if pos.is_some() {
|
2021-05-19 13:17:57 +00:00
|
|
|
// Continue name resolution with the new data.
|
|
|
|
ReachedFixedPoint::No
|
|
|
|
} else {
|
|
|
|
ReachedFixedPoint::Yes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-01 11:39:19 +00:00
|
|
|
fn inject_prelude(&mut self, crate_attrs: &Attrs) {
|
|
|
|
// See compiler/rustc_builtin_macros/src/standard_library_imports.rs
|
|
|
|
|
|
|
|
if crate_attrs.by_key("no_core").exists() {
|
|
|
|
// libcore does not get a prelude.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let krate = if crate_attrs.by_key("no_std").exists() {
|
|
|
|
name![core]
|
|
|
|
} else {
|
|
|
|
let std = name![std];
|
|
|
|
if self.def_map.extern_prelude().any(|(name, _)| *name == std) {
|
|
|
|
std
|
|
|
|
} else {
|
|
|
|
// If `std` does not exist for some reason, fall back to core. This mostly helps
|
|
|
|
// keep r-a's own tests minimal.
|
|
|
|
name![core]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let edition = match self.def_map.edition {
|
|
|
|
Edition::Edition2015 => name![rust_2015],
|
|
|
|
Edition::Edition2018 => name![rust_2018],
|
|
|
|
Edition::Edition2021 => name![rust_2021],
|
|
|
|
};
|
|
|
|
|
|
|
|
let path_kind = if self.def_map.edition == Edition::Edition2015 {
|
|
|
|
PathKind::Plain
|
|
|
|
} else {
|
|
|
|
PathKind::Abs
|
|
|
|
};
|
2021-06-01 17:03:00 +00:00
|
|
|
let path = ModPath::from_segments(
|
|
|
|
path_kind.clone(),
|
|
|
|
[krate.clone(), name![prelude], edition].iter().cloned(),
|
|
|
|
);
|
|
|
|
// Fall back to the older `std::prelude::v1` for compatibility with Rust <1.52.0
|
|
|
|
// FIXME remove this fallback
|
|
|
|
let fallback_path =
|
|
|
|
ModPath::from_segments(path_kind, [krate, name![prelude], name![v1]].iter().cloned());
|
|
|
|
|
|
|
|
for path in &[path, fallback_path] {
|
|
|
|
let (per_ns, _) = self.def_map.resolve_path(
|
|
|
|
self.db,
|
|
|
|
self.def_map.root,
|
|
|
|
&path,
|
|
|
|
BuiltinShadowMode::Other,
|
|
|
|
);
|
|
|
|
|
|
|
|
match &per_ns.types {
|
|
|
|
Some((ModuleDefId::ModuleId(m), _)) => {
|
|
|
|
self.def_map.prelude = Some(*m);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
log::debug!(
|
|
|
|
"could not resolve prelude path `{}` to module (resolved to {:?})",
|
|
|
|
path,
|
|
|
|
per_ns.types
|
|
|
|
);
|
|
|
|
}
|
2021-06-01 11:39:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-28 11:02:28 +00:00
|
|
|
/// Adds a definition of procedural macro `name` to the root module.
|
|
|
|
///
|
|
|
|
/// # Notes on procedural macro resolution
|
|
|
|
///
|
|
|
|
/// Procedural macro functionality is provided by the build system: It has to build the proc
|
|
|
|
/// macro and pass the resulting dynamic library to rust-analyzer.
|
|
|
|
///
|
|
|
|
/// When procedural macro support is enabled, the list of proc macros exported by a crate is
|
|
|
|
/// known before we resolve names in the crate. This list is stored in `self.proc_macros` and is
|
|
|
|
/// derived from the dynamic library.
|
|
|
|
///
|
|
|
|
/// However, we *also* would like to be able to at least *resolve* macros on our own, without
|
|
|
|
/// help by the build system. So, when the macro isn't found in `self.proc_macros`, we instead
|
|
|
|
/// use a dummy expander that always errors. This comes with the drawback of macros potentially
|
|
|
|
/// going out of sync with what the build system sees (since we resolve using VFS state, but
|
|
|
|
/// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
|
2021-03-18 18:56:37 +00:00
|
|
|
fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) {
|
2021-05-29 18:32:57 +00:00
|
|
|
let kind = def.kind.to_basedb_kind();
|
2020-09-18 15:50:04 +00:00
|
|
|
self.exports_proc_macros = true;
|
2021-03-18 18:56:37 +00:00
|
|
|
let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) {
|
2020-09-18 14:43:50 +00:00
|
|
|
Some((_, expander)) => MacroDefId {
|
2020-12-15 19:33:05 +00:00
|
|
|
krate: self.def_map.krate,
|
2021-05-29 18:32:57 +00:00
|
|
|
kind: MacroDefKind::ProcMacro(*expander, kind, ast_id),
|
2020-09-18 14:43:50 +00:00
|
|
|
local_inner: false,
|
|
|
|
},
|
|
|
|
None => MacroDefId {
|
2020-12-15 19:33:05 +00:00
|
|
|
krate: self.def_map.krate,
|
2021-05-29 18:32:57 +00:00
|
|
|
kind: MacroDefKind::ProcMacro(
|
|
|
|
ProcMacroExpander::dummy(self.def_map.krate),
|
|
|
|
kind,
|
|
|
|
ast_id,
|
|
|
|
),
|
2020-09-18 14:43:50 +00:00
|
|
|
local_inner: false,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2021-03-18 18:56:37 +00:00
|
|
|
self.define_proc_macro(def.name.clone(), macro_def);
|
|
|
|
self.def_map.exported_proc_macros.insert(macro_def, def);
|
2020-09-18 14:43:50 +00:00
|
|
|
}
|
|
|
|
|
2019-09-09 12:54:02 +00:00
|
|
|
/// 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!();
|
|
|
|
/// ```
|
|
|
|
///
|
2019-11-17 15:35:05 +00:00
|
|
|
/// Well, this code compiles, because the plain path `foo` in `use` is searched
|
2019-09-09 12:54:02 +00:00
|
|
|
/// in the legacy textual scope only.
|
|
|
|
/// ```rust
|
|
|
|
/// macro_rules! foo { () => {} }
|
|
|
|
/// use foo as bar;
|
|
|
|
/// ```
|
2021-03-27 05:44:54 +00:00
|
|
|
fn define_macro_rules(
|
2019-06-08 17:42:02 +00:00
|
|
|
&mut self,
|
2019-11-23 13:49:53 +00:00
|
|
|
module_id: LocalModuleId,
|
2019-06-08 17:42:02 +00:00
|
|
|
name: Name,
|
2019-10-31 15:45:10 +00:00
|
|
|
macro_: MacroDefId,
|
2019-06-08 17:42:02 +00:00
|
|
|
export: bool,
|
|
|
|
) {
|
2019-09-09 12:54:02 +00:00
|
|
|
// Textual scoping
|
|
|
|
self.define_legacy_macro(module_id, name.clone(), macro_);
|
2019-06-08 17:42:02 +00:00
|
|
|
|
2019-09-09 12:54:02 +00:00
|
|
|
// Module scoping
|
2019-06-08 17:42:02 +00:00
|
|
|
// In Rust, `#[macro_export]` macros are unconditionally visible at the
|
|
|
|
// crate root, even if the parent modules is **not** visible.
|
2019-03-26 10:09:39 +00:00
|
|
|
if export {
|
2019-12-25 14:00:10 +00:00
|
|
|
self.update(
|
|
|
|
self.def_map.root,
|
2020-07-21 15:52:43 +00:00
|
|
|
&[(Some(name), PerNs::macros(macro_, Visibility::Public))],
|
2019-12-26 15:00:10 +00:00
|
|
|
Visibility::Public,
|
2020-06-25 16:42:12 +00:00
|
|
|
ImportType::Named,
|
2019-12-25 14:00:10 +00:00
|
|
|
);
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2019-09-06 16:55:58 +00:00
|
|
|
}
|
|
|
|
|
2019-09-07 16:37:54 +00:00
|
|
|
/// Define a legacy textual scoped macro in module
|
2019-09-06 16:55:58 +00:00
|
|
|
///
|
2019-12-20 15:19:28 +00:00
|
|
|
/// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module.
|
2019-09-07 16:37:54 +00:00
|
|
|
/// It will clone all macros from parent legacy scope, whose definition is prior to
|
2019-09-06 16:55:58 +00:00
|
|
|
/// the definition of current module.
|
2019-12-20 15:19:28 +00:00
|
|
|
/// And also, `macro_use` on a module will import all legacy macros visible inside to
|
2019-09-07 16:37:54 +00:00
|
|
|
/// current legacy scope, with possible shadowing.
|
2019-12-20 16:09:13 +00:00
|
|
|
fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroDefId) {
|
2019-09-06 16:55:58 +00:00
|
|
|
// Always shadowing
|
2019-12-20 16:09:13 +00:00
|
|
|
self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2021-03-27 05:44:54 +00:00
|
|
|
/// Define a macro 2.0 macro
|
|
|
|
///
|
|
|
|
/// The scoped of macro 2.0 macro is equal to normal function
|
|
|
|
fn define_macro_def(
|
|
|
|
&mut self,
|
|
|
|
module_id: LocalModuleId,
|
|
|
|
name: Name,
|
|
|
|
macro_: MacroDefId,
|
|
|
|
vis: &RawVisibility,
|
|
|
|
) {
|
|
|
|
let vis =
|
|
|
|
self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public);
|
|
|
|
self.update(module_id, &[(Some(name), PerNs::macros(macro_, vis))], vis, ImportType::Named);
|
|
|
|
}
|
|
|
|
|
2020-03-18 09:47:59 +00:00
|
|
|
/// Define a proc macro
|
|
|
|
///
|
2021-01-08 14:46:48 +00:00
|
|
|
/// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped.
|
2020-03-18 09:47:59 +00:00
|
|
|
/// And unconditionally exported.
|
|
|
|
fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) {
|
|
|
|
self.update(
|
|
|
|
self.def_map.root,
|
2020-07-21 15:52:43 +00:00
|
|
|
&[(Some(name), PerNs::macros(macro_, Visibility::Public))],
|
2020-03-18 09:47:59 +00:00
|
|
|
Visibility::Public,
|
2020-06-25 16:42:12 +00:00
|
|
|
ImportType::Named,
|
2020-03-18 09:47:59 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-09-05 03:35:13 +00:00
|
|
|
/// Import macros from `#[macro_use] extern crate`.
|
2019-09-06 16:55:58 +00:00
|
|
|
fn import_macros_from_extern_crate(
|
|
|
|
&mut self,
|
2019-11-23 13:49:53 +00:00
|
|
|
current_module_id: LocalModuleId,
|
2020-09-17 13:28:23 +00:00
|
|
|
extern_crate: &item_tree::ExternCrate,
|
2019-09-06 16:55:58 +00:00
|
|
|
) {
|
2019-09-05 03:35:13 +00:00
|
|
|
log::debug!(
|
|
|
|
"importing macros from extern crate: {:?} ({:?})",
|
2020-09-17 13:28:23 +00:00
|
|
|
extern_crate,
|
2019-09-05 03:35:13 +00:00
|
|
|
self.def_map.edition,
|
|
|
|
);
|
|
|
|
|
2021-04-09 13:25:12 +00:00
|
|
|
let res = self.def_map.resolve_name_in_extern_prelude(self.db, &extern_crate.name);
|
2019-09-05 03:35:13 +00:00
|
|
|
|
2019-10-31 15:45:10 +00:00
|
|
|
if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
|
2021-05-16 18:05:52 +00:00
|
|
|
if m == self.def_map.module_id(current_module_id) {
|
2021-05-17 09:37:24 +00:00
|
|
|
cov_mark::hit!(ignore_macro_use_extern_crate_self);
|
2021-05-16 18:05:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
|
2019-10-31 15:45:10 +00:00
|
|
|
self.import_all_macros_exported(current_module_id, m.krate);
|
2019-09-05 08:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-05 03:35:13 +00:00
|
|
|
|
2019-09-09 12:54:02 +00:00
|
|
|
/// 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`.
|
2019-11-23 13:49:53 +00:00
|
|
|
fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
|
2019-09-09 12:54:02 +00:00
|
|
|
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);
|
2019-09-05 03:35:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-19 16:56:00 +00:00
|
|
|
/// Tries to resolve every currently unresolved import.
|
|
|
|
fn resolve_imports(&mut self) -> ReachedFixedPoint {
|
|
|
|
let mut res = ReachedFixedPoint::Yes;
|
|
|
|
let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
|
2021-05-19 17:05:03 +00:00
|
|
|
let imports = imports
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(|mut directive| {
|
2019-12-07 11:20:41 +00:00
|
|
|
directive.status = self.resolve_import(directive.module_id, &directive.import);
|
|
|
|
match directive.status {
|
|
|
|
PartialResolvedImport::Indeterminate(_) => {
|
|
|
|
self.record_resolved_import(&directive);
|
|
|
|
// FIXME: For avoid performance regression,
|
|
|
|
// we consider an imported resolved if it is indeterminate (i.e not all namespace resolved)
|
2021-05-19 17:05:03 +00:00
|
|
|
self.resolved_imports.push(directive);
|
|
|
|
res = ReachedFixedPoint::No;
|
|
|
|
None
|
2019-12-07 11:20:41 +00:00
|
|
|
}
|
|
|
|
PartialResolvedImport::Resolved(_) => {
|
|
|
|
self.record_resolved_import(&directive);
|
2021-05-19 17:05:03 +00:00
|
|
|
self.resolved_imports.push(directive);
|
|
|
|
res = ReachedFixedPoint::No;
|
|
|
|
None
|
2019-12-07 11:20:41 +00:00
|
|
|
}
|
2021-05-19 17:05:03 +00:00
|
|
|
PartialResolvedImport::Unresolved => Some(directive),
|
2019-12-07 11:20:41 +00:00
|
|
|
}
|
2021-05-19 17:05:03 +00:00
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
self.unresolved_imports = imports;
|
2021-05-19 16:56:00 +00:00
|
|
|
res
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2020-06-12 21:24:26 +00:00
|
|
|
fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
|
2019-03-13 13:04:28 +00:00
|
|
|
log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
|
|
|
|
if import.is_extern_crate {
|
|
|
|
let res = self.def_map.resolve_name_in_extern_prelude(
|
2021-04-09 13:25:12 +00:00
|
|
|
self.db,
|
2019-03-13 13:04:28 +00:00
|
|
|
&import
|
|
|
|
.path
|
|
|
|
.as_ident()
|
|
|
|
.expect("extern crate should have been desugared to one-element path"),
|
|
|
|
);
|
2020-09-16 13:46:56 +00:00
|
|
|
if res.is_none() {
|
|
|
|
PartialResolvedImport::Unresolved
|
|
|
|
} else {
|
|
|
|
PartialResolvedImport::Resolved(res)
|
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
} else {
|
2019-05-26 12:10:56 +00:00
|
|
|
let res = self.def_map.resolve_path_fp_with_macro(
|
|
|
|
self.db,
|
|
|
|
ResolveMode::Import,
|
|
|
|
module_id,
|
|
|
|
&import.path,
|
2019-11-30 15:29:21 +00:00
|
|
|
BuiltinShadowMode::Module,
|
2019-05-26 12:10:56 +00:00
|
|
|
);
|
2019-03-13 13:04:28 +00:00
|
|
|
|
2019-12-07 11:20:41 +00:00
|
|
|
let def = res.resolved_def;
|
2020-01-11 22:19:58 +00:00
|
|
|
if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
|
2019-12-07 11:20:41 +00:00
|
|
|
return PartialResolvedImport::Unresolved;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(krate) = res.krate {
|
|
|
|
if krate != self.def_map.krate {
|
|
|
|
return PartialResolvedImport::Resolved(def);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether all namespace is resolved
|
|
|
|
if def.take_types().is_some()
|
|
|
|
&& def.take_values().is_some()
|
|
|
|
&& def.take_macros().is_some()
|
|
|
|
{
|
|
|
|
PartialResolvedImport::Resolved(def)
|
|
|
|
} else {
|
|
|
|
PartialResolvedImport::Indeterminate(def)
|
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-07 11:20:41 +00:00
|
|
|
fn record_resolved_import(&mut self, directive: &ImportDirective) {
|
|
|
|
let module_id = directive.module_id;
|
|
|
|
let import = &directive.import;
|
|
|
|
let def = directive.status.namespaces();
|
2019-12-25 14:00:10 +00:00
|
|
|
let vis = self
|
|
|
|
.def_map
|
|
|
|
.resolve_visibility(self.db, module_id, &directive.import.visibility)
|
2019-12-26 15:00:10 +00:00
|
|
|
.unwrap_or(Visibility::Public);
|
2019-12-07 11:20:41 +00:00
|
|
|
|
2019-03-13 13:04:28 +00:00
|
|
|
if import.is_glob {
|
|
|
|
log::debug!("glob import: {:?}", import);
|
2019-09-09 12:54:02 +00:00
|
|
|
match def.take_types() {
|
2019-10-31 15:45:10 +00:00
|
|
|
Some(ModuleDefId::ModuleId(m)) => {
|
2019-03-13 13:04:28 +00:00
|
|
|
if import.is_prelude {
|
2021-06-01 11:39:19 +00:00
|
|
|
// Note: This dodgily overrides the injected prelude. The rustc
|
|
|
|
// implementation seems to work the same though.
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(std_prelude);
|
2019-03-13 13:04:28 +00:00
|
|
|
self.def_map.prelude = Some(m);
|
2019-10-31 15:45:10 +00:00
|
|
|
} else if m.krate != self.def_map.krate {
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(glob_across_crates);
|
2019-03-13 13:04:28 +00:00
|
|
|
// glob import from other crate => we can just import everything once
|
2021-01-22 15:31:40 +00:00
|
|
|
let item_map = m.def_map(self.db);
|
2019-11-27 18:31:51 +00:00
|
|
|
let scope = &item_map[m.local_id].scope;
|
2019-09-09 12:54:02 +00:00
|
|
|
|
|
|
|
// Module scoped macros is included
|
2019-12-25 17:05:16 +00:00
|
|
|
let items = scope
|
|
|
|
.resolutions()
|
|
|
|
// only keep visible names...
|
|
|
|
.map(|(n, res)| {
|
2019-12-27 10:24:31 +00:00
|
|
|
(n, res.filter_visibility(|v| v.is_visible_from_other_crate()))
|
2019-12-25 17:05:16 +00:00
|
|
|
})
|
|
|
|
.filter(|(_, res)| !res.is_none())
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
2020-06-25 16:42:12 +00:00
|
|
|
self.update(module_id, &items, vis, ImportType::Glob);
|
2019-03-13 13:04:28 +00:00
|
|
|
} else {
|
|
|
|
// glob import from same crate => we do an initial
|
|
|
|
// import, and then need to propagate any further
|
|
|
|
// additions
|
2021-02-02 11:25:13 +00:00
|
|
|
let def_map;
|
|
|
|
let scope = if m.block == self.def_map.block_id() {
|
|
|
|
&self.def_map[m.local_id].scope
|
|
|
|
} else {
|
|
|
|
def_map = m.def_map(self.db);
|
|
|
|
&def_map[m.local_id].scope
|
|
|
|
};
|
2019-09-09 12:54:02 +00:00
|
|
|
|
|
|
|
// Module scoped macros is included
|
2019-12-25 17:05:16 +00:00
|
|
|
let items = scope
|
|
|
|
.resolutions()
|
|
|
|
// only keep visible names...
|
|
|
|
.map(|(n, res)| {
|
|
|
|
(
|
|
|
|
n,
|
|
|
|
res.filter_visibility(|v| {
|
2021-02-23 16:56:16 +00:00
|
|
|
v.is_visible_from_def_map(self.db, &self.def_map, module_id)
|
2019-12-25 17:05:16 +00:00
|
|
|
}),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.filter(|(_, res)| !res.is_none())
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
2020-06-25 16:42:12 +00:00
|
|
|
self.update(module_id, &items, vis, ImportType::Glob);
|
2019-03-13 13:04:28 +00:00
|
|
|
// record the glob import in case we add further items
|
2019-12-07 01:50:21 +00:00
|
|
|
let glob = self.glob_imports.entry(m.local_id).or_default();
|
2019-12-25 17:05:16 +00:00
|
|
|
if !glob.iter().any(|(mid, _)| *mid == module_id) {
|
|
|
|
glob.push((module_id, vis));
|
2019-12-07 01:50:21 +00:00
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
2019-10-31 15:45:10 +00:00
|
|
|
Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(glob_enum);
|
2019-03-13 13:04:28 +00:00
|
|
|
// glob import from enum => just import all the variants
|
2020-04-11 15:52:26 +00:00
|
|
|
|
|
|
|
// XXX: urgh, so this works by accident! Here, we look at
|
|
|
|
// the enum data, and, in theory, this might require us to
|
|
|
|
// look back at the crate_def_map, creating a cycle. For
|
2021-01-08 14:46:48 +00:00
|
|
|
// example, `enum E { crate::some_macro!(); }`. Luckily, the
|
2020-04-11 15:52:26 +00:00
|
|
|
// only kind of macro that is allowed inside enum is a
|
|
|
|
// `cfg_macro`, and we don't need to run name resolution for
|
|
|
|
// it, but this is sheer luck!
|
2019-10-31 15:45:10 +00:00
|
|
|
let enum_data = self.db.enum_data(e);
|
|
|
|
let resolutions = enum_data
|
|
|
|
.variants
|
|
|
|
.iter()
|
2019-12-20 20:14:30 +00:00
|
|
|
.map(|(local_id, variant_data)| {
|
2019-11-27 20:22:20 +00:00
|
|
|
let name = variant_data.name.clone();
|
2019-10-31 15:45:10 +00:00
|
|
|
let variant = EnumVariantId { parent: e, local_id };
|
2019-12-25 14:00:10 +00:00
|
|
|
let res = PerNs::both(variant.into(), variant.into(), vis);
|
2020-07-21 15:52:43 +00:00
|
|
|
(Some(name), res)
|
2019-03-13 13:04:28 +00:00
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
2020-06-25 16:42:12 +00:00
|
|
|
self.update(module_id, &resolutions, vis, ImportType::Glob);
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
Some(d) => {
|
|
|
|
log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
log::debug!("glob import {:?} didn't resolve as type", import);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-03-17 21:24:51 +00:00
|
|
|
let name = match &import.alias {
|
|
|
|
Some(ImportAlias::Alias(name)) => Some(name.clone()),
|
|
|
|
Some(ImportAlias::Underscore) => None,
|
|
|
|
None => match import.path.segments().last() {
|
|
|
|
Some(last_segment) => Some(last_segment.clone()),
|
|
|
|
None => {
|
|
|
|
cov_mark::hit!(bogus_paths);
|
|
|
|
return;
|
2019-03-16 15:06:45 +00:00
|
|
|
}
|
2021-03-17 21:24:51 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
|
2019-05-26 12:10:56 +00:00
|
|
|
|
2021-03-17 21:24:51 +00:00
|
|
|
// 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), Some(name)) = (def.take_types(), name.as_ref()) {
|
|
|
|
self.def_map.extern_prelude.insert(name.clone(), def);
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-17 21:24:51 +00:00
|
|
|
|
|
|
|
self.update(module_id, &[(name, def)], vis, ImportType::Named);
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 01:42:44 +00:00
|
|
|
fn update(
|
|
|
|
&mut self,
|
|
|
|
module_id: LocalModuleId,
|
2020-07-21 15:52:43 +00:00
|
|
|
resolutions: &[(Option<Name>, PerNs)],
|
2020-06-25 01:42:44 +00:00
|
|
|
vis: Visibility,
|
2020-06-25 16:42:12 +00:00
|
|
|
import_type: ImportType,
|
2020-06-25 01:42:44 +00:00
|
|
|
) {
|
2021-05-17 17:07:10 +00:00
|
|
|
self.db.unwind_if_cancelled();
|
2020-06-25 16:42:12 +00:00
|
|
|
self.update_recursive(module_id, resolutions, vis, import_type, 0)
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 13:04:28 +00:00
|
|
|
fn update_recursive(
|
|
|
|
&mut self,
|
2019-11-23 13:49:53 +00:00
|
|
|
module_id: LocalModuleId,
|
2020-07-21 15:52:43 +00:00
|
|
|
resolutions: &[(Option<Name>, PerNs)],
|
2021-01-08 14:46:48 +00:00
|
|
|
// All resolutions are imported with this visibility; the visibilities in
|
2019-12-25 17:05:16 +00:00
|
|
|
// the `PerNs` values are ignored and overwritten
|
2019-12-26 15:00:10 +00:00
|
|
|
vis: Visibility,
|
2020-06-25 16:42:12 +00:00
|
|
|
import_type: ImportType,
|
2019-03-13 13:04:28 +00:00
|
|
|
depth: usize,
|
|
|
|
) {
|
2020-07-15 13:52:32 +00:00
|
|
|
if depth > GLOB_RECURSION_LIMIT {
|
2019-03-13 13:04:28 +00:00
|
|
|
// prevent stack overflows (but this shouldn't be possible)
|
|
|
|
panic!("infinite recursion in glob imports!");
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
let mut changed = false;
|
2020-07-21 15:52:43 +00:00
|
|
|
|
2019-03-13 13:04:28 +00:00
|
|
|
for (name, res) in resolutions {
|
2020-07-21 15:52:43 +00:00
|
|
|
match name {
|
|
|
|
Some(name) => {
|
|
|
|
let scope = &mut self.def_map.modules[module_id].scope;
|
|
|
|
changed |= scope.push_res_with_import(
|
|
|
|
&mut self.from_glob_import,
|
|
|
|
(module_id, name.clone()),
|
|
|
|
res.with_visibility(vis),
|
|
|
|
import_type,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let tr = match res.take_types() {
|
|
|
|
Some(ModuleDefId::TraitId(tr)) => tr,
|
|
|
|
Some(other) => {
|
|
|
|
log::debug!("non-trait `_` import of {:?}", other);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr);
|
|
|
|
let should_update = match old_vis {
|
|
|
|
None => true,
|
|
|
|
Some(old_vis) => {
|
|
|
|
let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
|
|
|
|
panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr);
|
|
|
|
});
|
|
|
|
|
2020-07-22 12:01:50 +00:00
|
|
|
if max_vis == old_vis {
|
|
|
|
false
|
|
|
|
} else {
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(upgrade_underscore_visibility);
|
2020-07-22 12:01:50 +00:00
|
|
|
true
|
|
|
|
}
|
2020-07-21 15:52:43 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if should_update {
|
|
|
|
changed = true;
|
|
|
|
self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
2019-05-26 12:10:56 +00:00
|
|
|
|
2019-03-13 13:04:28 +00:00
|
|
|
if !changed {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let glob_imports = self
|
|
|
|
.glob_imports
|
|
|
|
.get(&module_id)
|
|
|
|
.into_iter()
|
|
|
|
.flat_map(|v| v.iter())
|
2020-07-15 13:45:34 +00:00
|
|
|
.filter(|(glob_importing_module, _)| {
|
|
|
|
// we know all resolutions have the same visibility (`vis`), so we
|
|
|
|
// just need to check that once
|
2021-02-23 16:56:16 +00:00
|
|
|
vis.is_visible_from_def_map(self.db, &self.def_map, *glob_importing_module)
|
2020-07-15 13:45:34 +00:00
|
|
|
})
|
2019-03-13 13:04:28 +00:00
|
|
|
.cloned()
|
|
|
|
.collect::<Vec<_>>();
|
2020-07-15 13:45:34 +00:00
|
|
|
|
2019-12-25 17:05:16 +00:00
|
|
|
for (glob_importing_module, glob_import_vis) in glob_imports {
|
2020-06-25 01:42:44 +00:00
|
|
|
self.update_recursive(
|
|
|
|
glob_importing_module,
|
|
|
|
resolutions,
|
|
|
|
glob_import_vis,
|
2020-06-25 16:42:12 +00:00
|
|
|
ImportType::Glob,
|
2020-06-25 01:42:44 +00:00
|
|
|
depth + 1,
|
|
|
|
);
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_macros(&mut self) -> ReachedFixedPoint {
|
2021-05-20 11:12:29 +00:00
|
|
|
let mut macros = std::mem::replace(&mut self.unresolved_macros, Vec::new());
|
2019-03-13 13:04:28 +00:00
|
|
|
let mut resolved = Vec::new();
|
2019-03-16 16:40:41 +00:00
|
|
|
let mut res = ReachedFixedPoint::Yes;
|
2019-12-08 12:33:42 +00:00
|
|
|
macros.retain(|directive| {
|
2021-05-18 15:51:02 +00:00
|
|
|
let resolver = |path| {
|
|
|
|
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
|
|
|
self.db,
|
|
|
|
ResolveMode::Other,
|
|
|
|
directive.module_id,
|
|
|
|
&path,
|
|
|
|
BuiltinShadowMode::Module,
|
|
|
|
);
|
|
|
|
resolved_res.resolved_def.take_macros()
|
|
|
|
};
|
|
|
|
|
2021-03-23 16:23:10 +00:00
|
|
|
match &directive.kind {
|
2021-05-08 23:36:06 +00:00
|
|
|
MacroDirectiveKind::FnLike { ast_id, fragment } => {
|
2021-03-23 16:23:10 +00:00
|
|
|
match macro_call_as_call_id(
|
|
|
|
ast_id,
|
2021-05-08 23:36:06 +00:00
|
|
|
*fragment,
|
2020-06-11 10:08:24 +00:00
|
|
|
self.db,
|
2021-03-23 16:23:10 +00:00
|
|
|
self.def_map.krate,
|
2021-05-18 15:51:02 +00:00
|
|
|
&resolver,
|
2021-03-23 16:23:10 +00:00
|
|
|
&mut |_err| (),
|
|
|
|
) {
|
|
|
|
Ok(Ok(call_id)) => {
|
|
|
|
resolved.push((directive.module_id, call_id, directive.depth));
|
|
|
|
res = ReachedFixedPoint::No;
|
|
|
|
return false;
|
|
|
|
}
|
2021-04-16 13:48:03 +00:00
|
|
|
Err(UnresolvedMacro { .. }) | Ok(Err(_)) => {}
|
2021-03-23 16:23:10 +00:00
|
|
|
}
|
2021-02-28 11:12:11 +00:00
|
|
|
}
|
2021-04-09 11:38:01 +00:00
|
|
|
MacroDirectiveKind::Derive { ast_id, derive_attr } => {
|
|
|
|
match derive_macro_as_call_id(
|
|
|
|
ast_id,
|
|
|
|
*derive_attr,
|
|
|
|
self.db,
|
|
|
|
self.def_map.krate,
|
2021-05-18 15:51:02 +00:00
|
|
|
&resolver,
|
2021-04-09 11:38:01 +00:00
|
|
|
) {
|
2021-03-23 16:23:10 +00:00
|
|
|
Ok(call_id) => {
|
2021-04-08 16:49:30 +00:00
|
|
|
resolved.push((directive.module_id, call_id, directive.depth));
|
2021-03-23 16:23:10 +00:00
|
|
|
res = ReachedFixedPoint::No;
|
|
|
|
return false;
|
|
|
|
}
|
2021-04-16 13:48:03 +00:00
|
|
|
Err(UnresolvedMacro { .. }) => (),
|
2021-03-23 16:23:10 +00:00
|
|
|
}
|
2021-02-28 11:12:11 +00:00
|
|
|
}
|
2021-05-20 17:56:04 +00:00
|
|
|
MacroDirectiveKind::Attr { ast_id, mod_item, attr } => {
|
|
|
|
if let Some(ident) = ast_id.path.as_ident() {
|
|
|
|
if let Some(helpers) = self.derive_helpers_in_scope.get(&ast_id.ast_id) {
|
|
|
|
if helpers.contains(ident) {
|
|
|
|
cov_mark::hit!(resolved_derive_helper);
|
|
|
|
|
|
|
|
// Resolved to derive helper. Collect the item's attributes again,
|
|
|
|
// starting after the derive helper.
|
2021-05-20 18:08:39 +00:00
|
|
|
let file_id = ast_id.ast_id.file_id;
|
2021-05-20 17:56:04 +00:00
|
|
|
let item_tree = self.db.file_item_tree(file_id);
|
|
|
|
let mod_dir = self.mod_dirs[&directive.module_id].clone();
|
2021-05-31 11:37:11 +00:00
|
|
|
self.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id);
|
2021-05-20 17:56:04 +00:00
|
|
|
ModCollector {
|
|
|
|
def_collector: &mut *self,
|
|
|
|
macro_depth: directive.depth,
|
|
|
|
module_id: directive.module_id,
|
|
|
|
file_id,
|
|
|
|
item_tree: &item_tree,
|
|
|
|
mod_dir,
|
|
|
|
}
|
|
|
|
.collect(&[*mod_item]);
|
|
|
|
|
|
|
|
// Remove the original directive since we resolved it.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-03 14:11:20 +00:00
|
|
|
if !self.db.enable_proc_attr_macros() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-05-20 17:56:04 +00:00
|
|
|
// Not resolved to a derive helper, so try to resolve as a macro.
|
2021-05-31 11:37:11 +00:00
|
|
|
match attr_macro_as_call_id(
|
|
|
|
ast_id,
|
|
|
|
attr,
|
|
|
|
self.db,
|
|
|
|
self.def_map.krate,
|
|
|
|
&resolver,
|
|
|
|
) {
|
|
|
|
Ok(call_id) => {
|
|
|
|
let loc: MacroCallLoc = self.db.lookup_intern_macro(call_id);
|
|
|
|
if let MacroDefKind::ProcMacro(exp, ..) = &loc.def.kind {
|
|
|
|
if exp.is_dummy() {
|
|
|
|
// Proc macros that cannot be expanded are treated as not
|
|
|
|
// resolved, in order to fall back later.
|
|
|
|
self.def_map.diagnostics.push(
|
|
|
|
DefDiagnostic::unresolved_proc_macro(
|
|
|
|
directive.module_id,
|
|
|
|
loc.kind,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
let file_id = ast_id.ast_id.file_id;
|
|
|
|
let item_tree = self.db.file_item_tree(file_id);
|
|
|
|
let mod_dir = self.mod_dirs[&directive.module_id].clone();
|
|
|
|
self.skip_attrs
|
|
|
|
.insert(InFile::new(file_id, *mod_item), attr.id);
|
|
|
|
ModCollector {
|
|
|
|
def_collector: &mut *self,
|
|
|
|
macro_depth: directive.depth,
|
|
|
|
module_id: directive.module_id,
|
|
|
|
file_id,
|
|
|
|
item_tree: &item_tree,
|
|
|
|
mod_dir,
|
|
|
|
}
|
|
|
|
.collect(&[*mod_item]);
|
|
|
|
|
|
|
|
// Remove the macro directive.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
resolved.push((directive.module_id, call_id, directive.depth));
|
|
|
|
res = ReachedFixedPoint::No;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Err(UnresolvedMacro { .. }) => (),
|
|
|
|
}
|
2021-05-19 13:17:57 +00:00
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
2019-05-26 12:10:56 +00:00
|
|
|
|
|
|
|
true
|
2019-03-13 13:04:28 +00:00
|
|
|
});
|
2021-05-20 17:56:04 +00:00
|
|
|
// Attribute resolution can add unresolved macro invocations, so concatenate the lists.
|
|
|
|
self.unresolved_macros.extend(macros);
|
2019-05-14 15:55:24 +00:00
|
|
|
|
2020-03-13 12:57:44 +00:00
|
|
|
for (module_id, macro_call_id, depth) in resolved {
|
|
|
|
self.collect_macro_expansion(module_id, macro_call_id, depth);
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
2019-05-14 15:55:24 +00:00
|
|
|
|
2019-03-13 13:04:28 +00:00
|
|
|
res
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2020-03-13 12:57:44 +00:00
|
|
|
fn collect_macro_expansion(
|
|
|
|
&mut self,
|
|
|
|
module_id: LocalModuleId,
|
|
|
|
macro_call_id: MacroCallId,
|
|
|
|
depth: usize,
|
|
|
|
) {
|
2020-07-15 13:52:32 +00:00
|
|
|
if depth > EXPANSION_DEPTH_LIMIT {
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(macro_expansion_overflow);
|
2020-07-14 16:31:48 +00:00
|
|
|
log::warn!("macro expansion is too deep");
|
|
|
|
return;
|
|
|
|
}
|
2020-11-26 19:09:54 +00:00
|
|
|
let file_id = macro_call_id.as_file();
|
|
|
|
|
|
|
|
// First, fetch the raw expansion result for purposes of error reporting. This goes through
|
|
|
|
// `macro_expand_error` to avoid depending on the full expansion result (to improve
|
|
|
|
// incrementality).
|
2021-05-19 21:35:09 +00:00
|
|
|
let loc: MacroCallLoc = self.db.lookup_intern_macro(macro_call_id);
|
2020-11-26 19:09:54 +00:00
|
|
|
let err = self.db.macro_expand_error(macro_call_id);
|
|
|
|
if let Some(err) = err {
|
2021-05-19 18:19:08 +00:00
|
|
|
let diag = match err {
|
|
|
|
hir_expand::ExpandError::UnresolvedProcMacro => {
|
|
|
|
// Missing proc macros are non-fatal, so they are handled specially.
|
2021-05-19 21:35:09 +00:00
|
|
|
DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone())
|
2021-05-19 18:19:08 +00:00
|
|
|
}
|
2021-05-19 21:35:09 +00:00
|
|
|
_ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()),
|
2021-05-19 18:19:08 +00:00
|
|
|
};
|
2020-11-26 19:09:54 +00:00
|
|
|
|
2021-05-19 18:19:08 +00:00
|
|
|
self.def_map.diagnostics.push(diag);
|
2020-11-26 19:09:54 +00:00
|
|
|
}
|
|
|
|
|
2021-05-19 21:35:09 +00:00
|
|
|
// If we've just resolved a derive, record its helper attributes.
|
|
|
|
if let MacroCallKind::Derive { ast_id, .. } = &loc.kind {
|
|
|
|
if loc.def.krate != self.def_map.krate {
|
|
|
|
let def_map = self.db.crate_def_map(loc.def.krate);
|
|
|
|
if let Some(def) = def_map.exported_proc_macros.get(&loc.def) {
|
|
|
|
if let ProcMacroKind::CustomDerive { helpers } = &def.kind {
|
|
|
|
self.derive_helpers_in_scope
|
|
|
|
.entry(*ast_id)
|
|
|
|
.or_default()
|
|
|
|
.extend(helpers.iter().cloned());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-26 19:09:54 +00:00
|
|
|
// Then, fetch and process the item tree. This will reuse the expansion result from above.
|
2021-03-13 01:24:26 +00:00
|
|
|
let item_tree = self.db.file_item_tree(file_id);
|
2019-12-08 12:33:42 +00:00
|
|
|
let mod_dir = self.mod_dirs[&module_id].clone();
|
|
|
|
ModCollector {
|
|
|
|
def_collector: &mut *self,
|
2020-03-13 12:57:44 +00:00
|
|
|
macro_depth: depth,
|
2019-12-08 12:33:42 +00:00
|
|
|
file_id,
|
|
|
|
module_id,
|
2020-06-12 21:24:26 +00:00
|
|
|
item_tree: &item_tree,
|
2019-12-08 12:33:42 +00:00
|
|
|
mod_dir,
|
2019-04-20 15:05:25 +00:00
|
|
|
}
|
2020-06-12 21:24:26 +00:00
|
|
|
.collect(item_tree.top_level_items());
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 19:18:05 +00:00
|
|
|
fn finish(mut self) -> DefMap {
|
2021-01-05 14:42:43 +00:00
|
|
|
// Emit diagnostics for all remaining unexpanded macros.
|
|
|
|
|
2021-05-20 11:12:29 +00:00
|
|
|
for directive in &self.unresolved_macros {
|
2021-03-23 16:23:10 +00:00
|
|
|
match &directive.kind {
|
2021-05-08 23:36:06 +00:00
|
|
|
MacroDirectiveKind::FnLike { ast_id, fragment } => match macro_call_as_call_id(
|
2021-03-23 16:23:10 +00:00
|
|
|
ast_id,
|
2021-05-08 23:36:06 +00:00
|
|
|
*fragment,
|
2021-03-23 16:23:10 +00:00
|
|
|
self.db,
|
|
|
|
self.def_map.krate,
|
|
|
|
|path| {
|
|
|
|
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
|
|
|
self.db,
|
|
|
|
ResolveMode::Other,
|
|
|
|
directive.module_id,
|
|
|
|
&path,
|
|
|
|
BuiltinShadowMode::Module,
|
|
|
|
);
|
|
|
|
resolved_res.resolved_def.take_macros()
|
|
|
|
},
|
|
|
|
&mut |_| (),
|
|
|
|
) {
|
|
|
|
Ok(_) => (),
|
2021-04-16 13:48:03 +00:00
|
|
|
Err(UnresolvedMacro { path }) => {
|
2021-03-23 16:23:10 +00:00
|
|
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
|
|
|
directive.module_id,
|
|
|
|
ast_id.ast_id,
|
2021-04-16 13:48:03 +00:00
|
|
|
path,
|
2021-03-23 16:23:10 +00:00
|
|
|
));
|
|
|
|
}
|
2021-01-05 14:42:43 +00:00
|
|
|
},
|
2021-05-19 13:17:57 +00:00
|
|
|
MacroDirectiveKind::Derive { .. } | MacroDirectiveKind::Attr { .. } => {
|
2021-03-23 16:23:10 +00:00
|
|
|
// FIXME: we might want to diagnose this too
|
2021-02-28 11:12:11 +00:00
|
|
|
}
|
2021-03-23 16:23:10 +00:00
|
|
|
}
|
2021-01-05 14:42:43 +00:00
|
|
|
}
|
|
|
|
|
2020-09-17 12:48:17 +00:00
|
|
|
// Emit diagnostics for all remaining unresolved imports.
|
|
|
|
|
|
|
|
// We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
|
|
|
|
// resolve. We first emit diagnostics for unresolved extern crates and collect the missing
|
|
|
|
// crate names. Then we emit diagnostics for unresolved imports, but only if the import
|
|
|
|
// doesn't start with an unresolved crate's name. Due to renaming and reexports, this is a
|
|
|
|
// heuristic, but it works in practice.
|
|
|
|
let mut diagnosed_extern_crates = FxHashSet::default();
|
2020-09-16 13:47:58 +00:00
|
|
|
for directive in &self.unresolved_imports {
|
2020-09-17 12:48:17 +00:00
|
|
|
if let ImportSource::ExternCrate(krate) = directive.import.source {
|
2021-03-12 23:34:01 +00:00
|
|
|
let item_tree = krate.item_tree(self.db);
|
2020-09-17 12:48:17 +00:00
|
|
|
let extern_crate = &item_tree[krate.value];
|
|
|
|
|
2020-09-17 13:28:23 +00:00
|
|
|
diagnosed_extern_crates.insert(extern_crate.name.clone());
|
2020-09-17 12:48:17 +00:00
|
|
|
|
|
|
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate(
|
|
|
|
directive.module_id,
|
2021-03-12 23:34:01 +00:00
|
|
|
InFile::new(krate.file_id(), extern_crate.ast_id),
|
2020-09-17 12:48:17 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for directive in &self.unresolved_imports {
|
2021-05-25 23:01:58 +00:00
|
|
|
if let ImportSource::Import { id: import, use_tree } = &directive.import.source {
|
|
|
|
match (directive.import.path.segments().first(), &directive.import.path.kind) {
|
2020-09-17 12:48:17 +00:00
|
|
|
(Some(krate), PathKind::Plain) | (Some(krate), PathKind::Abs) => {
|
|
|
|
if diagnosed_extern_crates.contains(krate) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
2020-09-16 13:47:58 +00:00
|
|
|
}
|
2020-09-17 12:48:17 +00:00
|
|
|
|
|
|
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
|
|
|
|
directive.module_id,
|
2021-05-25 23:01:58 +00:00
|
|
|
*import,
|
|
|
|
*use_tree,
|
2020-09-17 12:48:17 +00:00
|
|
|
));
|
2020-09-16 13:47:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-02 20:59:04 +00:00
|
|
|
self.def_map
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-13 13:38:02 +00:00
|
|
|
/// Walks a single module, populating defs, imports and macros
|
2020-03-13 15:05:46 +00:00
|
|
|
struct ModCollector<'a, 'b> {
|
|
|
|
def_collector: &'a mut DefCollector<'b>,
|
2020-03-13 12:57:44 +00:00
|
|
|
macro_depth: usize,
|
2019-11-23 13:49:53 +00:00
|
|
|
module_id: LocalModuleId,
|
2019-03-13 13:38:02 +00:00
|
|
|
file_id: HirFileId,
|
2020-06-12 21:24:26 +00:00
|
|
|
item_tree: &'a ItemTree,
|
2019-10-10 11:45:05 +00:00
|
|
|
mod_dir: ModDir,
|
2019-03-13 13:38:02 +00:00
|
|
|
}
|
|
|
|
|
2020-03-13 15:05:46 +00:00
|
|
|
impl ModCollector<'_, '_> {
|
2020-06-12 21:24:26 +00:00
|
|
|
fn collect(&mut self, items: &[ModItem]) {
|
2020-12-17 23:23:46 +00:00
|
|
|
let krate = self.def_collector.def_map.krate;
|
|
|
|
|
2019-10-10 11:45:05 +00:00
|
|
|
// 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());
|
|
|
|
|
2019-09-05 08:20:36 +00:00
|
|
|
// Prelude module is always considered to be `#[macro_use]`.
|
|
|
|
if let Some(prelude_module) = self.def_collector.def_map.prelude {
|
2021-05-20 17:56:04 +00:00
|
|
|
if prelude_module.krate != krate {
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(prelude_is_macro_use);
|
2019-10-31 15:45:10 +00:00
|
|
|
self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
|
2019-09-07 18:43:41 +00:00
|
|
|
}
|
2019-09-05 08:20:36 +00:00
|
|
|
}
|
|
|
|
|
2019-09-05 10:39:56 +00:00
|
|
|
// 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 {
|
2020-12-17 23:23:46 +00:00
|
|
|
let attrs = self.item_tree.attrs(self.def_collector.db, krate, (*item).into());
|
2020-10-22 17:19:18 +00:00
|
|
|
if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
|
2020-06-22 13:07:06 +00:00
|
|
|
if let ModItem::ExternCrate(id) = item {
|
|
|
|
let import = self.item_tree[*id].clone();
|
2020-12-18 19:37:26 +00:00
|
|
|
let attrs = self.item_tree.attrs(
|
|
|
|
self.def_collector.db,
|
|
|
|
krate,
|
|
|
|
ModItem::from(*id).into(),
|
|
|
|
);
|
|
|
|
if attrs.by_key("macro_use").exists() {
|
2019-09-29 22:52:15 +00:00
|
|
|
self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
|
|
|
|
}
|
2019-09-05 10:39:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 17:16:14 +00:00
|
|
|
for &item in items {
|
2020-12-17 23:23:46 +00:00
|
|
|
let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
|
2020-10-22 17:19:18 +00:00
|
|
|
if let Some(cfg) = attrs.cfg() {
|
|
|
|
if !self.is_cfg_enabled(&cfg) {
|
|
|
|
self.emit_unconfigured_diagnostic(item, &cfg);
|
|
|
|
continue;
|
|
|
|
}
|
2020-09-18 10:32:07 +00:00
|
|
|
}
|
2021-05-19 13:17:57 +00:00
|
|
|
|
2021-05-20 17:56:04 +00:00
|
|
|
if let Err(()) = self.resolve_attributes(&attrs, item) {
|
2021-05-19 21:35:09 +00:00
|
|
|
// Do not process the item. It has at least one non-builtin attribute, so the
|
|
|
|
// fixed-point algorithm is required to resolve the rest of them.
|
2021-05-19 13:17:57 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-01-25 14:21:33 +00:00
|
|
|
let module = self.def_collector.def_map.module_id(self.module_id);
|
2020-09-18 10:32:07 +00:00
|
|
|
|
|
|
|
let mut def = None;
|
|
|
|
match item {
|
2020-12-17 23:23:46 +00:00
|
|
|
ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs),
|
2020-09-18 10:32:07 +00:00
|
|
|
ModItem::Import(import_id) => {
|
2021-05-25 23:01:58 +00:00
|
|
|
let module_id = self.module_id;
|
|
|
|
let imports = Import::from_use(
|
|
|
|
self.def_collector.db,
|
|
|
|
krate,
|
|
|
|
&self.item_tree,
|
|
|
|
ItemTreeId::new(self.file_id, import_id),
|
|
|
|
);
|
|
|
|
self.def_collector.unresolved_imports.extend(imports.into_iter().map(
|
|
|
|
|import| ImportDirective {
|
|
|
|
module_id,
|
|
|
|
import,
|
|
|
|
status: PartialResolvedImport::Unresolved,
|
|
|
|
},
|
|
|
|
));
|
2020-09-18 10:32:07 +00:00
|
|
|
}
|
|
|
|
ModItem::ExternCrate(import_id) => {
|
|
|
|
self.def_collector.unresolved_imports.push(ImportDirective {
|
|
|
|
module_id: self.module_id,
|
|
|
|
import: Import::from_extern_crate(
|
2020-12-18 19:37:26 +00:00
|
|
|
self.def_collector.db,
|
|
|
|
krate,
|
2020-09-18 10:32:07 +00:00
|
|
|
&self.item_tree,
|
2021-03-12 23:34:01 +00:00
|
|
|
ItemTreeId::new(self.file_id, import_id),
|
2020-09-18 10:32:07 +00:00
|
|
|
),
|
|
|
|
status: PartialResolvedImport::Unresolved,
|
|
|
|
})
|
|
|
|
}
|
2021-05-21 16:27:25 +00:00
|
|
|
ModItem::ExternBlock(block) => self.collect(&self.item_tree[block].children),
|
2020-12-15 14:37:37 +00:00
|
|
|
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
|
2020-12-16 22:42:03 +00:00
|
|
|
ModItem::MacroRules(id) => self.collect_macro_rules(id),
|
2021-03-27 05:44:54 +00:00
|
|
|
ModItem::MacroDef(id) => self.collect_macro_def(id),
|
2020-09-18 10:32:07 +00:00
|
|
|
ModItem::Impl(imp) => {
|
2021-01-25 14:21:33 +00:00
|
|
|
let module = self.def_collector.def_map.module_id(self.module_id);
|
2021-03-09 18:09:02 +00:00
|
|
|
let impl_id =
|
|
|
|
ImplLoc { container: module, id: ItemTreeId::new(self.file_id, imp) }
|
|
|
|
.intern(self.def_collector.db);
|
2020-09-18 10:32:07 +00:00
|
|
|
self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
|
|
|
|
}
|
|
|
|
ModItem::Function(id) => {
|
|
|
|
let func = &self.item_tree[id];
|
2020-09-18 14:43:50 +00:00
|
|
|
|
2021-03-18 15:11:18 +00:00
|
|
|
let ast_id = InFile::new(self.file_id, func.ast_id);
|
|
|
|
self.collect_proc_macro_def(&func.name, ast_id, &attrs);
|
2020-09-18 14:43:50 +00:00
|
|
|
|
2020-09-18 10:32:07 +00:00
|
|
|
def = Some(DefData {
|
|
|
|
id: FunctionLoc {
|
2021-03-09 17:27:16 +00:00
|
|
|
container: module.into(),
|
2020-09-18 10:32:07 +00:00
|
|
|
id: ItemTreeId::new(self.file_id, id),
|
|
|
|
}
|
|
|
|
.intern(self.def_collector.db)
|
|
|
|
.into(),
|
|
|
|
name: &func.name,
|
|
|
|
visibility: &self.item_tree[func.visibility],
|
|
|
|
has_constructor: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
ModItem::Struct(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
2020-06-15 17:16:14 +00:00
|
|
|
|
2020-09-18 10:32:07 +00:00
|
|
|
def = Some(DefData {
|
2021-03-09 18:09:02 +00:00
|
|
|
id: StructLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
|
2020-09-18 10:32:07 +00:00
|
|
|
.intern(self.def_collector.db)
|
|
|
|
.into(),
|
|
|
|
name: &it.name,
|
|
|
|
visibility: &self.item_tree[it.visibility],
|
2021-05-21 19:08:06 +00:00
|
|
|
has_constructor: !matches!(it.fields, Fields::Record(_)),
|
2020-09-18 10:32:07 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
ModItem::Union(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
2020-06-15 17:16:14 +00:00
|
|
|
|
2020-09-18 10:32:07 +00:00
|
|
|
def = Some(DefData {
|
2021-03-09 18:09:02 +00:00
|
|
|
id: UnionLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
|
2020-09-18 10:32:07 +00:00
|
|
|
.intern(self.def_collector.db)
|
|
|
|
.into(),
|
|
|
|
name: &it.name,
|
|
|
|
visibility: &self.item_tree[it.visibility],
|
|
|
|
has_constructor: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
ModItem::Enum(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
2020-06-15 17:16:14 +00:00
|
|
|
|
2020-09-18 10:32:07 +00:00
|
|
|
def = Some(DefData {
|
2021-03-09 18:09:02 +00:00
|
|
|
id: EnumLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
|
2020-09-18 10:32:07 +00:00
|
|
|
.intern(self.def_collector.db)
|
|
|
|
.into(),
|
|
|
|
name: &it.name,
|
|
|
|
visibility: &self.item_tree[it.visibility],
|
|
|
|
has_constructor: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
ModItem::Const(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
2021-04-07 01:12:40 +00:00
|
|
|
let const_id = ConstLoc {
|
|
|
|
container: module.into(),
|
|
|
|
id: ItemTreeId::new(self.file_id, id),
|
|
|
|
}
|
|
|
|
.intern(self.def_collector.db);
|
|
|
|
|
|
|
|
match &it.name {
|
|
|
|
Some(name) => {
|
|
|
|
def = Some(DefData {
|
|
|
|
id: const_id.into(),
|
|
|
|
name,
|
|
|
|
visibility: &self.item_tree[it.visibility],
|
|
|
|
has_constructor: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
// const _: T = ...;
|
|
|
|
self.def_collector.def_map.modules[self.module_id]
|
|
|
|
.scope
|
|
|
|
.define_unnamed_const(const_id);
|
|
|
|
}
|
2020-06-15 17:16:14 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-18 10:32:07 +00:00
|
|
|
ModItem::Static(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
2020-06-15 17:16:14 +00:00
|
|
|
|
2020-09-18 10:32:07 +00:00
|
|
|
def = Some(DefData {
|
2021-03-09 18:09:02 +00:00
|
|
|
id: StaticLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
|
2020-09-18 10:32:07 +00:00
|
|
|
.intern(self.def_collector.db)
|
|
|
|
.into(),
|
|
|
|
name: &it.name,
|
|
|
|
visibility: &self.item_tree[it.visibility],
|
|
|
|
has_constructor: false,
|
|
|
|
});
|
2019-09-29 22:52:15 +00:00
|
|
|
}
|
2020-09-18 10:32:07 +00:00
|
|
|
ModItem::Trait(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
|
|
|
|
|
|
|
def = Some(DefData {
|
2021-03-09 18:09:02 +00:00
|
|
|
id: TraitLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
|
2020-09-18 10:32:07 +00:00
|
|
|
.intern(self.def_collector.db)
|
|
|
|
.into(),
|
|
|
|
name: &it.name,
|
|
|
|
visibility: &self.item_tree[it.visibility],
|
|
|
|
has_constructor: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
ModItem::TypeAlias(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
|
|
|
|
|
|
|
def = Some(DefData {
|
|
|
|
id: TypeAliasLoc {
|
2021-03-09 17:27:16 +00:00
|
|
|
container: module.into(),
|
2020-09-18 10:32:07 +00:00
|
|
|
id: ItemTreeId::new(self.file_id, id),
|
|
|
|
}
|
|
|
|
.intern(self.def_collector.db)
|
|
|
|
.into(),
|
|
|
|
name: &it.name,
|
|
|
|
visibility: &self.item_tree[it.visibility],
|
|
|
|
has_constructor: false,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(DefData { id, name, visibility, has_constructor }) = def {
|
|
|
|
self.def_collector.def_map.modules[self.module_id].scope.define_def(id);
|
|
|
|
let vis = self
|
|
|
|
.def_collector
|
|
|
|
.def_map
|
|
|
|
.resolve_visibility(self.def_collector.db, self.module_id, visibility)
|
|
|
|
.unwrap_or(Visibility::Public);
|
|
|
|
self.def_collector.update(
|
|
|
|
self.module_id,
|
|
|
|
&[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
|
|
|
|
vis,
|
|
|
|
ImportType::Named,
|
|
|
|
)
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-12 21:24:26 +00:00
|
|
|
fn collect_module(&mut self, module: &Mod, attrs: &Attrs) {
|
2019-11-24 13:03:02 +00:00
|
|
|
let path_attr = attrs.by_key("path").string_value();
|
|
|
|
let is_macro_use = attrs.by_key("macro_use").exists();
|
2020-06-15 17:16:14 +00:00
|
|
|
match &module.kind {
|
2019-07-13 18:51:20 +00:00
|
|
|
// inline module, just recurse
|
2020-06-15 17:16:14 +00:00
|
|
|
ModKind::Inline { items } => {
|
2019-12-26 14:49:13 +00:00
|
|
|
let module_id = self.push_child_module(
|
2020-06-15 17:16:14 +00:00
|
|
|
module.name.clone(),
|
|
|
|
AstId::new(self.file_id, module.ast_id),
|
2019-12-26 14:49:13 +00:00
|
|
|
None,
|
2020-06-24 13:36:18 +00:00
|
|
|
&self.item_tree[module.visibility],
|
2019-12-26 14:49:13 +00:00
|
|
|
);
|
2019-09-06 16:55:58 +00:00
|
|
|
|
2020-11-04 14:31:35 +00:00
|
|
|
if let Some(mod_dir) = self.mod_dir.descend_into_definition(&module.name, path_attr)
|
|
|
|
{
|
|
|
|
ModCollector {
|
|
|
|
def_collector: &mut *self.def_collector,
|
|
|
|
macro_depth: self.macro_depth,
|
|
|
|
module_id,
|
|
|
|
file_id: self.file_id,
|
|
|
|
item_tree: self.item_tree,
|
|
|
|
mod_dir,
|
|
|
|
}
|
|
|
|
.collect(&*items);
|
|
|
|
if is_macro_use {
|
|
|
|
self.import_all_legacy_macros(module_id);
|
|
|
|
}
|
2019-09-06 16:55:58 +00:00
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2019-07-13 18:51:20 +00:00
|
|
|
// out of line module, resolve, parse and recurse
|
2020-06-15 17:16:14 +00:00
|
|
|
ModKind::Outline {} => {
|
|
|
|
let ast_id = AstId::new(self.file_id, module.ast_id);
|
2021-01-31 18:26:04 +00:00
|
|
|
let db = self.def_collector.db;
|
|
|
|
match self.mod_dir.resolve_declaration(db, self.file_id, &module.name, path_attr) {
|
2020-06-11 09:04:09 +00:00
|
|
|
Ok((file_id, is_mod_rs, mod_dir)) => {
|
2021-03-13 01:24:26 +00:00
|
|
|
let item_tree = db.file_item_tree(file_id.into());
|
2021-03-19 17:24:04 +00:00
|
|
|
if item_tree
|
|
|
|
.top_level_attrs(db, self.def_collector.def_map.krate)
|
|
|
|
.cfg()
|
|
|
|
.map_or(true, |cfg| {
|
|
|
|
self.def_collector.cfg_options.check(&cfg) != Some(false)
|
|
|
|
})
|
2021-01-31 18:26:04 +00:00
|
|
|
{
|
2021-03-19 17:24:04 +00:00
|
|
|
let module_id = self.push_child_module(
|
|
|
|
module.name.clone(),
|
|
|
|
ast_id,
|
|
|
|
Some((file_id, is_mod_rs)),
|
|
|
|
&self.item_tree[module.visibility],
|
|
|
|
);
|
|
|
|
ModCollector {
|
|
|
|
def_collector: &mut *self.def_collector,
|
|
|
|
macro_depth: self.macro_depth,
|
|
|
|
module_id,
|
|
|
|
file_id: file_id.into(),
|
|
|
|
item_tree: &item_tree,
|
|
|
|
mod_dir,
|
|
|
|
}
|
|
|
|
.collect(item_tree.top_level_items());
|
|
|
|
if is_macro_use
|
|
|
|
|| item_tree
|
|
|
|
.top_level_attrs(db, self.def_collector.def_map.krate)
|
|
|
|
.by_key("macro_use")
|
|
|
|
.exists()
|
|
|
|
{
|
|
|
|
self.import_all_legacy_macros(module_id);
|
|
|
|
}
|
2019-09-06 16:55:58 +00:00
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2020-09-16 12:52:39 +00:00
|
|
|
Err(candidate) => {
|
|
|
|
self.def_collector.def_map.diagnostics.push(
|
|
|
|
DefDiagnostic::unresolved_module(self.module_id, ast_id, candidate),
|
|
|
|
);
|
|
|
|
}
|
2019-03-23 15:35:14 +00:00
|
|
|
};
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-13 13:38:02 +00:00
|
|
|
fn push_child_module(
|
|
|
|
&mut self,
|
|
|
|
name: Name,
|
2019-03-26 14:25:14 +00:00
|
|
|
declaration: AstId<ast::Module>,
|
2020-06-11 09:04:09 +00:00
|
|
|
definition: Option<(FileId, bool)>,
|
2019-12-26 14:57:14 +00:00
|
|
|
visibility: &crate::visibility::RawVisibility,
|
2019-11-23 13:49:53 +00:00
|
|
|
) -> LocalModuleId {
|
2019-12-26 14:49:13 +00:00
|
|
|
let vis = self
|
|
|
|
.def_collector
|
|
|
|
.def_map
|
|
|
|
.resolve_visibility(self.def_collector.db, self.module_id, visibility)
|
2019-12-26 15:00:10 +00:00
|
|
|
.unwrap_or(Visibility::Public);
|
2019-03-13 13:38:02 +00:00
|
|
|
let modules = &mut self.def_collector.def_map.modules;
|
|
|
|
let res = modules.alloc(ModuleData::default());
|
|
|
|
modules[res].parent = Some(self.module_id);
|
2020-06-18 14:02:45 +00:00
|
|
|
modules[res].origin = match definition {
|
|
|
|
None => ModuleOrigin::Inline { definition: declaration },
|
2020-06-11 09:04:09 +00:00
|
|
|
Some((definition, is_mod_rs)) => {
|
|
|
|
ModuleOrigin::File { declaration, definition, is_mod_rs }
|
|
|
|
}
|
2020-06-18 14:02:45 +00:00
|
|
|
};
|
2019-12-20 16:09:13 +00:00
|
|
|
for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() {
|
|
|
|
modules[res].scope.define_legacy_macro(name, mac)
|
|
|
|
}
|
2019-03-14 08:53:40 +00:00
|
|
|
modules[self.module_id].children.insert(name.clone(), res);
|
2021-01-25 14:21:33 +00:00
|
|
|
let module = self.def_collector.def_map.module_id(res);
|
2019-12-22 14:08:57 +00:00
|
|
|
let def: ModuleDefId = module.into();
|
2019-12-22 14:21:48 +00:00
|
|
|
self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
|
2020-06-25 01:42:44 +00:00
|
|
|
self.def_collector.update(
|
|
|
|
self.module_id,
|
2020-07-21 15:52:43 +00:00
|
|
|
&[(Some(name), PerNs::from_def(def, vis, false))],
|
2020-06-25 01:42:44 +00:00
|
|
|
vis,
|
2020-06-25 16:42:12 +00:00
|
|
|
ImportType::Named,
|
2020-06-25 01:42:44 +00:00
|
|
|
);
|
2019-03-02 20:59:04 +00:00
|
|
|
res
|
|
|
|
}
|
|
|
|
|
2021-05-19 13:17:57 +00:00
|
|
|
/// Resolves attributes on an item.
|
|
|
|
///
|
|
|
|
/// Returns `Err` when some attributes could not be resolved to builtins and have been
|
|
|
|
/// registered as unresolved.
|
2021-05-20 17:56:04 +00:00
|
|
|
///
|
|
|
|
/// If `ignore_up_to` is `Some`, attributes precending and including that attribute will be
|
|
|
|
/// assumed to be resolved already.
|
|
|
|
fn resolve_attributes(&mut self, attrs: &Attrs, mod_item: ModItem) -> Result<(), ()> {
|
|
|
|
let mut ignore_up_to =
|
2021-05-20 18:18:53 +00:00
|
|
|
self.def_collector.skip_attrs.get(&InFile::new(self.file_id, mod_item)).copied();
|
2021-05-22 00:30:03 +00:00
|
|
|
let iter = attrs
|
|
|
|
.iter()
|
|
|
|
.dedup_by(|a, b| {
|
|
|
|
// FIXME: this should not be required, all attributes on an item should have a
|
|
|
|
// unique ID!
|
|
|
|
// Still, this occurs because `#[cfg_attr]` can "expand" to multiple attributes:
|
|
|
|
// #[cfg_attr(not(off), unresolved, unresolved)]
|
|
|
|
// struct S;
|
|
|
|
// We should come up with a different way to ID attributes.
|
|
|
|
a.id == b.id
|
|
|
|
})
|
|
|
|
.skip_while(|attr| match ignore_up_to {
|
|
|
|
Some(id) if attr.id == id => {
|
|
|
|
ignore_up_to = None;
|
|
|
|
true
|
|
|
|
}
|
|
|
|
Some(_) => true,
|
|
|
|
None => false,
|
|
|
|
});
|
|
|
|
|
|
|
|
for attr in iter {
|
2021-05-20 17:56:04 +00:00
|
|
|
if attr.path.as_ident() == Some(&hir_expand::name![derive]) {
|
|
|
|
self.collect_derive(attr, mod_item);
|
2021-05-20 18:40:02 +00:00
|
|
|
} else if self.is_builtin_or_registered_attr(&attr.path) {
|
2021-05-20 17:56:04 +00:00
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
log::debug!("non-builtin attribute {}", attr.path);
|
2021-05-19 13:17:57 +00:00
|
|
|
|
|
|
|
let ast_id = AstIdWithPath::new(
|
|
|
|
self.file_id,
|
|
|
|
mod_item.ast_id(self.item_tree),
|
2021-05-20 17:56:04 +00:00
|
|
|
attr.path.as_ref().clone(),
|
2021-05-19 13:17:57 +00:00
|
|
|
);
|
2021-05-20 11:12:29 +00:00
|
|
|
self.def_collector.unresolved_macros.push(MacroDirective {
|
2021-05-19 13:17:57 +00:00
|
|
|
module_id: self.module_id,
|
|
|
|
depth: self.macro_depth + 1,
|
2021-05-31 11:37:11 +00:00
|
|
|
kind: MacroDirectiveKind::Attr { ast_id, attr: attr.clone(), mod_item },
|
2021-05-19 13:17:57 +00:00
|
|
|
});
|
|
|
|
|
2021-05-20 17:56:04 +00:00
|
|
|
return Err(());
|
2021-05-19 13:17:57 +00:00
|
|
|
}
|
|
|
|
}
|
2021-05-20 17:56:04 +00:00
|
|
|
|
|
|
|
Ok(())
|
2021-05-19 13:17:57 +00:00
|
|
|
}
|
|
|
|
|
2021-05-20 18:40:02 +00:00
|
|
|
fn is_builtin_or_registered_attr(&self, path: &ModPath) -> bool {
|
|
|
|
if path.kind == PathKind::Plain {
|
|
|
|
if let Some(tool_module) = path.segments().first() {
|
|
|
|
let tool_module = tool_module.to_string();
|
|
|
|
if builtin_attr::TOOL_MODULES
|
|
|
|
.iter()
|
|
|
|
.copied()
|
|
|
|
.chain(self.def_collector.registered_tools.iter().map(|s| &**s))
|
|
|
|
.any(|m| tool_module == *m)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(name) = path.as_ident() {
|
|
|
|
let name = name.to_string();
|
|
|
|
if builtin_attr::INERT_ATTRIBUTES
|
|
|
|
.iter()
|
|
|
|
.chain(builtin_attr::EXTRA_ATTRIBUTES)
|
|
|
|
.copied()
|
|
|
|
.chain(self.def_collector.registered_attrs.iter().map(|s| &**s))
|
|
|
|
.any(|attr| name == *attr)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
2021-05-20 17:56:04 +00:00
|
|
|
fn collect_derive(&mut self, attr: &Attr, mod_item: ModItem) {
|
|
|
|
let ast_id: FileAstId<ast::Item> = match mod_item {
|
|
|
|
ModItem::Struct(it) => self.item_tree[it].ast_id.upcast(),
|
|
|
|
ModItem::Union(it) => self.item_tree[it].ast_id.upcast(),
|
|
|
|
ModItem::Enum(it) => self.item_tree[it].ast_id.upcast(),
|
|
|
|
_ => {
|
|
|
|
// Cannot use derive on this item.
|
|
|
|
// FIXME: diagnose
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
match attr.parse_derive() {
|
|
|
|
Some(derive_macros) => {
|
|
|
|
for path in derive_macros {
|
|
|
|
let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
|
|
|
|
self.def_collector.unresolved_macros.push(MacroDirective {
|
|
|
|
module_id: self.module_id,
|
|
|
|
depth: self.macro_depth + 1,
|
|
|
|
kind: MacroDirectiveKind::Derive { ast_id, derive_attr: attr.id },
|
|
|
|
});
|
2020-12-19 00:09:48 +00:00
|
|
|
}
|
2019-12-05 14:10:33 +00:00
|
|
|
}
|
2021-05-20 17:56:04 +00:00
|
|
|
None => {
|
|
|
|
// FIXME: diagnose
|
|
|
|
log::debug!("malformed derive: {:?}", attr);
|
|
|
|
}
|
2019-12-05 14:10:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 14:43:50 +00:00
|
|
|
/// If `attrs` registers a procedural macro, collects its definition.
|
2021-03-18 15:11:18 +00:00
|
|
|
fn collect_proc_macro_def(&mut self, func_name: &Name, ast_id: AstId<ast::Fn>, attrs: &Attrs) {
|
2020-09-18 14:43:50 +00:00
|
|
|
// FIXME: this should only be done in the root module of `proc-macro` crates, not everywhere
|
2021-03-18 18:56:37 +00:00
|
|
|
if let Some(proc_macro) = attrs.parse_proc_macro_decl(func_name) {
|
|
|
|
self.def_collector.export_proc_macro(proc_macro, ast_id);
|
|
|
|
}
|
2020-09-18 14:43:50 +00:00
|
|
|
}
|
|
|
|
|
2020-12-16 22:42:03 +00:00
|
|
|
fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) {
|
2020-12-17 23:23:46 +00:00
|
|
|
let krate = self.def_collector.def_map.krate;
|
2020-12-16 22:42:03 +00:00
|
|
|
let mac = &self.item_tree[id];
|
2020-12-17 23:23:46 +00:00
|
|
|
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
|
2020-12-15 17:43:19 +00:00
|
|
|
let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
|
2019-10-29 08:15:51 +00:00
|
|
|
|
2020-12-16 22:42:03 +00:00
|
|
|
let export_attr = attrs.by_key("macro_export");
|
|
|
|
|
|
|
|
let is_export = export_attr.exists();
|
|
|
|
let is_local_inner = if is_export {
|
|
|
|
export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it {
|
|
|
|
tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
|
|
|
|
ident.text.contains("local_inner_macros")
|
|
|
|
}
|
|
|
|
_ => false,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
};
|
|
|
|
|
2020-12-15 14:37:37 +00:00
|
|
|
// Case 1: builtin macros
|
2020-12-16 22:42:03 +00:00
|
|
|
if attrs.by_key("rustc_builtin_macro").exists() {
|
2021-04-03 01:13:04 +00:00
|
|
|
// `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name.
|
|
|
|
let name;
|
|
|
|
let name = match attrs.by_key("rustc_builtin_macro").string_value() {
|
|
|
|
Some(it) => {
|
|
|
|
// FIXME: a hacky way to create a Name from string.
|
|
|
|
name = tt::Ident { text: it.clone(), id: tt::TokenId::unspecified() }.as_name();
|
|
|
|
&name
|
|
|
|
}
|
|
|
|
None => &mac.name,
|
|
|
|
};
|
2020-12-15 14:37:37 +00:00
|
|
|
let krate = self.def_collector.def_map.krate;
|
2021-05-30 02:19:47 +00:00
|
|
|
match find_builtin_macro(name, krate, ast_id) {
|
|
|
|
Some(macro_id) => {
|
|
|
|
self.def_collector.define_macro_rules(
|
|
|
|
self.module_id,
|
|
|
|
mac.name.clone(),
|
|
|
|
macro_id,
|
|
|
|
is_export,
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
self.def_collector
|
|
|
|
.def_map
|
|
|
|
.diagnostics
|
|
|
|
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
|
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-15 14:37:37 +00:00
|
|
|
// Case 2: normal `macro_rules!` macro
|
|
|
|
let macro_id = MacroDefId {
|
2020-12-15 19:33:05 +00:00
|
|
|
krate: self.def_collector.def_map.krate,
|
2021-03-18 14:37:14 +00:00
|
|
|
kind: MacroDefKind::Declarative(ast_id),
|
2020-12-16 22:42:03 +00:00
|
|
|
local_inner: is_local_inner,
|
2020-12-15 14:37:37 +00:00
|
|
|
};
|
2021-03-27 05:44:54 +00:00
|
|
|
self.def_collector.define_macro_rules(
|
|
|
|
self.module_id,
|
|
|
|
mac.name.clone(),
|
|
|
|
macro_id,
|
|
|
|
is_export,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>) {
|
|
|
|
let krate = self.def_collector.def_map.krate;
|
|
|
|
let mac = &self.item_tree[id];
|
|
|
|
let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
|
|
|
|
|
|
|
|
// Case 1: bulitin macros
|
|
|
|
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
|
|
|
|
if attrs.by_key("rustc_builtin_macro").exists() {
|
|
|
|
let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
|
|
|
|
.or_else(|| find_builtin_derive(&mac.name, krate, ast_id));
|
|
|
|
|
2021-05-30 02:19:47 +00:00
|
|
|
match macro_id {
|
|
|
|
Some(macro_id) => {
|
|
|
|
self.def_collector.define_macro_def(
|
|
|
|
self.module_id,
|
|
|
|
mac.name.clone(),
|
|
|
|
macro_id,
|
|
|
|
&self.item_tree[mac.visibility],
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
self.def_collector
|
|
|
|
.def_map
|
|
|
|
.diagnostics
|
|
|
|
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
|
|
|
|
}
|
2021-03-27 05:44:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Case 2: normal `macro`
|
|
|
|
let macro_id = MacroDefId {
|
|
|
|
krate: self.def_collector.def_map.krate,
|
|
|
|
kind: MacroDefKind::Declarative(ast_id),
|
|
|
|
local_inner: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
self.def_collector.define_macro_def(
|
|
|
|
self.module_id,
|
|
|
|
mac.name.clone(),
|
|
|
|
macro_id,
|
|
|
|
&self.item_tree[mac.visibility],
|
|
|
|
);
|
2020-12-15 14:37:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn collect_macro_call(&mut self, mac: &MacroCall) {
|
2021-04-01 18:35:21 +00:00
|
|
|
let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, (*mac.path).clone());
|
2020-12-15 14:37:37 +00:00
|
|
|
|
|
|
|
// Case 1: try to resolve in legacy scope and expand macro_rules
|
2021-03-14 05:28:10 +00:00
|
|
|
let mut error = None;
|
|
|
|
match macro_call_as_call_id(
|
2021-02-28 11:12:11 +00:00
|
|
|
&ast_id,
|
2021-05-08 23:36:06 +00:00
|
|
|
mac.fragment,
|
2021-02-28 11:12:11 +00:00
|
|
|
self.def_collector.db,
|
|
|
|
self.def_collector.def_map.krate,
|
|
|
|
|path| {
|
2020-06-11 10:08:24 +00:00
|
|
|
path.as_ident().and_then(|name| {
|
2021-02-04 12:44:54 +00:00
|
|
|
self.def_collector.def_map.with_ancestor_maps(
|
|
|
|
self.def_collector.db,
|
|
|
|
self.module_id,
|
|
|
|
&mut |map, module| map[module].scope.get_legacy_macro(&name),
|
|
|
|
)
|
2020-06-11 10:08:24 +00:00
|
|
|
})
|
2021-02-28 11:12:11 +00:00
|
|
|
},
|
2021-03-17 20:40:36 +00:00
|
|
|
&mut |err| {
|
|
|
|
error.get_or_insert(err);
|
|
|
|
},
|
2021-02-28 11:12:11 +00:00
|
|
|
) {
|
2021-03-14 05:28:10 +00:00
|
|
|
Ok(Ok(macro_call_id)) => {
|
2021-03-21 00:45:24 +00:00
|
|
|
// Legacy macros need to be expanded immediately, so that any macros they produce
|
|
|
|
// are in scope.
|
|
|
|
self.def_collector.collect_macro_expansion(
|
|
|
|
self.module_id,
|
|
|
|
macro_call_id,
|
|
|
|
self.macro_depth + 1,
|
|
|
|
);
|
2019-12-08 12:33:42 +00:00
|
|
|
|
2021-03-14 05:28:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
Ok(Err(_)) => {
|
|
|
|
// Built-in macro failed eager expansion.
|
2021-05-08 23:36:06 +00:00
|
|
|
|
|
|
|
// FIXME: don't parse the file here
|
|
|
|
let fragment = hir_expand::to_fragment_kind(
|
|
|
|
&ast_id.ast_id.to_node(self.def_collector.db.upcast()),
|
|
|
|
);
|
2021-03-14 05:28:10 +00:00
|
|
|
self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
|
|
|
|
self.module_id,
|
2021-05-08 23:36:06 +00:00
|
|
|
MacroCallKind::FnLike { ast_id: ast_id.ast_id, fragment },
|
2021-03-15 18:16:58 +00:00
|
|
|
error.unwrap().to_string(),
|
2021-03-14 05:28:10 +00:00
|
|
|
));
|
|
|
|
return;
|
|
|
|
}
|
2021-04-16 13:48:03 +00:00
|
|
|
Err(UnresolvedMacro { .. }) => (),
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 14:37:37 +00:00
|
|
|
// Case 2: resolve in module scope, expand during name resolution.
|
2019-09-06 18:44:26 +00:00
|
|
|
// We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
|
2020-02-17 04:57:24 +00:00
|
|
|
if ast_id.path.is_ident() {
|
|
|
|
ast_id.path.kind = PathKind::Super(0);
|
2019-09-06 18:44:26 +00:00
|
|
|
}
|
2019-12-08 12:33:42 +00:00
|
|
|
|
2021-05-20 11:12:29 +00:00
|
|
|
self.def_collector.unresolved_macros.push(MacroDirective {
|
2019-12-08 12:33:42 +00:00
|
|
|
module_id: self.module_id,
|
2020-03-13 12:57:44 +00:00
|
|
|
depth: self.macro_depth + 1,
|
2021-05-08 23:36:06 +00:00
|
|
|
kind: MacroDirectiveKind::FnLike { ast_id, fragment: mac.fragment },
|
2019-12-08 12:33:42 +00:00
|
|
|
});
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2019-09-06 16:55:58 +00:00
|
|
|
|
2019-11-23 13:49:53 +00:00
|
|
|
fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
|
2019-12-20 16:09:13 +00:00
|
|
|
let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros();
|
2019-09-06 16:55:58 +00:00
|
|
|
for (name, macro_) in macros {
|
2019-09-09 12:54:02 +00:00
|
|
|
self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
|
2019-09-06 16:55:58 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-29 22:52:15 +00:00
|
|
|
|
2020-10-22 17:19:18 +00:00
|
|
|
fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool {
|
|
|
|
self.def_collector.cfg_options.check(cfg) != Some(false)
|
2019-09-29 22:52:15 +00:00
|
|
|
}
|
2020-10-20 15:49:21 +00:00
|
|
|
|
2020-10-22 17:19:18 +00:00
|
|
|
fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
|
2020-10-20 15:49:21 +00:00
|
|
|
let ast_id = item.ast_id(self.item_tree);
|
|
|
|
|
2020-11-26 16:29:09 +00:00
|
|
|
let ast_id = InFile::new(self.file_id, ast_id);
|
2020-10-22 17:19:18 +00:00
|
|
|
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
|
|
|
|
self.module_id,
|
2020-11-26 16:29:09 +00:00
|
|
|
ast_id,
|
2020-10-22 17:19:18 +00:00
|
|
|
cfg.clone(),
|
|
|
|
self.def_collector.cfg_options.clone(),
|
|
|
|
));
|
2020-10-20 15:49:21 +00:00
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2019-11-03 17:53:17 +00:00
|
|
|
#[cfg(test)]
|
2019-04-22 07:33:55 +00:00
|
|
|
mod tests {
|
2019-12-08 12:33:42 +00:00
|
|
|
use crate::{db::DefDatabase, test_db::TestDB};
|
2020-08-13 14:25:38 +00:00
|
|
|
use base_db::{fixture::WithFixture, SourceDatabase};
|
2019-11-03 17:53:17 +00:00
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
2021-01-18 19:18:05 +00:00
|
|
|
fn do_collect_defs(db: &dyn DefDatabase, def_map: DefMap) -> DefMap {
|
2019-04-22 07:33:55 +00:00
|
|
|
let mut collector = DefCollector {
|
|
|
|
db,
|
|
|
|
def_map,
|
|
|
|
glob_imports: FxHashMap::default(),
|
|
|
|
unresolved_imports: Vec::new(),
|
2019-12-07 11:20:41 +00:00
|
|
|
resolved_imports: Vec::new(),
|
2021-05-20 11:12:29 +00:00
|
|
|
unresolved_macros: Vec::new(),
|
2019-10-10 11:45:05 +00:00
|
|
|
mod_dirs: FxHashMap::default(),
|
2019-09-29 22:52:15 +00:00
|
|
|
cfg_options: &CfgOptions::default(),
|
2020-03-25 12:14:22 +00:00
|
|
|
proc_macros: Default::default(),
|
2020-09-18 15:50:04 +00:00
|
|
|
exports_proc_macros: false,
|
2020-06-26 01:34:39 +00:00
|
|
|
from_glob_import: Default::default(),
|
2021-05-20 18:18:53 +00:00
|
|
|
skip_attrs: Default::default(),
|
2021-05-20 18:40:02 +00:00
|
|
|
derive_helpers_in_scope: Default::default(),
|
|
|
|
registered_attrs: Default::default(),
|
|
|
|
registered_tools: Default::default(),
|
2019-04-22 07:33:55 +00:00
|
|
|
};
|
2021-01-21 14:22:17 +00:00
|
|
|
collector.seed_with_top_level();
|
2019-04-22 07:33:55 +00:00
|
|
|
collector.collect();
|
2019-12-08 12:33:42 +00:00
|
|
|
collector.def_map
|
2019-04-22 07:33:55 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 19:18:05 +00:00
|
|
|
fn do_resolve(code: &str) -> DefMap {
|
2019-11-03 17:53:17 +00:00
|
|
|
let (db, _file_id) = TestDB::with_single_file(&code);
|
2019-11-15 10:16:16 +00:00
|
|
|
let krate = db.test_crate();
|
2019-04-22 07:33:55 +00:00
|
|
|
|
2021-01-21 14:22:17 +00:00
|
|
|
let edition = db.crate_graph()[krate].edition;
|
|
|
|
let def_map = DefMap::empty(krate, edition);
|
2019-12-08 12:33:42 +00:00
|
|
|
do_collect_defs(&db, def_map)
|
2019-04-22 07:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-03-13 12:57:44 +00:00
|
|
|
fn test_macro_expand_will_stop_1() {
|
|
|
|
do_resolve(
|
|
|
|
r#"
|
|
|
|
macro_rules! foo {
|
|
|
|
($($ty:ty)*) => { foo!($($ty)*); }
|
|
|
|
}
|
|
|
|
foo!(KABOOM);
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[ignore] // this test does succeed, but takes quite a while :/
|
|
|
|
#[test]
|
|
|
|
fn test_macro_expand_will_stop_2() {
|
2019-12-08 12:33:42 +00:00
|
|
|
do_resolve(
|
2019-04-22 07:33:55 +00:00
|
|
|
r#"
|
|
|
|
macro_rules! foo {
|
2020-03-13 12:57:44 +00:00
|
|
|
($($ty:ty)*) => { foo!($($ty)* $($ty)*); }
|
2019-04-22 07:33:55 +00:00
|
|
|
}
|
2020-03-13 12:57:44 +00:00
|
|
|
foo!(KABOOM);
|
2019-04-22 07:33:55 +00:00
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|