about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorChayim Refael Friedman <chayimfr@gmail.com>2025-05-21 13:13:34 +0300
committerChayim Refael Friedman <chayimfr@gmail.com>2025-06-12 08:50:40 +0300
commitcd1298a2798c19dcb768290e0968468be5afe974 (patch)
treedb7c3127cb93b828ab548ab8cff4c3c39581d0a6 /src
parent8e06cef0be365e128bdb3a1c4c728fc8664a51bb (diff)
downloadrust-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')
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs158
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs76
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs187
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs212
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs176
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/signatures.rs400
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/src.rs106
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/visibility.rs82
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/files.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/drop.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/variance.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs233
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs25
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)
     }
 }