about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2024-03-04 11:10:06 +0100
committerLukas Wirth <lukastw97@gmail.com>2024-03-04 11:10:06 +0100
commit4303e741de62ec9e1ebbcfbafee0ed52a92f0f2a (patch)
treef8db2eca68ec5b5fcda564b555114a64a9f6eebd
parent4ef6a49b44e8aa380da7522442234bfd7a52c55e (diff)
downloadrust-4303e741de62ec9e1ebbcfbafee0ed52a92f0f2a.tar.gz
rust-4303e741de62ec9e1ebbcfbafee0ed52a92f0f2a.zip
Cleanup
-rw-r--r--Cargo.lock11
-rw-r--r--crates/base-db/Cargo.toml1
-rw-r--r--crates/hir-def/src/body.rs4
-rw-r--r--crates/hir-def/src/body/lower.rs2
-rw-r--r--crates/hir-def/src/item_tree.rs49
-rw-r--r--crates/hir-def/src/nameres.rs334
-rw-r--r--crates/hir-def/src/nameres/collector.rs175
-rw-r--r--crates/hir-def/src/nameres/diagnostics.rs24
-rw-r--r--crates/hir-def/src/nameres/mod_resolution.rs18
-rw-r--r--crates/hir-def/src/nameres/path_resolution.rs43
-rw-r--r--crates/hir-expand/Cargo.toml3
-rw-r--r--crates/hir-expand/src/builtin_attr_macro.rs25
-rw-r--r--crates/hir-expand/src/builtin_derive_macro.rs30
-rw-r--r--crates/hir-expand/src/builtin_fn_macro.rs54
-rw-r--r--crates/hir-expand/src/change.rs4
-rw-r--r--crates/hir-expand/src/mod_path.rs6
-rw-r--r--crates/hir-ty/Cargo.toml1
-rw-r--r--crates/hir/Cargo.toml1
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/ide-assists/Cargo.toml1
-rw-r--r--crates/ide-completion/Cargo.toml1
-rw-r--r--crates/ide-db/src/apply_change.rs4
-rw-r--r--crates/ide-db/src/lib.rs2
-rw-r--r--crates/ide-diagnostics/Cargo.toml1
-rw-r--r--crates/ide/src/lib.rs6
-rw-r--r--crates/load-cargo/src/lib.rs4
-rw-r--r--crates/parser/Cargo.toml2
-rw-r--r--crates/parser/src/lexed_str.rs1
-rw-r--r--crates/parser/src/lib.rs1
-rw-r--r--crates/parser/src/shortcuts.rs1
-rw-r--r--crates/proc-macro-api/Cargo.toml1
-rw-r--r--crates/profile/src/lib.rs23
-rw-r--r--crates/project-model/Cargo.toml3
-rw-r--r--crates/rust-analyzer/src/cli/rustc_tests.rs4
-rw-r--r--crates/rust-analyzer/src/global_state.rs4
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs14
-rw-r--r--crates/rust-analyzer/src/reload.rs6
-rw-r--r--crates/syntax/Cargo.toml1
-rw-r--r--crates/syntax/src/lib.rs1
-rw-r--r--crates/syntax/src/parsing.rs2
-rw-r--r--crates/syntax/src/validation.rs1
-rw-r--r--crates/test-fixture/src/lib.rs6
42 files changed, 421 insertions, 456 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9acace2fb33..f074bb4e30e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -71,7 +71,6 @@ version = "0.0.0"
 dependencies = [
  "cfg",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "profile",
  "rustc-hash",
  "salsa",
  "semver",
@@ -501,7 +500,6 @@ dependencies = [
  "hir-ty",
  "itertools",
  "once_cell",
- "profile",
  "rustc-hash",
  "smallvec",
  "span",
@@ -565,7 +563,6 @@ dependencies = [
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "limit",
  "mbe",
- "profile",
  "rustc-hash",
  "smallvec",
  "span",
@@ -601,7 +598,6 @@ dependencies = [
  "nohash-hasher",
  "once_cell",
  "oorandom",
- "profile",
  "project-model",
  "ra-ap-rustc_abi",
  "ra-ap-rustc_index 0.35.0",
@@ -673,7 +669,6 @@ dependencies = [
  "hir",
  "ide-db",
  "itertools",
- "profile",
  "smallvec",
  "sourcegen",
  "stdx",
@@ -695,7 +690,6 @@ dependencies = [
  "ide-db",
  "itertools",
  "once_cell",
- "profile",
  "smallvec",
  "stdx",
  "syntax",
@@ -753,7 +747,6 @@ dependencies = [
  "ide-db",
  "itertools",
  "once_cell",
- "profile",
  "serde_json",
  "sourcegen",
  "stdx",
@@ -1233,6 +1226,7 @@ dependencies = [
  "ra-ap-rustc_lexer",
  "sourcegen",
  "stdx",
+ "tracing",
 ]
 
 [[package]]
@@ -1302,7 +1296,6 @@ dependencies = [
  "memmap2",
  "object 0.32.0",
  "paths",
- "profile",
  "rustc-hash",
  "serde",
  "serde_json",
@@ -1386,7 +1379,6 @@ dependencies = [
  "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "paths",
- "profile",
  "rustc-hash",
  "semver",
  "serde",
@@ -1925,7 +1917,6 @@ dependencies = [
  "once_cell",
  "parser",
  "proc-macro2",
- "profile",
  "quote",
  "ra-ap-rustc_lexer",
  "rayon",
diff --git a/crates/base-db/Cargo.toml b/crates/base-db/Cargo.toml
index 801ba2d1f6c..118abf5d6eb 100644
--- a/crates/base-db/Cargo.toml
+++ b/crates/base-db/Cargo.toml
@@ -21,7 +21,6 @@ tracing.workspace = true
 
 # local deps
 cfg.workspace = true
-profile.workspace = true
 stdx.workspace = true
 syntax.workspace = true
 vfs.workspace = true
diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs
index ce8a9eab14a..37d37fd3311 100644
--- a/crates/hir-def/src/body.rs
+++ b/crates/hir-def/src/body.rs
@@ -13,7 +13,6 @@ use cfg::{CfgExpr, CfgOptions};
 use either::Either;
 use hir_expand::{name::Name, HirFileId, InFile};
 use la_arena::{Arena, ArenaMap};
-use profile::Count;
 use rustc_hash::FxHashMap;
 use syntax::{ast, AstPtr, SyntaxNodePtr};
 use triomphe::Arc;
@@ -51,7 +50,6 @@ pub struct Body {
     pub body_expr: ExprId,
     /// Block expressions in this body that may contain inner items.
     block_scopes: Vec<BlockId>,
-    _c: Count<Self>,
 }
 
 pub type ExprPtr = AstPtr<ast::Expr>;
@@ -216,7 +214,6 @@ impl Body {
 
     fn shrink_to_fit(&mut self) {
         let Self {
-            _c: _,
             body_expr: _,
             block_scopes,
             exprs,
@@ -300,7 +297,6 @@ impl Default for Body {
             params: Default::default(),
             block_scopes: Default::default(),
             binding_owners: Default::default(),
-            _c: Default::default(),
         }
     }
 }
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index ad8782d3d1e..c9300898b38 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -10,7 +10,6 @@ use hir_expand::{
     ExpandError, InFile,
 };
 use intern::Interned;
-use profile::Count;
 use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
 use span::AstIdMap;
@@ -76,7 +75,6 @@ pub(super) fn lower(
             params: Vec::new(),
             body_expr: dummy_expr_id(),
             block_scopes: Vec::new(),
-            _c: Count::new(),
         },
         expander,
         current_try_block_label: None,
diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index c7cf611589b..008fa7ef13a 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -50,7 +50,6 @@ use either::Either;
 use hir_expand::{attrs::RawAttrs, name::Name, ExpandTo, HirFileId, InFile};
 use intern::Interned;
 use la_arena::{Arena, Idx, IdxRange, RawIdx};
-use profile::Count;
 use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
 use span::{AstIdNode, FileAstId, Span};
@@ -94,8 +93,6 @@ impl fmt::Debug for RawVisibilityId {
 /// The item tree of a source file.
 #[derive(Debug, Default, Eq, PartialEq)]
 pub struct ItemTree {
-    _c: Count<Self>,
-
     top_level: SmallVec<[ModItem; 1]>,
     attrs: FxHashMap<AttrOwner, RawAttrs>,
 
@@ -263,14 +260,6 @@ impl ItemVisibilities {
     }
 }
 
-static VIS_PUB: RawVisibility = RawVisibility::Public;
-static VIS_PRIV_IMPLICIT: RawVisibility =
-    RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicitness::Implicit);
-static VIS_PRIV_EXPLICIT: RawVisibility =
-    RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)), VisibilityExplicitness::Explicit);
-static VIS_PUB_CRATE: RawVisibility =
-    RawVisibility::Module(ModPath::from_kind(PathKind::Crate), VisibilityExplicitness::Explicit);
-
 #[derive(Default, Debug, Eq, PartialEq)]
 struct ItemTreeData {
     uses: Arena<Use>,
@@ -562,6 +551,20 @@ impl_index!(fields: Field, variants: Variant, params: Param);
 impl Index<RawVisibilityId> for ItemTree {
     type Output = RawVisibility;
     fn index(&self, index: RawVisibilityId) -> &Self::Output {
+        static VIS_PUB: RawVisibility = RawVisibility::Public;
+        static VIS_PRIV_IMPLICIT: RawVisibility = RawVisibility::Module(
+            ModPath::from_kind(PathKind::Super(0)),
+            VisibilityExplicitness::Implicit,
+        );
+        static VIS_PRIV_EXPLICIT: RawVisibility = RawVisibility::Module(
+            ModPath::from_kind(PathKind::Super(0)),
+            VisibilityExplicitness::Explicit,
+        );
+        static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(
+            ModPath::from_kind(PathKind::Crate),
+            VisibilityExplicitness::Explicit,
+        );
+
         match index {
             RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT,
             RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT,
@@ -871,25 +874,19 @@ impl UseTree {
             prefix: Option<ModPath>,
             path: &ModPath,
         ) -> Option<(ModPath, ImportKind)> {
-            match (prefix, &path.kind) {
+            match (prefix, path.kind) {
                 (None, _) => Some((path.clone(), ImportKind::Plain)),
                 (Some(mut prefix), PathKind::Plain) => {
-                    for segment in path.segments() {
-                        prefix.push_segment(segment.clone());
-                    }
+                    prefix.extend(path.segments().iter().cloned());
                     Some((prefix, ImportKind::Plain))
                 }
-                (Some(mut prefix), PathKind::Super(n))
-                    if *n > 0 && prefix.segments().is_empty() =>
-                {
+                (Some(mut prefix), PathKind::Super(n)) if n > 0 && prefix.segments().is_empty() => {
                     // `super::super` + `super::rest`
                     match &mut prefix.kind {
                         PathKind::Super(m) => {
                             cov_mark::hit!(concat_super_mod_paths);
-                            *m += *n;
-                            for segment in path.segments() {
-                                prefix.push_segment(segment.clone());
-                            }
+                            *m += n;
+                            prefix.extend(path.segments().iter().cloned());
                             Some((prefix, ImportKind::Plain))
                         }
                         _ => None,
@@ -963,10 +960,10 @@ impl ModItem {
             | ModItem::Mod(_)
             | ModItem::MacroRules(_)
             | ModItem::Macro2(_) => None,
-            ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
-            ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
-            ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
-            ModItem::Function(func) => Some(AssocItem::Function(*func)),
+            &ModItem::MacroCall(call) => Some(AssocItem::MacroCall(call)),
+            &ModItem::Const(konst) => Some(AssocItem::Const(konst)),
+            &ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(alias)),
+            &ModItem::Function(func) => Some(AssocItem::Function(func)),
         }
     }
 
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 270468ad0a6..764617eafb7 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -65,7 +65,6 @@ use hir_expand::{
 };
 use itertools::Itertools;
 use la_arena::Arena;
-use profile::Count;
 use rustc_hash::{FxHashMap, FxHashSet};
 use span::FileAstId;
 use stdx::format_to;
@@ -95,7 +94,6 @@ use crate::{
 /// is computed by the `block_def_map` query.
 #[derive(Debug, PartialEq, Eq)]
 pub struct DefMap {
-    _c: Count<Self>,
     /// When this is a block def map, this will hold the block id of the block and module that
     /// contains this block.
     block: Option<BlockInfo>,
@@ -154,6 +152,23 @@ struct DefMapCrateData {
 }
 
 impl DefMapCrateData {
+    fn new(edition: Edition) -> Self {
+        Self {
+            extern_prelude: FxHashMap::default(),
+            exported_derives: FxHashMap::default(),
+            fn_proc_macro_mapping: FxHashMap::default(),
+            proc_macro_loading_error: None,
+            registered_attrs: Vec::new(),
+            registered_tools: Vec::new(),
+            unstable_features: FxHashSet::default(),
+            rustc_coherence_is_core: false,
+            no_core: false,
+            no_std: false,
+            edition,
+            recursion_limit: None,
+        }
+    }
+
     fn shrink_to_fit(&mut self) {
         let Self {
             extern_prelude,
@@ -305,67 +320,67 @@ impl DefMap {
     /// The module id of a crate or block root.
     pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
 
-    pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<DefMap> {
+    pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: CrateId) -> Arc<DefMap> {
         let crate_graph = db.crate_graph();
-        let krate_name = crate_graph[krate].display_name.as_deref().unwrap_or_default();
-
-        let _p = tracing::span!(tracing::Level::INFO, "crate_def_map_query", ?krate_name).entered();
+        let krate = &crate_graph[crate_id];
+        let name = krate.display_name.as_deref().unwrap_or_default();
+        let _p = tracing::span!(tracing::Level::INFO, "crate_def_map_query", ?name).entered();
 
-        let crate_graph = db.crate_graph();
+        let module_data = ModuleData::new(
+            ModuleOrigin::CrateRoot { definition: krate.root_file_id },
+            Visibility::Public,
+        );
 
-        let edition = crate_graph[krate].edition;
-        let origin = ModuleOrigin::CrateRoot { definition: crate_graph[krate].root_file_id };
-        let def_map = DefMap::empty(krate, edition, ModuleData::new(origin, Visibility::Public));
-        let def_map = collector::collect_defs(
-            db,
-            def_map,
-            TreeId::new(crate_graph[krate].root_file_id.into(), None),
+        let def_map = DefMap::empty(
+            crate_id,
+            Arc::new(DefMapCrateData::new(krate.edition)),
+            module_data,
+            None,
         );
+        let def_map =
+            collector::collect_defs(db, def_map, TreeId::new(krate.root_file_id.into(), None));
 
         Arc::new(def_map)
     }
 
     pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> {
-        let block: BlockLoc = block_id.lookup(db);
-
-        let parent_map = block.module.def_map(db);
-        let krate = block.module.krate;
-        let local_id = LocalModuleId::from_raw(la_arena::RawIdx::from(0));
-        // NB: we use `None` as block here, which would be wrong for implicit
-        // modules declared by blocks with items. At the moment, we don't use
-        // this visibility for anything outside IDE, so that's probably OK.
+        let BlockLoc { ast_id, module } = block_id.lookup(db);
+
         let visibility = Visibility::Module(
-            ModuleId { krate, local_id, block: None },
+            ModuleId { krate: module.krate, local_id: Self::ROOT, block: module.block },
             VisibilityExplicitness::Implicit,
         );
-        let module_data = ModuleData::new(
-            ModuleOrigin::BlockExpr { block: block.ast_id, id: block_id },
-            visibility,
+        let module_data =
+            ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
+
+        let parent_map = module.def_map(db);
+        let def_map = DefMap::empty(
+            module.krate,
+            parent_map.data.clone(),
+            module_data,
+            Some(BlockInfo {
+                block: block_id,
+                parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id },
+            }),
         );
 
-        let mut def_map = DefMap::empty(krate, parent_map.data.edition, module_data);
-        def_map.data = parent_map.data.clone();
-        def_map.block = Some(BlockInfo {
-            block: block_id,
-            parent: BlockRelativeModuleId {
-                block: block.module.block,
-                local_id: block.module.local_id,
-            },
-        });
-
         let def_map =
-            collector::collect_defs(db, def_map, TreeId::new(block.ast_id.file_id, Some(block_id)));
+            collector::collect_defs(db, def_map, TreeId::new(ast_id.file_id, Some(block_id)));
         Arc::new(def_map)
     }
 
-    fn empty(krate: CrateId, edition: Edition, module_data: ModuleData) -> DefMap {
+    fn empty(
+        krate: CrateId,
+        crate_data: Arc<DefMapCrateData>,
+        module_data: ModuleData,
+        block: Option<BlockInfo>,
+    ) -> DefMap {
         let mut modules: Arena<ModuleData> = Arena::default();
         let root = modules.alloc(module_data);
         assert_eq!(root, Self::ROOT);
 
         DefMap {
-            _c: Count::new(),
-            block: None,
+            block,
             modules,
             krate,
             prelude: None,
@@ -373,23 +388,36 @@ impl DefMap {
             derive_helpers_in_scope: FxHashMap::default(),
             diagnostics: Vec::new(),
             enum_definitions: FxHashMap::default(),
-            data: Arc::new(DefMapCrateData {
-                extern_prelude: FxHashMap::default(),
-                exported_derives: FxHashMap::default(),
-                fn_proc_macro_mapping: FxHashMap::default(),
-                proc_macro_loading_error: None,
-                registered_attrs: Vec::new(),
-                registered_tools: Vec::new(),
-                unstable_features: FxHashSet::default(),
-                rustc_coherence_is_core: false,
-                no_core: false,
-                no_std: false,
-                edition,
-                recursion_limit: None,
-            }),
+            data: crate_data,
+        }
+    }
+    fn shrink_to_fit(&mut self) {
+        // Exhaustive match to require handling new fields.
+        let Self {
+            macro_use_prelude,
+            diagnostics,
+            modules,
+            derive_helpers_in_scope,
+            block: _,
+            krate: _,
+            prelude: _,
+            data: _,
+            enum_definitions,
+        } = self;
+
+        macro_use_prelude.shrink_to_fit();
+        diagnostics.shrink_to_fit();
+        modules.shrink_to_fit();
+        derive_helpers_in_scope.shrink_to_fit();
+        enum_definitions.shrink_to_fit();
+        for (_, module) in modules.iter_mut() {
+            module.children.shrink_to_fit();
+            module.scope.shrink_to_fit();
         }
     }
+}
 
+impl DefMap {
     pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ {
         self.modules
             .iter()
@@ -440,26 +468,6 @@ impl DefMap {
         self.krate
     }
 
-    pub(crate) fn block_id(&self) -> Option<BlockId> {
-        self.block.map(|block| block.block)
-    }
-
-    pub(crate) fn prelude(&self) -> Option<(ModuleId, Option<UseId>)> {
-        self.prelude
-    }
-
-    pub(crate) fn extern_prelude(
-        &self,
-    ) -> impl Iterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_ {
-        self.data.extern_prelude.iter().map(|(name, &def)| (name, def))
-    }
-
-    pub(crate) fn macro_use_prelude(
-        &self,
-    ) -> impl Iterator<Item = (&Name, (MacroId, Option<ExternCrateId>))> + '_ {
-        self.macro_use_prelude.iter().map(|(name, &def)| (name, def))
-    }
-
     pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId {
         let block = self.block.map(|b| b.block);
         ModuleId { krate: self.krate, local_id, block }
@@ -475,68 +483,6 @@ impl DefMap {
         self.module_id(Self::ROOT)
     }
 
-    pub(crate) fn resolve_path(
-        &self,
-        db: &dyn DefDatabase,
-        original_module: LocalModuleId,
-        path: &ModPath,
-        shadow: BuiltinShadowMode,
-        expected_macro_subns: Option<MacroSubNs>,
-    ) -> (PerNs, Option<usize>) {
-        let res = self.resolve_path_fp_with_macro(
-            db,
-            ResolveMode::Other,
-            original_module,
-            path,
-            shadow,
-            expected_macro_subns,
-        );
-        (res.resolved_def, res.segment_index)
-    }
-
-    pub(crate) fn resolve_path_locally(
-        &self,
-        db: &dyn DefDatabase,
-        original_module: LocalModuleId,
-        path: &ModPath,
-        shadow: BuiltinShadowMode,
-    ) -> (PerNs, Option<usize>) {
-        let res = self.resolve_path_fp_with_macro_single(
-            db,
-            ResolveMode::Other,
-            original_module,
-            path,
-            shadow,
-            None, // Currently this function isn't used for macro resolution.
-        );
-        (res.resolved_def, res.segment_index)
-    }
-
-    /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module.
-    ///
-    /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns
-    /// `None`, iteration continues.
-    pub(crate) fn with_ancestor_maps<T>(
-        &self,
-        db: &dyn DefDatabase,
-        local_mod: LocalModuleId,
-        f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>,
-    ) -> Option<T> {
-        if let Some(it) = f(self, local_mod) {
-            return Some(it);
-        }
-        let mut block = self.block;
-        while let Some(block_info) = block {
-            let parent = block_info.parent.def_map(db, self.krate);
-            if let Some(it) = f(&parent, block_info.parent.local_id) {
-                return Some(it);
-            }
-            block = parent.block;
-        }
-
-        None
-    }
-
     /// If this `DefMap` is for a block expression, returns the module containing the block (which
     /// might again be a block, or a module inside a block).
     pub fn parent(&self) -> Option<ModuleId> {
@@ -559,6 +505,16 @@ impl DefMap {
         }
     }
 
+    /// Get a reference to the def map's diagnostics.
+    pub fn diagnostics(&self) -> &[DefDiagnostic] {
+        self.diagnostics.as_slice()
+    }
+
+    pub fn recursion_limit(&self) -> u32 {
+        // 128 is the default in rustc
+        self.data.recursion_limit.unwrap_or(128)
+    }
+
     // FIXME: this can use some more human-readable format (ideally, an IR
     // even), as this should be a great debugging aid.
     pub fn dump(&self, db: &dyn DefDatabase) -> String {
@@ -608,41 +564,89 @@ impl DefMap {
         format_to!(buf, "crate scope\n");
         buf
     }
+}
 
-    fn shrink_to_fit(&mut self) {
-        // Exhaustive match to require handling new fields.
-        let Self {
-            _c: _,
-            macro_use_prelude,
-            diagnostics,
-            modules,
-            derive_helpers_in_scope,
-            block: _,
-            krate: _,
-            prelude: _,
-            data: _,
-            enum_definitions,
-        } = self;
+impl DefMap {
+    pub(crate) fn block_id(&self) -> Option<BlockId> {
+        self.block.map(|block| block.block)
+    }
 
-        macro_use_prelude.shrink_to_fit();
-        diagnostics.shrink_to_fit();
-        modules.shrink_to_fit();
-        derive_helpers_in_scope.shrink_to_fit();
-        enum_definitions.shrink_to_fit();
-        for (_, module) in modules.iter_mut() {
-            module.children.shrink_to_fit();
-            module.scope.shrink_to_fit();
-        }
+    pub(crate) fn prelude(&self) -> Option<(ModuleId, Option<UseId>)> {
+        self.prelude
     }
 
-    /// Get a reference to the def map's diagnostics.
-    pub fn diagnostics(&self) -> &[DefDiagnostic] {
-        self.diagnostics.as_slice()
+    pub(crate) fn extern_prelude(
+        &self,
+    ) -> impl Iterator<Item = (&Name, (CrateRootModuleId, Option<ExternCrateId>))> + '_ {
+        self.data.extern_prelude.iter().map(|(name, &def)| (name, def))
     }
 
-    pub fn recursion_limit(&self) -> u32 {
-        // 128 is the default in rustc
-        self.data.recursion_limit.unwrap_or(128)
+    pub(crate) fn macro_use_prelude(
+        &self,
+    ) -> impl Iterator<Item = (&Name, (MacroId, Option<ExternCrateId>))> + '_ {
+        self.macro_use_prelude.iter().map(|(name, &def)| (name, def))
+    }
+
+    pub(crate) fn resolve_path(
+        &self,
+        db: &dyn DefDatabase,
+        original_module: LocalModuleId,
+        path: &ModPath,
+        shadow: BuiltinShadowMode,
+        expected_macro_subns: Option<MacroSubNs>,
+    ) -> (PerNs, Option<usize>) {
+        let res = self.resolve_path_fp_with_macro(
+            db,
+            ResolveMode::Other,
+            original_module,
+            path,
+            shadow,
+            expected_macro_subns,
+        );
+        (res.resolved_def, res.segment_index)
+    }
+
+    pub(crate) fn resolve_path_locally(
+        &self,
+        db: &dyn DefDatabase,
+        original_module: LocalModuleId,
+        path: &ModPath,
+        shadow: BuiltinShadowMode,
+    ) -> (PerNs, Option<usize>) {
+        let res = self.resolve_path_fp_with_macro_single(
+            db,
+            ResolveMode::Other,
+            original_module,
+            path,
+            shadow,
+            None, // Currently this function isn't used for macro resolution.
+        );
+        (res.resolved_def, res.segment_index)
+    }
+
+    /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module.
+    ///
+    /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns
+    /// `None`, iteration continues.
+    pub(crate) fn with_ancestor_maps<T>(
+        &self,
+        db: &dyn DefDatabase,
+        local_mod: LocalModuleId,
+        f: &mut dyn FnMut(&DefMap, LocalModuleId) -> Option<T>,
+    ) -> Option<T> {
+        if let Some(it) = f(self, local_mod) {
+            return Some(it);
+        }
+        let mut block = self.block;
+        while let Some(block_info) = block {
+            let parent = block_info.parent.def_map(db, self.krate);
+            if let Some(it) = f(&parent, block_info.parent.local_id) {
+                return Some(it);
+            }
+            block = parent.block;
+        }
+
+        None
     }
 }
 
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 538e735688b..18aefbf332c 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -64,19 +64,18 @@ static FIXED_POINT_LIMIT: Limit = Limit::new(8192);
 pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeId) -> DefMap {
     let crate_graph = db.crate_graph();
 
-    let mut deps = FxHashMap::default();
-    // populate external prelude and dependency list
     let krate = &crate_graph[def_map.krate];
+
+    // populate external prelude and dependency list
+    let mut deps =
+        FxHashMap::with_capacity_and_hasher(krate.dependencies.len(), Default::default());
     for dep in &krate.dependencies {
         tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
 
         deps.insert(dep.as_name(), dep.clone());
     }
 
-    let cfg_options = &krate.cfg_options;
-
-    let is_proc_macro = krate.is_proc_macro;
-    let proc_macros = if is_proc_macro {
+    let proc_macros = if krate.is_proc_macro {
         match db.proc_macros().get(&def_map.krate) {
             Some(Ok(proc_macros)) => {
                 Ok(proc_macros
@@ -124,11 +123,11 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
         indeterminate_imports: Vec::new(),
         unresolved_macros: Vec::new(),
         mod_dirs: FxHashMap::default(),
-        cfg_options,
+        cfg_options: &krate.cfg_options,
         proc_macros,
         from_glob_import: Default::default(),
         skip_attrs: Default::default(),
-        is_proc_macro,
+        is_proc_macro: krate.is_proc_macro,
     };
     if tree_id.is_block() {
         collector.seed_with_inner(tree_id);
@@ -302,71 +301,50 @@ impl DefCollector<'_> {
                     return;
                 }
             }
-            let attr_name = match attr.path.as_ident() {
-                Some(name) => name,
-                None => continue,
-            };
+            let Some(attr_name) = attr.path.as_ident() else { continue };
 
-            if *attr_name == hir_expand::name![recursion_limit] {
-                if let Some(limit) = attr.string_value() {
-                    if let Ok(limit) = limit.parse() {
-                        crate_data.recursion_limit = Some(limit);
+            match () {
+                () if *attr_name == hir_expand::name![recursion_limit] => {
+                    if let Some(limit) = attr.string_value() {
+                        if let Ok(limit) = limit.parse() {
+                            crate_data.recursion_limit = Some(limit);
+                        }
                     }
                 }
-                continue;
-            }
-
-            if *attr_name == hir_expand::name![crate_type] {
-                if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) {
-                    self.is_proc_macro = true;
+                () if *attr_name == hir_expand::name![crate_type] => {
+                    if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) {
+                        self.is_proc_macro = true;
+                    }
                 }
-                continue;
-            }
-
-            if *attr_name == hir_expand::name![no_core] {
-                crate_data.no_core = true;
-                continue;
-            }
-
-            if *attr_name == hir_expand::name![no_std] {
-                crate_data.no_std = true;
-                continue;
-            }
-
-            if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") {
-                crate_data.rustc_coherence_is_core = true;
-                continue;
-            }
-
-            if *attr_name == hir_expand::name![feature] {
-                let features = attr
-                    .parse_path_comma_token_tree(self.db.upcast())
-                    .into_iter()
-                    .flatten()
-                    .filter_map(|(feat, _)| match feat.segments() {
-                        [name] => Some(name.to_smol_str()),
-                        _ => None,
-                    });
-                crate_data.unstable_features.extend(features);
-            }
-
-            let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
-                || *attr_name == hir_expand::name![register_tool];
-            if !attr_is_register_like {
-                continue;
-            }
-
-            let registered_name = match attr.single_ident_value() {
-                Some(ident) => ident.as_name(),
-                _ => continue,
-            };
-
-            if *attr_name == hir_expand::name![register_attr] {
-                crate_data.registered_attrs.push(registered_name.to_smol_str());
-                cov_mark::hit!(register_attr);
-            } else {
-                crate_data.registered_tools.push(registered_name.to_smol_str());
-                cov_mark::hit!(register_tool);
+                () if *attr_name == hir_expand::name![no_core] => crate_data.no_core = true,
+                () if *attr_name == hir_expand::name![no_std] => crate_data.no_std = true,
+                () if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") => {
+                    crate_data.rustc_coherence_is_core = true;
+                }
+                () if *attr_name == hir_expand::name![feature] => {
+                    let features = attr
+                        .parse_path_comma_token_tree(self.db.upcast())
+                        .into_iter()
+                        .flatten()
+                        .filter_map(|(feat, _)| match feat.segments() {
+                            [name] => Some(name.to_smol_str()),
+                            _ => None,
+                        });
+                    crate_data.unstable_features.extend(features);
+                }
+                () if *attr_name == hir_expand::name![register_attr] => {
+                    if let Some(ident) = attr.single_ident_value() {
+                        crate_data.registered_attrs.push(ident.text.clone());
+                        cov_mark::hit!(register_attr);
+                    }
+                }
+                () if *attr_name == hir_expand::name![register_tool] => {
+                    if let Some(ident) = attr.single_ident_value() {
+                        crate_data.registered_tools.push(ident.text.clone());
+                        cov_mark::hit!(register_tool);
+                    }
+                }
+                () => (),
             }
         }
 
@@ -409,6 +387,7 @@ impl DefCollector<'_> {
         // main name resolution fixed-point loop.
         let mut i = 0;
         'resolve_attr: loop {
+            let _p = tracing::span!(tracing::Level::INFO, "resolve_macros loop").entered();
             'resolve_macros: loop {
                 self.db.unwind_if_cancelled();
 
@@ -466,9 +445,8 @@ impl DefCollector<'_> {
             // Additionally, while the proc macro entry points must be `pub`, they are not publicly
             // exported in type/value namespace. This function reduces the visibility of all items
             // in the crate root that aren't proc macros.
-            let root = DefMap::ROOT;
-            let module_id = self.def_map.module_id(root);
-            let root = &mut self.def_map.modules[root];
+            let module_id = self.def_map.module_id(DefMap::ROOT);
+            let root = &mut self.def_map.modules[DefMap::ROOT];
             root.scope.censor_non_proc_macros(module_id);
         }
     }
@@ -828,12 +806,10 @@ impl DefCollector<'_> {
                     return PartialResolvedImport::Unresolved;
                 }
 
-                if let Some(krate) = res.krate {
-                    if krate != self.def_map.krate {
-                        return PartialResolvedImport::Resolved(
-                            def.filter_visibility(|v| matches!(v, Visibility::Public)),
-                        );
-                    }
+                if res.from_differing_crate {
+                    return PartialResolvedImport::Resolved(
+                        def.filter_visibility(|v| matches!(v, Visibility::Public)),
+                    );
                 }
 
                 // Check whether all namespaces are resolved.
@@ -1920,7 +1896,7 @@ impl ModCollector<'_, '_> {
     }
 
     fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
-        let path_attr = attrs.by_key("path").string_value();
+        let path_attr = attrs.by_key("path").string_value().map(SmolStr::as_str);
         let is_macro_use = attrs.by_key("macro_use").exists();
         let module = &self.item_tree[module_id];
         match &module.kind {
@@ -1934,25 +1910,26 @@ impl ModCollector<'_, '_> {
                     module_id,
                 );
 
-                if let Some(mod_dir) = self.mod_dir.descend_into_definition(&module.name, path_attr)
-                {
-                    ModCollector {
-                        def_collector: &mut *self.def_collector,
-                        macro_depth: self.macro_depth,
-                        module_id,
-                        tree_id: self.tree_id,
-                        item_tree: self.item_tree,
-                        mod_dir,
-                    }
-                    .collect_in_top_module(items);
-                    if is_macro_use {
-                        self.import_all_legacy_macros(module_id);
-                    }
+                let Some(mod_dir) = self.mod_dir.descend_into_definition(&module.name, path_attr)
+                else {
+                    return;
+                };
+                ModCollector {
+                    def_collector: &mut *self.def_collector,
+                    macro_depth: self.macro_depth,
+                    module_id,
+                    tree_id: self.tree_id,
+                    item_tree: self.item_tree,
+                    mod_dir,
+                }
+                .collect_in_top_module(items);
+                if is_macro_use {
+                    self.import_all_legacy_macros(module_id);
                 }
             }
             // out of line module, resolve, parse and recurse
             ModKind::Outline => {
-                let ast_id = AstId::new(self.tree_id.file_id(), module.ast_id);
+                let ast_id = AstId::new(self.file_id(), module.ast_id);
                 let db = self.def_collector.db;
                 match self.mod_dir.resolve_declaration(db, self.file_id(), &module.name, path_attr)
                 {
@@ -2445,7 +2422,7 @@ mod tests {
     use base_db::SourceDatabase;
     use test_fixture::WithFixture;
 
-    use crate::test_db::TestDB;
+    use crate::{nameres::DefMapCrateData, test_db::TestDB};
 
     use super::*;
 
@@ -2476,8 +2453,12 @@ mod tests {
 
         let edition = db.crate_graph()[krate].edition;
         let module_origin = ModuleOrigin::CrateRoot { definition: file_id };
-        let def_map =
-            DefMap::empty(krate, edition, ModuleData::new(module_origin, Visibility::Public));
+        let def_map = DefMap::empty(
+            krate,
+            Arc::new(DefMapCrateData::new(edition)),
+            ModuleData::new(module_origin, Visibility::Public),
+            None,
+        );
         do_collect_defs(&db, def_map)
     }
 
diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs
index 161b2c05990..b5a302dbcaf 100644
--- a/crates/hir-def/src/nameres/diagnostics.rs
+++ b/crates/hir-def/src/nameres/diagnostics.rs
@@ -1,5 +1,7 @@
 //! Diagnostics emitted during DefMap construction.
 
+use std::ops::Not;
+
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
 use hir_expand::{attrs::AttrId, ErasedAstId, MacroCallKind};
@@ -16,27 +18,16 @@ use crate::{
 #[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 { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions },
-
     UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
-
     UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
-
     MacroError { ast: MacroCallKind, message: String },
-
     MacroExpansionParseError { ast: MacroCallKind, errors: Box<[SyntaxError]> },
-
     UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
-
     InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
-
     MalformedDerive { ast: AstId<ast::Adt>, id: usize },
-
     MacroDefError { ast: AstId<ast::Macro>, message: String },
 }
 
@@ -45,11 +36,12 @@ pub struct DefDiagnostics(Option<triomphe::Arc<Box<[DefDiagnostic]>>>);
 
 impl DefDiagnostics {
     pub fn new(diagnostics: Vec<DefDiagnostic>) -> Self {
-        Self(if diagnostics.is_empty() {
-            None
-        } else {
-            Some(triomphe::Arc::new(diagnostics.into_boxed_slice()))
-        })
+        Self(
+            diagnostics
+                .is_empty()
+                .not()
+                .then(|| triomphe::Arc::new(diagnostics.into_boxed_slice())),
+        )
     }
 
     pub fn iter(&self) -> impl Iterator<Item = &DefDiagnostic> {
diff --git a/crates/hir-def/src/nameres/mod_resolution.rs b/crates/hir-def/src/nameres/mod_resolution.rs
index c45200e2de9..696fb6a961c 100644
--- a/crates/hir-def/src/nameres/mod_resolution.rs
+++ b/crates/hir-def/src/nameres/mod_resolution.rs
@@ -3,7 +3,6 @@ use arrayvec::ArrayVec;
 use base_db::{AnchoredPath, FileId};
 use hir_expand::{name::Name, HirFileIdExt, MacroFileIdExt};
 use limit::Limit;
-use syntax::SmolStr;
 
 use crate::{db::DefDatabase, HirFileId};
 
@@ -29,9 +28,9 @@ impl ModDir {
     pub(super) fn descend_into_definition(
         &self,
         name: &Name,
-        attr_path: Option<&SmolStr>,
+        attr_path: Option<&str>,
     ) -> Option<ModDir> {
-        let path = match attr_path.map(SmolStr::as_str) {
+        let path = match attr_path {
             None => {
                 let mut path = self.dir_path.clone();
                 path.push(&name.unescaped().to_smol_str());
@@ -63,10 +62,9 @@ impl ModDir {
         db: &dyn DefDatabase,
         file_id: HirFileId,
         name: &Name,
-        attr_path: Option<&SmolStr>,
+        attr_path: Option<&str>,
     ) -> Result<(FileId, bool, ModDir), Box<[String]>> {
         let name = name.unescaped();
-        let orig_file_id = file_id.original_file_respecting_includes(db.upcast());
 
         let mut candidate_files = ArrayVec::<_, 2>::new();
         match attr_path {
@@ -91,17 +89,19 @@ impl ModDir {
             }
         };
 
+        let orig_file_id = file_id.original_file_respecting_includes(db.upcast());
         for candidate in candidate_files.iter() {
             let path = AnchoredPath { anchor: orig_file_id, path: candidate.as_str() };
             if let Some(file_id) = db.resolve_path(path) {
                 let is_mod_rs = candidate.ends_with("/mod.rs");
 
-                let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() {
-                    (DirPath::empty(), false)
+                let root_dir_owner = is_mod_rs || attr_path.is_some();
+                let dir_path = if root_dir_owner {
+                    DirPath::empty()
                 } else {
-                    (DirPath::new(format!("{}/", name.display(db.upcast()))), true)
+                    DirPath::new(format!("{}/", name.display(db.upcast())))
                 };
-                if let Some(mod_dir) = self.child(dir_path, root_non_dir_owner) {
+                if let Some(mod_dir) = self.child(dir_path, !root_dir_owner) {
                     return Ok((file_id, is_mod_rs, mod_dir));
                 }
             }
diff --git a/crates/hir-def/src/nameres/path_resolution.rs b/crates/hir-def/src/nameres/path_resolution.rs
index 1e13f7f8fd0..9e53b037283 100644
--- a/crates/hir-def/src/nameres/path_resolution.rs
+++ b/crates/hir-def/src/nameres/path_resolution.rs
@@ -22,7 +22,7 @@ use crate::{
     path::{ModPath, PathKind},
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
-    AdtId, CrateId, LocalModuleId, ModuleDefId,
+    AdtId, LocalModuleId, ModuleDefId,
 };
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -42,21 +42,21 @@ pub(super) struct ResolvePathResult {
     pub(super) resolved_def: PerNs,
     pub(super) segment_index: Option<usize>,
     pub(super) reached_fixedpoint: ReachedFixedPoint,
-    pub(super) krate: Option<CrateId>,
+    pub(super) from_differing_crate: bool,
 }
 
 impl ResolvePathResult {
     fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
-        ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None)
+        ResolvePathResult::new(PerNs::none(), reached_fixedpoint, None, false)
     }
 
-    fn with(
+    fn new(
         resolved_def: PerNs,
         reached_fixedpoint: ReachedFixedPoint,
         segment_index: Option<usize>,
-        krate: Option<CrateId>,
+        from_differing_crate: bool,
     ) -> ResolvePathResult {
-        ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, krate }
+        ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, from_differing_crate }
     }
 }
 
@@ -134,7 +134,19 @@ impl DefMap {
         // resolving them to. Pass `None` otherwise, e.g. when we're resolving import paths.
         expected_macro_subns: Option<MacroSubNs>,
     ) -> ResolvePathResult {
-        let mut result = ResolvePathResult::empty(ReachedFixedPoint::No);
+        let mut result = self.resolve_path_fp_with_macro_single(
+            db,
+            mode,
+            original_module,
+            path,
+            shadow,
+            expected_macro_subns,
+        );
+
+        if self.block.is_none() {
+            // If we're in the root `DefMap`, we can resolve the path directly.
+            return result;
+        }
 
         let mut arc;
         let mut current_map = self;
@@ -153,8 +165,7 @@ impl DefMap {
             if result.reached_fixedpoint == ReachedFixedPoint::No {
                 result.reached_fixedpoint = new.reached_fixedpoint;
             }
-            // FIXME: this doesn't seem right; what if the different namespace resolutions come from different crates?
-            result.krate = result.krate.or(new.krate);
+            result.from_differing_crate |= new.from_differing_crate;
             result.segment_index = match (result.segment_index, new.segment_index) {
                 (Some(idx), None) => Some(idx),
                 (Some(old), Some(new)) => Some(old.max(new)),
@@ -333,11 +344,11 @@ impl DefMap {
                         // expectation is discarded.
                         let (def, s) =
                             defp_map.resolve_path(db, module.local_id, &path, shadow, None);
-                        return ResolvePathResult::with(
+                        return ResolvePathResult::new(
                             def,
                             ReachedFixedPoint::Yes,
                             s.map(|s| s + i),
-                            Some(module.krate),
+                            true,
                         );
                     }
 
@@ -385,11 +396,11 @@ impl DefMap {
                     match res {
                         Some(res) => res,
                         None => {
-                            return ResolvePathResult::with(
+                            return ResolvePathResult::new(
                                 PerNs::types(e.into(), vis, imp),
                                 ReachedFixedPoint::Yes,
                                 Some(i),
-                                Some(self.krate),
+                                false,
                             )
                         }
                     }
@@ -403,11 +414,11 @@ impl DefMap {
                         curr,
                     );
 
-                    return ResolvePathResult::with(
+                    return ResolvePathResult::new(
                         PerNs::types(s, vis, imp),
                         ReachedFixedPoint::Yes,
                         Some(i),
-                        Some(self.krate),
+                        false,
                     );
                 }
             };
@@ -416,7 +427,7 @@ impl DefMap {
                 .filter_visibility(|vis| vis.is_visible_from_def_map(db, self, original_module));
         }
 
-        ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate))
+        ResolvePathResult::new(curr_per_ns, ReachedFixedPoint::Yes, None, false)
     }
 
     fn resolve_name_in_module(
diff --git a/crates/hir-expand/Cargo.toml b/crates/hir-expand/Cargo.toml
index 506a188a211..4f308080156 100644
--- a/crates/hir-expand/Cargo.toml
+++ b/crates/hir-expand/Cargo.toml
@@ -28,7 +28,6 @@ intern.workspace = true
 base-db.workspace = true
 cfg.workspace = true
 syntax.workspace = true
-profile.workspace = true
 tt.workspace = true
 mbe.workspace = true
 limit.workspace = true
@@ -38,4 +37,4 @@ span.workspace = true
 expect-test = "1.4.0"
 
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/crates/hir-expand/src/builtin_attr_macro.rs b/crates/hir-expand/src/builtin_attr_macro.rs
index 903b0d48070..a0102f36aff 100644
--- a/crates/hir-expand/src/builtin_attr_macro.rs
+++ b/crates/hir-expand/src/builtin_attr_macro.rs
@@ -4,23 +4,17 @@ use span::{MacroCallId, Span};
 use crate::{db::ExpandDatabase, name, tt, ExpandResult, MacroCallKind};
 
 macro_rules! register_builtin {
-    ($expand_fn:ident: $(($name:ident, $variant:ident) => $expand:ident),* ) => {
+    ($(($name:ident, $variant:ident) => $expand:ident),* ) => {
         #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
         pub enum BuiltinAttrExpander {
             $($variant),*
         }
 
         impl BuiltinAttrExpander {
-            pub fn $expand_fn(
-                &self,
-                db: &dyn ExpandDatabase,
-                id: MacroCallId,
-                tt: &tt::Subtree,
-            ) -> ExpandResult<tt::Subtree> {
-                let expander = match *self {
+            pub fn expander(&self) -> fn (&dyn ExpandDatabase, MacroCallId, &tt::Subtree) -> ExpandResult<tt::Subtree>  {
+                match *self {
                     $( BuiltinAttrExpander::$variant => $expand, )*
-                };
-                expander(db, id, tt)
+                }
             }
 
             fn find_by_name(name: &name::Name) -> Option<Self> {
@@ -35,6 +29,15 @@ macro_rules! register_builtin {
 }
 
 impl BuiltinAttrExpander {
+    pub fn expand(
+        &self,
+        db: &dyn ExpandDatabase,
+        id: MacroCallId,
+        tt: &tt::Subtree,
+    ) -> ExpandResult<tt::Subtree> {
+        self.expander()(db, id, tt)
+    }
+
     pub fn is_derive(self) -> bool {
         matches!(self, BuiltinAttrExpander::Derive | BuiltinAttrExpander::DeriveConst)
     }
@@ -46,7 +49,7 @@ impl BuiltinAttrExpander {
     }
 }
 
-register_builtin! { expand:
+register_builtin! {
     (bench, Bench) => dummy_attr_expand,
     (cfg, Cfg) => dummy_attr_expand,
     (cfg_attr, CfgAttr) => dummy_attr_expand,
diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs
index 27954875143..f36f48baaee 100644
--- a/crates/hir-expand/src/builtin_derive_macro.rs
+++ b/crates/hir-expand/src/builtin_derive_macro.rs
@@ -25,20 +25,10 @@ macro_rules! register_builtin {
         }
 
         impl BuiltinDeriveExpander {
-            pub fn expand(
-                &self,
-                db: &dyn ExpandDatabase,
-                id: MacroCallId,
-                tt: &ast::Adt,
-                token_map: SpanMapRef<'_>,
-            ) -> ExpandResult<tt::Subtree> {
-                let expander = match *self {
+            pub fn expander(&self) -> fn(Span, &ast::Adt, SpanMapRef<'_>) -> ExpandResult<tt::Subtree>  {
+                match *self {
                     $( BuiltinDeriveExpander::$trait => $expand, )*
-                };
-
-                let span = db.lookup_intern_macro_call(id).call_site;
-                let span = span_with_def_site_ctxt(db, span, id);
-                expander(span, tt, token_map)
+                }
             }
 
             fn find_by_name(name: &name::Name) -> Option<Self> {
@@ -52,6 +42,20 @@ macro_rules! register_builtin {
     };
 }
 
+impl BuiltinDeriveExpander {
+    pub fn expand(
+        &self,
+        db: &dyn ExpandDatabase,
+        id: MacroCallId,
+        tt: &ast::Adt,
+        token_map: SpanMapRef<'_>,
+    ) -> ExpandResult<tt::Subtree> {
+        let span = db.lookup_intern_macro_call(id).call_site;
+        let span = span_with_def_site_ctxt(db, span, id);
+        self.expander()(span, tt, token_map)
+    }
+}
+
 register_builtin! {
     Copy => copy_expand,
     Clone => clone_expand,
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index 90cd3af7578..0fd0c25dcce 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -31,36 +31,18 @@ macro_rules! register_builtin {
         }
 
         impl BuiltinFnLikeExpander {
-            pub fn expand(
-                &self,
-                db: &dyn ExpandDatabase,
-                id: MacroCallId,
-                tt: &tt::Subtree,
-            ) -> ExpandResult<tt::Subtree> {
-                let expander = match *self {
+            pub fn expander(&self) -> fn (&dyn ExpandDatabase, MacroCallId, &tt::Subtree, Span) -> ExpandResult<tt::Subtree>  {
+                match *self {
                     $( BuiltinFnLikeExpander::$kind => $expand, )*
-                };
-
-                let span = db.lookup_intern_macro_call(id).call_site;
-                let span = span_with_def_site_ctxt(db, span, id);
-                expander(db, id, tt, span)
+                }
             }
         }
 
         impl EagerExpander {
-            pub fn expand(
-                &self,
-                db: &dyn ExpandDatabase,
-                id: MacroCallId,
-                tt: &tt::Subtree,
-            ) -> ExpandResult<tt::Subtree> {
-                let expander = match *self {
+            pub fn expander(&self) -> fn (&dyn ExpandDatabase, MacroCallId, &tt::Subtree, Span) -> ExpandResult<tt::Subtree>  {
+                match *self {
                     $( EagerExpander::$e_kind => $e_expand, )*
-                };
-
-                let span = db.lookup_intern_macro_call(id).call_site;
-                let span = span_with_def_site_ctxt(db, span, id);
-                expander(db, id, tt, span)
+                }
             }
         }
 
@@ -74,7 +56,31 @@ macro_rules! register_builtin {
     };
 }
 
+impl BuiltinFnLikeExpander {
+    pub fn expand(
+        &self,
+        db: &dyn ExpandDatabase,
+        id: MacroCallId,
+        tt: &tt::Subtree,
+    ) -> ExpandResult<tt::Subtree> {
+        let span = db.lookup_intern_macro_call(id).call_site;
+        let span = span_with_def_site_ctxt(db, span, id);
+        self.expander()(db, id, tt, span)
+    }
+}
+
 impl EagerExpander {
+    pub fn expand(
+        &self,
+        db: &dyn ExpandDatabase,
+        id: MacroCallId,
+        tt: &tt::Subtree,
+    ) -> ExpandResult<tt::Subtree> {
+        let span = db.lookup_intern_macro_call(id).call_site;
+        let span = span_with_def_site_ctxt(db, span, id);
+        self.expander()(db, id, tt, span)
+    }
+
     pub fn is_include(&self) -> bool {
         matches!(self, EagerExpander::Include)
     }
diff --git a/crates/hir-expand/src/change.rs b/crates/hir-expand/src/change.rs
index c6611438e64..8b9e5a59df8 100644
--- a/crates/hir-expand/src/change.rs
+++ b/crates/hir-expand/src/change.rs
@@ -11,14 +11,14 @@ use triomphe::Arc;
 use crate::{db::ExpandDatabase, proc_macro::ProcMacros};
 
 #[derive(Debug, Default)]
-pub struct Change {
+pub struct ChangeWithProcMacros {
     pub source_change: FileChange,
     pub proc_macros: Option<ProcMacros>,
     pub toolchains: Option<Vec<Option<Version>>>,
     pub target_data_layouts: Option<Vec<TargetLayoutLoadResult>>,
 }
 
-impl Change {
+impl ChangeWithProcMacros {
     pub fn new() -> Self {
         Self::default()
     }
diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs
index 0cf1fadec97..ae10ad2f801 100644
--- a/crates/hir-expand/src/mod_path.rs
+++ b/crates/hir-expand/src/mod_path.rs
@@ -144,6 +144,12 @@ impl ModPath {
     }
 }
 
+impl Extend<Name> for ModPath {
+    fn extend<T: IntoIterator<Item = Name>>(&mut self, iter: T) {
+        self.segments.extend(iter);
+    }
+}
+
 struct Display<'a> {
     db: &'a dyn ExpandDatabase,
     path: &'a ModPath,
diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml
index 1f8f8744f9e..41e2f7ad73c 100644
--- a/crates/hir-ty/Cargo.toml
+++ b/crates/hir-ty/Cargo.toml
@@ -45,7 +45,6 @@ intern.workspace = true
 hir-def.workspace = true
 hir-expand.workspace = true
 base-db.workspace = true
-profile.workspace = true
 syntax.workspace = true
 limit.workspace = true
 
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml
index 7fea8372876..190722075a2 100644
--- a/crates/hir/Cargo.toml
+++ b/crates/hir/Cargo.toml
@@ -27,7 +27,6 @@ cfg.workspace = true
 hir-def.workspace = true
 hir-expand.workspace = true
 hir-ty.workspace = true
-profile.workspace = true
 stdx.workspace = true
 syntax.workspace = true
 tt.workspace = true
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 5c607030167..1e16f78ca2d 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -126,7 +126,7 @@ pub use {
     },
     hir_expand::{
         attrs::{Attr, AttrId},
-        change::Change,
+        change::ChangeWithProcMacros,
         hygiene::{marks_rev, SyntaxContextExt},
         name::{known, Name},
         proc_macro::ProcMacros,
diff --git a/crates/ide-assists/Cargo.toml b/crates/ide-assists/Cargo.toml
index 98961a18de2..e1375f9c3ee 100644
--- a/crates/ide-assists/Cargo.toml
+++ b/crates/ide-assists/Cargo.toml
@@ -23,7 +23,6 @@ tracing.workspace = true
 stdx.workspace = true
 syntax.workspace = true
 text-edit.workspace = true
-profile.workspace = true
 ide-db.workspace = true
 hir.workspace = true
 
diff --git a/crates/ide-completion/Cargo.toml b/crates/ide-completion/Cargo.toml
index f2a11276ba2..6a4c70d460f 100644
--- a/crates/ide-completion/Cargo.toml
+++ b/crates/ide-completion/Cargo.toml
@@ -23,7 +23,6 @@ smallvec.workspace = true
 # local deps
 base-db.workspace = true
 ide-db.workspace = true
-profile.workspace = true
 stdx.workspace = true
 syntax.workspace = true
 text-edit.workspace = true
diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs
index 2b2df144d6d..f769f72d462 100644
--- a/crates/ide-db/src/apply_change.rs
+++ b/crates/ide-db/src/apply_change.rs
@@ -11,7 +11,7 @@ use profile::{memory_usage, Bytes};
 use rustc_hash::FxHashSet;
 use triomphe::Arc;
 
-use crate::{symbol_index::SymbolsDatabase, Change, RootDatabase};
+use crate::{symbol_index::SymbolsDatabase, ChangeWithProcMacros, RootDatabase};
 
 impl RootDatabase {
     pub fn request_cancellation(&mut self) {
@@ -20,7 +20,7 @@ impl RootDatabase {
         self.synthetic_write(Durability::LOW);
     }
 
-    pub fn apply_change(&mut self, change: Change) {
+    pub fn apply_change(&mut self, change: ChangeWithProcMacros) {
         let _p = tracing::span!(tracing::Level::INFO, "RootDatabase::apply_change").entered();
         self.request_cancellation();
         tracing::trace!("apply_change {:?}", change);
diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs
index 3e6cb7476bb..a9f7e58de95 100644
--- a/crates/ide-db/src/lib.rs
+++ b/crates/ide-db/src/lib.rs
@@ -44,7 +44,7 @@ pub mod syntax_helpers {
     pub use parser::LexedStr;
 }
 
-pub use hir::Change;
+pub use hir::ChangeWithProcMacros;
 
 use std::{fmt, mem::ManuallyDrop};
 
diff --git a/crates/ide-diagnostics/Cargo.toml b/crates/ide-diagnostics/Cargo.toml
index 69768041389..509c5a152f7 100644
--- a/crates/ide-diagnostics/Cargo.toml
+++ b/crates/ide-diagnostics/Cargo.toml
@@ -20,7 +20,6 @@ tracing.workspace = true
 once_cell = "1.17.0"
 
 # local deps
-profile.workspace = true
 stdx.workspace = true
 syntax.workspace = true
 text-edit.workspace = true
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index a076c7ca9fa..4eb4acdf183 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -61,7 +61,7 @@ use std::ffi::OsStr;
 
 use cfg::CfgOptions;
 use fetch_crates::CrateInfo;
-use hir::Change;
+use hir::ChangeWithProcMacros;
 use ide_db::{
     base_db::{
         salsa::{self, ParallelDatabase},
@@ -184,7 +184,7 @@ impl AnalysisHost {
 
     /// Applies changes to the current state of the world. If there are
     /// outstanding snapshots, they will be canceled.
-    pub fn apply_change(&mut self, change: Change) {
+    pub fn apply_change(&mut self, change: ChangeWithProcMacros) {
         self.db.apply_change(change);
     }
 
@@ -239,7 +239,7 @@ impl Analysis {
         file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_owned()));
         let source_root = SourceRoot::new_local(file_set);
 
-        let mut change = Change::new();
+        let mut change = ChangeWithProcMacros::new();
         change.set_roots(vec![source_root]);
         let mut crate_graph = CrateGraph::default();
         // FIXME: cfg options
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs
index 2b5f515c3ad..29c1251ccee 100644
--- a/crates/load-cargo/src/lib.rs
+++ b/crates/load-cargo/src/lib.rs
@@ -11,7 +11,7 @@ use hir_expand::proc_macro::{
 };
 use ide_db::{
     base_db::{CrateGraph, Env, SourceRoot},
-    prime_caches, Change, FxHashMap, RootDatabase,
+    prime_caches, ChangeWithProcMacros, FxHashMap, RootDatabase,
 };
 use itertools::Itertools;
 use proc_macro_api::{MacroDylib, ProcMacroServer};
@@ -314,7 +314,7 @@ fn load_crate_graph(
 
     let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
     let mut db = RootDatabase::new(lru_cap);
-    let mut analysis_change = Change::new();
+    let mut analysis_change = ChangeWithProcMacros::new();
 
     db.enable_proc_attr_macros();
 
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index e74b340126c..1f84e3f3af3 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -15,6 +15,7 @@ doctest = false
 drop_bomb = "0.1.5"
 ra-ap-rustc_lexer.workspace = true
 limit.workspace = true
+tracing = { workspace = true, optional = true }
 
 [dev-dependencies]
 expect-test = "1.4.0"
@@ -23,6 +24,7 @@ stdx.workspace = true
 sourcegen.workspace = true
 
 [features]
+default = ["tracing"]
 in-rust-tree = []
 
 [lints]
diff --git a/crates/parser/src/lexed_str.rs b/crates/parser/src/lexed_str.rs
index 2da9184693d..48e4c8a6225 100644
--- a/crates/parser/src/lexed_str.rs
+++ b/crates/parser/src/lexed_str.rs
@@ -31,6 +31,7 @@ struct LexError {
 
 impl<'a> LexedStr<'a> {
     pub fn new(text: &'a str) -> LexedStr<'a> {
+        let _p = tracing::span!(tracing::Level::INFO, "LexedStr::new").entered();
         let mut conv = Converter::new(text);
         if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
             conv.res.push(SHEBANG, conv.offset);
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 3ca285e787e..86c771c0008 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -87,6 +87,7 @@ pub enum TopEntryPoint {
 
 impl TopEntryPoint {
     pub fn parse(&self, input: &Input) -> Output {
+        let _p = tracing::span!(tracing::Level::INFO, "TopEntryPoint::parse", ?self).entered();
         let entry_point: fn(&'_ mut parser::Parser<'_>) = match self {
             TopEntryPoint::SourceFile => grammar::entry::top::source_file,
             TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts,
diff --git a/crates/parser/src/shortcuts.rs b/crates/parser/src/shortcuts.rs
index 57005a6834c..680a70997d4 100644
--- a/crates/parser/src/shortcuts.rs
+++ b/crates/parser/src/shortcuts.rs
@@ -26,6 +26,7 @@ pub enum StrStep<'a> {
 
 impl LexedStr<'_> {
     pub fn to_input(&self) -> crate::Input {
+        let _p = tracing::span!(tracing::Level::INFO, "LexedStr::to_input").entered();
         let mut res = crate::Input::default();
         let mut was_joint = false;
         for i in 0..self.len() {
diff --git a/crates/proc-macro-api/Cargo.toml b/crates/proc-macro-api/Cargo.toml
index cf01b94c0a2..e98d70776c9 100644
--- a/crates/proc-macro-api/Cargo.toml
+++ b/crates/proc-macro-api/Cargo.toml
@@ -32,7 +32,6 @@ indexmap = "2.1.0"
 paths.workspace = true
 tt.workspace = true
 stdx.workspace = true
-profile.workspace = true
 text-size.workspace = true
 span.workspace = true
 # Ideally this crate would not depend on salsa things, but we need span information here which wraps
diff --git a/crates/profile/src/lib.rs b/crates/profile/src/lib.rs
index 36399815606..a3fdb72a6d1 100644
--- a/crates/profile/src/lib.rs
+++ b/crates/profile/src/lib.rs
@@ -23,29 +23,6 @@ pub use countme::Count;
 
 thread_local!(static IN_SCOPE: RefCell<bool> = const { RefCell::new(false) });
 
-/// Allows to check if the current code is within some dynamic scope, can be
-/// useful during debugging to figure out why a function is called.
-pub struct Scope {
-    prev: bool,
-}
-
-impl Scope {
-    #[must_use]
-    pub fn enter() -> Scope {
-        let prev = IN_SCOPE.with(|slot| std::mem::replace(&mut *slot.borrow_mut(), true));
-        Scope { prev }
-    }
-    pub fn is_active() -> bool {
-        IN_SCOPE.with(|slot| *slot.borrow())
-    }
-}
-
-impl Drop for Scope {
-    fn drop(&mut self) {
-        IN_SCOPE.with(|slot| *slot.borrow_mut() = self.prev);
-    }
-}
-
 /// A wrapper around google_cpu_profiler.
 ///
 /// Usage:
diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml
index 3552ed19162..924a4a89e21 100644
--- a/crates/project-model/Cargo.toml
+++ b/crates/project-model/Cargo.toml
@@ -27,7 +27,6 @@ itertools.workspace = true
 base-db.workspace = true
 cfg.workspace = true
 paths.workspace = true
-profile.workspace = true
 stdx.workspace = true
 toolchain.workspace = true
 
@@ -35,4 +34,4 @@ toolchain.workspace = true
 expect-test = "1.4.0"
 
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs
index 9276d241aff..7ad87ab97fc 100644
--- a/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -5,7 +5,7 @@ use std::thread::Builder;
 use std::time::{Duration, Instant};
 use std::{cell::RefCell, fs::read_to_string, panic::AssertUnwindSafe, path::PathBuf};
 
-use hir::{Change, Crate};
+use hir::{ChangeWithProcMacros, Crate};
 use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
 use itertools::Either;
 use profile::StopWatch;
@@ -122,7 +122,7 @@ impl Tester {
             FxHashMap::default()
         };
         let text = read_to_string(&p).unwrap();
-        let mut change = Change::new();
+        let mut change = ChangeWithProcMacros::new();
         // Ignore unstable tests, since they move too fast and we do not intend to support all of them.
         let mut ignore_test = text.contains("#![feature");
         // Ignore test with extern crates, as this infra don't support them yet.
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index b2d507491b1..eb472792053 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -7,7 +7,7 @@ use std::{collections::hash_map::Entry, time::Instant};
 
 use crossbeam_channel::{unbounded, Receiver, Sender};
 use flycheck::FlycheckHandle;
-use hir::Change;
+use hir::ChangeWithProcMacros;
 use ide::{Analysis, AnalysisHost, Cancellable, FileId};
 use ide_db::base_db::{CrateId, ProcMacroPaths};
 use load_cargo::SourceRootConfig;
@@ -238,7 +238,7 @@ impl GlobalState {
 
         let mut file_changes = FxHashMap::<_, (bool, ChangedFile)>::default();
         let (change, modified_rust_files, workspace_structure_change) = {
-            let mut change = Change::new();
+            let mut change = ChangeWithProcMacros::new();
             let mut guard = self.vfs.write();
             let changed_files = guard.0.take_changes();
             if changed_files.is_empty() {
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 9d692175203..008c63c35a6 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -10,7 +10,7 @@
 //! in release mode in VS Code. There's however "rust-analyzer: Copy Run Command Line"
 //! which you can use to paste the command in terminal and add `--release` manually.
 
-use hir::Change;
+use hir::ChangeWithProcMacros;
 use ide::{AnalysisHost, CallableSnippets, CompletionConfig, FilePosition, TextSize};
 use ide_db::{
     imports::insert_use::{ImportGranularity, InsertUseConfig},
@@ -55,19 +55,19 @@ fn integrated_highlighting_benchmark() {
         vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}"))
     };
 
+    crate::tracing::hprof::init("*>100");
+
     {
         let _it = stdx::timeit("initial");
         let analysis = host.analysis();
         analysis.highlight_as_html(file_id, false).unwrap();
     }
 
-    crate::tracing::hprof::init("*>100");
-
     {
         let _it = stdx::timeit("change");
         let mut text = host.analysis().file_text(file_id).unwrap().to_string();
         text.push_str("\npub fn _dummy() {}\n");
-        let mut change = Change::new();
+        let mut change = ChangeWithProcMacros::new();
         change.change_file(file_id, Some(Arc::from(text)));
         host.apply_change(change);
     }
@@ -120,7 +120,7 @@ fn integrated_completion_benchmark() {
         let completion_offset =
             patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)")
                 + "sel".len();
-        let mut change = Change::new();
+        let mut change = ChangeWithProcMacros::new();
         change.change_file(file_id, Some(Arc::from(text)));
         host.apply_change(change);
         completion_offset
@@ -163,7 +163,7 @@ fn integrated_completion_benchmark() {
         let completion_offset =
             patch(&mut text, "sel;\ndb.struct_data(self.id)", ";sel;\ndb.struct_data(self.id)")
                 + ";sel".len();
-        let mut change = Change::new();
+        let mut change = ChangeWithProcMacros::new();
         change.change_file(file_id, Some(Arc::from(text)));
         host.apply_change(change);
         completion_offset
@@ -205,7 +205,7 @@ fn integrated_completion_benchmark() {
         let completion_offset =
             patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)")
                 + "self.".len();
-        let mut change = Change::new();
+        let mut change = ChangeWithProcMacros::new();
         change.change_file(file_id, Some(Arc::from(text)));
         host.apply_change(change);
         completion_offset
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index f6bc032c019..95d51baab38 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -16,7 +16,7 @@
 use std::{iter, mem};
 
 use flycheck::{FlycheckConfig, FlycheckHandle};
-use hir::{db::DefDatabase, Change, ProcMacros};
+use hir::{db::DefDatabase, ChangeWithProcMacros, ProcMacros};
 use ide::CrateId;
 use ide_db::{
     base_db::{salsa::Durability, CrateGraph, ProcMacroPaths, Version},
@@ -357,7 +357,7 @@ impl GlobalState {
     }
 
     pub(crate) fn set_proc_macros(&mut self, proc_macros: ProcMacros) {
-        let mut change = Change::new();
+        let mut change = ChangeWithProcMacros::new();
         change.set_proc_macros(proc_macros);
         self.analysis_host.apply_change(change);
     }
@@ -548,7 +548,7 @@ impl GlobalState {
 
             ws_to_crate_graph(&self.workspaces, self.config.extra_env(), load)
         };
-        let mut change = Change::new();
+        let mut change = ChangeWithProcMacros::new();
         if self.config.expand_proc_macros() {
             change.set_proc_macros(
                 crate_graph
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index a0fd73ee13f..9a8d73cf7ff 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -27,7 +27,6 @@ tracing.workspace = true
 ra-ap-rustc_lexer.workspace = true
 
 parser.workspace = true
-profile.workspace = true
 stdx.workspace = true
 text-edit.workspace = true
 
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index b755de86d32..e8bb9ee938f 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -168,6 +168,7 @@ pub use crate::ast::SourceFile;
 
 impl SourceFile {
     pub fn parse(text: &str) -> Parse<SourceFile> {
+        let _p = tracing::span!(tracing::Level::INFO, "SourceFile::parse").entered();
         let (green, mut errors) = parsing::parse_text(text);
         let root = SyntaxNode::new_root(green.clone());
 
diff --git a/crates/syntax/src/parsing.rs b/crates/syntax/src/parsing.rs
index 1250b5274c1..d750476f63c 100644
--- a/crates/syntax/src/parsing.rs
+++ b/crates/syntax/src/parsing.rs
@@ -10,6 +10,7 @@ use crate::{syntax_node::GreenNode, SyntaxError, SyntaxTreeBuilder};
 pub(crate) use crate::parsing::reparsing::incremental_reparse;
 
 pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec<SyntaxError>) {
+    let _p = tracing::span!(tracing::Level::INFO, "parse_text").entered();
     let lexed = parser::LexedStr::new(text);
     let parser_input = lexed.to_input();
     let parser_output = parser::TopEntryPoint::SourceFile.parse(&parser_input);
@@ -21,6 +22,7 @@ pub(crate) fn build_tree(
     lexed: parser::LexedStr<'_>,
     parser_output: parser::Output,
 ) -> (GreenNode, Vec<SyntaxError>, bool) {
+    let _p = tracing::span!(tracing::Level::INFO, "build_tree").entered();
     let mut builder = SyntaxTreeBuilder::default();
 
     let is_eof = lexed.intersperse_trivia(&parser_output, &mut |step| match step {
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs
index 5c5b26f525f..5b3f449eeeb 100644
--- a/crates/syntax/src/validation.rs
+++ b/crates/syntax/src/validation.rs
@@ -16,6 +16,7 @@ use crate::{
 };
 
 pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
+    let _p = tracing::span!(tracing::Level::INFO, "parser::validate").entered();
     // FIXME:
     // * Add unescape validation of raw string literals and raw byte string literals
     // * Add validation of doc comments are being attached to nodes
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index e118262b4ed..ca3007d4370 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -7,7 +7,7 @@ use base_db::{
 };
 use cfg::CfgOptions;
 use hir_expand::{
-    change::Change,
+    change::ChangeWithProcMacros,
     db::ExpandDatabase,
     proc_macro::{
         ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacros,
@@ -103,7 +103,7 @@ impl<DB: ExpandDatabase + SourceDatabaseExt + Default + 'static> WithFixture for
 pub struct ChangeFixture {
     pub file_position: Option<(FileId, RangeOrOffset)>,
     pub files: Vec<FileId>,
-    pub change: Change,
+    pub change: ChangeWithProcMacros,
 }
 
 const SOURCE_ROOT_PREFIX: &str = "/";
@@ -317,7 +317,7 @@ impl ChangeFixture {
         };
         roots.push(root);
 
-        let mut change = Change {
+        let mut change = ChangeWithProcMacros {
             source_change,
             proc_macros: proc_macros.is_empty().not().then_some(proc_macros),
             toolchains: Some(iter::repeat(toolchain).take(crate_graph.len()).collect()),