diff options
| author | Chayim Refael Friedman <chayimfr@gmail.com> | 2025-05-21 13:13:34 +0300 |
|---|---|---|
| committer | Chayim Refael Friedman <chayimfr@gmail.com> | 2025-06-12 08:50:40 +0300 |
| commit | cd1298a2798c19dcb768290e0968468be5afe974 (patch) | |
| tree | db7c3127cb93b828ab548ab8cff4c3c39581d0a6 /src | |
| parent | 8e06cef0be365e128bdb3a1c4c728fc8664a51bb (diff) | |
| download | rust-cd1298a2798c19dcb768290e0968468be5afe974.tar.gz rust-cd1298a2798c19dcb768290e0968468be5afe974.zip | |
Avoid referring to the item tree except in the def map
Item tree IDs are very unstable (adding an item of a kind invalidates all following items of the same kind). Instead use ast ids, which, since the previous commit, are pretty stable.
Diffstat (limited to 'src')
37 files changed, 981 insertions, 955 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index bb6222b1d46..a7328809a82 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -14,6 +14,7 @@ use intern::{Symbol, sym}; use la_arena::{ArenaMap, Idx, RawIdx}; use mbe::DelimiterKind; use rustc_abi::ReprOptions; +use span::AstIdNode; use syntax::{ AstPtr, ast::{self, HasAttrs}, @@ -22,10 +23,10 @@ use triomphe::Arc; use tt::iter::{TtElement, TtIter}; use crate::{ - AdtId, AttrDefId, GenericParamId, HasModule, ItemTreeLoc, LocalFieldId, Lookup, MacroId, + AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId, VariantId, db::DefDatabase, - item_tree::{AttrOwner, FieldParent, ItemTreeNode}, + item_tree::AttrOwner, lang_item::LangItem, nameres::{ModuleOrigin, ModuleSource}, src::{HasChildSource, HasSource}, @@ -42,6 +43,15 @@ pub struct AttrsWithOwner { } impl Attrs { + pub fn new( + db: &dyn DefDatabase, + owner: &dyn ast::HasAttrs, + span_map: SpanMapRef<'_>, + cfg_options: &CfgOptions, + ) -> Self { + Attrs(RawAttrs::new_expanded(db, owner, span_map, cfg_options)) + } + pub fn get(&self, id: AttrId) -> Option<&Attr> { (**self).iter().find(|attr| attr.id == id) } @@ -94,44 +104,64 @@ impl Attrs { v: VariantId, ) -> Arc<ArenaMap<LocalFieldId, Attrs>> { let _p = tracing::info_span!("fields_attrs_query").entered(); - // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids let mut res = ArenaMap::default(); - let item_tree; - let (parent, fields, krate) = match v { + let (fields, file_id, krate) = match v { VariantId::EnumVariantId(it) => { let loc = it.lookup(db); let krate = loc.parent.lookup(db).container.krate; - item_tree = loc.id.item_tree(db); - let variant = &item_tree[loc.id.value]; - (FieldParent::EnumVariant(loc.id.value), &variant.fields, krate) + let source = loc.source(db); + (source.value.field_list(), source.file_id, krate) } VariantId::StructId(it) => { let loc = it.lookup(db); let krate = loc.container.krate; - item_tree = loc.id.item_tree(db); - let struct_ = &item_tree[loc.id.value]; - (FieldParent::Struct(loc.id.value), &struct_.fields, krate) + let source = loc.source(db); + (source.value.field_list(), source.file_id, krate) } VariantId::UnionId(it) => { let loc = it.lookup(db); let krate = loc.container.krate; - item_tree = loc.id.item_tree(db); - let union_ = &item_tree[loc.id.value]; - (FieldParent::Union(loc.id.value), &union_.fields, krate) + let source = loc.source(db); + ( + source.value.record_field_list().map(ast::FieldList::RecordFieldList), + source.file_id, + krate, + ) } }; + let Some(fields) = fields else { + return Arc::new(res); + }; let cfg_options = krate.cfg_options(db); - - let mut idx = 0; - for (id, _field) in fields.iter().enumerate() { - let attrs = item_tree.attrs(db, krate, AttrOwner::make_field_indexed(parent, id)); - if attrs.is_cfg_enabled(cfg_options) { - res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); - idx += 1; + let span_map = db.span_map(file_id); + + match fields { + ast::FieldList::RecordFieldList(fields) => { + let mut idx = 0; + for field in fields.fields() { + let attrs = + Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options)); + if attrs.is_cfg_enabled(cfg_options).is_ok() { + res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); + idx += 1; + } + } + } + ast::FieldList::TupleFieldList(fields) => { + let mut idx = 0; + for field in fields.fields() { + let attrs = + Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options)); + if attrs.is_cfg_enabled(cfg_options).is_ok() { + res.insert(Idx::from_raw(RawIdx::from(idx)), attrs); + idx += 1; + } + } } } + res.shrink_to_fit(); Arc::new(res) } } @@ -167,11 +197,10 @@ impl Attrs { } #[inline] - pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { - match self.cfg() { - None => true, - Some(cfg) => cfg_options.check(&cfg) != Some(false), - } + pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Result<(), CfgExpr> { + self.cfgs().try_for_each(|cfg| { + if cfg_options.check(&cfg) != Some(false) { Ok(()) } else { Err(cfg) } + }) } #[inline] @@ -488,12 +517,12 @@ impl AttrsWithOwner { pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { let _p = tracing::info_span!("attrs_query").entered(); // FIXME: this should use `Trace` to avoid duplication in `source_map` below - let raw_attrs = match def { + match def { AttrDefId::ModuleId(module) => { let def_map = module.def_map(db); let mod_data = &def_map[module.local_id]; - match mod_data.origin { + let raw_attrs = match mod_data.origin { ModuleOrigin::File { definition, declaration_tree_id, .. } => { let decl_attrs = declaration_tree_id .item_tree(db) @@ -515,34 +544,33 @@ impl AttrsWithOwner { let tree = db.block_item_tree(id); tree.raw_attrs(AttrOwner::TopLevel).clone() } - } - } - AttrDefId::FieldId(it) => { - return db.fields_attrs(it.parent)[it.local_id].clone(); + }; + Attrs::expand_cfg_attr(db, module.krate, raw_attrs) } - AttrDefId::EnumVariantId(it) => attrs_from_item_tree_loc(db, it), + AttrDefId::FieldId(it) => db.fields_attrs(it.parent)[it.local_id].clone(), + AttrDefId::EnumVariantId(it) => attrs_from_ast_id_loc(db, it), AttrDefId::AdtId(it) => match it { - AdtId::StructId(it) => attrs_from_item_tree_loc(db, it), - AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it), - AdtId::UnionId(it) => attrs_from_item_tree_loc(db, it), + AdtId::StructId(it) => attrs_from_ast_id_loc(db, it), + AdtId::EnumId(it) => attrs_from_ast_id_loc(db, it), + AdtId::UnionId(it) => attrs_from_ast_id_loc(db, it), }, - AttrDefId::TraitId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::TraitAliasId(it) => attrs_from_item_tree_loc(db, it), + AttrDefId::TraitId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::TraitAliasId(it) => attrs_from_ast_id_loc(db, it), AttrDefId::MacroId(it) => match it { - MacroId::Macro2Id(it) => attrs_from_item_tree_loc(db, it), - MacroId::MacroRulesId(it) => attrs_from_item_tree_loc(db, it), - MacroId::ProcMacroId(it) => attrs_from_item_tree_loc(db, it), + MacroId::Macro2Id(it) => attrs_from_ast_id_loc(db, it), + MacroId::MacroRulesId(it) => attrs_from_ast_id_loc(db, it), + MacroId::ProcMacroId(it) => attrs_from_ast_id_loc(db, it), }, - AttrDefId::ImplId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::ConstId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::StaticId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::FunctionId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::TypeAliasId(it) => attrs_from_item_tree_loc(db, it), + AttrDefId::ImplId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::ConstId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::StaticId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::FunctionId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::TypeAliasId(it) => attrs_from_ast_id_loc(db, it), AttrDefId::GenericParamId(it) => match it { GenericParamId::ConstParamId(it) => { let src = it.parent().child_source(db); // FIXME: We should be never getting `None` here. - return Attrs(match src.value.get(it.local_id()) { + Attrs(match src.value.get(it.local_id()) { Some(val) => RawAttrs::new_expanded( db, val, @@ -550,12 +578,12 @@ impl AttrsWithOwner { def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - }); + }) } GenericParamId::TypeParamId(it) => { let src = it.parent().child_source(db); // FIXME: We should be never getting `None` here. - return Attrs(match src.value.get(it.local_id()) { + Attrs(match src.value.get(it.local_id()) { Some(val) => RawAttrs::new_expanded( db, val, @@ -563,12 +591,12 @@ impl AttrsWithOwner { def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - }); + }) } GenericParamId::LifetimeParamId(it) => { let src = it.parent.child_source(db); // FIXME: We should be never getting `None` here. - return Attrs(match src.value.get(it.local_id) { + Attrs(match src.value.get(it.local_id) { Some(val) => RawAttrs::new_expanded( db, val, @@ -576,16 +604,13 @@ impl AttrsWithOwner { def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - }); + }) } }, - AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::ExternCrateId(it) => attrs_from_item_tree_loc(db, it), - AttrDefId::UseId(it) => attrs_from_item_tree_loc(db, it), - }; - - let attrs = raw_attrs.expand_cfg_attr(db, def.krate(db)); - Attrs(attrs) + AttrDefId::ExternBlockId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::ExternCrateId(it) => attrs_from_ast_id_loc(db, it), + AttrDefId::UseId(it) => attrs_from_ast_id_loc(db, it), + } } pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap { @@ -787,14 +812,15 @@ fn any_has_attrs<'db>( id.lookup(db).source(db).map(ast::AnyHasAttrs::new) } -fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>( +fn attrs_from_ast_id_loc<'db, N: AstIdNode + HasAttrs>( db: &(dyn DefDatabase + 'db), - lookup: impl Lookup<Database = dyn DefDatabase, Data = impl ItemTreeLoc<Id = N>>, -) -> RawAttrs { - let id = lookup.lookup(db).item_tree_id(); - let tree = id.item_tree(db); - let attr_owner = N::attr_owner(id.value); - tree.raw_attrs(attr_owner).clone() + lookup: impl Lookup<Database = dyn DefDatabase, Data = impl AstIdLoc<Ast = N> + HasModule>, +) -> Attrs { + let loc = lookup.lookup(db); + let source = loc.source(db); + let span_map = db.span_map(source.file_id); + let cfg_options = loc.krate(db).cfg_options(db); + Attrs(RawAttrs::new_expanded(db, &source.value, span_map.as_ref(), cfg_options)) } pub(crate) fn fields_attrs_source_map( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 4a9a3b12cfa..362c0daa9bb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -1,8 +1,11 @@ //! Defines database & queries for name resolution. use base_db::{Crate, RootQueryDb, SourceDatabase}; use either::Either; -use hir_expand::{EditionedFileId, HirFileId, MacroCallId, MacroDefId, db::ExpandDatabase}; -use intern::sym; +use hir_expand::{ + EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind, + db::ExpandDatabase, +}; +use intern::{Symbol, sym}; use la_arena::ArenaMap; use syntax::{AstPtr, ast}; use thin_vec::ThinVec; @@ -11,8 +14,8 @@ use triomphe::Arc; use crate::{ AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, - FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId, - MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, + FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander, + MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, attr::{Attrs, AttrsWithOwner}, @@ -123,6 +126,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { id: VariantId, ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>); + // FIXME: Should we make this transparent? The only unstable thing in `enum_variants_with_diagnostics()` + // is ast ids, and ast ids are pretty stable now. #[salsa::tracked] fn enum_variants(&self, id: EnumId) -> Arc<EnumVariants> { self.enum_variants_with_diagnostics(id).0 @@ -263,6 +268,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { e: TypeAliasId, ) -> (Arc<TypeAliasSignature>, Arc<ExpressionStoreSourceMap>); + #[salsa::invoke(crate::signatures::extern_block_abi_query)] + fn extern_block_abi(&self, extern_block: ExternBlockId) -> Option<Symbol>; + // endregion:data #[salsa::invoke(Body::body_with_source_map_query)] @@ -399,10 +407,6 @@ fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool { } fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { - use hir_expand::InFile; - - use crate::{Lookup, MacroDefKind, MacroExpander}; - let kind = |expander, file_id, m| { let in_file = InFile::new(file_id, m); match expander { @@ -418,11 +422,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { MacroId::Macro2Id(it) => { let loc: Macro2Loc = it.lookup(db); - let item_tree = loc.id.item_tree(db); - let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, - kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), + kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), local_inner: false, allow_internal_unsafe: loc.allow_internal_unsafe, edition: loc.edition, @@ -431,11 +433,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { MacroId::MacroRulesId(it) => { let loc: MacroRulesLoc = it.lookup(db); - let item_tree = loc.id.item_tree(db); - let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, - kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), + kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()), local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER), allow_internal_unsafe: loc .flags @@ -446,15 +446,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { MacroId::ProcMacroId(it) => { let loc = it.lookup(db); - let item_tree = loc.id.item_tree(db); - let makro = &item_tree[loc.id.value]; MacroDefId { krate: loc.container.krate, - kind: MacroDefKind::ProcMacro( - InFile::new(loc.id.file_id(), makro.ast_id), - loc.expander, - loc.kind, - ), + kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind), local_inner: false, allow_internal_unsafe: false, edition: loc.edition, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index 3823fb5a1e7..23b9712d1e6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -6,6 +6,7 @@ use base_db::Crate; use cfg::CfgOptions; use drop_bomb::DropBomb; use hir_expand::AstId; +use hir_expand::span_map::SpanMapRef; use hir_expand::{ ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId, eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap, @@ -223,9 +224,15 @@ impl Expander { } } + #[inline] pub(super) fn ast_id_map(&self) -> &AstIdMap { &self.ast_id_map } + + #[inline] + pub(super) fn span_map(&self) -> SpanMapRef<'_> { + self.span_map.as_ref() + } } #[derive(Debug)] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index b7a482a85db..89eeaf00bc3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -10,9 +10,10 @@ use std::mem; use cfg::CfgOptions; use either::Either; use hir_expand::{ - HirFileId, InFile, Lookup, MacroDefId, + HirFileId, InFile, MacroDefId, mod_path::tool_path, name::{AsName, Name}, + span_map::SpanMapRef, }; use intern::{Symbol, sym}; use rustc_hash::FxHashMap; @@ -30,8 +31,8 @@ use triomphe::Arc; use tt::TextRange; use crate::{ - AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, ItemTreeLoc, - MacroId, ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro, + AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId, + ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro, builtin_type::BuiltinUint, db::DefDatabase, expr_store::{ @@ -564,6 +565,11 @@ impl ExprCollector<'_> { } } + #[inline] + pub(crate) fn span_map(&self) -> SpanMapRef<'_> { + self.expander.span_map() + } + pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId { // FIXME: Keyword check? let lifetime_ref = match &*lifetime.text() { @@ -2244,11 +2250,8 @@ impl ExprCollector<'_> { match resolved.take_values() { Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())), Some(ModuleDefId::EnumVariantId(variant)) - if { - let loc = variant.lookup(self.db); - let tree = loc.item_tree_id().item_tree(self.db); - tree[loc.id.value].shape != FieldsShape::Record - } => + // FIXME: This can cause a cycle if the user is writing invalid code + if self.db.variant_fields(variant.into()).shape != FieldsShape::Record => { (None, Pat::Path(name.into())) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs index f12a9b7a544..7b452721dfe 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs @@ -9,9 +9,10 @@ use std::{ use hir_expand::{Lookup, mod_path::PathKind}; use itertools::Itertools; use span::Edition; +use syntax::ast::HasName; use crate::{ - AdtId, DefWithBodyId, GenericDefId, ItemTreeLoc, TypeParamId, VariantId, + AdtId, DefWithBodyId, GenericDefId, TypeParamId, VariantId, expr_store::path::{GenericArg, GenericArgs}, hir::{ Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement, @@ -19,6 +20,7 @@ use crate::{ }, lang_item::LangItemTarget, signatures::{FnFlags, FunctionSignature, StructSignature}, + src::HasSource, type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef}, }; use crate::{LifetimeParamId, signatures::StructFlags}; @@ -48,6 +50,17 @@ pub enum LineFormat { Indentation, } +fn item_name<Id, Loc>(db: &dyn DefDatabase, id: Id, default: &str) -> String +where + Id: Lookup<Database = dyn DefDatabase, Data = Loc>, + Loc: HasSource, + Loc::Value: ast::HasName, +{ + let loc = id.lookup(db); + let source = loc.source(db); + source.value.name().map_or_else(|| default.to_owned(), |name| name.to_string()) +} + pub fn print_body_hir( db: &dyn DefDatabase, body: &Body, @@ -55,31 +68,14 @@ pub fn print_body_hir( edition: Edition, ) -> String { let header = match owner { - DefWithBodyId::FunctionId(it) => { - it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db, edition))) - } - DefWithBodyId::StaticId(it) => it - .lookup(db) - .id - .resolved(db, |it| format!("static {} = ", it.name.display(db, edition))), - DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| { - format!( - "const {} = ", - match &it.name { - Some(name) => name.display(db, edition).to_string(), - None => "_".to_owned(), - } - ) - }), - DefWithBodyId::VariantId(it) => { - let loc = it.lookup(db); - let enum_loc = loc.parent.lookup(db); - format!( - "enum {}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), - loc.id.item_tree(db)[loc.id.value].name.display(db, edition), - ) - } + DefWithBodyId::FunctionId(it) => format!("fn {}", item_name(db, it, "<missing>")), + DefWithBodyId::StaticId(it) => format!("static {} = ", item_name(db, it, "<missing>")), + DefWithBodyId::ConstId(it) => format!("const {} = ", item_name(db, it, "_")), + DefWithBodyId::VariantId(it) => format!( + "enum {}::{}", + item_name(db, it.lookup(db).parent, "<missing>"), + item_name(db, it, "<missing>") + ), }; let mut p = Printer { @@ -116,22 +112,13 @@ pub fn print_body_hir( pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: Edition) -> String { let header = match owner { - VariantId::StructId(it) => { - it.lookup(db).id.resolved(db, |it| format!("struct {}", it.name.display(db, edition))) - } - VariantId::EnumVariantId(enum_variant_id) => { - let loc = enum_variant_id.lookup(db); - let enum_loc = loc.parent.lookup(db); - format!( - "enum {}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), - loc.id.item_tree(db)[loc.id.value].name.display(db, edition), - ) - } - VariantId::UnionId(union_id) => union_id - .lookup(db) - .id - .resolved(db, |it| format!("union {}", it.name.display(db, edition))), + VariantId::StructId(it) => format!("struct {}", item_name(db, it, "<missing>")), + VariantId::EnumVariantId(it) => format!( + "enum {}::{}", + item_name(db, it.lookup(db).parent, "<missing>"), + item_name(db, it, "<missing>") + ), + VariantId::UnionId(it) => format!("union {}", item_name(db, it, "<missing>")), }; let fields = db.variant_fields(owner); @@ -1089,10 +1076,7 @@ impl Printer<'_> { w!(self, "builtin#lang("); macro_rules! write_name { ($it:ident) => {{ - let loc = $it.lookup(self.db); - let tree = loc.item_tree_id().item_tree(self.db); - let name = &tree[loc.id.value].name; - w!(self, "{}", name.display(self.db, self.edition)); + w!(self, "{}", item_name(self.db, $it, "<missing>")); }}; } match *it { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 1b97eb72b6f..65dc35337a5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -46,7 +46,7 @@ use std::{ use ast::{AstNode, StructKind}; use base_db::Crate; use hir_expand::{ - ExpandTo, HirFileId, InFile, + ExpandTo, HirFileId, attrs::RawAttrs, mod_path::{ModPath, PathKind}, name::Name, @@ -62,6 +62,8 @@ use triomphe::Arc; use crate::{BlockId, Lookup, attr::Attrs, db::DefDatabase}; +pub(crate) use crate::item_tree::lower::{lower_use_tree, visibility_from_ast}; + #[derive(Copy, Clone, Eq, PartialEq)] pub struct RawVisibilityId(u32); @@ -446,6 +448,7 @@ impl TreeId { } } + #[inline] pub fn file_id(self) -> HirFileId { self.file } @@ -878,43 +881,6 @@ pub struct Macro2 { pub ast_id: FileAstId<ast::MacroDef>, } -impl Use { - /// Maps a `UseTree` contained in this import back to its AST node. - pub fn use_tree_to_ast( - &self, - db: &dyn DefDatabase, - file_id: HirFileId, - index: Idx<ast::UseTree>, - ) -> ast::UseTree { - // Re-lower the AST item and get the source map. - // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. - let ast = InFile::new(file_id, self.ast_id).to_node(db); - let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); - let (_, source_map) = lower::lower_use_tree(db, ast_use_tree, &mut |range| { - db.span_map(file_id).span_for_range(range).ctx - }) - .expect("failed to lower use tree"); - source_map[index].clone() - } - - /// Maps a `UseTree` contained in this import back to its AST node. - pub fn use_tree_source_map( - &self, - db: &dyn DefDatabase, - file_id: HirFileId, - ) -> Arena<ast::UseTree> { - // Re-lower the AST item and get the source map. - // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. - let ast = InFile::new(file_id, self.ast_id).to_node(db); - let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); - lower::lower_use_tree(db, ast_use_tree, &mut |range| { - db.span_map(file_id).span_for_range(range).ctx - }) - .expect("failed to lower use tree") - .1 - } -} - #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ImportKind { /// The `ModPath` is imported normally. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index b490e1683c0..57765427693 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -626,7 +626,7 @@ fn private_vis() -> RawVisibility { ) } -fn visibility_from_ast( +pub(crate) fn visibility_from_ast( db: &dyn DefDatabase, node: Option<ast::Visibility>, span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index 51172c0a1ee..8ff14751c67 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -258,7 +258,7 @@ impl Printer<'_> { let Enum { name, visibility, variants, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "enum {}", name.display(self.db, self.edition)); + w!(self, "enum {} {{", name.display(self.db, self.edition)); let edition = self.edition; self.indented(|this| { for variant in FileItemTreeId::range_iter(variants.clone()) { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs index abfff283ef6..7a85e8d175e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs @@ -147,7 +147,7 @@ enum E { } // AstId: Enum[7FF8, 0] - pub(self) enum E + pub(self) enum E { // AstId: Variant[C717, 0] #[doc = " comment on Unit"] Unit, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 4ad44775ea1..1614ef0da43 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -125,7 +125,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt } ModuleDefId::AdtId(AdtId::EnumId(e)) => { lang_items.collect_lang_item(db, e, LangItemTarget::EnumId); - db.enum_variants(e).variants.iter().for_each(|&(id, _)| { + db.enum_variants(e).variants.iter().for_each(|&(id, _, _)| { lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant); }); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 1e8859a9cc9..dcc18666a57 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -74,12 +74,11 @@ use hir_expand::{ name::Name, proc_macro::{CustomProcMacroExpander, ProcMacroKind}, }; -use item_tree::ExternBlock; use la_arena::Idx; use nameres::DefMap; use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; use stdx::impl_from; -use syntax::ast; +use syntax::{AstNode, ast}; pub use hir_expand::{Intern, Lookup, tt}; @@ -88,10 +87,6 @@ use crate::{ builtin_type::BuiltinType, db::DefDatabase, hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId}, - item_tree::{ - Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules, - Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant, - }, nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map}, signatures::VariantFields, }; @@ -113,70 +108,110 @@ pub struct ImportPathConfig { } #[derive(Debug)] -pub struct ItemLoc<N: ItemTreeNode> { +pub struct ItemLoc<N: AstIdNode> { pub container: ModuleId, - pub id: ItemTreeId<N>, + pub id: AstId<N>, } -impl<N: ItemTreeNode> Clone for ItemLoc<N> { +impl<N: AstIdNode> Clone for ItemLoc<N> { fn clone(&self) -> Self { *self } } -impl<N: ItemTreeNode> Copy for ItemLoc<N> {} +impl<N: AstIdNode> Copy for ItemLoc<N> {} -impl<N: ItemTreeNode> PartialEq for ItemLoc<N> { +impl<N: AstIdNode> PartialEq for ItemLoc<N> { fn eq(&self, other: &Self) -> bool { self.container == other.container && self.id == other.id } } -impl<N: ItemTreeNode> Eq for ItemLoc<N> {} +impl<N: AstIdNode> Eq for ItemLoc<N> {} -impl<N: ItemTreeNode> Hash for ItemLoc<N> { +impl<N: AstIdNode> Hash for ItemLoc<N> { fn hash<H: Hasher>(&self, state: &mut H) { self.container.hash(state); self.id.hash(state); } } +impl<N: AstIdNode> HasModule for ItemLoc<N> { + #[inline] + fn module(&self, _db: &dyn DefDatabase) -> ModuleId { + self.container + } +} + #[derive(Debug)] -pub struct AssocItemLoc<N: ItemTreeNode> { +pub struct AssocItemLoc<N: AstIdNode> { pub container: ItemContainerId, - pub id: ItemTreeId<N>, + pub id: AstId<N>, } -impl<N: ItemTreeNode> Clone for AssocItemLoc<N> { +impl<N: AstIdNode> Clone for AssocItemLoc<N> { fn clone(&self) -> Self { *self } } -impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {} +impl<N: AstIdNode> Copy for AssocItemLoc<N> {} -impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> { +impl<N: AstIdNode> PartialEq for AssocItemLoc<N> { fn eq(&self, other: &Self) -> bool { self.container == other.container && self.id == other.id } } -impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {} +impl<N: AstIdNode> Eq for AssocItemLoc<N> {} -impl<N: ItemTreeNode> Hash for AssocItemLoc<N> { +impl<N: AstIdNode> Hash for AssocItemLoc<N> { fn hash<H: Hasher>(&self, state: &mut H) { self.container.hash(state); self.id.hash(state); } } -pub trait ItemTreeLoc { +impl<N: AstIdNode> HasModule for AssocItemLoc<N> { + #[inline] + fn module(&self, db: &dyn DefDatabase) -> ModuleId { + self.container.module(db) + } +} + +pub trait AstIdLoc { type Container; - type Id; - fn item_tree_id(&self) -> ItemTreeId<Self::Id>; + type Ast: AstNode; + fn ast_id(&self) -> AstId<Self::Ast>; fn container(&self) -> Self::Container; } +impl<N: AstIdNode> AstIdLoc for ItemLoc<N> { + type Container = ModuleId; + type Ast = N; + #[inline] + fn ast_id(&self) -> AstId<Self::Ast> { + self.id + } + #[inline] + fn container(&self) -> Self::Container { + self.container + } +} + +impl<N: AstIdNode> AstIdLoc for AssocItemLoc<N> { + type Container = ItemContainerId; + type Ast = N; + #[inline] + fn ast_id(&self) -> AstId<Self::Ast> { + self.id + } + #[inline] + fn container(&self) -> Self::Container { + self.container + } +} + macro_rules! impl_intern { ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => { impl_intern_key!($id, $loc); @@ -186,74 +221,68 @@ macro_rules! impl_intern { macro_rules! impl_loc { ($loc:ident, $id:ident: $id_ty:ident, $container:ident: $container_type:ident) => { - impl ItemTreeLoc for $loc { + impl AstIdLoc for $loc { type Container = $container_type; - type Id = $id_ty; - fn item_tree_id(&self) -> ItemTreeId<Self::Id> { + type Ast = ast::$id_ty; + fn ast_id(&self) -> AstId<Self::Ast> { self.$id } fn container(&self) -> Self::Container { self.$container } } + + impl HasModule for $loc { + #[inline] + fn module(&self, db: &dyn DefDatabase) -> ModuleId { + self.$container.module(db) + } + } }; } -type FunctionLoc = AssocItemLoc<Function>; +type FunctionLoc = AssocItemLoc<ast::Fn>; impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function); -impl_loc!(FunctionLoc, id: Function, container: ItemContainerId); -type StructLoc = ItemLoc<Struct>; +type StructLoc = ItemLoc<ast::Struct>; impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct); -impl_loc!(StructLoc, id: Struct, container: ModuleId); -pub type UnionLoc = ItemLoc<Union>; +pub type UnionLoc = ItemLoc<ast::Union>; impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union); -impl_loc!(UnionLoc, id: Union, container: ModuleId); -pub type EnumLoc = ItemLoc<Enum>; +pub type EnumLoc = ItemLoc<ast::Enum>; impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum); -impl_loc!(EnumLoc, id: Enum, container: ModuleId); -type ConstLoc = AssocItemLoc<Const>; +type ConstLoc = AssocItemLoc<ast::Const>; impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const); -impl_loc!(ConstLoc, id: Const, container: ItemContainerId); -pub type StaticLoc = AssocItemLoc<Static>; +pub type StaticLoc = AssocItemLoc<ast::Static>; impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static); -impl_loc!(StaticLoc, id: Static, container: ItemContainerId); -pub type TraitLoc = ItemLoc<Trait>; +pub type TraitLoc = ItemLoc<ast::Trait>; impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait); -impl_loc!(TraitLoc, id: Trait, container: ModuleId); -pub type TraitAliasLoc = ItemLoc<TraitAlias>; +pub type TraitAliasLoc = ItemLoc<ast::TraitAlias>; impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias); -impl_loc!(TraitAliasLoc, id: TraitAlias, container: ModuleId); -type TypeAliasLoc = AssocItemLoc<TypeAlias>; +type TypeAliasLoc = AssocItemLoc<ast::TypeAlias>; impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias); -impl_loc!(TypeAliasLoc, id: TypeAlias, container: ItemContainerId); -type ImplLoc = ItemLoc<Impl>; +type ImplLoc = ItemLoc<ast::Impl>; impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl); -impl_loc!(ImplLoc, id: Impl, container: ModuleId); -type UseLoc = ItemLoc<Use>; +type UseLoc = ItemLoc<ast::Use>; impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use); -impl_loc!(UseLoc, id: Use, container: ModuleId); -type ExternCrateLoc = ItemLoc<ExternCrate>; +type ExternCrateLoc = ItemLoc<ast::ExternCrate>; impl_intern!(ExternCrateId, ExternCrateLoc, intern_extern_crate, lookup_intern_extern_crate); -impl_loc!(ExternCrateLoc, id: ExternCrate, container: ModuleId); -type ExternBlockLoc = ItemLoc<ExternBlock>; +type ExternBlockLoc = ItemLoc<ast::ExternBlock>; impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block); -impl_loc!(ExternBlockLoc, id: ExternBlock, container: ModuleId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumVariantLoc { - pub id: ItemTreeId<Variant>, + pub id: AstId<ast::Variant>, pub parent: EnumId, pub index: u32, } @@ -262,18 +291,18 @@ impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Macro2Loc { pub container: ModuleId, - pub id: ItemTreeId<Macro2>, + pub id: AstId<ast::MacroDef>, pub expander: MacroExpander, pub allow_internal_unsafe: bool, pub edition: Edition, } impl_intern!(Macro2Id, Macro2Loc, intern_macro2, lookup_intern_macro2); -impl_loc!(Macro2Loc, id: Macro2, container: ModuleId); +impl_loc!(Macro2Loc, id: MacroDef, container: ModuleId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroRulesLoc { pub container: ModuleId, - pub id: ItemTreeId<MacroRules>, + pub id: AstId<ast::MacroRules>, pub expander: MacroExpander, pub flags: MacroRulesLocFlags, pub edition: Edition, @@ -301,13 +330,13 @@ pub enum MacroExpander { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ProcMacroLoc { pub container: CrateRootModuleId, - pub id: ItemTreeId<Function>, + pub id: AstId<ast::Fn>, pub expander: CustomProcMacroExpander, pub kind: ProcMacroKind, pub edition: Edition, } impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro); -impl_loc!(ProcMacroLoc, id: Function, container: CrateRootModuleId); +impl_loc!(ProcMacroLoc, id: Fn, container: CrateRootModuleId); #[derive(Debug, Hash, PartialEq, Eq, Clone)] pub struct BlockLoc { @@ -338,6 +367,18 @@ impl CrateRootModuleId { } } +impl HasModule for CrateRootModuleId { + #[inline] + fn module(&self, _db: &dyn DefDatabase) -> ModuleId { + ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT } + } + + #[inline] + fn krate(&self, _db: &dyn DefDatabase) -> Crate { + self.krate + } +} + impl PartialEq<ModuleId> for CrateRootModuleId { fn eq(&self, other: &ModuleId) -> bool { other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate @@ -466,6 +507,13 @@ impl ModuleId { } } +impl HasModule for ModuleId { + #[inline] + fn module(&self, _db: &dyn DefDatabase) -> ModuleId { + *self + } +} + /// An ID of a module, **local** to a `DefMap`. pub type LocalModuleId = Idx<nameres::ModuleData>; @@ -642,15 +690,10 @@ impl GeneralConstId { pub fn name(self, db: &dyn DefDatabase) -> String { match self { GeneralConstId::StaticId(it) => { - let loc = it.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - let name = tree[loc.id.value].name.display(db, Edition::CURRENT); - name.to_string() + db.static_signature(it).name.display(db, Edition::CURRENT).to_string() } GeneralConstId::ConstId(const_id) => { - let loc = const_id.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - tree[loc.id.value].name.as_ref().map_or_else( + db.const_signature(const_id).name.as_ref().map_or_else( || "_".to_owned(), |name| name.display(db, Edition::CURRENT).to_string(), ) @@ -768,8 +811,8 @@ impl GenericDefId { GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it), - GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None), - GenericDefId::StaticId(it) => (it.lookup(db).id.file_id(), None), + GenericDefId::ConstId(it) => (it.lookup(db).id.file_id, None), + GenericDefId::StaticId(it) => (it.lookup(db).id.file_id, None), } } @@ -935,9 +978,9 @@ impl VariantId { pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId { match self { - VariantId::EnumVariantId(it) => it.lookup(db).id.file_id(), - VariantId::StructId(it) => it.lookup(db).id.file_id(), - VariantId::UnionId(it) => it.lookup(db).id.file_id(), + VariantId::EnumVariantId(it) => it.lookup(db).id.file_id, + VariantId::StructId(it) => it.lookup(db).id.file_id, + VariantId::UnionId(it) => it.lookup(db).id.file_id, } } @@ -977,7 +1020,7 @@ pub trait HasModule { impl<N, ItemId> HasModule for ItemId where - N: ItemTreeNode, + N: AstIdNode, ItemId: Lookup<Database = dyn DefDatabase, Data = ItemLoc<N>> + Copy, { #[inline] @@ -1003,7 +1046,7 @@ where #[inline] fn module_for_assoc_item_loc<'db>( db: &(dyn 'db + DefDatabase), - id: impl Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<impl ItemTreeNode>>, + id: impl Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<impl AstIdNode>>, ) -> ModuleId { id.lookup(db).container.module(db) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index f337f83156a..c908e457540 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -171,12 +171,10 @@ pub struct DefMap { /// ExternCrateId being None implies it being imported from the general prelude import. macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>, - // FIXME: AstId's are fairly unstable /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper /// attributes. // FIXME: Figure out a better way for the IDE layer to resolve these? derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>, - // FIXME: AstId's are fairly unstable /// A mapping from [`hir_expand::MacroDefId`] to [`crate::MacroId`]. pub macro_def_to_macro_id: FxHashMap<ErasedAstId, MacroId>, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs index 86225d33b4e..cf123d14f50 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs @@ -1,14 +1,28 @@ //! Expansion of associated items -use hir_expand::{AstId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind, name::Name}; -use syntax::ast; +use std::mem; + +use cfg::CfgOptions; +use hir_expand::{ + AstId, ExpandTo, HirFileId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind, + mod_path::ModPath, + name::{AsName, Name}, + span_map::SpanMap, +}; +use intern::Interned; +use span::AstIdMap; +use syntax::{ + AstNode, + ast::{self, HasModuleItem, HasName}, +}; +use thin_vec::ThinVec; use triomphe::Arc; use crate::{ AssocItemId, AstIdWithPath, ConstLoc, FunctionId, FunctionLoc, ImplId, ItemContainerId, ItemLoc, MacroCallId, ModuleId, TraitId, TypeAliasId, TypeAliasLoc, + attr::Attrs, db::DefDatabase, - item_tree::{AssocItem, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId}, macro_call_as_call_id, nameres::{ DefMap, LocalDefMap, MacroSubNs, @@ -20,9 +34,8 @@ use crate::{ #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraitItems { pub items: Box<[(Name, AssocItemId)]>, - // box it as the vec is usually empty anyways - // FIXME: AstIds are rather unstable... - pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, + // `ThinVec` as the vec is usually empty anyways + pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>, } impl TraitItems { @@ -35,12 +48,12 @@ impl TraitItems { db: &dyn DefDatabase, tr: TraitId, ) -> (Arc<TraitItems>, DefDiagnostics) { - let ItemLoc { container: module_id, id: tree_id } = tr.lookup(db); + let ItemLoc { container: module_id, id: ast_id } = tr.lookup(db); - let collector = AssocItemCollector::new(db, module_id, ItemContainerId::TraitId(tr)); - let item_tree = tree_id.item_tree(db); - let (items, macro_calls, diagnostics) = - collector.collect(&item_tree, tree_id.tree_id(), &item_tree[tree_id.value].items); + let collector = + AssocItemCollector::new(db, module_id, ItemContainerId::TraitId(tr), ast_id.file_id); + let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db); + let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list()); (Arc::new(TraitItems { macro_calls, items }), DefDiagnostics::new(diagnostics)) } @@ -76,16 +89,15 @@ impl TraitItems { } pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ { - self.macro_calls.iter().flat_map(|it| it.iter()).copied() + self.macro_calls.iter().copied() } } #[derive(Debug, PartialEq, Eq)] pub struct ImplItems { pub items: Box<[(Name, AssocItemId)]>, - // box it as the vec is usually empty anyways - // FIXME: AstIds are rather unstable... - pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, + // `ThinVec` as the vec is usually empty anyways + pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>, } impl ImplItems { @@ -99,18 +111,18 @@ impl ImplItems { id: ImplId, ) -> (Arc<ImplItems>, DefDiagnostics) { let _p = tracing::info_span!("impl_items_with_diagnostics_query").entered(); - let ItemLoc { container: module_id, id: tree_id } = id.lookup(db); + let ItemLoc { container: module_id, id: ast_id } = id.lookup(db); - let collector = AssocItemCollector::new(db, module_id, ItemContainerId::ImplId(id)); - let item_tree = tree_id.item_tree(db); - let (items, macro_calls, diagnostics) = - collector.collect(&item_tree, tree_id.tree_id(), &item_tree[tree_id.value].items); + let collector = + AssocItemCollector::new(db, module_id, ItemContainerId::ImplId(id), ast_id.file_id); + let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db); + let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list()); (Arc::new(ImplItems { items, macro_calls }), DefDiagnostics::new(diagnostics)) } pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ { - self.macro_calls.iter().flat_map(|it| it.iter()).copied() + self.macro_calls.iter().copied() } } @@ -119,67 +131,73 @@ struct AssocItemCollector<'a> { module_id: ModuleId, def_map: &'a DefMap, local_def_map: &'a LocalDefMap, + ast_id_map: Arc<AstIdMap>, + span_map: SpanMap, + cfg_options: &'a CfgOptions, + file_id: HirFileId, diagnostics: Vec<DefDiagnostic>, container: ItemContainerId, depth: usize, items: Vec<(Name, AssocItemId)>, - macro_calls: Vec<(AstId<ast::Item>, MacroCallId)>, + macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>, } impl<'a> AssocItemCollector<'a> { - fn new(db: &'a dyn DefDatabase, module_id: ModuleId, container: ItemContainerId) -> Self { + fn new( + db: &'a dyn DefDatabase, + module_id: ModuleId, + container: ItemContainerId, + file_id: HirFileId, + ) -> Self { let (def_map, local_def_map) = module_id.local_def_map(db); Self { db, module_id, def_map, local_def_map, + ast_id_map: db.ast_id_map(file_id), + span_map: db.span_map(file_id), + cfg_options: module_id.krate.cfg_options(db), + file_id, container, items: Vec::new(), depth: 0, - macro_calls: Vec::new(), + macro_calls: ThinVec::new(), diagnostics: Vec::new(), } } fn collect( mut self, - item_tree: &ItemTree, - tree_id: TreeId, - assoc_items: &[AssocItem], - ) -> ( - Box<[(Name, AssocItemId)]>, - Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, - Vec<DefDiagnostic>, - ) { - self.items.reserve(assoc_items.len()); - for &item in assoc_items { - self.collect_item(item_tree, tree_id, item); + item_list: Option<ast::AssocItemList>, + ) -> (Box<[(Name, AssocItemId)]>, ThinVec<(AstId<ast::Item>, MacroCallId)>, Vec<DefDiagnostic>) + { + if let Some(item_list) = item_list { + for item in item_list.assoc_items() { + self.collect_item(item); + } } - ( - self.items.into_boxed_slice(), - if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) }, - self.diagnostics, - ) + self.macro_calls.shrink_to_fit(); + (self.items.into_boxed_slice(), self.macro_calls, self.diagnostics) } - fn collect_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem) { - let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into()); - if !attrs.is_cfg_enabled(self.module_id.krate.cfg_options(self.db)) { + fn collect_item(&mut self, item: ast::AssocItem) { + let ast_id = self.ast_id_map.ast_id(&item); + let attrs = Attrs::new(self.db, &item, self.span_map.as_ref(), self.cfg_options); + if let Err(cfg) = attrs.is_cfg_enabled(self.cfg_options) { self.diagnostics.push(DefDiagnostic::unconfigured_code( self.module_id.local_id, - tree_id, - ModItem::from(item).into(), - attrs.cfg().unwrap(), - self.module_id.krate.cfg_options(self.db).clone(), + InFile::new(self.file_id, ast_id.erase()), + cfg, + self.cfg_options.clone(), )); return; } + let ast_id = InFile::new(self.file_id, ast_id.upcast()); 'attrs: for attr in &*attrs { - let ast_id = AstId::new(tree_id.file_id(), item.ast_id(item_tree).upcast()); let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id }; match self.def_map.resolve_attr_macro( @@ -223,34 +241,51 @@ impl<'a> AssocItemCollector<'a> { } } - self.record_item(item_tree, tree_id, item); + self.record_item(item); } - fn record_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem) { + fn record_item(&mut self, item: ast::AssocItem) { match item { - AssocItem::Function(id) => { - let item = &item_tree[id]; - let def = - FunctionLoc { container: self.container, id: ItemTreeId::new(tree_id, id) } - .intern(self.db); - self.items.push((item.name.clone(), def.into())); + ast::AssocItem::Fn(function) => { + let Some(name) = function.name() else { return }; + let ast_id = self.ast_id_map.ast_id(&function); + let def = FunctionLoc { + container: self.container, + id: InFile::new(self.file_id, ast_id), + } + .intern(self.db); + self.items.push((name.as_name(), def.into())); + } + ast::AssocItem::TypeAlias(type_alias) => { + let Some(name) = type_alias.name() else { return }; + let ast_id = self.ast_id_map.ast_id(&type_alias); + let def = TypeAliasLoc { + container: self.container, + id: InFile::new(self.file_id, ast_id), + } + .intern(self.db); + self.items.push((name.as_name(), def.into())); } - AssocItem::TypeAlias(id) => { - let item = &item_tree[id]; + ast::AssocItem::Const(konst) => { + let Some(name) = konst.name() else { return }; + let ast_id = self.ast_id_map.ast_id(&konst); let def = - TypeAliasLoc { container: self.container, id: ItemTreeId::new(tree_id, id) } + ConstLoc { container: self.container, id: InFile::new(self.file_id, ast_id) } .intern(self.db); - self.items.push((item.name.clone(), def.into())); - } - AssocItem::Const(id) => { - let item = &item_tree[id]; - let Some(name) = item.name.clone() else { return }; - let def = ConstLoc { container: self.container, id: ItemTreeId::new(tree_id, id) } - .intern(self.db); - self.items.push((name, def.into())); + self.items.push((name.as_name(), def.into())); } - AssocItem::MacroCall(call) => { - let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call]; + ast::AssocItem::MacroCall(call) => { + let ast_id = self.ast_id_map.ast_id(&call); + let ast_id = InFile::new(self.file_id, ast_id); + let Some(path) = call.path() else { return }; + let range = path.syntax().text_range(); + let Some(path) = ModPath::from_src(self.db, path, &mut |range| { + self.span_map.span_for_range(range).ctx + }) else { + return; + }; + let path = Interned::new(path); + let ctxt = self.span_map.span_for_range(range).ctx; let resolver = |path: &_| { self.def_map @@ -268,10 +303,10 @@ impl<'a> AssocItemCollector<'a> { }; match macro_call_as_call_id( self.db, - InFile::new(tree_id.file_id(), ast_id), - path, + ast_id, + &path, ctxt, - expand_to, + ExpandTo::Items, self.module_id.krate(), resolver, &mut |ptr, call_id| { @@ -281,8 +316,7 @@ impl<'a> AssocItemCollector<'a> { // FIXME: Expansion error? Ok(call_id) => match call_id.value { Some(call_id) => { - self.macro_calls - .push((InFile::new(tree_id.file_id(), ast_id.upcast()), call_id)); + self.macro_calls.push((ast_id.upcast(), call_id)); self.collect_macro_items(call_id); } None => (), @@ -291,11 +325,11 @@ impl<'a> AssocItemCollector<'a> { self.diagnostics.push(DefDiagnostic::unresolved_macro_call( self.module_id.local_id, MacroCallKind::FnLike { - ast_id: InFile::new(tree_id.file_id(), ast_id), - expand_to, + ast_id, + expand_to: ExpandTo::Items, eager: None, }, - Clone::clone(path), + (*path).clone(), )); } } @@ -308,13 +342,29 @@ impl<'a> AssocItemCollector<'a> { tracing::warn!("macro expansion is too deep"); return; } - let tree_id = TreeId::new(macro_call_id.into(), None); - let item_tree = self.db.file_item_tree(macro_call_id.into()); + let (syntax, span_map) = self.db.parse_macro_expansion(macro_call_id).value; + let old_file_id = mem::replace(&mut self.file_id, macro_call_id.into()); + let old_ast_id_map = mem::replace(&mut self.ast_id_map, self.db.ast_id_map(self.file_id)); + let old_span_map = mem::replace(&mut self.span_map, SpanMap::ExpansionSpanMap(span_map)); self.depth += 1; - for item in item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item) { - self.collect_item(&item_tree, tree_id, item); + + let items = ast::MacroItems::cast(syntax.syntax_node()).expect("not `MacroItems`"); + for item in items.items() { + let item = match item { + ast::Item::Fn(it) => ast::AssocItem::from(it), + ast::Item::Const(it) => it.into(), + ast::Item::TypeAlias(it) => it.into(), + ast::Item::MacroCall(it) => it.into(), + // FIXME: Should error on disallowed item kinds. + _ => continue, + }; + self.collect_item(item); } + self.depth -= 1; + self.file_id = old_file_id; + self.ast_id_map = old_ast_id_map; + self.span_map = old_span_map; } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 350c97c3982..34a129a88ea 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -9,8 +9,8 @@ use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin}; use cfg::{CfgAtom, CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ - EditionedFileId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, - MacroDefKind, + EditionedFileId, ErasedAstId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, + MacroDefId, MacroDefKind, attrs::{Attr, AttrId}, builtin::{find_builtin_attr, find_builtin_derive, find_builtin_macro}, mod_path::{ModPath, PathKind}, @@ -35,9 +35,8 @@ use crate::{ db::DefDatabase, item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports}, item_tree::{ - self, AttrOwner, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, - ItemTreeId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, - UseTreeKind, + self, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree, ItemTreeId, + ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, }, macro_call_as_call_id, nameres::{ @@ -141,6 +140,7 @@ struct ImportSource { id: UseId, is_prelude: bool, kind: ImportKind, + item_tree_id: ItemTreeId<item_tree::Use>, } #[derive(Debug, Eq, PartialEq)] @@ -166,7 +166,7 @@ impl Import { path, alias, visibility: visibility.clone(), - source: ImportSource { use_tree: idx, id, is_prelude, kind }, + source: ImportSource { use_tree: idx, id, is_prelude, kind, item_tree_id }, }); }); } @@ -576,13 +576,7 @@ impl DefCollector<'_> { /// 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. - fn export_proc_macro( - &mut self, - def: ProcMacroDef, - id: ItemTreeId<item_tree::Function>, - ast_id: AstId<ast::Fn>, - fn_id: FunctionId, - ) { + fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>, fn_id: FunctionId) { let kind = def.kind.to_basedb_kind(); let (expander, kind) = match self.proc_macros.iter().find(|(n, _, _)| n == &def.name) { Some(_) @@ -598,7 +592,7 @@ impl DefCollector<'_> { let proc_macro_id = ProcMacroLoc { container: self.def_map.crate_root(), - id, + id: ast_id, expander, kind, edition: self.def_map.data.edition, @@ -866,6 +860,7 @@ impl DefCollector<'_> { kind: kind @ (ImportKind::Plain | ImportKind::TypeOnly), id, use_tree, + item_tree_id, .. } => { let name = match &import.alias { @@ -887,9 +882,33 @@ impl DefCollector<'_> { let imp = ImportOrExternCrate::Import(ImportId { use_: id, idx: use_tree }); tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); + // `extern crate crate_name` things can be re-exported as `pub use crate_name`. + // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name` + // or `pub use ::crate_name`. + // + // This has been historically allowed, but may be not allowed in future + // https://github.com/rust-lang/rust/issues/127909 + if let Some(def) = def.types.as_mut() { + let is_extern_crate_reimport_without_prefix = || { + let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else { + return false; + }; + let item_tree = item_tree_id.item_tree(self.db); + let use_kind = item_tree[item_tree_id.value].use_tree.kind(); + let UseTreeKind::Single { path, .. } = use_kind else { + return false; + }; + matches!(path.kind, PathKind::Plain | PathKind::SELF) + && path.segments().len() < 2 + }; + if is_extern_crate_reimport_without_prefix() { + def.vis = vis; + } + } + self.update(module_id, &[(name.cloned(), def)], vis, Some(imp)); } - ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree } => { + ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree, .. } => { tracing::debug!("glob import: {:?}", import); let glob = GlobId { use_: id, idx: use_tree }; match def.take_types() { @@ -978,7 +997,7 @@ impl DefCollector<'_> { .enum_variants(e) .variants .iter() - .map(|&(variant, ref name)| { + .map(|&(variant, ref name, _)| { let res = PerNs::both(variant.into(), variant.into(), vis, None); (Some(name.clone()), res) }) @@ -1150,33 +1169,8 @@ impl DefCollector<'_> { vis: Visibility, def_import_type: Option<ImportOrExternCrate>, ) -> bool { - // `extern crate crate_name` things can be re-exported as `pub use crate_name`. - // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name` - // or `pub use ::crate_name`. - // - // This has been historically allowed, but may be not allowed in future - // https://github.com/rust-lang/rust/issues/127909 if let Some(def) = defs.types.as_mut() { - let is_extern_crate_reimport_without_prefix = || { - let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else { - return false; - }; - let Some(ImportOrExternCrate::Import(id)) = def_import_type else { - return false; - }; - let use_id = id.use_.lookup(self.db).id; - let item_tree = use_id.item_tree(self.db); - let use_kind = item_tree[use_id.value].use_tree.kind(); - let UseTreeKind::Single { path, .. } = use_kind else { - return false; - }; - path.segments().len() < 2 - }; - if is_extern_crate_reimport_without_prefix() { - def.vis = vis; - } else { - def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis); - } + def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis); } if let Some(def) = defs.values.as_mut() { def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis); @@ -1648,7 +1642,8 @@ impl DefCollector<'_> { import: Import { ref path, - source: ImportSource { use_tree, id, is_prelude: _, kind: _ }, + source: + ImportSource { use_tree, id, is_prelude: _, kind: _, item_tree_id: _ }, .. }, .. @@ -1730,7 +1725,26 @@ impl ModCollector<'_, '_> { let attrs = self.item_tree.attrs(db, krate, item.into()); if let Some(cfg) = attrs.cfg() { if !self.is_cfg_enabled(&cfg) { - self.emit_unconfigured_diagnostic(self.tree_id, item.into(), &cfg); + let ast_id = match item { + ModItem::Use(it) => self.item_tree[it].ast_id.erase(), + ModItem::ExternCrate(it) => self.item_tree[it].ast_id.erase(), + ModItem::ExternBlock(it) => self.item_tree[it].ast_id.erase(), + ModItem::Function(it) => self.item_tree[it].ast_id.erase(), + ModItem::Struct(it) => self.item_tree[it].ast_id.erase(), + ModItem::Union(it) => self.item_tree[it].ast_id.erase(), + ModItem::Enum(it) => self.item_tree[it].ast_id.erase(), + ModItem::Const(it) => self.item_tree[it].ast_id.erase(), + ModItem::Static(it) => self.item_tree[it].ast_id.erase(), + ModItem::Trait(it) => self.item_tree[it].ast_id.erase(), + ModItem::TraitAlias(it) => self.item_tree[it].ast_id.erase(), + ModItem::Impl(it) => self.item_tree[it].ast_id.erase(), + ModItem::TypeAlias(it) => self.item_tree[it].ast_id.erase(), + ModItem::Mod(it) => self.item_tree[it].ast_id.erase(), + ModItem::MacroCall(it) => self.item_tree[it].ast_id.erase(), + ModItem::MacroRules(it) => self.item_tree[it].ast_id.erase(), + ModItem::Macro2(it) => self.item_tree[it].ast_id.erase(), + }; + self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg); return; } } @@ -1751,7 +1765,7 @@ impl ModCollector<'_, '_> { ModItem::Use(item_tree_id) => { let id = UseLoc { container: module, - id: ItemTreeId::new(self.tree_id, item_tree_id), + id: InFile::new(self.file_id(), self.item_tree[item_tree_id].ast_id), } .intern(db); let is_prelude = attrs.by_key(sym::prelude_import).exists(); @@ -1770,16 +1784,16 @@ impl ModCollector<'_, '_> { ) } ModItem::ExternCrate(item_tree_id) => { + let item_tree::ExternCrate { name, visibility, alias, ast_id } = + &self.item_tree[item_tree_id]; + let id = ExternCrateLoc { container: module, - id: ItemTreeId::new(self.tree_id, item_tree_id), + id: InFile::new(self.tree_id.file_id(), *ast_id), } .intern(db); def_map.modules[self.module_id].scope.define_extern_crate_decl(id); - let item_tree::ExternCrate { name, visibility, alias, ast_id } = - &self.item_tree[item_tree_id]; - let is_self = *name == sym::self_; let resolved = if is_self { cov_mark::hit!(extern_crate_self_as); @@ -1846,7 +1860,7 @@ impl ModCollector<'_, '_> { ModItem::ExternBlock(block) => { let extern_block_id = ExternBlockLoc { container: module, - id: ItemTreeId::new(self.tree_id, block), + id: InFile::new(self.file_id(), self.item_tree[block].ast_id), } .intern(db); self.def_collector.def_map.modules[self.module_id] @@ -1861,15 +1875,20 @@ impl ModCollector<'_, '_> { ModItem::MacroRules(id) => self.collect_macro_rules(id, module), ModItem::Macro2(id) => self.collect_macro_def(id, module), ModItem::Impl(imp) => { - let impl_id = - ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) } - .intern(db); + let impl_id = ImplLoc { + container: module, + id: InFile::new(self.file_id(), self.item_tree[imp].ast_id), + } + .intern(db); self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id) } ModItem::Function(id) => { let it = &self.item_tree[id]; - let fn_id = - FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db); + let fn_id = FunctionLoc { + container, + id: InFile::new(self.tree_id.file_id(), it.ast_id), + } + .intern(db); let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); @@ -1880,7 +1899,6 @@ impl ModCollector<'_, '_> { if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) { self.def_collector.export_proc_macro( proc_macro, - ItemTreeId::new(self.tree_id, id), InFile::new(self.file_id(), self.item_tree[id].ast_id()), fn_id, ); @@ -1895,7 +1913,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } + StructLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) } .intern(db) .into(), &it.name, @@ -1909,7 +1927,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } + UnionLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) } .intern(db) .into(), &it.name, @@ -1919,9 +1937,11 @@ impl ModCollector<'_, '_> { } ModItem::Enum(id) => { let it = &self.item_tree[id]; - let enum_ = - EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } - .intern(db); + let enum_ = EnumLoc { + container: module, + id: InFile::new(self.tree_id.file_id(), it.ast_id), + } + .intern(db); let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def(self.def_collector, enum_.into(), &it.name, vis, false); @@ -1929,7 +1949,8 @@ impl ModCollector<'_, '_> { ModItem::Const(id) => { let it = &self.item_tree[id]; let const_id = - ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db); + ConstLoc { container, id: InFile::new(self.tree_id.file_id(), it.ast_id) } + .intern(db); match &it.name { Some(name) => { @@ -1951,7 +1972,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) } + StaticLoc { container, id: InFile::new(self.file_id(), it.ast_id) } .intern(db) .into(), &it.name, @@ -1965,7 +1986,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } + TraitLoc { container: module, id: InFile::new(self.file_id(), it.ast_id) } .intern(db) .into(), &it.name, @@ -1979,9 +2000,12 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - TraitAliasLoc { container: module, id: ItemTreeId::new(self.tree_id, id) } - .intern(db) - .into(), + TraitAliasLoc { + container: module, + id: InFile::new(self.file_id(), it.ast_id), + } + .intern(db) + .into(), &it.name, vis, false, @@ -1993,7 +2017,7 @@ impl ModCollector<'_, '_> { let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]); update_def( self.def_collector, - TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) } + TypeAliasLoc { container, id: InFile::new(self.file_id(), it.ast_id) } .intern(db) .into(), &it.name, @@ -2110,8 +2134,10 @@ impl ModCollector<'_, '_> { match is_enabled { Err(cfg) => { self.emit_unconfigured_diagnostic( - self.tree_id, - AttrOwner::ModItem(module_id.into()), + InFile::new( + self.file_id(), + self.item_tree[module_id].ast_id.erase(), + ), &cfg, ); } @@ -2352,7 +2378,7 @@ impl ModCollector<'_, '_> { let macro_id = MacroRulesLoc { container: module, - id: ItemTreeId::new(self.tree_id, id), + id: InFile::new(self.file_id(), mac.ast_id), flags, expander, edition: self.def_collector.def_map.data.edition, @@ -2420,7 +2446,7 @@ impl ModCollector<'_, '_> { let macro_id = Macro2Loc { container: module, - id: ItemTreeId::new(self.tree_id, id), + id: InFile::new(self.file_id(), mac.ast_id), expander, allow_internal_unsafe, edition: self.def_collector.def_map.data.edition, @@ -2565,16 +2591,16 @@ impl ModCollector<'_, '_> { self.def_collector.cfg_options.check(cfg) != Some(false) } - fn emit_unconfigured_diagnostic(&mut self, tree_id: TreeId, item: AttrOwner, cfg: &CfgExpr) { + fn emit_unconfigured_diagnostic(&mut self, ast_id: ErasedAstId, cfg: &CfgExpr) { self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code( self.module_id, - tree_id, - item, + ast_id, cfg.clone(), self.def_collector.cfg_options.clone(), )); } + #[inline] fn file_id(&self) -> HirFileId { self.tree_id.file_id() } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs index de3d2f48367..c495a074491 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs @@ -3,22 +3,18 @@ use std::ops::Not; use cfg::{CfgExpr, CfgOptions}; -use hir_expand::{ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath}; +use hir_expand::{ErasedAstId, ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath}; use la_arena::Idx; use syntax::ast; -use crate::{ - AstId, - item_tree::{self, AttrOwner, ItemTreeId, TreeId}, - nameres::LocalModuleId, -}; +use crate::{AstId, nameres::LocalModuleId}; #[derive(Debug, PartialEq, Eq)] pub enum DefDiagnosticKind { UnresolvedModule { ast: AstId<ast::Module>, candidates: Box<[String]> }, UnresolvedExternCrate { ast: AstId<ast::ExternCrate> }, - UnresolvedImport { id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree> }, - UnconfiguredCode { tree: TreeId, item: AttrOwner, cfg: CfgExpr, opts: CfgOptions }, + UnresolvedImport { id: AstId<ast::Use>, index: Idx<ast::UseTree> }, + UnconfiguredCode { ast_id: ErasedAstId, cfg: CfgExpr, opts: CfgOptions }, UnresolvedMacroCall { ast: MacroCallKind, path: ModPath }, UnimplementedBuiltinMacro { ast: AstId<ast::Macro> }, InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize }, @@ -28,7 +24,7 @@ pub enum DefDiagnosticKind { } #[derive(Clone, Debug, PartialEq, Eq)] -pub struct DefDiagnostics(Option<triomphe::Arc<Box<[DefDiagnostic]>>>); +pub struct DefDiagnostics(Option<triomphe::ThinArc<(), DefDiagnostic>>); impl DefDiagnostics { pub fn new(diagnostics: Vec<DefDiagnostic>) -> Self { @@ -36,12 +32,12 @@ impl DefDiagnostics { diagnostics .is_empty() .not() - .then(|| triomphe::Arc::new(diagnostics.into_boxed_slice())), + .then(|| triomphe::ThinArc::from_header_and_iter((), diagnostics.into_iter())), ) } pub fn iter(&self) -> impl Iterator<Item = &DefDiagnostic> { - self.0.as_ref().into_iter().flat_map(|it| &***it) + self.0.as_ref().into_iter().flat_map(|it| &it.slice) } } @@ -75,7 +71,7 @@ impl DefDiagnostic { pub(super) fn unresolved_import( container: LocalModuleId, - id: ItemTreeId<item_tree::Use>, + id: AstId<ast::Use>, index: Idx<ast::UseTree>, ) -> Self { Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } } @@ -92,14 +88,13 @@ impl DefDiagnostic { pub fn unconfigured_code( container: LocalModuleId, - tree: TreeId, - item: AttrOwner, + ast_id: ErasedAstId, cfg: CfgExpr, opts: CfgOptions, ) -> Self { Self { in_module: container, - kind: DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts }, + kind: DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts }, } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index 74ce33a6419..e0e32a77735 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -12,7 +12,6 @@ use either::Either; use hir_expand::{ - Lookup, mod_path::{ModPath, PathKind}, name::Name, }; @@ -529,23 +528,22 @@ impl DefMap { // enum variant cov_mark::hit!(can_import_enum_variant); - let res = - db.enum_variants(e).variants.iter().find(|(_, name)| name == segment).map( - |&(variant, _)| { - let item_tree_id = variant.lookup(db).id; - match item_tree_id.item_tree(db)[item_tree_id.value].shape { - FieldsShape::Record => { - PerNs::types(variant.into(), Visibility::Public, None) - } - FieldsShape::Tuple | FieldsShape::Unit => PerNs::both( - variant.into(), - variant.into(), - Visibility::Public, - None, - ), - } - }, - ); + let res = db + .enum_variants(e) + .variants + .iter() + .find(|(_, name, _)| name == segment) + .map(|&(variant, _, shape)| match shape { + FieldsShape::Record => { + PerNs::types(variant.into(), Visibility::Public, None) + } + FieldsShape::Tuple | FieldsShape::Unit => PerNs::both( + variant.into(), + variant.into(), + Visibility::Public, + None, + ), + }); // FIXME: Need to filter visibility here and below? Not sure. return match res { Some(res) => { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 16988ddf04b..491b6204bce 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -5,21 +5,22 @@ use base_db::Crate; use hir_expand::{ MacroDefId, mod_path::{ModPath, PathKind}, - name::Name, + name::{AsName, Name}, }; use intern::{Symbol, sym}; use itertools::Itertools as _; use rustc_hash::FxHashSet; use smallvec::{SmallVec, smallvec}; use span::SyntaxContext; +use syntax::ast::HasName; use triomphe::Arc; use crate::{ - AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, - ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, - ImplId, ItemContainerId, ItemTreeLoc, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, - MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, - TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, + AdtId, AstIdLoc, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, + EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, + GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, + Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, + TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId, builtin_type::BuiltinType, db::DefDatabase, expr_store::{ @@ -32,10 +33,10 @@ use crate::{ generics::{GenericParams, TypeOrConstParamData}, }, item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope}, - item_tree::ImportAlias, lang_item::LangItemTarget, nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map}, per_ns::PerNs, + src::HasSource, type_ref::LifetimeRef, visibility::{RawVisibility, Visibility}, }; @@ -627,14 +628,14 @@ impl<'db> Resolver<'db> { .extern_crate_decls() .filter_map(|id| { let loc = id.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - match &tree[loc.id.value].alias { - Some(alias) => match alias { - ImportAlias::Underscore => None, - ImportAlias::Alias(name) => Some(name.clone()), - }, - None => Some(tree[loc.id.value].name.clone()), - } + let extern_crate = loc.source(db); + // If there is a rename (`as x`), extract the renamed name, or remove the `extern crate` + // if it is an underscore. + extern_crate + .value + .rename() + .map(|a| a.name().map(|it| it.as_name())) + .unwrap_or_else(|| extern_crate.value.name_ref().map(|it| it.as_name())) }) } @@ -1471,10 +1472,7 @@ impl HasResolver for MacroRulesId { fn lookup_resolver( db: &dyn DefDatabase, - lookup: impl Lookup< - Database = dyn DefDatabase, - Data = impl ItemTreeLoc<Container = impl HasResolver>, - >, + lookup: impl Lookup<Database = dyn DefDatabase, Data = impl AstIdLoc<Container = impl HasResolver>>, ) -> Resolver<'_> { lookup.lookup(db).container().resolver(db) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs index 44cfd72c48f..b7d29f54d08 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs @@ -4,21 +4,25 @@ use std::ops::Not as _; use bitflags::bitflags; use cfg::{CfgExpr, CfgOptions}; -use either::Either; -use hir_expand::{InFile, Intern, Lookup, name::Name}; +use hir_expand::{ + InFile, Intern, Lookup, + name::{AsName, Name}, +}; use intern::{Symbol, sym}; use la_arena::{Arena, Idx}; use rustc_abi::{IntegerType, ReprOptions}; use syntax::{ - AstNode, SyntaxNodePtr, - ast::{self, HasGenericParams, IsString}, + NodeOrToken, SyntaxNodePtr, T, + ast::{self, HasGenericParams, HasName, HasVisibility, IsString}, }; use thin_vec::ThinVec; use triomphe::Arc; use crate::{ - ConstId, EnumId, EnumVariantId, EnumVariantLoc, FunctionId, HasModule, ImplId, ItemContainerId, - ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, VariantId, + ConstId, EnumId, EnumVariantId, EnumVariantLoc, ExternBlockId, FunctionId, HasModule, ImplId, + ItemContainerId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, + VariantId, + attr::Attrs, db::DefDatabase, expr_store::{ ExpressionStore, ExpressionStoreSourceMap, @@ -28,15 +32,17 @@ use crate::{ }, }, hir::{ExprId, PatId, generics::GenericParams}, - item_tree::{ - AttrOwner, Field, FieldParent, FieldsShape, FileItemTreeId, ItemTree, ItemTreeId, ModItem, - RawVisibility, RawVisibilityId, - }, + item_tree::{FieldsShape, RawVisibility, visibility_from_ast}, lang_item::LangItem, src::HasSource, type_ref::{TraitRef, TypeBound, TypeRefId}, }; +#[inline] +fn as_name_opt(name: Option<ast::Name>) -> Name { + name.map_or_else(Name::missing, |it| it.as_name()) +} + #[derive(Debug, PartialEq, Eq)] pub struct StructSignature { pub name: Name, @@ -70,8 +76,8 @@ bitflags! { impl StructSignature { pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); + let InFile { file_id, value: source } = loc.source(db); + let attrs = db.attrs(id.into()); let mut flags = StructFlags::empty(); if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { @@ -91,23 +97,23 @@ impl StructSignature { } } let repr = attrs.repr(); + let shape = adt_shape(source.kind()); - let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db); let (store, generic_params, source_map) = lower_generic_params( db, loc.container, id.into(), file_id, - value.generic_param_list(), - value.where_clause(), + source.generic_param_list(), + source.where_clause(), ); ( Arc::new(StructSignature { generic_params, store, flags, - shape: item_tree[loc.id.value].shape, - name: item_tree[loc.id.value].name.clone(), + shape, + name: as_name_opt(source.name()), repr, }), Arc::new(source_map), @@ -115,6 +121,15 @@ impl StructSignature { } } +#[inline] +fn adt_shape(adt_kind: ast::StructKind) -> FieldsShape { + match adt_kind { + ast::StructKind::Record(_) => FieldsShape::Record, + ast::StructKind::Tuple(_) => FieldsShape::Tuple, + ast::StructKind::Unit => FieldsShape::Unit, + } +} + #[derive(Debug, PartialEq, Eq)] pub struct UnionSignature { pub name: Name, @@ -127,9 +142,7 @@ pub struct UnionSignature { impl UnionSignature { pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { let loc = id.lookup(db); - let krate = loc.container.krate; - let item_tree = loc.id.item_tree(db); - let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); let mut flags = StructFlags::empty(); if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { flags |= StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS; @@ -140,14 +153,14 @@ impl UnionSignature { let repr = attrs.repr(); - let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db); + let InFile { file_id, value: source } = loc.source(db); let (store, generic_params, source_map) = lower_generic_params( db, loc.container, id.into(), file_id, - value.generic_param_list(), - value.where_clause(), + source.generic_param_list(), + source.where_clause(), ); ( Arc::new(UnionSignature { @@ -155,7 +168,7 @@ impl UnionSignature { store, flags, repr, - name: item_tree[loc.id.value].name.clone(), + name: as_name_opt(source.name()), }), Arc::new(source_map), ) @@ -181,8 +194,7 @@ pub struct EnumSignature { impl EnumSignature { pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); let mut flags = EnumFlags::empty(); if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { flags |= EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS; @@ -190,14 +202,14 @@ impl EnumSignature { let repr = attrs.repr(); - let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db); + let InFile { file_id, value: source } = loc.source(db); let (store, generic_params, source_map) = lower_generic_params( db, loc.container, id.into(), file_id, - value.generic_param_list(), - value.where_clause(), + source.generic_param_list(), + source.where_clause(), ); ( @@ -206,7 +218,7 @@ impl EnumSignature { store, flags, repr, - name: item_tree[loc.id.value].name.clone(), + name: as_name_opt(source.name()), }), Arc::new(source_map), ) @@ -239,10 +251,9 @@ pub struct ConstSignature { impl ConstSignature { pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let module = loc.container.module(db); - let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); let mut flags = ConstFlags::empty(); if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() { flags |= ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL; @@ -253,14 +264,14 @@ impl ConstSignature { } let (store, source_map, type_ref) = - crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty())); + crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty())); ( Arc::new(ConstSignature { store: Arc::new(store), type_ref, flags, - name: item_tree[loc.id.value].name.clone(), + name: source.value.name().map(|it| it.as_name()), }), Arc::new(source_map), ) @@ -295,10 +306,9 @@ pub struct StaticSignature { impl StaticSignature { pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let module = loc.container.module(db); - let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); let mut flags = StaticFlags::empty(); if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() { flags |= StaticFlags::RUSTC_ALLOW_INCOHERENT_IMPL; @@ -323,14 +333,14 @@ impl StaticSignature { } let (store, source_map, type_ref) = - crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty())); + crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty())); ( Arc::new(StaticSignature { store: Arc::new(store), type_ref, flags, - name: item_tree[loc.id.value].name.clone(), + name: as_name_opt(source.value.name()), }), Arc::new(source_map), ) @@ -407,10 +417,9 @@ pub struct TraitSignature { impl TraitSignature { pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let mut flags = TraitFlags::empty(); - let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); let source = loc.source(db); if source.value.auto_token().is_some() { flags.insert(TraitFlags::AUTO); @@ -446,15 +455,11 @@ impl TraitSignature { flags |= TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH; } + let name = as_name_opt(source.value.name()); let (store, source_map, generic_params) = lower_trait(db, loc.container, source, id); ( - Arc::new(TraitSignature { - store: Arc::new(store), - generic_params, - flags, - name: item_tree[loc.id.value].name.clone(), - }), + Arc::new(TraitSignature { store: Arc::new(store), generic_params, flags, name }), Arc::new(source_map), ) } @@ -473,17 +478,13 @@ impl TraitAliasSignature { id: TraitAliasId, ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let source = loc.source(db); + let name = as_name_opt(source.value.name()); let (store, source_map, generic_params) = lower_trait_alias(db, loc.container, source, id); ( - Arc::new(TraitAliasSignature { - generic_params, - store: Arc::new(store), - name: item_tree[loc.id.value].name.clone(), - }), + Arc::new(TraitAliasSignature { generic_params, store: Arc::new(store), name }), Arc::new(source_map), ) } @@ -530,10 +531,9 @@ impl FunctionSignature { ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { let loc = id.lookup(db); let module = loc.container.module(db); - let item_tree = loc.id.item_tree(db); let mut flags = FnFlags::empty(); - let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into()); + let attrs = db.attrs(id.into()); if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() { flags.insert(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL); } @@ -568,6 +568,7 @@ impl FunctionSignature { flags.insert(FnFlags::HAS_BODY); } + let name = as_name_opt(source.value.name()); let abi = source.value.abi().map(|abi| { abi.abi_string().map_or_else(|| sym::C, |it| Symbol::intern(it.text_without_quotes())) }); @@ -588,7 +589,7 @@ impl FunctionSignature { abi, flags, legacy_const_generics_indices, - name: item_tree[loc.id.value].name.clone(), + name, }), Arc::new(source_map), ) @@ -662,14 +663,9 @@ impl TypeAliasSignature { id: TypeAliasId, ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let mut flags = TypeAliasFlags::empty(); - let attrs = item_tree.attrs( - db, - loc.container.module(db).krate(), - ModItem::from(loc.id.value).into(), - ); + let attrs = db.attrs(id.into()); if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() { flags.insert(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPL); } @@ -680,6 +676,7 @@ impl TypeAliasSignature { flags.insert(TypeAliasFlags::IS_EXTERN); } let source = loc.source(db); + let name = as_name_opt(source.value.name()); let (store, source_map, generic_params, bounds, ty) = lower_type_alias(db, loc.container.module(db), source, id); @@ -689,7 +686,7 @@ impl TypeAliasSignature { generic_params, flags, bounds, - name: item_tree[loc.id.value].name.clone(), + name, ty, }), Arc::new(source_map), @@ -743,104 +740,41 @@ impl VariantFields { let (shape, (fields, store, source_map)) = match id { VariantId::EnumVariantId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); let parent = loc.parent.lookup(db); - let variant = &item_tree[loc.id.value]; - ( - variant.shape, - lower_fields( - db, - parent.container, - &item_tree, - FieldParent::EnumVariant(loc.id.value), - loc.source(db).map(|src| { - variant.fields.iter().zip( - src.field_list() - .map(|it| { - match it { - ast::FieldList::RecordFieldList(record_field_list) => { - Either::Left(record_field_list.fields().map(|it| { - (SyntaxNodePtr::new(it.syntax()), it.ty()) - })) - } - ast::FieldList::TupleFieldList(field_list) => { - Either::Right(field_list.fields().map(|it| { - (SyntaxNodePtr::new(it.syntax()), it.ty()) - })) - } - } - .into_iter() - }) - .into_iter() - .flatten(), - ) - }), - Some(item_tree[parent.id.value].visibility), - ), - ) + let source = loc.source(db); + let shape = adt_shape(source.value.kind()); + let span_map = db.span_map(source.file_id); + let override_visibility = visibility_from_ast( + db, + source.value.parent_enum().visibility(), + &mut |range| span_map.span_for_range(range).ctx, + ); + let fields = lower_field_list( + db, + parent.container, + source.map(|src| src.field_list()), + Some(override_visibility), + ); + (shape, fields) } VariantId::StructId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - let strukt = &item_tree[loc.id.value]; - ( - strukt.shape, - lower_fields( - db, - loc.container, - &item_tree, - FieldParent::Struct(loc.id.value), - loc.source(db).map(|src| { - strukt.fields.iter().zip( - src.field_list() - .map(|it| { - match it { - ast::FieldList::RecordFieldList(record_field_list) => { - Either::Left(record_field_list.fields().map(|it| { - (SyntaxNodePtr::new(it.syntax()), it.ty()) - })) - } - ast::FieldList::TupleFieldList(field_list) => { - Either::Right(field_list.fields().map(|it| { - (SyntaxNodePtr::new(it.syntax()), it.ty()) - })) - } - } - .into_iter() - }) - .into_iter() - .flatten(), - ) - }), - None, - ), - ) + let source = loc.source(db); + let shape = adt_shape(source.value.kind()); + let fields = + lower_field_list(db, loc.container, source.map(|src| src.field_list()), None); + (shape, fields) } VariantId::UnionId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - let union = &item_tree[loc.id.value]; - ( - FieldsShape::Record, - lower_fields( - db, - loc.container, - &item_tree, - FieldParent::Union(loc.id.value), - loc.source(db).map(|src| { - union.fields.iter().zip( - src.record_field_list() - .map(|it| { - it.fields() - .map(|it| (SyntaxNodePtr::new(it.syntax()), it.ty())) - }) - .into_iter() - .flatten(), - ) - }), - None, - ), - ) + let source = loc.source(db); + let fields = lower_field_list( + db, + loc.container, + source.map(|src| src.record_field_list().map(ast::FieldList::RecordFieldList)), + None, + ); + (FieldsShape::Record, fields) } }; @@ -860,39 +794,81 @@ impl VariantFields { } } -fn lower_fields<'a>( +fn lower_field_list( db: &dyn DefDatabase, module: ModuleId, - item_tree: &ItemTree, - parent: FieldParent, - fields: InFile<impl Iterator<Item = (&'a Field, (SyntaxNodePtr, Option<ast::Type>))>>, - override_visibility: Option<RawVisibilityId>, + fields: InFile<Option<ast::FieldList>>, + override_visibility: Option<RawVisibility>, +) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) { + let file_id = fields.file_id; + match fields.value { + Some(ast::FieldList::RecordFieldList(fields)) => lower_fields( + db, + module, + InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))), + |_, field| as_name_opt(field.name()), + override_visibility, + ), + Some(ast::FieldList::TupleFieldList(fields)) => lower_fields( + db, + module, + InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))), + |idx, _| Name::new_tuple_field(idx), + override_visibility, + ), + None => lower_fields( + db, + module, + InFile::new(file_id, std::iter::empty::<(Option<ast::Type>, ast::RecordField)>()), + |_, _| Name::missing(), + None, + ), + } +} + +fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>( + db: &dyn DefDatabase, + module: ModuleId, + fields: InFile<impl Iterator<Item = (Option<ast::Type>, Field)>>, + mut field_name: impl FnMut(usize, &Field) -> Name, + override_visibility: Option<RawVisibility>, ) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) { let mut arena = Arena::new(); let cfg_options = module.krate.cfg_options(db); let mut col = ExprCollector::new(db, module, fields.file_id); - for (idx, (field, (ptr, ty))) in fields.value.enumerate() { - let attr_owner = AttrOwner::make_field_indexed(parent, idx); - let attrs = item_tree.attrs(db, module.krate, attr_owner); - if attrs.is_cfg_enabled(cfg_options) { - arena.alloc(FieldData { - name: field.name.clone(), - type_ref: col - .lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator), - visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), - is_unsafe: field.is_unsafe, - }); - } else { - col.source_map.diagnostics.push( - crate::expr_store::ExpressionStoreDiagnostics::InactiveCode { - node: InFile::new(fields.file_id, ptr), - cfg: attrs.cfg().unwrap(), - opts: cfg_options.clone(), - }, - ); + let mut idx = 0; + for (ty, field) in fields.value { + match Attrs::is_cfg_enabled_for(db, &field, col.span_map(), cfg_options) { + Ok(()) => { + let type_ref = + col.lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator); + let visibility = override_visibility.clone().unwrap_or_else(|| { + visibility_from_ast(db, field.visibility(), &mut |range| { + col.span_map().span_for_range(range).ctx + }) + }); + let is_unsafe = field + .syntax() + .children_with_tokens() + .filter_map(NodeOrToken::into_token) + .any(|token| token.kind() == T![unsafe]); + let name = field_name(idx, &field); + arena.alloc(FieldData { name, type_ref, visibility, is_unsafe }); + idx += 1; + } + Err(cfg) => { + col.source_map.diagnostics.push( + crate::expr_store::ExpressionStoreDiagnostics::InactiveCode { + node: InFile::new(fields.file_id, SyntaxNodePtr::new(field.syntax())), + cfg, + opts: cfg_options.clone(), + }, + ); + } } } let store = col.store.finish(); + arena.shrink_to_fit(); (arena, store, col.source_map) } @@ -905,7 +881,7 @@ pub struct InactiveEnumVariantCode { #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnumVariants { - pub variants: Box<[(EnumVariantId, Name)]>, + pub variants: Box<[(EnumVariantId, Name, FieldsShape)]>, } impl EnumVariants { @@ -914,30 +890,38 @@ impl EnumVariants { e: EnumId, ) -> (Arc<EnumVariants>, Option<Arc<ThinVec<InactiveEnumVariantCode>>>) { let loc = e.lookup(db); - let item_tree = loc.id.item_tree(db); + let source = loc.source(db); + let ast_id_map = db.ast_id_map(source.file_id); + let span_map = db.span_map(source.file_id); let mut diagnostics = ThinVec::new(); let cfg_options = loc.container.krate.cfg_options(db); let mut index = 0; - let variants = FileItemTreeId::range_iter(item_tree[loc.id.value].variants.clone()) + let Some(variants) = source.value.variant_list() else { + return (Arc::new(EnumVariants { variants: Box::default() }), None); + }; + let variants = variants + .variants() .filter_map(|variant| { - let attrs = item_tree.attrs(db, loc.container.krate, variant.into()); - if attrs.is_cfg_enabled(cfg_options) { - let enum_variant = EnumVariantLoc { - id: ItemTreeId::new(loc.id.tree_id(), variant), - parent: e, - index, + let ast_id = ast_id_map.ast_id(&variant); + match Attrs::is_cfg_enabled_for(db, &variant, span_map.as_ref(), cfg_options) { + Ok(()) => { + let enum_variant = + EnumVariantLoc { id: source.with_value(ast_id), parent: e, index } + .intern(db); + index += 1; + let name = as_name_opt(variant.name()); + let shape = adt_shape(variant.kind()); + Some((enum_variant, name, shape)) + } + Err(cfg) => { + diagnostics.push(InactiveEnumVariantCode { + ast_id, + cfg, + opts: cfg_options.clone(), + }); + None } - .intern(db); - index += 1; - Some((enum_variant, item_tree[variant].name.clone())) - } else { - diagnostics.push(InactiveEnumVariantCode { - ast_id: item_tree[variant].ast_id, - cfg: attrs.cfg().unwrap(), - opts: cfg_options.clone(), - }); - None } }) .collect(); @@ -949,12 +933,18 @@ impl EnumVariants { } pub fn variant(&self, name: &Name) -> Option<EnumVariantId> { - self.variants.iter().find_map(|(v, n)| if n == name { Some(*v) } else { None }) + self.variants.iter().find_map(|(v, n, _)| if n == name { Some(*v) } else { None }) + } + + pub fn variant_name_by_id(&self, variant_id: EnumVariantId) -> Option<Name> { + self.variants + .iter() + .find_map(|(id, name, _)| if *id == variant_id { Some(name.clone()) } else { None }) } // [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448) pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool { - self.variants.iter().all(|&(v, _)| { + self.variants.iter().all(|&(v, _, _)| { // The condition check order is slightly modified from rustc // to improve performance by early returning with relatively fast checks let variant = &db.variant_fields(v.into()); @@ -973,3 +963,17 @@ impl EnumVariants { }) } } + +pub(crate) fn extern_block_abi_query( + db: &dyn DefDatabase, + extern_block: ExternBlockId, +) -> Option<Symbol> { + let source = extern_block.lookup(db).source(db); + source.value.abi().map(|abi| { + match abi.abi_string() { + Some(tok) => Symbol::intern(tok.text_without_quotes()), + // `extern` default to be `extern "C"`. + _ => sym::C, + } + }) +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/src.rs b/src/tools/rust-analyzer/crates/hir-def/src/src.rs index 3867f39b8b1..aa373a27b0d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/src.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/src.rs @@ -1,15 +1,13 @@ //! Utilities for mapping between hir IDs and the surface syntax. use either::Either; -use hir_expand::InFile; -use la_arena::ArenaMap; +use hir_expand::{AstId, InFile}; +use la_arena::{Arena, ArenaMap, Idx}; use syntax::{AstNode, AstPtr, ast}; use crate::{ - GenericDefId, ItemTreeLoc, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, - UseId, VariantId, - db::DefDatabase, - item_tree::{AttrOwner, FieldParent, ItemTreeNode}, + AstIdLoc, GenericDefId, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, + UseId, VariantId, attr::Attrs, db::DefDatabase, }; pub trait HasSource { @@ -23,18 +21,13 @@ pub trait HasSource { impl<T> HasSource for T where - T: ItemTreeLoc, - T::Id: ItemTreeNode, + T: AstIdLoc, { - type Value = <T::Id as ItemTreeNode>::Source; + type Value = T::Ast; fn ast_ptr(&self, db: &dyn DefDatabase) -> InFile<AstPtr<Self::Value>> { - let id = self.item_tree_id(); - let file_id = id.file_id(); - let tree = id.item_tree(db); - let ast_id_map = db.ast_id_map(file_id); - let node = &tree[id.value]; - - InFile::new(file_id, ast_id_map.get(node.ast_id())) + let id = self.ast_id(); + let ast_id_map = db.ast_id_map(id.file_id); + InFile::new(id.file_id, ast_id_map.get(id.value)) } } @@ -43,18 +36,37 @@ pub trait HasChildSource<ChildId> { fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<ChildId, Self::Value>>; } +/// Maps a `UseTree` contained in this import back to its AST node. +pub fn use_tree_to_ast( + db: &dyn DefDatabase, + use_ast_id: AstId<ast::Use>, + index: Idx<ast::UseTree>, +) -> ast::UseTree { + use_tree_source_map(db, use_ast_id)[index].clone() +} + +/// Maps a `UseTree` contained in this import back to its AST node. +fn use_tree_source_map(db: &dyn DefDatabase, use_ast_id: AstId<ast::Use>) -> Arena<ast::UseTree> { + // Re-lower the AST item and get the source map. + // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. + let ast = use_ast_id.to_node(db); + let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); + let mut span_map = None; + crate::item_tree::lower_use_tree(db, ast_use_tree, &mut |range| { + span_map.get_or_insert_with(|| db.span_map(use_ast_id.file_id)).span_for_range(range).ctx + }) + .expect("failed to lower use tree") + .1 +} + impl HasChildSource<la_arena::Idx<ast::UseTree>> for UseId { type Value = ast::UseTree; fn child_source( &self, db: &dyn DefDatabase, ) -> InFile<ArenaMap<la_arena::Idx<ast::UseTree>, Self::Value>> { - let loc = &self.lookup(db); - let use_ = &loc.id.item_tree(db)[loc.id.value]; - InFile::new( - loc.id.file_id(), - use_.use_tree_source_map(db, loc.id.file_id()).into_iter().collect(), - ) + let loc = self.lookup(db); + InFile::new(loc.id.file_id, use_tree_source_map(db, loc.id).into_iter().collect()) } } @@ -124,49 +136,30 @@ impl HasChildSource<LocalFieldId> for VariantId { type Value = Either<ast::TupleField, ast::RecordField>; fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<LocalFieldId, Self::Value>> { - let item_tree; - let (src, parent, container) = match *self { + let (src, container) = match *self { VariantId::EnumVariantId(it) => { let lookup = it.lookup(db); - item_tree = lookup.id.item_tree(db); - ( - lookup.source(db).map(|it| it.kind()), - FieldParent::EnumVariant(lookup.id.value), - lookup.parent.lookup(db).container, - ) + (lookup.source(db).map(|it| it.kind()), lookup.parent.lookup(db).container) } VariantId::StructId(it) => { let lookup = it.lookup(db); - item_tree = lookup.id.item_tree(db); - ( - lookup.source(db).map(|it| it.kind()), - FieldParent::Struct(lookup.id.value), - lookup.container, - ) + (lookup.source(db).map(|it| it.kind()), lookup.container) } VariantId::UnionId(it) => { let lookup = it.lookup(db); - item_tree = lookup.id.item_tree(db); - ( - lookup.source(db).map(|it| it.kind()), - FieldParent::Union(lookup.id.value), - lookup.container, - ) + (lookup.source(db).map(|it| it.kind()), lookup.container) } }; - + let span_map = db.span_map(src.file_id); let mut map = ArenaMap::new(); match &src.value { ast::StructKind::Tuple(fl) => { let cfg_options = container.krate.cfg_options(db); let mut idx = 0; - for (i, fd) in fl.fields().enumerate() { - let attrs = item_tree.attrs( - db, - container.krate, - AttrOwner::make_field_indexed(parent, i), - ); - if !attrs.is_cfg_enabled(cfg_options) { + for fd in fl.fields() { + let enabled = + Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok(); + if !enabled { continue; } map.insert( @@ -179,13 +172,10 @@ impl HasChildSource<LocalFieldId> for VariantId { ast::StructKind::Record(fl) => { let cfg_options = container.krate.cfg_options(db); let mut idx = 0; - for (i, fd) in fl.fields().enumerate() { - let attrs = item_tree.attrs( - db, - container.krate, - AttrOwner::make_field_indexed(parent, i), - ); - if !attrs.is_cfg_enabled(cfg_options) { + for fd in fl.fields() { + let enabled = + Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok(); + if !enabled { continue; } map.insert( @@ -195,7 +185,7 @@ impl HasChildSource<LocalFieldId> for VariantId { idx += 1; } } - _ => (), + ast::StructKind::Unit => (), } InFile::new(src.file_id, map) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 3c67ee9fe5b..14d67ea804f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -2,16 +2,18 @@ use std::iter; -use hir_expand::Lookup; +use hir_expand::{InFile, Lookup}; use la_arena::ArenaMap; +use syntax::ast::{self, HasVisibility}; use triomphe::Arc; use crate::{ - ConstId, FunctionId, HasModule, ItemContainerId, ItemLoc, ItemTreeLoc, LocalFieldId, - LocalModuleId, ModuleId, TraitId, TypeAliasId, VariantId, + ConstId, FunctionId, HasModule, ItemContainerId, LocalFieldId, LocalModuleId, ModuleId, + TraitId, TypeAliasId, VariantId, db::DefDatabase, nameres::DefMap, resolver::{HasResolver, Resolver}, + src::HasSource, }; pub use crate::item_tree::{RawVisibility, VisibilityExplicitness}; @@ -217,49 +219,69 @@ pub(crate) fn field_visibilities_query( for (field_id, field_data) in fields.iter() { res.insert(field_id, Visibility::resolve(db, &resolver, &field_data.visibility)); } + res.shrink_to_fit(); Arc::new(res) } +pub fn visibility_from_ast( + db: &dyn DefDatabase, + resolver: &Resolver<'_>, + ast_vis: InFile<Option<ast::Visibility>>, +) -> Visibility { + let mut span_map = None; + let raw_vis = crate::item_tree::visibility_from_ast(db, ast_vis.value, &mut |range| { + span_map.get_or_insert_with(|| db.span_map(ast_vis.file_id)).span_for_range(range).ctx + }); + Visibility::resolve(db, resolver, &raw_vis) +} + +fn trait_item_visibility( + db: &dyn DefDatabase, + resolver: &Resolver<'_>, + container: ItemContainerId, +) -> Option<Visibility> { + match container { + ItemContainerId::TraitId(trait_) => Some(trait_visibility(db, resolver, trait_)), + _ => None, + } +} + /// Resolve visibility of a function. pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { - let resolver = def.resolver(db); let loc = def.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - if let ItemContainerId::TraitId(trait_id) = loc.container { - trait_vis(db, &resolver, trait_id) - } else { - Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility]) - } + let resolver = def.resolver(db); + trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, &resolver, source.map(|src| src.visibility())) + }) } /// Resolve visibility of a const. pub(crate) fn const_visibility_query(db: &dyn DefDatabase, def: ConstId) -> Visibility { - let resolver = def.resolver(db); let loc = def.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - if let ItemContainerId::TraitId(trait_id) = loc.container { - trait_vis(db, &resolver, trait_id) - } else { - Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility]) - } + let resolver = def.resolver(db); + trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, &resolver, source.map(|src| src.visibility())) + }) } /// Resolve visibility of a type alias. pub(crate) fn type_alias_visibility_query(db: &dyn DefDatabase, def: TypeAliasId) -> Visibility { - let resolver = def.resolver(db); let loc = def.lookup(db); - let tree = loc.item_tree_id().item_tree(db); - if let ItemContainerId::TraitId(trait_id) = loc.container { - trait_vis(db, &resolver, trait_id) - } else { - Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility]) - } + let resolver = def.resolver(db); + trait_item_visibility(db, &resolver, loc.container).unwrap_or_else(|| { + let source = loc.source(db); + visibility_from_ast(db, &resolver, source.map(|src| src.visibility())) + }) } -#[inline] -fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver<'_>, trait_id: TraitId) -> Visibility { - let ItemLoc { id: tree_id, .. } = trait_id.lookup(db); - let item_tree = tree_id.item_tree(db); - let tr_def = &item_tree[tree_id.value]; - Visibility::resolve(db, resolver, &item_tree[tr_def.visibility]) +pub(crate) fn trait_visibility( + db: &dyn DefDatabase, + resolver: &Resolver<'_>, + def: TraitId, +) -> Visibility { + let loc = def.lookup(db); + let source = loc.source(db); + visibility_from_ast(db, resolver, source.map(|src| src.visibility())) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs index e8f6b82434e..a73a22370d2 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use either::Either; -use span::{ErasedFileAstId, FileAstId, FileId, SyntaxContext}; +use span::{AstIdNode, ErasedFileAstId, FileAstId, FileId, SyntaxContext}; use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize}; use crate::{ @@ -122,6 +122,13 @@ impl<N: AstNode> AstId<N> { pub fn erase(&self) -> ErasedAstId { crate::InFile::new(self.file_id, self.value.erase()) } + #[inline] + pub fn upcast<M: AstIdNode>(self) -> AstId<M> + where + N: Into<M>, + { + self.map(|it| it.upcast()) + } } pub type ErasedAstId = crate::InFile<ErasedFileAstId>; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 22b96b55cbb..710ac6e5422 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -817,7 +817,7 @@ pub(crate) fn adt_datum_query( .enum_variants(id) .variants .iter() - .map(|&(variant_id, _)| variant_id_to_fields(variant_id.into())) + .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into())) .collect(); (rust_ir::AdtKind::Enum, variants) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index 099100a7328..fae129fddbf 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -397,7 +397,7 @@ impl<'a> DeclValidator<'a> { fn validate_enum_variants(&mut self, enum_id: EnumId) { let data = self.db.enum_variants(enum_id); - for (variant_id, _) in data.variants.iter() { + for (variant_id, _, _) in data.variants.iter() { self.validate_enum_variant_fields(*variant_id); } @@ -405,7 +405,7 @@ impl<'a> DeclValidator<'a> { let mut enum_variants_replacements = data .variants .iter() - .filter_map(|(_, name)| { + .filter_map(|(_, name, _)| { to_camel_case(&name.display_no_db(edition).to_smolstr()).map(|new_name| { Replacement { current_name: name.clone(), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index dd82a0f45ca..0914b5aac50 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -465,7 +465,7 @@ impl PatCx for MatchCheckCtx<'_> { ConstructorSet::NoConstructors } else { let mut variants = IndexVec::with_capacity(enum_data.variants.len()); - for &(variant, _) in enum_data.variants.iter() { + for &(variant, _, _) in enum_data.variants.iter() { let is_uninhabited = is_enum_variant_uninhabited_from( cx.db, variant, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index 70763759ef0..b9b0f982866 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -71,7 +71,7 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm .enum_variants(id) .variants .iter() - .map(|&(variant, _)| { + .map(|&(variant, _, _)| { db.field_types(variant.into()) .iter() .map(|(_, field_ty)| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index e81a5e3c311..8be812d8d5e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -115,7 +115,7 @@ impl UninhabitedFrom<'_> { AdtId::EnumId(e) => { let enum_data = self.db.enum_variants(e); - for &(variant, _) in enum_data.variants.iter() { + for &(variant, _, _) in enum_data.variants.iter() { let variant_inhabitedness = self.visit_variant(variant.into(), subst); match variant_inhabitedness { Break(VisiblyUninhabited) => (), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs index 3a020bf050d..a886c33d157 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs @@ -60,7 +60,7 @@ pub fn layout_of_adt_query( let r = variants .variants .iter() - .map(|&(v, _)| handle_variant(v.into(), &db.variant_fields(v.into()))) + .map(|&(v, _, _)| handle_variant(v.into(), &db.variant_fields(v.into()))) .collect::<Result<SmallVec<_>, _>>()?; (r, db.enum_signature(e).repr.unwrap_or_default(), false) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 21e5428520e..8fb8d64779b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -2771,12 +2771,15 @@ impl Evaluator<'_> { Err(e) => { let db = self.db; let loc = variant.lookup(db); - let enum_loc = loc.parent.lookup(db); let edition = self.crate_id.data(self.db).edition; let name = format!( "{}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), - loc.id.item_tree(db)[loc.id.value].name.display(db, edition), + self.db.enum_signature(loc.parent).name.display(db, edition), + self.db + .enum_variants(loc.parent) + .variant_name_by_id(variant) + .unwrap() + .display(db, edition), ); Err(MirEvalError::ConstEvalError(name, Box::new(e))) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 90c52ee96f1..512a275aa75 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -65,9 +65,7 @@ impl Evaluator<'_> { Some(abi) => *abi == sym::rust_dash_intrinsic, None => match def.lookup(self.db).container { hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db).id; - id.item_tree(self.db)[id.value].abi.as_ref() - == Some(&sym::rust_dash_intrinsic) + self.db.extern_block_abi(block) == Some(sym::rust_dash_intrinsic) } _ => false, }, @@ -87,8 +85,7 @@ impl Evaluator<'_> { } let is_extern_c = match def.lookup(self.db).container { hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db).id; - id.item_tree(self.db)[id.value].abi.as_ref() == Some(&sym::C) + self.db.extern_block_abi(block) == Some(sym::C) } _ => false, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 99d93515303..ef1f215500c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -1922,11 +1922,14 @@ impl<'ctx> MirLowerCtx<'ctx> { let edition = self.edition(); let db = self.db; let loc = variant.lookup(db); - let enum_loc = loc.parent.lookup(db); let name = format!( "{}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), - loc.id.item_tree(db)[loc.id.value].name.display(db, edition), + self.db.enum_signature(loc.parent).name.display(db, edition), + self.db + .enum_variants(loc.parent) + .variant_name_by_id(variant) + .unwrap() + .display(db, edition), ); Err(MirLowerError::ConstEvalError(name.into(), Box::new(e))) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index 7ae6e907e7a..91dc2627d18 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -63,16 +63,15 @@ impl MirBody { } hir_def::DefWithBodyId::VariantId(id) => { let loc = id.lookup(db); - let enum_loc = loc.parent.lookup(db); + let edition = this.display_target.edition; w!( this, "enum {}::{} = ", - enum_loc.id.item_tree(db)[enum_loc.id.value] - .name - .display(db, this.display_target.edition), - loc.id.item_tree(db)[loc.id.value] - .name - .display(db, this.display_target.edition), + db.enum_signature(loc.parent).name.display(db, edition), + db.enum_variants(loc.parent) + .variant_name_by_id(id) + .unwrap() + .display(db, edition), ) } }); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index 2b75bd6f160..48af7b2e32a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -479,7 +479,7 @@ pub(crate) fn visit_module( visit_body(db, &body, cb); } ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => { - db.enum_variants(it).variants.iter().for_each(|&(it, _)| { + db.enum_variants(it).variants.iter().for_each(|&(it, _, _)| { let body = db.body(it.into()); cb(it.into()); visit_body(db, &body, cb); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 6ac260ac768..a055ef879d6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -353,6 +353,7 @@ impl SomeStruct { "impl_self_ty_with_diagnostics_shim".to_owned(), "struct_signature_shim".to_owned(), "struct_signature_with_source_map_shim".to_owned(), + "attrs_shim".to_owned(), "type_for_adt_tracked".to_owned(), ]; @@ -442,6 +443,6 @@ fn main() { let _inference_result = db.infer(def); } }); - assert!(format!("{events:?}").contains("trait_solve_shim")) + assert!(!format!("{events:?}").contains("trait_solve_shim")) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 1e0ff423ded..f797e60b05e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -293,9 +293,7 @@ pub fn is_fn_unsafe_to_call( let loc = func.lookup(db); match loc.container { hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(db).id; - let is_intrinsic_block = - id.item_tree(db)[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic); + let is_intrinsic_block = db.extern_block_abi(block) == Some(sym::rust_dash_intrinsic); if is_intrinsic_block { // legacy intrinsics // extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index d6b43aeed4d..62478d4fd86 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -213,7 +213,7 @@ impl Context<'_> { AdtId::StructId(s) => add_constraints_from_variant(VariantId::StructId(s)), AdtId::UnionId(u) => add_constraints_from_variant(VariantId::UnionId(u)), AdtId::EnumId(e) => { - db.enum_variants(e).variants.iter().for_each(|&(variant, _)| { + db.enum_variants(e).variants.iter().for_each(|&(variant, _, _)| { add_constraints_from_variant(VariantId::EnumVariantId(variant)) }); } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 969fd3eb480..c746b88c5b1 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -52,12 +52,14 @@ use hir_def::{ BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, }, - item_tree::{AttrOwner, FieldParent, ImportAlias, ItemTreeFieldId, ItemTreeNode}, + item_tree::ImportAlias, layout::{self, ReprOptions, TargetDataLayout}, nameres::{self, diagnostics::DefDiagnostic}, per_ns::PerNs, resolver::{HasResolver, Resolver}, signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields}, + src::HasSource as _, + visibility::visibility_from_ast, }; use hir_expand::{ AstId, MacroCallKind, RenderedExpandError, ValueResult, attrs::collect_attrs, @@ -81,11 +83,11 @@ use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; use smallvec::SmallVec; -use span::{Edition, FileId}; +use span::{AstIdNode, Edition, FileId}; use stdx::{format_to, impl_from, never}; use syntax::{ AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr, - ast::{self, HasAttrs as _, HasName}, + ast::{self, HasAttrs as _, HasName, HasVisibility as _}, format_smolstr, }; use triomphe::{Arc, ThinArc}; @@ -687,7 +689,7 @@ impl Module { let source_map = db.enum_signature_with_source_map(e.id).1; expr_store_diagnostics(db, acc, &source_map); let (variants, diagnostics) = db.enum_variants_with_diagnostics(e.id); - let file = e.id.lookup(db).id.file_id(); + let file = e.id.lookup(db).id.file_id; let ast_id_map = db.ast_id_map(file); if let Some(diagnostics) = &diagnostics { for diag in diagnostics.iter() { @@ -704,7 +706,7 @@ impl Module { ); } } - for &(v, _) in &variants.variants { + for &(v, _, _) in &variants.variants { let source_map = db.variant_fields_with_source_map(v.into()).1; push_ty_diagnostics( db, @@ -742,12 +744,10 @@ impl Module { GenericDef::Impl(impl_def).diagnostics(db, acc); let loc = impl_def.id.lookup(db); - let tree = loc.id.item_tree(db); let source_map = db.impl_signature_with_source_map(impl_def.id).1; expr_store_diagnostics(db, acc, &source_map); - let node = &tree[loc.id.value]; - let file_id = loc.id.file_id(); + let file_id = loc.id.file_id; if file_id.macro_file().is_some_and(|it| it.kind(db) == MacroKind::DeriveBuiltIn) { // these expansion come from us, diagnosing them is a waste of resources // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow @@ -765,11 +765,11 @@ impl Module { } if inherent_impls.invalid_impls().contains(&impl_def.id) { - acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) + acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } if !impl_def.check_orphan_rules(db) { - acc.push(TraitImplOrphan { impl_: ast_id_map.get(node.ast_id()), file_id }.into()) + acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into()) } let trait_ = impl_def.trait_(db); @@ -808,11 +808,11 @@ impl Module { // unsafe negative impl (true, _, true, _) | // unsafe impl for safe trait - (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: true }.into()), + (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: true }.into()), // safe impl for unsafe trait (false, true, false, _) | // safe impl of dangling drop - (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: false }.into()), + (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: false }.into()), _ => (), }; @@ -839,7 +839,7 @@ impl Module { TraitImplRedundantAssocItems { trait_, file_id, - impl_: ast_id_map.get(node.ast_id()), + impl_: ast_id_map.get(loc.id.value), assoc_item: (name, assoc_item), } .into(), @@ -889,7 +889,7 @@ impl Module { if !missing.is_empty() { acc.push( TraitImplMissingAssocItems { - impl_: ast_id_map.get(node.ast_id()), + impl_: ast_id_map.get(loc.id.value), file_id, missing, } @@ -1076,73 +1076,25 @@ fn emit_def_diagnostic_( ) } DefDiagnosticKind::UnresolvedImport { id, index } => { - let file_id = id.file_id(); - let item_tree = id.item_tree(db); - let import = &item_tree[id.value]; + let file_id = id.file_id; - let use_tree = import.use_tree_to_ast(db, file_id, *index); + let use_tree = hir_def::src::use_tree_to_ast(db, *id, *index); acc.push( UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(), ); } - DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts } => { - let item_tree = tree.item_tree(db); - let ast_id_map = db.ast_id_map(tree.file_id()); - // FIXME: This parses... We could probably store relative ranges for the children things - // here in the item tree? - (|| { - let process_field_list = - |field_list: Option<_>, idx: ItemTreeFieldId| match field_list? { - ast::FieldList::RecordFieldList(it) => Some(SyntaxNodePtr::new( - it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(), - )), - ast::FieldList::TupleFieldList(it) => Some(SyntaxNodePtr::new( - it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(), - )), - }; - let ptr = match *item { - AttrOwner::ModItem(it) => { - ast_id_map.get(it.ast_id(&item_tree)).syntax_node_ptr() - } - AttrOwner::TopLevel => ast_id_map.root(), - AttrOwner::Variant(it) => { - ast_id_map.get(item_tree[it].ast_id).syntax_node_ptr() - } - AttrOwner::Field(FieldParent::EnumVariant(parent), idx) => process_field_list( - ast_id_map - .get(item_tree[parent].ast_id) - .to_node(&db.parse_or_expand(tree.file_id())) - .field_list(), - idx, - )?, - AttrOwner::Field(FieldParent::Struct(parent), idx) => process_field_list( - ast_id_map - .get(item_tree[parent.index()].ast_id) - .to_node(&db.parse_or_expand(tree.file_id())) - .field_list(), - idx, - )?, - AttrOwner::Field(FieldParent::Union(parent), idx) => SyntaxNodePtr::new( - ast_id_map - .get(item_tree[parent.index()].ast_id) - .to_node(&db.parse_or_expand(tree.file_id())) - .record_field_list()? - .fields() - .nth(idx.into_raw().into_u32() as usize)? - .syntax(), - ), - }; - acc.push( - InactiveCode { - node: InFile::new(tree.file_id(), ptr), - cfg: cfg.clone(), - opts: opts.clone(), - } - .into(), - ); - Some(()) - })(); + DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts } => { + let ast_id_map = db.ast_id_map(ast_id.file_id); + let ptr = ast_id_map.get_erased(ast_id.value); + acc.push( + InactiveCode { + node: InFile::new(ast_id.file_id, ptr), + cfg: cfg.clone(), + opts: opts.clone(), + } + .into(), + ); } DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { let (node, precise_location) = precise_macro_call_location(ast, db); @@ -1478,12 +1430,8 @@ impl Struct { impl HasVisibility for Struct { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -1536,12 +1484,8 @@ impl Union { impl HasVisibility for Union { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -1560,7 +1504,7 @@ impl Enum { } pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> { - db.enum_variants(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect() + db.enum_variants(self.id).variants.iter().map(|&(id, _, _)| Variant { id }).collect() } pub fn num_variants(self, db: &dyn HirDatabase) -> usize { @@ -1629,12 +1573,8 @@ impl Enum { impl HasVisibility for Enum { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -2708,10 +2648,9 @@ impl ExternCrateDecl { pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option<Crate> { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); let krate = loc.container.krate(); - let name = &item_tree[loc.id.value].name; - if *name == sym::self_ { + let name = self.name(db); + if name == sym::self_ { Some(krate.into()) } else { krate.data(db).dependencies.iter().find_map(|dep| { @@ -2722,25 +2661,29 @@ impl ExternCrateDecl { pub fn name(self, db: &dyn HirDatabase) -> Name { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - item_tree[loc.id.value].name.clone() + let source = loc.source(db); + as_name_opt(source.value.name_ref()) } pub fn alias(self, db: &dyn HirDatabase) -> Option<ImportAlias> { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - item_tree[loc.id.value].alias.clone() + let source = loc.source(db); + let rename = source.value.rename()?; + if let Some(name) = rename.name() { + Some(ImportAlias::Alias(name.as_name())) + } else if rename.underscore_token().is_some() { + Some(ImportAlias::Underscore) + } else { + None + } } /// Returns the name under which this crate is made accessible, taking `_` into account. pub fn alias_or_name(self, db: &dyn HirDatabase) -> Option<Name> { - let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - - match &item_tree[loc.id.value].alias { + match self.alias(db) { Some(ImportAlias::Underscore) => None, - Some(ImportAlias::Alias(alias)) => Some(alias.clone()), - None => Some(item_tree[loc.id.value].name.clone()), + Some(ImportAlias::Alias(alias)) => Some(alias), + None => Some(self.name(db)), } } } @@ -2748,12 +2691,8 @@ impl ExternCrateDecl { impl HasVisibility for ExternCrateDecl { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -2873,12 +2812,8 @@ impl Static { impl HasVisibility for Static { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -2967,11 +2902,7 @@ impl Trait { } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> { - db.trait_items(self.id) - .macro_calls - .as_ref() - .map(|it| it.as_ref().clone().into_boxed_slice()) - .unwrap_or_default() + db.trait_items(self.id).macro_calls.to_vec().into_boxed_slice() } /// `#[rust_analyzer::completions(...)]` mode. @@ -2983,12 +2914,8 @@ impl Trait { impl HasVisibility for Trait { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -3010,12 +2937,8 @@ impl TraitAlias { impl HasVisibility for TraitAlias { fn visibility(&self, db: &dyn HirDatabase) -> Visibility { let loc = self.id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &self.id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &self.id.resolver(db), source.map(|src| src.visibility())) } } @@ -3163,25 +3086,23 @@ impl Macro { match self.id { MacroId::Macro2Id(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - item_tree[loc.id.value].name.clone() + let source = loc.source(db); + as_name_opt(source.value.name()) } MacroId::MacroRulesId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - item_tree[loc.id.value].name.clone() + let source = loc.source(db); + as_name_opt(source.value.name()) } MacroId::ProcMacroId(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); + let source = loc.source(db); match loc.kind { ProcMacroKind::CustomDerive => db .attrs(id.into()) .parse_proc_macro_derive() - .map_or_else(|| item_tree[loc.id.value].name.clone(), |(it, _)| it), - ProcMacroKind::Bang | ProcMacroKind::Attr => { - item_tree[loc.id.value].name.clone() - } + .map_or_else(|| as_name_opt(source.value.name()), |(it, _)| it), + ProcMacroKind::Bang | ProcMacroKind::Attr => as_name_opt(source.value.name()), } } } @@ -3278,12 +3199,8 @@ impl HasVisibility for Macro { match self.id { MacroId::Macro2Id(id) => { let loc = id.lookup(db); - let item_tree = loc.id.item_tree(db); - Visibility::resolve( - db, - &id.resolver(db), - &item_tree[item_tree[loc.id.value].visibility], - ) + let source = loc.source(db); + visibility_from_ast(db, &id.resolver(db), source.map(|src| src.visibility())) } MacroId::MacroRulesId(_) => Visibility::Public, MacroId::ProcMacroId(_) => Visibility::Public, @@ -3437,7 +3354,7 @@ fn as_assoc_item<'db, ID, DEF, LOC>( where ID: Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<LOC>>, DEF: From<ID>, - LOC: ItemTreeNode, + LOC: AstIdNode, { match id.lookup(db).container { ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))), @@ -3453,7 +3370,7 @@ fn as_extern_assoc_item<'db, ID, DEF, LOC>( where ID: Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<LOC>>, DEF: From<ID>, - LOC: ItemTreeNode, + LOC: AstIdNode, { match id.lookup(db).container { ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))), @@ -4545,11 +4462,7 @@ impl Impl { } fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> { - db.impl_items(self.id) - .macro_calls - .as_ref() - .map(|it| it.as_ref().clone().into_boxed_slice()) - .unwrap_or_default() + db.impl_items(self.id).macro_calls.to_vec().into_boxed_slice() } } @@ -6510,3 +6423,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>( }) .flatten() } + +fn as_name_opt(name: Option<impl AsName>) -> Name { + name.map_or_else(Name::missing, |name| name.as_name()) +} diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs index 1a6d63c88c6..ea44451a8ee 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs @@ -6,10 +6,11 @@ use either::Either; use hir_expand::{HirFileId, attrs::collect_attrs}; +use span::AstIdNode; use syntax::{AstPtr, ast}; use hir_def::{ - AdtId, AssocItemId, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, ItemTreeLoc, + AdtId, AssocItemId, AstIdLoc, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, LifetimeParamId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, TypeOrConstParamId, VariantId, db::DefDatabase, @@ -19,7 +20,6 @@ use hir_def::{ }, hir::generics::GenericParams, item_scope::ItemScope, - item_tree::ItemTreeNode, nameres::DefMap, src::{HasChildSource, HasSource}, }; @@ -113,7 +113,7 @@ impl ChildBySource for ItemScope { ids.iter().for_each(|&id| { if let MacroId::MacroRulesId(id) = id { let loc = id.lookup(db); - if loc.id.file_id() == file_id { + if loc.id.file_id == file_id { res[keys::MACRO_RULES].insert(loc.ast_ptr(db).value, id); } } @@ -199,16 +199,14 @@ impl ChildBySource for VariantId { impl ChildBySource for EnumId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { let loc = &self.lookup(db); - if file_id != loc.id.file_id() { + if file_id != loc.id.file_id { return; } - let tree = loc.id.item_tree(db); - let ast_id_map = db.ast_id_map(loc.id.file_id()); + let ast_id_map = db.ast_id_map(loc.id.file_id); - db.enum_variants(*self).variants.iter().for_each(|&(variant, _)| { - res[keys::ENUM_VARIANT] - .insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant); + db.enum_variants(*self).variants.iter().for_each(|&(variant, _, _)| { + res[keys::ENUM_VARIANT].insert(ast_id_map.get(variant.lookup(db).id.value), variant); }); let (_, source_map) = db.enum_signature_with_source_map(*self); source_map @@ -287,15 +285,14 @@ fn insert_item_loc<ID, N, Data>( res: &mut DynMap, file_id: HirFileId, id: ID, - key: Key<N::Source, ID>, + key: Key<N, ID>, ) where ID: Lookup<Database = dyn DefDatabase, Data = Data> + 'static, - Data: ItemTreeLoc<Id = N>, - N: ItemTreeNode, - N::Source: 'static, + Data: AstIdLoc<Ast = N>, + N: AstIdNode + 'static, { let loc = id.lookup(db); - if loc.item_tree_id().file_id() == file_id { + if loc.ast_id().file_id == file_id { res[key].insert(loc.ast_ptr(db).value, id) } } |
