about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-18 12:18:24 +0000
committerbors <bors@rust-lang.org>2023-12-18 12:18:24 +0000
commitcfc959d73a9259f0eb3b1813df7e9db8108945b7 (patch)
tree82fcc57d0e9a99018a3af4131bc55e69a1b9a29c
parent9a82f8ce521d5fc2500dfd222bd888dead1457c5 (diff)
parent35620306a6dc1e108f86e8891c9b3103397ca1e3 (diff)
downloadrust-cfc959d73a9259f0eb3b1813df7e9db8108945b7.tar.gz
rust-cfc959d73a9259f0eb3b1813df7e9db8108945b7.zip
Auto merge of #16143 - Veykril:base-db-no-proc-macros, r=lnicola
internal: Move proc-macro knowledge out of base-db into hir-expand

It does not make much sense to me to have that live in base-db, additionally, it kind of conflicts with moving span things out into a separate crate
-rw-r--r--Cargo.lock2
-rw-r--r--crates/base-db/src/change.rs18
-rw-r--r--crates/base-db/src/input.rs47
-rw-r--r--crates/base-db/src/lib.rs12
-rw-r--r--crates/hir-def/src/body/scope.rs4
-rw-r--r--crates/hir-def/src/body/tests.rs3
-rw-r--r--crates/hir-def/src/find_path.rs3
-rw-r--r--crates/hir-def/src/import_map.rs3
-rw-r--r--crates/hir-def/src/item_tree/tests.rs2
-rw-r--r--crates/hir-def/src/lib.rs6
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mod.rs16
-rw-r--r--crates/hir-def/src/nameres.rs7
-rw-r--r--crates/hir-def/src/nameres/collector.rs17
-rw-r--r--crates/hir-def/src/nameres/proc_macro.rs10
-rw-r--r--crates/hir-def/src/nameres/tests.rs3
-rw-r--r--crates/hir-expand/Cargo.toml1
-rw-r--r--crates/hir-expand/src/db.rs14
-rw-r--r--crates/hir-expand/src/fixture.rs (renamed from crates/base-db/src/fixture.rs)81
-rw-r--r--crates/hir-expand/src/lib.rs21
-rw-r--r--crates/hir-expand/src/proc_macro.rs51
-rw-r--r--crates/hir-ty/src/consteval/tests.rs3
-rw-r--r--crates/hir-ty/src/layout/tests.rs2
-rw-r--r--crates/hir-ty/src/mir/eval/tests.rs3
-rw-r--r--crates/hir-ty/src/tests.rs4
-rw-r--r--crates/hir-ty/src/tests/incremental.rs3
-rw-r--r--crates/hir/src/db.rs2
-rw-r--r--crates/hir/src/lib.rs6
-rw-r--r--crates/ide-assists/src/handlers/auto_import.rs8
-rw-r--r--crates/ide-assists/src/tests.rs4
-rw-r--r--crates/ide-assists/src/utils/suggest_name.rs3
-rw-r--r--crates/ide-completion/src/tests.rs4
-rw-r--r--crates/ide-db/src/apply_change.rs8
-rw-r--r--crates/ide-db/src/imports/insert_use/tests.rs3
-rw-r--r--crates/ide-db/src/lib.rs5
-rw-r--r--crates/ide-db/src/symbol_index.rs3
-rw-r--r--crates/ide-db/src/traits.rs4
-rw-r--r--crates/ide-diagnostics/src/tests.rs5
-rw-r--r--crates/ide-ssr/src/tests.rs4
-rw-r--r--crates/ide/src/fixture.rs2
-rw-r--r--crates/ide/src/lib.rs5
-rw-r--r--crates/ide/src/shuffle_crate_graph.rs3
-rw-r--r--crates/ide/src/signature_help.rs2
-rw-r--r--crates/ide/src/ssr.rs5
-rw-r--r--crates/load-cargo/Cargo.toml2
-rw-r--r--crates/load-cargo/src/lib.rs12
-rw-r--r--crates/rust-analyzer/src/cli/rustc_tests.rs4
-rw-r--r--crates/rust-analyzer/src/cli/scip.rs2
-rw-r--r--crates/rust-analyzer/src/global_state.rs3
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs3
-rw-r--r--crates/rust-analyzer/src/reload.rs5
50 files changed, 256 insertions, 187 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 227d1db0ec7..91dec9f3b9b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -544,6 +544,7 @@ dependencies = [
  "smallvec",
  "stdx",
  "syntax",
+ "test-utils",
  "tracing",
  "triomphe",
  "tt",
@@ -903,6 +904,7 @@ version = "0.0.0"
 dependencies = [
  "anyhow",
  "crossbeam-channel",
+ "hir-expand",
  "ide",
  "ide-db",
  "itertools",
diff --git a/crates/base-db/src/change.rs b/crates/base-db/src/change.rs
index 6a3b36b2312..4332e572e20 100644
--- a/crates/base-db/src/change.rs
+++ b/crates/base-db/src/change.rs
@@ -7,18 +7,17 @@ use salsa::Durability;
 use triomphe::Arc;
 use vfs::FileId;
 
-use crate::{CrateGraph, ProcMacros, SourceDatabaseExt, SourceRoot, SourceRootId};
+use crate::{CrateGraph, SourceDatabaseExt, SourceRoot, SourceRootId};
 
 /// Encapsulate a bunch of raw `.set` calls on the database.
 #[derive(Default)]
-pub struct Change {
+pub struct FileChange {
     pub roots: Option<Vec<SourceRoot>>,
     pub files_changed: Vec<(FileId, Option<Arc<str>>)>,
     pub crate_graph: Option<CrateGraph>,
-    pub proc_macros: Option<ProcMacros>,
 }
 
-impl fmt::Debug for Change {
+impl fmt::Debug for FileChange {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut d = fmt.debug_struct("Change");
         if let Some(roots) = &self.roots {
@@ -34,9 +33,9 @@ impl fmt::Debug for Change {
     }
 }
 
-impl Change {
+impl FileChange {
     pub fn new() -> Self {
-        Change::default()
+        FileChange::default()
     }
 
     pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
@@ -51,10 +50,6 @@ impl Change {
         self.crate_graph = Some(graph);
     }
 
-    pub fn set_proc_macros(&mut self, proc_macros: ProcMacros) {
-        self.proc_macros = Some(proc_macros);
-    }
-
     pub fn apply(self, db: &mut dyn SourceDatabaseExt) {
         let _p = profile::span("RootDatabase::apply_change");
         if let Some(roots) = self.roots {
@@ -79,9 +74,6 @@ impl Change {
         if let Some(crate_graph) = self.crate_graph {
             db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH);
         }
-        if let Some(proc_macros) = self.proc_macros {
-            db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH);
-        }
     }
 }
 
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index c2472363aac..f0ce7e619d7 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -6,7 +6,7 @@
 //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how
 //! actual IO is done and lowered to input.
 
-use std::{fmt, mem, ops, panic::RefUnwindSafe, str::FromStr, sync};
+use std::{fmt, mem, ops, str::FromStr};
 
 use cfg::CfgOptions;
 use la_arena::{Arena, Idx};
@@ -15,13 +15,9 @@ use syntax::SmolStr;
 use triomphe::Arc;
 use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath};
 
-use crate::span::SpanData;
-
 // Map from crate id to the name of the crate and path of the proc-macro. If the value is `None`,
 // then the crate for the proc-macro hasn't been build yet as the build data is missing.
 pub type ProcMacroPaths = FxHashMap<CrateId, Result<(Option<String>, AbsPathBuf), String>>;
-pub type ProcMacros = FxHashMap<CrateId, ProcMacroLoadResult>;
-
 /// Files are grouped into source roots. A source root is a directory on the
 /// file systems which is watched for changes. Typically it corresponds to a
 /// Rust crate. Source roots *might* be nested: in this case, a file belongs to
@@ -242,49 +238,8 @@ impl CrateDisplayName {
         CrateDisplayName { crate_name, canonical_name }
     }
 }
-
-// FIXME: These should not be defined in here? Why does base db know about proc-macros
-// ProcMacroKind is used in [`fixture`], but that module probably shouldn't be in this crate either.
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct ProcMacroId(pub u32);
-
-#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
-pub enum ProcMacroKind {
-    CustomDerive,
-    FuncLike,
-    Attr,
-}
-
-pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe {
-    fn expand(
-        &self,
-        subtree: &tt::Subtree<SpanData>,
-        attrs: Option<&tt::Subtree<SpanData>>,
-        env: &Env,
-        def_site: SpanData,
-        call_site: SpanData,
-        mixed_site: SpanData,
-    ) -> Result<tt::Subtree<SpanData>, ProcMacroExpansionError>;
-}
-
-#[derive(Debug)]
-pub enum ProcMacroExpansionError {
-    Panic(String),
-    /// Things like "proc macro server was killed by OOM".
-    System(String),
-}
-
-pub type ProcMacroLoadResult = Result<Vec<ProcMacro>, String>;
 pub type TargetLayoutLoadResult = Result<Arc<str>, Arc<str>>;
 
-#[derive(Debug, Clone)]
-pub struct ProcMacro {
-    pub name: SmolStr,
-    pub kind: ProcMacroKind,
-    pub expander: sync::Arc<dyn ProcMacroExpander>,
-}
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub enum ReleaseChannel {
     Stable,
diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs
index 57e7934367b..3e874adbe54 100644
--- a/crates/base-db/src/lib.rs
+++ b/crates/base-db/src/lib.rs
@@ -4,7 +4,6 @@
 
 mod input;
 mod change;
-pub mod fixture;
 pub mod span;
 
 use std::panic;
@@ -14,12 +13,11 @@ use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
 use triomphe::Arc;
 
 pub use crate::{
-    change::Change,
+    change::FileChange,
     input::{
         CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency,
-        DependencyKind, Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander,
-        ProcMacroExpansionError, ProcMacroId, ProcMacroKind, ProcMacroLoadResult, ProcMacroPaths,
-        ProcMacros, ReleaseChannel, SourceRoot, SourceRootId, TargetLayoutLoadResult,
+        DependencyKind, Edition, Env, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, SourceRoot,
+        SourceRootId, TargetLayoutLoadResult,
     },
 };
 pub use salsa::{self, Cancelled};
@@ -74,10 +72,6 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug {
     /// The crate graph.
     #[salsa::input]
     fn crate_graph(&self) -> Arc<CrateGraph>;
-
-    /// The proc macros.
-    #[salsa::input]
-    fn proc_macros(&self) -> Arc<ProcMacros>;
 }
 
 fn parse(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
diff --git a/crates/hir-def/src/body/scope.rs b/crates/hir-def/src/body/scope.rs
index baca293e290..9e1f21c5480 100644
--- a/crates/hir-def/src/body/scope.rs
+++ b/crates/hir-def/src/body/scope.rs
@@ -267,8 +267,8 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
 
 #[cfg(test)]
 mod tests {
-    use base_db::{fixture::WithFixture, FileId, SourceDatabase};
-    use hir_expand::{name::AsName, InFile};
+    use base_db::{FileId, SourceDatabase};
+    use hir_expand::{fixture::WithFixture, name::AsName, InFile};
     use syntax::{algo::find_node_at_offset, ast, AstNode};
     use test_utils::{assert_eq_text, extract_offset};
 
diff --git a/crates/hir-def/src/body/tests.rs b/crates/hir-def/src/body/tests.rs
index 2b432dfbb92..5e78685b10e 100644
--- a/crates/hir-def/src/body/tests.rs
+++ b/crates/hir-def/src/body/tests.rs
@@ -1,7 +1,8 @@
 mod block;
 
-use base_db::{fixture::WithFixture, SourceDatabase};
+use base_db::SourceDatabase;
 use expect_test::{expect, Expect};
+use hir_expand::fixture::WithFixture;
 
 use crate::{test_db::TestDB, ModuleDefId};
 
diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs
index 13af0b0218e..95339201776 100644
--- a/crates/hir-def/src/find_path.rs
+++ b/crates/hir-def/src/find_path.rs
@@ -585,8 +585,7 @@ fn find_local_import_locations(
 
 #[cfg(test)]
 mod tests {
-    use base_db::fixture::WithFixture;
-    use hir_expand::db::ExpandDatabase;
+    use hir_expand::{db::ExpandDatabase, fixture::WithFixture};
     use syntax::ast::AstNode;
 
     use crate::test_db::TestDB;
diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs
index fbd754c30f5..911511a3ba6 100644
--- a/crates/hir-def/src/import_map.rs
+++ b/crates/hir-def/src/import_map.rs
@@ -473,8 +473,9 @@ pub fn search_dependencies(
 
 #[cfg(test)]
 mod tests {
-    use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
+    use base_db::{SourceDatabase, Upcast};
     use expect_test::{expect, Expect};
+    use hir_expand::fixture::WithFixture;
 
     use crate::{db::DefDatabase, test_db::TestDB, ItemContainerId, Lookup};
 
diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs
index 96c65b941c1..bec8e78ac94 100644
--- a/crates/hir-def/src/item_tree/tests.rs
+++ b/crates/hir-def/src/item_tree/tests.rs
@@ -1,5 +1,5 @@
-use base_db::fixture::WithFixture;
 use expect_test::{expect, Expect};
+use hir_expand::fixture::WithFixture;
 
 use crate::{db::DefDatabase, test_db::TestDB};
 
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index b5333861cc8..1e68fd932cc 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -63,7 +63,7 @@ use std::{
     panic::{RefUnwindSafe, UnwindSafe},
 };
 
-use base_db::{impl_intern_key, salsa, span::SyntaxContextId, CrateId, ProcMacroKind};
+use base_db::{impl_intern_key, salsa, span::SyntaxContextId, CrateId};
 use hir_expand::{
     ast_id_map::{AstIdNode, FileAstId},
     attrs::{Attr, AttrId, AttrInput},
@@ -73,7 +73,7 @@ use hir_expand::{
     db::ExpandDatabase,
     eager::expand_eager_macro_input,
     name::Name,
-    proc_macro::ProcMacroExpander,
+    proc_macro::{CustomProcMacroExpander, ProcMacroKind},
     AstId, ExpandError, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind,
     MacroDefId, MacroDefKind,
 };
@@ -400,7 +400,7 @@ pub struct ProcMacroId(salsa::InternId);
 pub struct ProcMacroLoc {
     pub container: CrateRootModuleId,
     pub id: ItemTreeId<Function>,
-    pub expander: ProcMacroExpander,
+    pub expander: CustomProcMacroExpander,
     pub kind: ProcMacroKind,
 }
 impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro);
diff --git a/crates/hir-def/src/macro_expansion_tests/mod.rs b/crates/hir-def/src/macro_expansion_tests/mod.rs
index be2a503d82b..804645ff43d 100644
--- a/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -16,9 +16,15 @@ mod proc_macros;
 
 use std::{iter, ops::Range, sync};
 
-use base_db::{fixture::WithFixture, span::SpanData, ProcMacro, SourceDatabase};
+use base_db::{span::SpanData, SourceDatabase};
 use expect_test::Expect;
-use hir_expand::{db::ExpandDatabase, span::SpanMapRef, InFile, MacroFileId, MacroFileIdExt};
+use hir_expand::{
+    db::ExpandDatabase,
+    fixture::WithFixture,
+    proc_macro::{ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind},
+    span::SpanMapRef,
+    InFile, MacroFileId, MacroFileIdExt,
+};
 use stdx::format_to;
 use syntax::{
     ast::{self, edit::IndentLevel},
@@ -50,7 +56,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
         .into(),
         ProcMacro {
             name: "identity_when_valid".into(),
-            kind: base_db::ProcMacroKind::Attr,
+            kind: ProcMacroKind::Attr,
             expander: sync::Arc::new(IdentityWhenValidProcMacroExpander),
         },
     )];
@@ -307,7 +313,7 @@ fn pretty_print_macro_expansion(
 // compile errors.
 #[derive(Debug)]
 struct IdentityWhenValidProcMacroExpander;
-impl base_db::ProcMacroExpander for IdentityWhenValidProcMacroExpander {
+impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
     fn expand(
         &self,
         subtree: &Subtree,
@@ -316,7 +322,7 @@ impl base_db::ProcMacroExpander for IdentityWhenValidProcMacroExpander {
         _: SpanData,
         _: SpanData,
         _: SpanData,
-    ) -> Result<Subtree, base_db::ProcMacroExpansionError> {
+    ) -> Result<Subtree, ProcMacroExpansionError> {
         let (parse, _) =
             ::mbe::token_tree_to_syntax_node(subtree, ::mbe::TopEntryPoint::MacroItems);
         if parse.errors().is_empty() {
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 9a9fa0e02b0..41560c05451 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -59,8 +59,11 @@ mod tests;
 
 use std::{cmp::Ord, ops::Deref};
 
-use base_db::{CrateId, Edition, FileId, ProcMacroKind};
-use hir_expand::{ast_id_map::FileAstId, name::Name, HirFileId, InFile, MacroCallId, MacroDefId};
+use base_db::{CrateId, Edition, FileId};
+use hir_expand::{
+    ast_id_map::FileAstId, name::Name, proc_macro::ProcMacroKind, HirFileId, InFile, MacroCallId,
+    MacroDefId,
+};
 use itertools::Itertools;
 use la_arena::Arena;
 use profile::Count;
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index b3a10a3869a..d77be4a8a04 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -15,7 +15,7 @@ use hir_expand::{
     builtin_derive_macro::find_builtin_derive,
     builtin_fn_macro::find_builtin_macro,
     name::{name, AsName, Name},
-    proc_macro::ProcMacroExpander,
+    proc_macro::CustomProcMacroExpander,
     ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc,
     MacroDefId, MacroDefKind,
 };
@@ -95,7 +95,12 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
                                 ctx: SyntaxContextId::ROOT,
                             },
                         };
-                        (name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32)))
+                        (
+                            name.as_name(),
+                            CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId(
+                                idx as u32,
+                            )),
+                        )
                     })
                     .collect())
             }
@@ -253,7 +258,7 @@ struct DefCollector<'a> {
     /// built by the build system, and is the list of proc. macros we can actually expand. It is
     /// empty when proc. macro support is disabled (in which case we still do name resolution for
     /// them).
-    proc_macros: Result<Vec<(Name, ProcMacroExpander)>, Box<str>>,
+    proc_macros: Result<Vec<(Name, CustomProcMacroExpander)>, Box<str>>,
     is_proc_macro: bool,
     from_glob_import: PerNsGlobImports,
     /// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute.
@@ -603,7 +608,7 @@ impl DefCollector<'_> {
         let (expander, kind) =
             match self.proc_macros.as_ref().map(|it| it.iter().find(|(n, _)| n == &def.name)) {
                 Ok(Some(&(_, expander))) => (expander, kind),
-                _ => (ProcMacroExpander::dummy(), kind),
+                _ => (CustomProcMacroExpander::dummy(), kind),
             };
 
         let proc_macro_id =
@@ -2363,8 +2368,10 @@ impl ModCollector<'_, '_> {
 
 #[cfg(test)]
 mod tests {
+    use base_db::SourceDatabase;
+    use hir_expand::fixture::WithFixture;
+
     use crate::{db::DefDatabase, test_db::TestDB};
-    use base_db::{fixture::WithFixture, SourceDatabase};
 
     use super::*;
 
diff --git a/crates/hir-def/src/nameres/proc_macro.rs b/crates/hir-def/src/nameres/proc_macro.rs
index 751b7beaac1..c126fdac1c6 100644
--- a/crates/hir-def/src/nameres/proc_macro.rs
+++ b/crates/hir-def/src/nameres/proc_macro.rs
@@ -19,11 +19,13 @@ pub enum ProcMacroKind {
 }
 
 impl ProcMacroKind {
-    pub(super) fn to_basedb_kind(&self) -> base_db::ProcMacroKind {
+    pub(super) fn to_basedb_kind(&self) -> hir_expand::proc_macro::ProcMacroKind {
         match self {
-            ProcMacroKind::CustomDerive { .. } => base_db::ProcMacroKind::CustomDerive,
-            ProcMacroKind::FnLike => base_db::ProcMacroKind::FuncLike,
-            ProcMacroKind::Attr => base_db::ProcMacroKind::Attr,
+            ProcMacroKind::CustomDerive { .. } => {
+                hir_expand::proc_macro::ProcMacroKind::CustomDerive
+            }
+            ProcMacroKind::FnLike => hir_expand::proc_macro::ProcMacroKind::FuncLike,
+            ProcMacroKind::Attr => hir_expand::proc_macro::ProcMacroKind::Attr,
         }
     }
 }
diff --git a/crates/hir-def/src/nameres/tests.rs b/crates/hir-def/src/nameres/tests.rs
index b2ffbbe4c5d..b950234212f 100644
--- a/crates/hir-def/src/nameres/tests.rs
+++ b/crates/hir-def/src/nameres/tests.rs
@@ -4,8 +4,9 @@ mod macros;
 mod mod_resolution;
 mod primitives;
 
-use base_db::{fixture::WithFixture, SourceDatabase};
+use base_db::SourceDatabase;
 use expect_test::{expect, Expect};
+use hir_expand::fixture::WithFixture;
 use triomphe::Arc;
 
 use crate::{db::DefDatabase, nameres::DefMap, test_db::TestDB};
diff --git a/crates/hir-expand/Cargo.toml b/crates/hir-expand/Cargo.toml
index 361bbec4318..3d1549225fa 100644
--- a/crates/hir-expand/Cargo.toml
+++ b/crates/hir-expand/Cargo.toml
@@ -32,6 +32,7 @@ profile.workspace = true
 tt.workspace = true
 mbe.workspace = true
 limit.workspace = true
+test-utils.workspace = true
 
 [dev-dependencies]
 expect-test = "1.4.0"
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index 935669d49b5..1e86618ce87 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -22,10 +22,12 @@ use crate::{
     builtin_fn_macro::EagerExpander,
     fixup::{self, reverse_fixups, SyntaxFixupUndoInfo},
     hygiene::{apply_mark, SyntaxContextData, Transparency},
+    proc_macro::ProcMacros,
     span::{RealSpanMap, SpanMap, SpanMapRef},
-    tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo,
-    ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap, HirFileId, HirFileIdRepr, MacroCallId,
-    MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFileId, ProcMacroExpander,
+    tt, AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
+    CustomProcMacroExpander, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap,
+    HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
+    MacroFileId,
 };
 
 /// Total limit on the number of tokens produced by any macro invocation.
@@ -86,11 +88,15 @@ pub enum TokenExpander {
     /// `derive(Copy)` and such.
     BuiltInDerive(BuiltinDeriveExpander),
     /// The thing we love the most here in rust-analyzer -- procedural macros.
-    ProcMacro(ProcMacroExpander),
+    ProcMacro(CustomProcMacroExpander),
 }
 
 #[salsa::query_group(ExpandDatabaseStorage)]
 pub trait ExpandDatabase: SourceDatabase {
+    /// The proc macros.
+    #[salsa::input]
+    fn proc_macros(&self) -> Arc<ProcMacros>;
+
     fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
 
     /// Main public API -- parses a hir file, not caring whether it's a real
diff --git a/crates/base-db/src/fixture.rs b/crates/hir-expand/src/fixture.rs
index bfdd21555f0..9a65a5c5b72 100644
--- a/crates/base-db/src/fixture.rs
+++ b/crates/hir-expand/src/fixture.rs
@@ -1,6 +1,11 @@
 //! A set of high-level utility fixture methods to use in tests.
-use std::{mem, str::FromStr, sync};
+use std::{mem, ops::Not, str::FromStr, sync};
 
+use base_db::{
+    salsa::Durability, span::SpanData, CrateDisplayName, CrateGraph, CrateId, CrateName,
+    CrateOrigin, Dependency, DependencyKind, Edition, Env, FileChange, FileId, FilePosition,
+    FileRange, FileSet, LangCrateOrigin, ReleaseChannel, SourceDatabaseExt, SourceRoot, VfsPath,
+};
 use cfg::CfgOptions;
 use rustc_hash::FxHashMap;
 use test_utils::{
@@ -9,19 +14,13 @@ use test_utils::{
 };
 use triomphe::Arc;
 use tt::{Leaf, Subtree, TokenTree};
-use vfs::{file_set::FileSet, VfsPath};
 
 use crate::{
-    input::{CrateName, CrateOrigin, LangCrateOrigin},
-    span::SpanData,
-    Change, CrateDisplayName, CrateGraph, CrateId, Dependency, DependencyKind, Edition, Env,
-    FileId, FilePosition, FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError,
-    ProcMacros, ReleaseChannel, SourceDatabaseExt, SourceRoot, SourceRootId,
+    db::ExpandDatabase,
+    proc_macro::{ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacros},
 };
 
-pub const WORKSPACE: SourceRootId = SourceRootId(0);
-
-pub trait WithFixture: Default + SourceDatabaseExt + 'static {
+pub trait WithFixture: Default + ExpandDatabase + SourceDatabaseExt + 'static {
     #[track_caller]
     fn with_single_file(ra_fixture: &str) -> (Self, FileId) {
         let fixture = ChangeFixture::parse(ra_fixture);
@@ -80,6 +79,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
         let fixture = ChangeFixture::parse(ra_fixture);
         let mut db = Self::default();
         fixture.change.apply(&mut db);
+
         let (file_id, range_or_offset) = fixture
             .file_position
             .expect("Could not find file position in fixture. Did you forget to add an `$0`?");
@@ -95,7 +95,42 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
     }
 }
 
-impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {}
+impl<DB: ExpandDatabase + SourceDatabaseExt + Default + 'static> WithFixture for DB {}
+
+#[derive(Debug, Default)]
+pub struct Change {
+    pub source_change: FileChange,
+    pub proc_macros: Option<ProcMacros>,
+}
+
+impl Change {
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    pub fn apply(self, db: &mut (impl ExpandDatabase + SourceDatabaseExt)) {
+        self.source_change.apply(db);
+        if let Some(proc_macros) = self.proc_macros {
+            db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH);
+        }
+    }
+
+    pub fn change_file(&mut self, file_id: FileId, new_text: Option<Arc<str>>) {
+        self.source_change.change_file(file_id, new_text)
+    }
+
+    pub fn set_crate_graph(&mut self, graph: CrateGraph) {
+        self.source_change.set_crate_graph(graph)
+    }
+
+    pub fn set_proc_macros(&mut self, proc_macros: ProcMacros) {
+        self.proc_macros = Some(proc_macros);
+    }
+
+    pub fn set_roots(&mut self, roots: Vec<SourceRoot>) {
+        self.source_change.set_roots(roots)
+    }
+}
 
 pub struct ChangeFixture {
     pub file_position: Option<(FileId, RangeOrOffset)>,
@@ -122,7 +157,7 @@ impl ChangeFixture {
                     .unwrap_or_else(|| panic!("unknown release channel found: {it}"))
             })
             .unwrap_or(ReleaseChannel::Stable);
-        let mut change = Change::new();
+        let mut source_change = FileChange::new();
 
         let mut files = Vec::new();
         let mut crate_graph = CrateGraph::default();
@@ -206,7 +241,7 @@ impl ChangeFixture {
                 default_target_data_layout = meta.target_data_layout;
             }
 
-            change.change_file(file_id, Some(Arc::from(text)));
+            source_change.change_file(file_id, Some(Arc::from(text)));
             let path = VfsPath::new_virtual_path(meta.path);
             file_set.insert(file_id, path);
             files.push(file_id);
@@ -261,7 +296,7 @@ impl ChangeFixture {
             fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_string()));
             roots.push(SourceRoot::new_library(fs));
 
-            change.change_file(core_file, Some(Arc::from(mini_core.source_code())));
+            source_change.change_file(core_file, Some(Arc::from(mini_core.source_code())));
 
             let all_crates = crate_graph.crates_in_topological_order();
 
@@ -306,7 +341,7 @@ impl ChangeFixture {
             );
             roots.push(SourceRoot::new_library(fs));
 
-            change.change_file(proc_lib_file, Some(Arc::from(source)));
+            source_change.change_file(proc_lib_file, Some(Arc::from(source)));
 
             let all_crates = crate_graph.crates_in_topological_order();
 
@@ -344,11 +379,17 @@ impl ChangeFixture {
             SourceRootKind::Library => SourceRoot::new_library(mem::take(&mut file_set)),
         };
         roots.push(root);
-        change.set_roots(roots);
-        change.set_crate_graph(crate_graph);
-        change.set_proc_macros(proc_macros);
-
-        ChangeFixture { file_position, files, change }
+        source_change.set_roots(roots);
+        source_change.set_crate_graph(crate_graph);
+
+        ChangeFixture {
+            file_position,
+            files,
+            change: Change {
+                source_change,
+                proc_macros: proc_macros.is_empty().not().then(|| proc_macros),
+            },
+        }
     }
 }
 
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index d7819b315c4..bb2cb3f5b5b 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -6,20 +6,21 @@
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-pub mod db;
 pub mod ast_id_map;
-pub mod name;
-pub mod hygiene;
+pub mod attrs;
 pub mod builtin_attr_macro;
 pub mod builtin_derive_macro;
 pub mod builtin_fn_macro;
-pub mod proc_macro;
-pub mod quote;
+pub mod db;
 pub mod eager;
+pub mod files;
+pub mod fixture;
+pub mod hygiene;
 pub mod mod_path;
-pub mod attrs;
+pub mod name;
+pub mod proc_macro;
+pub mod quote;
 pub mod span;
-pub mod files;
 mod fixup;
 
 use attrs::collect_attrs;
@@ -29,7 +30,7 @@ use std::{fmt, hash::Hash};
 
 use base_db::{
     span::{HirFileIdRepr, SpanData, SyntaxContextId},
-    CrateId, FileId, FileRange, ProcMacroKind,
+    CrateId, FileId, FileRange,
 };
 use either::Either;
 use syntax::{
@@ -45,7 +46,7 @@ use crate::{
     db::TokenExpander,
     fixup::SyntaxFixupUndoInfo,
     mod_path::ModPath,
-    proc_macro::ProcMacroExpander,
+    proc_macro::{CustomProcMacroExpander, ProcMacroKind},
     span::{ExpansionSpanMap, SpanMap},
 };
 
@@ -138,7 +139,7 @@ pub enum MacroDefKind {
     BuiltInAttr(BuiltinAttrExpander, AstId<ast::Macro>),
     BuiltInDerive(BuiltinDeriveExpander, AstId<ast::Macro>),
     BuiltInEager(EagerExpander, AstId<ast::Macro>),
-    ProcMacro(ProcMacroExpander, ProcMacroKind, AstId<ast::Fn>),
+    ProcMacro(CustomProcMacroExpander, ProcMacroKind, AstId<ast::Fn>),
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs
index de577796831..2707df9d1ae 100644
--- a/crates/hir-expand/src/proc_macro.rs
+++ b/crates/hir-expand/src/proc_macro.rs
@@ -1,18 +1,63 @@
 //! Proc Macro Expander stub
 
-use base_db::{span::SpanData, CrateId, ProcMacroExpansionError, ProcMacroId, ProcMacroKind};
+use core::fmt;
+use std::{panic::RefUnwindSafe, sync};
+
+use base_db::{span::SpanData, CrateId, Env};
+use rustc_hash::FxHashMap;
 use stdx::never;
+use syntax::SmolStr;
 
 use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult};
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct ProcMacroId(pub u32);
+
+#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
+pub enum ProcMacroKind {
+    CustomDerive,
+    FuncLike,
+    Attr,
+}
+
+pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe {
+    fn expand(
+        &self,
+        subtree: &tt::Subtree,
+        attrs: Option<&tt::Subtree>,
+        env: &Env,
+        def_site: SpanData,
+        call_site: SpanData,
+        mixed_site: SpanData,
+    ) -> Result<tt::Subtree, ProcMacroExpansionError>;
+}
+
+#[derive(Debug)]
+pub enum ProcMacroExpansionError {
+    Panic(String),
+    /// Things like "proc macro server was killed by OOM".
+    System(String),
+}
+
+pub type ProcMacroLoadResult = Result<Vec<ProcMacro>, String>;
+
+pub type ProcMacros = FxHashMap<CrateId, ProcMacroLoadResult>;
+
+#[derive(Debug, Clone)]
+pub struct ProcMacro {
+    pub name: SmolStr,
+    pub kind: ProcMacroKind,
+    pub expander: sync::Arc<dyn ProcMacroExpander>,
+}
+
 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
-pub struct ProcMacroExpander {
+pub struct CustomProcMacroExpander {
     proc_macro_id: ProcMacroId,
 }
 
 const DUMMY_ID: u32 = !0;
 
-impl ProcMacroExpander {
+impl CustomProcMacroExpander {
     pub fn new(proc_macro_id: ProcMacroId) -> Self {
         assert_ne!(proc_macro_id.0, DUMMY_ID);
         Self { proc_macro_id }
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index b395e7f4a81..518e34b4d77 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -1,6 +1,7 @@
-use base_db::{fixture::WithFixture, FileId};
+use base_db::FileId;
 use chalk_ir::Substitution;
 use hir_def::db::DefDatabase;
+use hir_expand::fixture::WithFixture;
 use test_utils::skip_slow_tests;
 
 use crate::{
diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs
index 5e3a86c80e3..f8b55ae4d06 100644
--- a/crates/hir-ty/src/layout/tests.rs
+++ b/crates/hir-ty/src/layout/tests.rs
@@ -1,9 +1,9 @@
 use std::collections::HashMap;
 
-use base_db::fixture::WithFixture;
 use chalk_ir::{AdtId, TyKind};
 use either::Either;
 use hir_def::db::DefDatabase;
+use hir_expand::fixture::WithFixture;
 use triomphe::Arc;
 
 use crate::{
diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs
index ff30dc6dade..b902af7c87c 100644
--- a/crates/hir-ty/src/mir/eval/tests.rs
+++ b/crates/hir-ty/src/mir/eval/tests.rs
@@ -1,5 +1,6 @@
-use base_db::{fixture::WithFixture, FileId};
+use base_db::FileId;
 use hir_def::db::DefDatabase;
+use hir_expand::fixture::WithFixture;
 use syntax::{TextRange, TextSize};
 
 use crate::{db::HirDatabase, test_db::TestDB, Interner, Substitution};
diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs
index 1446e83fa88..0ac8f796fd5 100644
--- a/crates/hir-ty/src/tests.rs
+++ b/crates/hir-ty/src/tests.rs
@@ -12,7 +12,7 @@ mod diagnostics;
 
 use std::{collections::HashMap, env};
 
-use base_db::{fixture::WithFixture, FileRange, SourceDatabaseExt};
+use base_db::{FileRange, SourceDatabaseExt};
 use expect_test::Expect;
 use hir_def::{
     body::{Body, BodySourceMap, SyntheticSyntax},
@@ -23,7 +23,7 @@ use hir_def::{
     src::HasSource,
     AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId,
 };
-use hir_expand::{db::ExpandDatabase, InFile};
+use hir_expand::{db::ExpandDatabase, fixture::WithFixture, InFile};
 use once_cell::race::OnceBool;
 use stdx::format_to;
 use syntax::{
diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs
index 28e84e480d7..e21d74bf5ba 100644
--- a/crates/hir-ty/src/tests/incremental.rs
+++ b/crates/hir-ty/src/tests/incremental.rs
@@ -1,4 +1,5 @@
-use base_db::{fixture::WithFixture, SourceDatabaseExt};
+use base_db::SourceDatabaseExt;
+use hir_expand::fixture::WithFixture;
 use triomphe::Arc;
 
 use crate::{db::HirDatabase, test_db::TestDB};
diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs
index d98e3decd21..7204868464b 100644
--- a/crates/hir/src/db.rs
+++ b/crates/hir/src/db.rs
@@ -24,6 +24,6 @@ pub use hir_def::db::{
 pub use hir_expand::db::{
     AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage,
     ExpandProcMacroQuery, InternMacroCallQuery, InternSyntaxContextQuery, MacroArgQuery,
-    ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, RealSpanMapQuery,
+    ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacrosQuery, RealSpanMapQuery,
 };
 pub use hir_ty::db::*;
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index e0230fa3761..ccf031df0ce 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -37,7 +37,7 @@ mod display;
 use std::{iter, mem::discriminant, ops::ControlFlow};
 
 use arrayvec::ArrayVec;
-use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId, ProcMacroKind};
+use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId};
 use either::Either;
 use hir_def::{
     body::{BodyDiagnostic, SyntheticSyntax},
@@ -59,7 +59,7 @@ use hir_def::{
     Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, TraitAliasId, TraitId,
     TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId,
 };
-use hir_expand::{attrs::collect_attrs, name::name, MacroCallKind};
+use hir_expand::{attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, MacroCallKind};
 use hir_ty::{
     all_super_traits, autoderef, check_orphan_rules,
     consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
@@ -125,8 +125,10 @@ pub use {
     },
     hir_expand::{
         attrs::{Attr, AttrId},
+        fixture::{Change, ChangeFixture, WithFixture},
         hygiene::{marks_rev, SyntaxContextExt},
         name::{known, Name},
+        proc_macro::ProcMacros,
         tt, ExpandResult, HirFileId, HirFileIdExt, InFile, InMacroFile, InRealFile, MacroFileId,
         MacroFileIdExt,
     },
diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs
index f508c42c53e..5348667981e 100644
--- a/crates/ide-assists/src/handlers/auto_import.rs
+++ b/crates/ide-assists/src/handlers/auto_import.rs
@@ -280,12 +280,8 @@ fn module_distance_heuristic(db: &dyn HirDatabase, current: &Module, item: &Modu
 mod tests {
     use super::*;
 
-    use hir::Semantics;
-    use ide_db::{
-        assists::AssistResolveStrategy,
-        base_db::{fixture::WithFixture, FileRange},
-        RootDatabase,
-    };
+    use hir::{Semantics, WithFixture};
+    use ide_db::{assists::AssistResolveStrategy, base_db::FileRange, RootDatabase};
 
     use crate::tests::{
         check_assist, check_assist_by_label, check_assist_not_applicable, check_assist_target,
diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs
index 25b3d6d9da9..87332d896a3 100644
--- a/crates/ide-assists/src/tests.rs
+++ b/crates/ide-assists/src/tests.rs
@@ -3,9 +3,9 @@ mod generated;
 mod sourcegen;
 
 use expect_test::expect;
-use hir::Semantics;
+use hir::{Semantics, WithFixture};
 use ide_db::{
-    base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt},
+    base_db::{FileId, FileRange, SourceDatabaseExt},
     imports::insert_use::{ImportGranularity, InsertUseConfig},
     source_change::FileSystemEdit,
     RootDatabase, SnippetCap,
diff --git a/crates/ide-assists/src/utils/suggest_name.rs b/crates/ide-assists/src/utils/suggest_name.rs
index 16704d598ef..4dca23abe99 100644
--- a/crates/ide-assists/src/utils/suggest_name.rs
+++ b/crates/ide-assists/src/utils/suggest_name.rs
@@ -275,7 +275,8 @@ fn from_field_name(expr: &ast::Expr) -> Option<String> {
 
 #[cfg(test)]
 mod tests {
-    use ide_db::base_db::{fixture::WithFixture, FileRange};
+    use hir::WithFixture;
+    use ide_db::base_db::FileRange;
 
     use super::*;
 
diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index f28afacc586..dfaa2588cf4 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -24,9 +24,9 @@ mod use_tree;
 mod visibility;
 
 use expect_test::Expect;
-use hir::PrefixKind;
+use hir::{ChangeFixture, PrefixKind};
 use ide_db::{
-    base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
+    base_db::{FileLoader, FilePosition},
     imports::insert_use::{ImportGranularity, InsertUseConfig},
     RootDatabase, SnippetCap,
 };
diff --git a/crates/ide-db/src/apply_change.rs b/crates/ide-db/src/apply_change.rs
index 343be870c9e..0b22143126e 100644
--- a/crates/ide-db/src/apply_change.rs
+++ b/crates/ide-db/src/apply_change.rs
@@ -5,13 +5,13 @@ use base_db::{
         debug::{DebugQueryTable, TableEntry},
         Database, Durability, Query, QueryTable,
     },
-    Change, SourceRootId,
+    SourceRootId,
 };
 use profile::{memory_usage, Bytes};
 use rustc_hash::FxHashSet;
 use triomphe::Arc;
 
-use crate::{symbol_index::SymbolsDatabase, RootDatabase};
+use crate::{fixture::Change, symbol_index::SymbolsDatabase, RootDatabase};
 
 impl RootDatabase {
     pub fn request_cancellation(&mut self) {
@@ -23,7 +23,7 @@ impl RootDatabase {
         let _p = profile::span("RootDatabase::apply_change");
         self.request_cancellation();
         tracing::trace!("apply_change {:?}", change);
-        if let Some(roots) = &change.roots {
+        if let Some(roots) = &change.source_change.roots {
             let mut local_roots = FxHashSet::default();
             let mut library_roots = FxHashSet::default();
             for (idx, root) in roots.iter().enumerate() {
@@ -87,7 +87,6 @@ impl RootDatabase {
             // SourceDatabase
             base_db::ParseQuery
             base_db::CrateGraphQuery
-            base_db::ProcMacrosQuery
 
             // SourceDatabaseExt
             base_db::FileTextQuery
@@ -104,6 +103,7 @@ impl RootDatabase {
             hir::db::MacroArgQuery
             hir::db::ParseMacroExpansionQuery
             hir::db::RealSpanMapQuery
+            hir::db::ProcMacrosQuery
 
             // DefDatabase
             hir::db::FileItemTreeQuery
diff --git a/crates/ide-db/src/imports/insert_use/tests.rs b/crates/ide-db/src/imports/insert_use/tests.rs
index 01d2f1970c3..942d262ddf6 100644
--- a/crates/ide-db/src/imports/insert_use/tests.rs
+++ b/crates/ide-db/src/imports/insert_use/tests.rs
@@ -1,5 +1,4 @@
-use base_db::fixture::WithFixture;
-use hir::PrefixKind;
+use hir::{PrefixKind, WithFixture};
 use stdx::trim_indent;
 use test_utils::{assert_eq_text, CURSOR_MARKER};
 
diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs
index fefc05e5355..63020758d58 100644
--- a/crates/ide-db/src/lib.rs
+++ b/crates/ide-db/src/lib.rs
@@ -43,6 +43,11 @@ pub mod syntax_helpers {
     pub use parser::LexedStr;
 }
 
+pub mod fixture {
+    pub use hir::{Change, ChangeFixture, WithFixture};
+    pub const WORKSPACE: base_db::SourceRootId = base_db::SourceRootId(0);
+}
+
 use std::{fmt, mem::ManuallyDrop};
 
 use base_db::{
diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs
index be8566b759c..6493e1535a9 100644
--- a/crates/ide-db/src/symbol_index.rs
+++ b/crates/ide-db/src/symbol_index.rs
@@ -378,9 +378,8 @@ impl Query {
 #[cfg(test)]
 mod tests {
 
-    use base_db::fixture::WithFixture;
     use expect_test::expect_file;
-    use hir::symbols::SymbolCollector;
+    use hir::{symbols::SymbolCollector, WithFixture};
 
     use super::*;
 
diff --git a/crates/ide-db/src/traits.rs b/crates/ide-db/src/traits.rs
index 9abbc344142..4c9ecfcc844 100644
--- a/crates/ide-db/src/traits.rs
+++ b/crates/ide-db/src/traits.rs
@@ -113,9 +113,9 @@ fn assoc_item_of_trait(
 
 #[cfg(test)]
 mod tests {
-    use base_db::{fixture::ChangeFixture, FilePosition};
+    use base_db::FilePosition;
     use expect_test::{expect, Expect};
-    use hir::Semantics;
+    use hir::{ChangeFixture, Semantics};
     use syntax::ast::{self, AstNode};
 
     use crate::RootDatabase;
diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs
index 48e0363c9ca..e5b1cf2bc04 100644
--- a/crates/ide-diagnostics/src/tests.rs
+++ b/crates/ide-diagnostics/src/tests.rs
@@ -2,10 +2,9 @@
 mod sourcegen;
 
 use expect_test::Expect;
+use hir::WithFixture;
 use ide_db::{
-    assists::AssistResolveStrategy,
-    base_db::{fixture::WithFixture, SourceDatabaseExt},
-    LineIndexDatabase, RootDatabase,
+    assists::AssistResolveStrategy, base_db::SourceDatabaseExt, LineIndexDatabase, RootDatabase,
 };
 use itertools::Itertools;
 use stdx::trim_indent;
diff --git a/crates/ide-ssr/src/tests.rs b/crates/ide-ssr/src/tests.rs
index 424ba3d7fd5..0083e8faff8 100644
--- a/crates/ide-ssr/src/tests.rs
+++ b/crates/ide-ssr/src/tests.rs
@@ -65,7 +65,7 @@ fn parser_undefined_placeholder_in_replacement() {
 /// `code` may optionally contain a cursor marker `$0`. If it doesn't, then the position will be
 /// the start of the file. If there's a second cursor marker, then we'll return a single range.
 pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Vec<FileRange>) {
-    use ide_db::base_db::fixture::WithFixture;
+    use hir::WithFixture;
     use ide_db::symbol_index::SymbolsDatabase;
     let (mut db, file_id, range_or_offset) = if code.contains(test_utils::CURSOR_MARKER) {
         ide_db::RootDatabase::with_range_or_offset(code)
@@ -86,7 +86,7 @@ pub(crate) fn single_file(code: &str) -> (ide_db::RootDatabase, FilePosition, Ve
         }
     }
     let mut local_roots = FxHashSet::default();
-    local_roots.insert(ide_db::base_db::fixture::WORKSPACE);
+    local_roots.insert(ide_db::fixture::WORKSPACE);
     db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
     (db, position, selections)
 }
diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs
index 2e5903c0602..2fc64ae4571 100644
--- a/crates/ide/src/fixture.rs
+++ b/crates/ide/src/fixture.rs
@@ -1,5 +1,5 @@
 //! Utilities for creating `Analysis` instances for tests.
-use ide_db::base_db::fixture::ChangeFixture;
+use ide_db::fixture::ChangeFixture;
 use test_utils::{extract_annotations, RangeOrOffset};
 
 use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange};
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index a19952e4cae..6ff16b9e2f7 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -67,6 +67,7 @@ use std::ffi::OsStr;
 
 use cfg::CfgOptions;
 use fetch_crates::CrateInfo;
+use hir::Change;
 use ide_db::{
     base_db::{
         salsa::{self, ParallelDatabase},
@@ -122,7 +123,7 @@ pub use ide_completion::{
 };
 pub use ide_db::{
     base_db::{
-        Cancelled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange,
+        Cancelled, CrateGraph, CrateId, Edition, FileChange, FileId, FilePosition, FileRange,
         SourceRoot, SourceRootId,
     },
     documentation::Documentation,
@@ -183,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) {
-        self.db.apply_change(change)
+        self.db.apply_change(change);
     }
 
     /// NB: this clears the database
diff --git a/crates/ide/src/shuffle_crate_graph.rs b/crates/ide/src/shuffle_crate_graph.rs
index f85700daf1f..af55b9cc987 100644
--- a/crates/ide/src/shuffle_crate_graph.rs
+++ b/crates/ide/src/shuffle_crate_graph.rs
@@ -1,5 +1,6 @@
+use hir::{db::ExpandDatabase, ProcMacros};
 use ide_db::{
-    base_db::{salsa::Durability, CrateGraph, ProcMacros, SourceDatabase},
+    base_db::{salsa::Durability, CrateGraph, SourceDatabase},
     FxHashMap, RootDatabase,
 };
 use triomphe::Arc;
diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs
index 990376a4965..479a5e151ad 100644
--- a/crates/ide/src/signature_help.rs
+++ b/crates/ide/src/signature_help.rs
@@ -646,7 +646,7 @@ mod tests {
     use std::iter;
 
     use expect_test::{expect, Expect};
-    use ide_db::base_db::{fixture::ChangeFixture, FilePosition};
+    use ide_db::{base_db::FilePosition, fixture::ChangeFixture};
     use stdx::format_to;
 
     use crate::RootDatabase;
diff --git a/crates/ide/src/ssr.rs b/crates/ide/src/ssr.rs
index d8d81869a2f..312481c9bbc 100644
--- a/crates/ide/src/ssr.rs
+++ b/crates/ide/src/ssr.rs
@@ -59,7 +59,8 @@ mod tests {
     use expect_test::expect;
     use ide_assists::{Assist, AssistResolveStrategy};
     use ide_db::{
-        base_db::{fixture::WithFixture, salsa::Durability, FileRange},
+        base_db::{salsa::Durability, FileRange},
+        fixture::WithFixture,
         symbol_index::SymbolsDatabase,
         FxHashSet, RootDatabase,
     };
@@ -70,7 +71,7 @@ mod tests {
     fn get_assists(ra_fixture: &str, resolve: AssistResolveStrategy) -> Vec<Assist> {
         let (mut db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture);
         let mut local_roots = FxHashSet::default();
-        local_roots.insert(ide_db::base_db::fixture::WORKSPACE);
+        local_roots.insert(ide_db::fixture::WORKSPACE);
         db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
         ssr_assists(&db, &resolve, FileRange { file_id, range: range_or_offset.into() })
     }
diff --git a/crates/load-cargo/Cargo.toml b/crates/load-cargo/Cargo.toml
index 31b9f6c76d0..06b3b945876 100644
--- a/crates/load-cargo/Cargo.toml
+++ b/crates/load-cargo/Cargo.toml
@@ -23,3 +23,5 @@ project-model.workspace = true
 tt.workspace = true
 vfs.workspace = true
 vfs-notify.workspace = true
+
+hir-expand.workspace = true
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs
index db9654220dd..cab8d609ead 100644
--- a/crates/load-cargo/src/lib.rs
+++ b/crates/load-cargo/src/lib.rs
@@ -5,12 +5,14 @@
 use std::{collections::hash_map::Entry, mem, path::Path, sync};
 
 use crossbeam_channel::{unbounded, Receiver};
-use ide::{AnalysisHost, Change, SourceRoot};
+use hir_expand::proc_macro::{
+    ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, ProcMacroLoadResult,
+    ProcMacros,
+};
+use ide::{AnalysisHost, SourceRoot};
 use ide_db::{
-    base_db::{
-        span::SpanData, CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError,
-        ProcMacroKind, ProcMacroLoadResult, ProcMacros,
-    },
+    base_db::{span::SpanData, CrateGraph, Env},
+    fixture::Change,
     FxHashMap,
 };
 use itertools::Itertools;
diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs
index c89b88ac0f9..b8f6138161e 100644
--- a/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -4,8 +4,8 @@ use std::{
     cell::RefCell, collections::HashMap, fs::read_to_string, panic::AssertUnwindSafe, path::PathBuf,
 };
 
-use hir::Crate;
-use ide::{AnalysisHost, Change, DiagnosticCode, DiagnosticsConfig};
+use hir::{Change, Crate};
+use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
 use profile::StopWatch;
 use project_model::{CargoConfig, ProjectWorkspace, RustLibSource, Sysroot};
 
diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs
index 30e11402cd8..dfc7cbf510b 100644
--- a/crates/rust-analyzer/src/cli/scip.rs
+++ b/crates/rust-analyzer/src/cli/scip.rs
@@ -278,7 +278,7 @@ fn token_to_symbol(token: &TokenStaticData) -> Option<scip_types::Symbol> {
 mod test {
     use super::*;
     use ide::{AnalysisHost, FilePosition, StaticIndex, TextSize};
-    use ide_db::base_db::fixture::ChangeFixture;
+    use ide_db::fixture::ChangeFixture;
     use scip::symbol::format_symbol;
 
     fn position(ra_fixture: &str) -> (AnalysisHost, FilePosition) {
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 0f31fe16054..f57a27305f0 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -7,7 +7,8 @@ use std::time::Instant;
 
 use crossbeam_channel::{unbounded, Receiver, Sender};
 use flycheck::FlycheckHandle;
-use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId};
+use hir::Change;
+use ide::{Analysis, AnalysisHost, Cancellable, FileId};
 use ide_db::base_db::{CrateId, FileLoader, ProcMacroPaths, SourceDatabase};
 use load_cargo::SourceRootConfig;
 use lsp_types::{SemanticTokens, Url};
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 41ff17f5e43..d94f7cefa60 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -10,7 +10,8 @@
 //! 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 ide::{CallableSnippets, Change, CompletionConfig, FilePosition, TextSize};
+use hir::Change;
+use ide::{CallableSnippets, CompletionConfig, FilePosition, TextSize};
 use ide_db::{
     imports::insert_use::{ImportGranularity, InsertUseConfig},
     SnippetCap,
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 7ab528f4975..cc7cb276ad0 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -16,10 +16,9 @@
 use std::{iter, mem};
 
 use flycheck::{FlycheckConfig, FlycheckHandle};
-use hir::db::DefDatabase;
-use ide::Change;
+use hir::{db::DefDatabase, Change, ProcMacros};
 use ide_db::{
-    base_db::{salsa::Durability, CrateGraph, ProcMacroPaths, ProcMacros},
+    base_db::{salsa::Durability, CrateGraph, ProcMacroPaths},
     FxHashMap,
 };
 use itertools::Itertools;