mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
Move collector
This commit is contained in:
parent
f9417bcf49
commit
9d24412929
1 changed files with 193 additions and 108 deletions
|
@ -4,6 +4,7 @@
|
|||
//! resolves imports and expands macros.
|
||||
|
||||
use hir_expand::{
|
||||
ast_id_map::FileAstId,
|
||||
builtin_derive::find_builtin_derive,
|
||||
builtin_macro::find_builtin_macro,
|
||||
name::{name, AsName, Name},
|
||||
|
@ -19,14 +20,14 @@ use test_utils::mark;
|
|||
use crate::{
|
||||
attr::Attrs,
|
||||
db::DefDatabase,
|
||||
item_tree::{Import, ItemTree, Mod, ModItem},
|
||||
item_tree::{Import, ItemTree, MacroCall, Mod, ModItem, ModKind, StructDefKind},
|
||||
nameres::{
|
||||
diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
|
||||
BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
|
||||
},
|
||||
path::{ImportAlias, ModPath, PathKind},
|
||||
per_ns::PerNs,
|
||||
visibility::Visibility,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
AdtId, AsMacroCall, AstId, AstIdWithPath, ConstLoc, ContainerId, EnumLoc, EnumVariantId,
|
||||
FunctionLoc, ImplLoc, Intern, LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc,
|
||||
TraitLoc, TypeAliasLoc, UnionLoc,
|
||||
|
@ -125,6 +126,13 @@ struct DeriveDirective {
|
|||
ast_id: AstIdWithPath<ast::ModuleItem>,
|
||||
}
|
||||
|
||||
struct DefData<'a> {
|
||||
id: ModuleDefId,
|
||||
name: &'a Name,
|
||||
visibility: &'a RawVisibility,
|
||||
has_constructor: bool,
|
||||
}
|
||||
|
||||
/// Walks the tree of module recursively
|
||||
struct DefCollector<'a> {
|
||||
db: &'a dyn DefDatabase,
|
||||
|
@ -693,9 +701,9 @@ impl ModCollector<'_, '_> {
|
|||
// `#[macro_use] extern crate` is hoisted to imports macros before collecting
|
||||
// any other items.
|
||||
for item in items {
|
||||
if self.is_cfg_enabled(&item.attrs) {
|
||||
if let raw::RawItemKind::Import(import_id) = item.kind {
|
||||
let import = self.item_tree[import_id].clone();
|
||||
if self.is_cfg_enabled(self.item_tree.attrs(*item)) {
|
||||
if let ModItem::Import(import_id) = item {
|
||||
let import = self.item_tree[*import_id].clone();
|
||||
if import.is_extern_crate && import.is_macro_use {
|
||||
self.def_collector.import_macros_from_extern_crate(self.module_id, &import);
|
||||
}
|
||||
|
@ -703,13 +711,17 @@ impl ModCollector<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
for item in items {
|
||||
if self.is_cfg_enabled(&item.attrs) {
|
||||
match item.kind {
|
||||
raw::RawItemKind::Module(m) => {
|
||||
self.collect_module(&self.item_tree[m], &item.attrs)
|
||||
}
|
||||
raw::RawItemKind::Import(import_id) => {
|
||||
for &item in items {
|
||||
let attrs = self.item_tree.attrs(item);
|
||||
if self.is_cfg_enabled(attrs) {
|
||||
let module =
|
||||
ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
|
||||
let container = ContainerId::ModuleId(module);
|
||||
|
||||
let mut def = None;
|
||||
match item {
|
||||
ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs),
|
||||
ModItem::Import(import_id) => {
|
||||
self.def_collector.unresolved_imports.push(ImportDirective {
|
||||
module_id: self.module_id,
|
||||
import_id,
|
||||
|
@ -717,11 +729,8 @@ impl ModCollector<'_, '_> {
|
|||
status: PartialResolvedImport::Unresolved,
|
||||
})
|
||||
}
|
||||
raw::RawItemKind::Def(def) => {
|
||||
self.define_def(&self.item_tree[def], &item.attrs)
|
||||
}
|
||||
raw::RawItemKind::Macro(mac) => self.collect_macro(&self.item_tree[mac]),
|
||||
raw::RawItemKind::Impl(imp) => {
|
||||
ModItem::MacroCall(mac) => self.collect_macro(&self.item_tree[mac]),
|
||||
ModItem::Impl(imp) => {
|
||||
let module = ModuleId {
|
||||
krate: self.def_collector.def_map.krate,
|
||||
local_id: self.module_id,
|
||||
|
@ -735,6 +744,147 @@ impl ModCollector<'_, '_> {
|
|||
.scope
|
||||
.define_impl(impl_id)
|
||||
}
|
||||
ModItem::Function(it) => {
|
||||
let it = &self.item_tree[it];
|
||||
def = Some(DefData {
|
||||
id: FunctionLoc {
|
||||
container: container.into(),
|
||||
ast_id: AstId::new(self.file_id, it.ast_id),
|
||||
}
|
||||
.intern(self.def_collector.db)
|
||||
.into(),
|
||||
name: &it.name,
|
||||
visibility: &it.visibility,
|
||||
has_constructor: false,
|
||||
});
|
||||
}
|
||||
ModItem::Struct(it) => {
|
||||
let it = &self.item_tree[it];
|
||||
|
||||
// FIXME: check attrs to see if this is an attribute macro invocation;
|
||||
// in which case we don't add the invocation, just a single attribute
|
||||
// macro invocation
|
||||
self.collect_derives(attrs, it.ast_id.upcast());
|
||||
|
||||
def = Some(DefData {
|
||||
id: StructLoc {
|
||||
container,
|
||||
ast_id: AstId::new(self.file_id, it.ast_id),
|
||||
}
|
||||
.intern(self.def_collector.db)
|
||||
.into(),
|
||||
name: &it.name,
|
||||
visibility: &it.visibility,
|
||||
has_constructor: it.kind != StructDefKind::Record,
|
||||
});
|
||||
}
|
||||
ModItem::Union(it) => {
|
||||
let it = &self.item_tree[it];
|
||||
|
||||
// FIXME: check attrs to see if this is an attribute macro invocation;
|
||||
// in which case we don't add the invocation, just a single attribute
|
||||
// macro invocation
|
||||
self.collect_derives(attrs, it.ast_id.upcast());
|
||||
|
||||
def = Some(DefData {
|
||||
id: UnionLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) }
|
||||
.intern(self.def_collector.db)
|
||||
.into(),
|
||||
name: &it.name,
|
||||
visibility: &it.visibility,
|
||||
has_constructor: false,
|
||||
});
|
||||
}
|
||||
ModItem::Enum(it) => {
|
||||
let it = &self.item_tree[it];
|
||||
|
||||
// FIXME: check attrs to see if this is an attribute macro invocation;
|
||||
// in which case we don't add the invocation, just a single attribute
|
||||
// macro invocation
|
||||
self.collect_derives(attrs, it.ast_id.upcast());
|
||||
|
||||
def = Some(DefData {
|
||||
id: EnumLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) }
|
||||
.intern(self.def_collector.db)
|
||||
.into(),
|
||||
name: &it.name,
|
||||
visibility: &it.visibility,
|
||||
has_constructor: false,
|
||||
});
|
||||
}
|
||||
ModItem::Const(it) => {
|
||||
let it = &self.item_tree[it];
|
||||
|
||||
if let Some(name) = &it.name {
|
||||
def = Some(DefData {
|
||||
id: ConstLoc {
|
||||
container: container.into(),
|
||||
ast_id: AstId::new(self.file_id, it.ast_id),
|
||||
}
|
||||
.intern(self.def_collector.db)
|
||||
.into(),
|
||||
name,
|
||||
visibility: &it.visibility,
|
||||
has_constructor: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
ModItem::Static(it) => {
|
||||
let it = &self.item_tree[it];
|
||||
|
||||
def = Some(DefData {
|
||||
id: StaticLoc {
|
||||
container,
|
||||
ast_id: AstId::new(self.file_id, it.ast_id),
|
||||
}
|
||||
.intern(self.def_collector.db)
|
||||
.into(),
|
||||
name: &it.name,
|
||||
visibility: &it.visibility,
|
||||
has_constructor: false,
|
||||
});
|
||||
}
|
||||
ModItem::Trait(it) => {
|
||||
let it = &self.item_tree[it];
|
||||
|
||||
def = Some(DefData {
|
||||
id: TraitLoc { container, ast_id: AstId::new(self.file_id, it.ast_id) }
|
||||
.intern(self.def_collector.db)
|
||||
.into(),
|
||||
name: &it.name,
|
||||
visibility: &it.visibility,
|
||||
has_constructor: false,
|
||||
});
|
||||
}
|
||||
ModItem::TypeAlias(it) => {
|
||||
let it = &self.item_tree[it];
|
||||
|
||||
def = Some(DefData {
|
||||
id: TypeAliasLoc {
|
||||
container: container.into(),
|
||||
ast_id: AstId::new(self.file_id, it.ast_id),
|
||||
}
|
||||
.intern(self.def_collector.db)
|
||||
.into(),
|
||||
name: &it.name,
|
||||
visibility: &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,
|
||||
&[(name.clone(), PerNs::from_def(id, vis, has_constructor))],
|
||||
vis,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -743,14 +893,14 @@ impl ModCollector<'_, '_> {
|
|||
fn collect_module(&mut self, module: &Mod, attrs: &Attrs) {
|
||||
let path_attr = attrs.by_key("path").string_value();
|
||||
let is_macro_use = attrs.by_key("macro_use").exists();
|
||||
match module {
|
||||
match &module.kind {
|
||||
// inline module, just recurse
|
||||
raw::ModuleData::Definition { name, visibility, items, ast_id } => {
|
||||
ModKind::Inline { items } => {
|
||||
let module_id = self.push_child_module(
|
||||
name.clone(),
|
||||
AstId::new(self.file_id, *ast_id),
|
||||
module.name.clone(),
|
||||
AstId::new(self.file_id, module.ast_id),
|
||||
None,
|
||||
&visibility,
|
||||
&module.visibility,
|
||||
);
|
||||
|
||||
ModCollector {
|
||||
|
@ -759,7 +909,7 @@ impl ModCollector<'_, '_> {
|
|||
module_id,
|
||||
file_id: self.file_id,
|
||||
item_tree: self.item_tree,
|
||||
mod_dir: self.mod_dir.descend_into_definition(name, path_attr),
|
||||
mod_dir: self.mod_dir.descend_into_definition(&module.name, path_attr),
|
||||
}
|
||||
.collect(&*items);
|
||||
if is_macro_use {
|
||||
|
@ -767,31 +917,31 @@ impl ModCollector<'_, '_> {
|
|||
}
|
||||
}
|
||||
// out of line module, resolve, parse and recurse
|
||||
raw::ModuleData::Declaration { name, visibility, ast_id } => {
|
||||
let ast_id = AstId::new(self.file_id, *ast_id);
|
||||
ModKind::Outline {} => {
|
||||
let ast_id = AstId::new(self.file_id, module.ast_id);
|
||||
match self.mod_dir.resolve_declaration(
|
||||
self.def_collector.db,
|
||||
self.file_id,
|
||||
name,
|
||||
&module.name,
|
||||
path_attr,
|
||||
) {
|
||||
Ok((file_id, is_mod_rs, mod_dir)) => {
|
||||
let module_id = self.push_child_module(
|
||||
name.clone(),
|
||||
module.name.clone(),
|
||||
ast_id,
|
||||
Some((file_id, is_mod_rs)),
|
||||
&visibility,
|
||||
&module.visibility,
|
||||
);
|
||||
let raw_items = self.def_collector.db.raw_items(file_id.into());
|
||||
let item_tree = self.def_collector.db.item_tree(file_id.into());
|
||||
ModCollector {
|
||||
def_collector: &mut *self.def_collector,
|
||||
macro_depth: self.macro_depth,
|
||||
module_id,
|
||||
file_id: file_id.into(),
|
||||
item_tree: &raw_items,
|
||||
item_tree: &item_tree,
|
||||
mod_dir,
|
||||
}
|
||||
.collect(raw_items.items());
|
||||
.collect(item_tree.top_level_items());
|
||||
if is_macro_use {
|
||||
self.import_all_legacy_macros(module_id);
|
||||
}
|
||||
|
@ -840,77 +990,7 @@ impl ModCollector<'_, '_> {
|
|||
res
|
||||
}
|
||||
|
||||
fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) {
|
||||
let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
|
||||
// FIXME: check attrs to see if this is an attribute macro invocation;
|
||||
// in which case we don't add the invocation, just a single attribute
|
||||
// macro invocation
|
||||
self.collect_derives(attrs, def);
|
||||
|
||||
let name = def.name.clone();
|
||||
let container = ContainerId::ModuleId(module);
|
||||
let vis = &def.visibility;
|
||||
let mut has_constructor = false;
|
||||
|
||||
let def: ModuleDefId = match def.kind {
|
||||
raw::DefKind::Function(ast_id) => FunctionLoc {
|
||||
container: container.into(),
|
||||
ast_id: AstId::new(self.file_id, ast_id),
|
||||
}
|
||||
.intern(self.def_collector.db)
|
||||
.into(),
|
||||
raw::DefKind::Struct(ast_id, mode) => {
|
||||
has_constructor = mode != raw::StructDefKind::Record;
|
||||
StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
|
||||
.intern(self.def_collector.db)
|
||||
.into()
|
||||
}
|
||||
raw::DefKind::Union(ast_id) => {
|
||||
UnionLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
|
||||
.intern(self.def_collector.db)
|
||||
.into()
|
||||
}
|
||||
raw::DefKind::Enum(ast_id) => {
|
||||
EnumLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
|
||||
.intern(self.def_collector.db)
|
||||
.into()
|
||||
}
|
||||
raw::DefKind::Const(ast_id) => {
|
||||
ConstLoc { container: container.into(), ast_id: AstId::new(self.file_id, ast_id) }
|
||||
.intern(self.def_collector.db)
|
||||
.into()
|
||||
}
|
||||
raw::DefKind::Static(ast_id) => {
|
||||
StaticLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
|
||||
.intern(self.def_collector.db)
|
||||
.into()
|
||||
}
|
||||
raw::DefKind::Trait(ast_id) => {
|
||||
TraitLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
|
||||
.intern(self.def_collector.db)
|
||||
.into()
|
||||
}
|
||||
raw::DefKind::TypeAlias(ast_id) => TypeAliasLoc {
|
||||
container: container.into(),
|
||||
ast_id: AstId::new(self.file_id, ast_id),
|
||||
}
|
||||
.intern(self.def_collector.db)
|
||||
.into(),
|
||||
};
|
||||
self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
|
||||
let vis = self
|
||||
.def_collector
|
||||
.def_map
|
||||
.resolve_visibility(self.def_collector.db, self.module_id, vis)
|
||||
.unwrap_or(Visibility::Public);
|
||||
self.def_collector.update(
|
||||
self.module_id,
|
||||
&[(name, PerNs::from_def(def, vis, has_constructor))],
|
||||
vis,
|
||||
)
|
||||
}
|
||||
|
||||
fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) {
|
||||
fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::ModuleItem>) {
|
||||
for derive_subtree in attrs.by_key("derive").tt_values() {
|
||||
// for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
|
||||
for tt in &derive_subtree.token_trees {
|
||||
|
@ -921,7 +1001,7 @@ impl ModCollector<'_, '_> {
|
|||
};
|
||||
let path = ModPath::from_tt_ident(ident);
|
||||
|
||||
let ast_id = AstIdWithPath::new(self.file_id, def.kind.ast_id(), path);
|
||||
let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
|
||||
self.def_collector
|
||||
.unexpanded_attribute_macros
|
||||
.push(DeriveDirective { module_id: self.module_id, ast_id });
|
||||
|
@ -929,11 +1009,11 @@ impl ModCollector<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_macro(&mut self, mac: &raw::MacroData) {
|
||||
fn collect_macro(&mut self, mac: &MacroCall) {
|
||||
let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
|
||||
|
||||
// Case 0: builtin macros
|
||||
if mac.builtin {
|
||||
if mac.is_builtin {
|
||||
if let Some(name) = &mac.name {
|
||||
let krate = self.def_collector.def_map.krate;
|
||||
if let Some(macro_id) = find_builtin_macro(name, krate, ast_id.ast_id) {
|
||||
|
@ -941,7 +1021,7 @@ impl ModCollector<'_, '_> {
|
|||
self.module_id,
|
||||
name.clone(),
|
||||
macro_id,
|
||||
mac.export,
|
||||
mac.is_export,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -955,9 +1035,14 @@ impl ModCollector<'_, '_> {
|
|||
ast_id: Some(ast_id.ast_id),
|
||||
krate: Some(self.def_collector.def_map.krate),
|
||||
kind: MacroDefKind::Declarative,
|
||||
local_inner: mac.local_inner,
|
||||
local_inner: mac.is_local_inner,
|
||||
};
|
||||
self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
|
||||
self.def_collector.define_macro(
|
||||
self.module_id,
|
||||
name.clone(),
|
||||
macro_id,
|
||||
mac.is_export,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue