Improve fixture support

Support more features beside highlighting, and support items from minicore.
diff --git a/Cargo.lock b/Cargo.lock
index 55e5bdc..539f8cf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -930,6 +930,7 @@
  "ide-diagnostics",
  "ide-ssr",
  "itertools",
+ "macros",
  "nohash-hasher",
  "oorandom",
  "profile",
@@ -976,6 +977,7 @@
  "hir",
  "ide-db",
  "itertools",
+ "macros",
  "smallvec",
  "stdx",
  "syntax",
@@ -1000,6 +1002,7 @@
  "indexmap",
  "itertools",
  "line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "macros",
  "memchr",
  "nohash-hasher",
  "parser",
@@ -1009,6 +1012,7 @@
  "rustc-hash 2.1.1",
  "salsa",
  "salsa-macros",
+ "smallvec",
  "span",
  "stdx",
  "syntax",
diff --git a/crates/ide-completion/Cargo.toml b/crates/ide-completion/Cargo.toml
index 9bad21f..277d5df 100644
--- a/crates/ide-completion/Cargo.toml
+++ b/crates/ide-completion/Cargo.toml
@@ -28,6 +28,7 @@
 # completions crate should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
 hir.workspace = true
+macros.workspace = true
 
 [dev-dependencies]
 expect-test = "1.5.1"
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index b822f53..ed58e86 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -16,6 +16,7 @@
 pub(crate) mod mod_;
 pub(crate) mod pattern;
 pub(crate) mod postfix;
+pub(crate) mod ra_fixture;
 pub(crate) mod record;
 pub(crate) mod snippet;
 pub(crate) mod r#type;
@@ -74,6 +75,10 @@
         self.buf.push(item)
     }
 
+    fn add_many(&mut self, items: impl IntoIterator<Item = CompletionItem>) {
+        self.buf.extend(items)
+    }
+
     fn add_opt(&mut self, item: Option<CompletionItem>) {
         if let Some(item) = item {
             self.buf.push(item)
diff --git a/crates/ide-completion/src/completions/ra_fixture.rs b/crates/ide-completion/src/completions/ra_fixture.rs
new file mode 100644
index 0000000..b44c907
--- /dev/null
+++ b/crates/ide-completion/src/completions/ra_fixture.rs
@@ -0,0 +1,113 @@
+//! Injected completions for `#[rust_analyzer::rust_fixture]`.
+
+use hir::FilePositionWrapper;
+use ide_db::{
+    impl_empty_upmap_from_ra_fixture,
+    ra_fixture::{RaFixtureAnalysis, UpmapFromRaFixture},
+};
+use syntax::ast;
+
+use crate::{
+    CompletionItemKind, CompletionItemRefMode, CompletionRelevance, completions::Completions,
+    context::CompletionContext, item::CompletionItemLabel,
+};
+
+pub(crate) fn complete_ra_fixture(
+    acc: &mut Completions,
+    ctx: &CompletionContext<'_>,
+    original: &ast::String,
+    expanded: &ast::String,
+) -> Option<()> {
+    let analysis = RaFixtureAnalysis::analyze_ra_fixture(
+        &ctx.sema,
+        original.clone(),
+        expanded,
+        ctx.config.minicore,
+        &mut |_| {},
+    )?;
+    let (virtual_file_id, virtual_offset) = analysis.map_offset_down(ctx.position.offset)?;
+    let completions = hir::attach_db_allow_change(&analysis.db, || {
+        crate::completions(
+            &analysis.db,
+            ctx.config,
+            FilePositionWrapper { file_id: virtual_file_id, offset: virtual_offset },
+            ctx.trigger_character,
+        )
+    })?;
+    let completions =
+        completions.upmap_from_ra_fixture(&analysis, virtual_file_id, ctx.position.file_id).ok()?;
+    acc.add_many(completions);
+    Some(())
+}
+
+impl_empty_upmap_from_ra_fixture!(
+    CompletionItemLabel,
+    CompletionItemKind,
+    CompletionRelevance,
+    CompletionItemRefMode,
+);
+
+#[cfg(test)]
+mod tests {
+    use expect_test::expect;
+
+    use crate::tests::check;
+
+    #[test]
+    fn it_works() {
+        check(
+            r##"
+fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
+
+fn foo() {
+    fixture(r#"
+fn complete_me() {}
+
+fn baz() {
+    let foo_bar_baz = 123;
+    f$0
+}
+    "#);
+}
+        "##,
+            expect![[r#"
+                fn baz()         fn()
+                fn complete_me() fn()
+                lc foo_bar_baz    i32
+                bt u32            u32
+                kw async
+                kw const
+                kw crate::
+                kw enum
+                kw extern
+                kw false
+                kw fn
+                kw for
+                kw if
+                kw if let
+                kw impl
+                kw impl for
+                kw let
+                kw letm
+                kw loop
+                kw match
+                kw mod
+                kw return
+                kw self::
+                kw static
+                kw struct
+                kw trait
+                kw true
+                kw type
+                kw union
+                kw unsafe
+                kw use
+                kw while
+                kw while let
+                sn macro_rules
+                sn pd
+                sn ppd
+            "#]],
+        );
+    }
+}
diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs
index b7367cb..5623257 100644
--- a/crates/ide-completion/src/config.rs
+++ b/crates/ide-completion/src/config.rs
@@ -6,13 +6,13 @@
 
 use hir::FindPathConfig;
 use ide_db::{
-    SnippetCap,
+    MiniCore, SnippetCap,
     imports::{import_assets::ImportPathConfig, insert_use::InsertUseConfig},
 };
 
 use crate::{CompletionFieldsToResolve, snippet::Snippet};
 
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug)]
 pub struct CompletionConfig<'a> {
     pub enable_postfix_completions: bool,
     pub enable_imports_on_the_fly: bool,
@@ -35,6 +35,7 @@
     pub fields_to_resolve: CompletionFieldsToResolve,
     pub exclude_flyimport: Vec<(String, AutoImportExclusionType)>,
     pub exclude_traits: &'a [String],
+    pub minicore: MiniCore<'a>,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 4032329..fc2cc3b 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -440,6 +440,7 @@
     pub(crate) config: &'a CompletionConfig<'a>,
     pub(crate) position: FilePosition,
 
+    pub(crate) trigger_character: Option<char>,
     /// The token before the cursor, in the original file.
     pub(crate) original_token: SyntaxToken,
     /// The token before the cursor, in the macro-expanded file.
@@ -703,6 +704,7 @@
         db: &'db RootDatabase,
         position @ FilePosition { file_id, offset }: FilePosition,
         config: &'db CompletionConfig<'db>,
+        trigger_character: Option<char>,
     ) -> Option<(CompletionContext<'db>, CompletionAnalysis<'db>)> {
         let _p = tracing::info_span!("CompletionContext::new").entered();
         let sema = Semantics::new(db);
@@ -871,6 +873,7 @@
             db,
             config,
             position,
+            trigger_character,
             original_token,
             token,
             krate,
diff --git a/crates/ide-completion/src/context/tests.rs b/crates/ide-completion/src/context/tests.rs
index e798f3b..51d28bd 100644
--- a/crates/ide-completion/src/context/tests.rs
+++ b/crates/ide-completion/src/context/tests.rs
@@ -10,7 +10,7 @@
     let (db, pos) = position(ra_fixture);
     let config = TEST_CONFIG;
     let (completion_context, _analysis) =
-        hir::attach_db(&db, || CompletionContext::new(&db, pos, &config).unwrap());
+        hir::attach_db(&db, || CompletionContext::new(&db, pos, &config, None).unwrap());
 
     let ty = completion_context
         .expected_type
diff --git a/crates/ide-completion/src/item.rs b/crates/ide-completion/src/item.rs
index 5fb9dc9..303c712 100644
--- a/crates/ide-completion/src/item.rs
+++ b/crates/ide-completion/src/item.rs
@@ -9,6 +9,7 @@
     imports::import_assets::LocatedImport,
 };
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 use smallvec::SmallVec;
 use stdx::{format_to, impl_from, never};
 use syntax::{Edition, SmolStr, TextRange, TextSize, format_smolstr};
@@ -23,7 +24,7 @@
 ///
 /// It is basically a POD with various properties. To construct a [`CompletionItem`],
 /// use [`Builder::new`] method and the [`Builder`] struct.
-#[derive(Clone)]
+#[derive(Clone, UpmapFromRaFixture)]
 #[non_exhaustive]
 pub struct CompletionItem {
     /// Label in the completion pop up which identifies completion.
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index a70a113..8a0aaf3 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -187,7 +187,7 @@
     position: FilePosition,
     trigger_character: Option<char>,
 ) -> Option<Vec<CompletionItem>> {
-    let (ctx, analysis) = &CompletionContext::new(db, position, config)?;
+    let (ctx, analysis) = &CompletionContext::new(db, position, config, trigger_character)?;
     let mut completions = Completions::default();
 
     // prevent `(` from triggering unwanted completion noise
@@ -241,6 +241,7 @@
                 completions::extern_abi::complete_extern_abi(acc, ctx, expanded);
                 completions::format_string::format_string(acc, ctx, original, expanded);
                 completions::env_vars::complete_cargo_env_vars(acc, ctx, original, expanded);
+                completions::ra_fixture::complete_ra_fixture(acc, ctx, original, expanded);
             }
             CompletionAnalysis::UnexpandedAttrTT {
                 colon_prefix,
diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index ec9cd9f..b32a895 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -29,7 +29,7 @@
 use hir::db::HirDatabase;
 use hir::{PrefixKind, setup_tracing};
 use ide_db::{
-    FilePosition, RootDatabase, SnippetCap,
+    FilePosition, MiniCore, RootDatabase, SnippetCap,
     imports::insert_use::{ImportGranularity, InsertUseConfig},
 };
 use itertools::Itertools;
@@ -90,6 +90,7 @@
     exclude_traits: &[],
     enable_auto_await: true,
     enable_auto_iter: true,
+    minicore: MiniCore::default(),
 };
 
 pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index 2d3ebad..0cd4208 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -16,7 +16,8 @@
     expect: Expect,
 ) {
     let (db, position) = crate::tests::position(ra_fixture);
-    let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap();
+    let (ctx, analysis) =
+        crate::context::CompletionContext::new(&db, position, &config, None).unwrap();
 
     let mut acc = crate::completions::Completions::default();
     hir::attach_db(ctx.db, || {
diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml
index e065adb..b714816 100644
--- a/crates/ide-db/Cargo.toml
+++ b/crates/ide-db/Cargo.toml
@@ -30,6 +30,7 @@
 triomphe.workspace = true
 nohash-hasher.workspace = true
 bitflags.workspace = true
+smallvec.workspace = true
 
 # local deps
 base-db.workspace = true
@@ -42,15 +43,15 @@
 # ide should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
 hir.workspace = true
+macros.workspace = true
+
+test-utils.workspace = true
+test-fixture.workspace = true
 
 line-index.workspace = true
 
 [dev-dependencies]
 expect-test = "1.5.1"
 
-# local deps
-test-utils.workspace = true
-test-fixture.workspace = true
-
 [lints]
 workspace = true
diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs
index 44bccd8..7efa97b 100644
--- a/crates/ide-db/src/lib.rs
+++ b/crates/ide-db/src/lib.rs
@@ -2,6 +2,8 @@
 //!
 //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search.
 
+extern crate self as ide_db;
+
 mod apply_change;
 
 pub mod active_parameter;
@@ -14,6 +16,8 @@
 pub mod label;
 pub mod path_transform;
 pub mod prime_caches;
+pub mod ra_fixture;
+pub mod range_mapper;
 pub mod rename;
 pub mod rust_doc;
 pub mod search;
@@ -364,3 +368,25 @@
     WeakWarning,
     Allow,
 }
+
+#[derive(Debug, Clone, Copy)]
+pub struct MiniCore<'a>(&'a str);
+
+impl<'a> MiniCore<'a> {
+    #[inline]
+    pub fn new(minicore: &'a str) -> Self {
+        Self(minicore)
+    }
+
+    #[inline]
+    pub const fn default() -> Self {
+        Self(test_utils::MiniCore::RAW_SOURCE)
+    }
+}
+
+impl<'a> Default for MiniCore<'a> {
+    #[inline]
+    fn default() -> Self {
+        Self::default()
+    }
+}
diff --git a/crates/ide-db/src/ra_fixture.rs b/crates/ide-db/src/ra_fixture.rs
new file mode 100644
index 0000000..1f056a8
--- /dev/null
+++ b/crates/ide-db/src/ra_fixture.rs
@@ -0,0 +1,532 @@
+//! Working with the fixtures in r-a tests, and providing IDE services for them.
+
+use std::hash::{BuildHasher, Hash};
+
+use hir::{CfgExpr, FilePositionWrapper, FileRangeWrapper, Semantics};
+use smallvec::SmallVec;
+use span::{TextRange, TextSize};
+use syntax::{
+    AstToken, SmolStr,
+    ast::{self, IsString},
+};
+
+use crate::{
+    MiniCore, RootDatabase, SymbolKind, active_parameter::ActiveParameter,
+    documentation::Documentation, range_mapper::RangeMapper, search::ReferenceCategory,
+};
+
+pub use span::FileId;
+
+impl RootDatabase {
+    fn from_ra_fixture(
+        text: &str,
+        minicore: MiniCore<'_>,
+    ) -> Result<(RootDatabase, Vec<(FileId, usize)>, Vec<FileId>), ()> {
+        // We don't want a mistake in the fixture to crash r-a, so we wrap this in `catch_unwind()`.
+        std::panic::catch_unwind(|| {
+            let mut db = RootDatabase::default();
+            let fixture = test_fixture::ChangeFixture::parse_with_proc_macros(
+                &db,
+                text,
+                minicore.0,
+                Vec::new(),
+            );
+            db.apply_change(fixture.change);
+            let files = fixture
+                .files
+                .into_iter()
+                .zip(fixture.file_lines)
+                .map(|(file_id, range)| (file_id.file_id(&db), range))
+                .collect();
+            (db, files, fixture.sysroot_files)
+        })
+        .map_err(|error| {
+            tracing::error!(
+                "cannot crate the crate graph: {}\nCrate graph:\n{}\n",
+                if let Some(&s) = error.downcast_ref::<&'static str>() {
+                    s
+                } else if let Some(s) = error.downcast_ref::<String>() {
+                    s.as_str()
+                } else {
+                    "Box<dyn Any>"
+                },
+                text,
+            );
+        })
+    }
+}
+
+pub struct RaFixtureAnalysis {
+    pub db: RootDatabase,
+    tmp_file_ids: Vec<(FileId, usize)>,
+    line_offsets: Vec<TextSize>,
+    virtual_file_id_to_line: Vec<usize>,
+    mapper: RangeMapper,
+    literal: ast::String,
+    // `minicore` etc..
+    sysroot_files: Vec<FileId>,
+    combined_len: TextSize,
+}
+
+impl RaFixtureAnalysis {
+    pub fn analyze_ra_fixture(
+        sema: &Semantics<'_, RootDatabase>,
+        literal: ast::String,
+        expanded: &ast::String,
+        minicore: MiniCore<'_>,
+        on_cursor: &mut dyn FnMut(TextRange),
+    ) -> Option<RaFixtureAnalysis> {
+        if !literal.is_raw() {
+            return None;
+        }
+
+        let active_parameter = ActiveParameter::at_token(sema, expanded.syntax().clone())?;
+        let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| {
+            attrs.filter_map(|attr| attr.as_simple_path()).any(|path| {
+                path.segments()
+                    .zip(["rust_analyzer", "rust_fixture"])
+                    .all(|(seg, name)| seg.name_ref().map_or(false, |nr| nr.text() == name))
+            })
+        });
+        if !has_rust_fixture_attr {
+            return None;
+        }
+        let value = literal.value().ok()?;
+
+        let mut mapper = RangeMapper::default();
+
+        // This is used for the `Injector`, to resolve precise location in the string literal,
+        // which will then be used to resolve precise location in the enclosing file.
+        let mut offset_with_indent = TextSize::new(0);
+        // This is used to resolve the location relative to the virtual file into a location
+        // relative to the indentation-trimmed file which will then (by the `Injector`) used
+        // to resolve to a location in the actual file.
+        // Besides indentation, we also skip `$0` cursors for this, since they are not included
+        // in the virtual files.
+        let mut offset_without_indent = TextSize::new(0);
+
+        let mut text = &*value;
+        if let Some(t) = text.strip_prefix('\n') {
+            offset_with_indent += TextSize::of("\n");
+            text = t;
+        }
+        // This stores the offsets of each line, **after we remove indentation**.
+        let mut line_offsets = Vec::new();
+        for mut line in text.split_inclusive('\n') {
+            line_offsets.push(offset_without_indent);
+
+            if line.starts_with("@@") {
+                // Introducing `//` into a fixture inside fixture causes all sorts of problems,
+                // so for testing purposes we escape it as `@@` and replace it here.
+                mapper.add("//", TextRange::at(offset_with_indent, TextSize::of("@@")));
+                line = &line["@@".len()..];
+                offset_with_indent += TextSize::of("@@");
+                offset_without_indent += TextSize::of("@@");
+            }
+
+            // Remove indentation to simplify the mapping with fixture (which de-indents).
+            // Removing indentation shouldn't affect highlighting.
+            let mut unindented_line = line.trim_start();
+            if unindented_line.is_empty() {
+                // The whole line was whitespaces, but we need the newline.
+                unindented_line = "\n";
+            }
+            offset_with_indent += TextSize::of(line) - TextSize::of(unindented_line);
+
+            let marker = "$0";
+            match unindented_line.find(marker) {
+                Some(marker_pos) => {
+                    let (before_marker, after_marker) = unindented_line.split_at(marker_pos);
+                    let after_marker = &after_marker[marker.len()..];
+
+                    mapper.add(
+                        before_marker,
+                        TextRange::at(offset_with_indent, TextSize::of(before_marker)),
+                    );
+                    offset_with_indent += TextSize::of(before_marker);
+                    offset_without_indent += TextSize::of(before_marker);
+
+                    if let Some(marker_range) = literal
+                        .map_range_up(TextRange::at(offset_with_indent, TextSize::of(marker)))
+                    {
+                        on_cursor(marker_range);
+                    }
+                    offset_with_indent += TextSize::of(marker);
+
+                    mapper.add(
+                        after_marker,
+                        TextRange::at(offset_with_indent, TextSize::of(after_marker)),
+                    );
+                    offset_with_indent += TextSize::of(after_marker);
+                    offset_without_indent += TextSize::of(after_marker);
+                }
+                None => {
+                    mapper.add(
+                        unindented_line,
+                        TextRange::at(offset_with_indent, TextSize::of(unindented_line)),
+                    );
+                    offset_with_indent += TextSize::of(unindented_line);
+                    offset_without_indent += TextSize::of(unindented_line);
+                }
+            }
+        }
+
+        let combined = mapper.take_text();
+        let combined_len = TextSize::of(&combined);
+        let (analysis, tmp_file_ids, sysroot_files) =
+            RootDatabase::from_ra_fixture(&combined, minicore).ok()?;
+
+        // We use a `Vec` because we know the `FileId`s will always be close.
+        let mut virtual_file_id_to_line = Vec::new();
+        for &(file_id, line) in &tmp_file_ids {
+            virtual_file_id_to_line.resize(file_id.index() as usize + 1, usize::MAX);
+            virtual_file_id_to_line[file_id.index() as usize] = line;
+        }
+
+        Some(RaFixtureAnalysis {
+            db: analysis,
+            tmp_file_ids,
+            line_offsets,
+            virtual_file_id_to_line,
+            mapper,
+            literal,
+            sysroot_files,
+            combined_len,
+        })
+    }
+
+    pub fn files(&self) -> impl Iterator<Item = FileId> {
+        self.tmp_file_ids.iter().map(|(file, _)| *file)
+    }
+
+    /// This returns `None` for minicore or other sysroot files.
+    fn virtual_file_id_to_line(&self, file_id: FileId) -> Option<usize> {
+        if self.is_sysroot_file(file_id) {
+            None
+        } else {
+            Some(self.virtual_file_id_to_line[file_id.index() as usize])
+        }
+    }
+
+    pub fn map_offset_down(&self, offset: TextSize) -> Option<(FileId, TextSize)> {
+        let inside_literal_range = self.literal.map_offset_down(offset)?;
+        let combined_offset = self.mapper.map_offset_down(inside_literal_range)?;
+        // There is usually a small number of files, so a linear search is smaller and faster.
+        let (_, &(file_id, file_line)) =
+            self.tmp_file_ids.iter().enumerate().find(|&(idx, &(_, file_line))| {
+                let file_start = self.line_offsets[file_line];
+                let file_end = self
+                    .tmp_file_ids
+                    .get(idx + 1)
+                    .map(|&(_, next_file_line)| self.line_offsets[next_file_line])
+                    .unwrap_or_else(|| self.combined_len);
+                TextRange::new(file_start, file_end).contains(combined_offset)
+            })?;
+        let file_line_offset = self.line_offsets[file_line];
+        let file_offset = combined_offset - file_line_offset;
+        Some((file_id, file_offset))
+    }
+
+    pub fn map_range_down(&self, range: TextRange) -> Option<(FileId, TextRange)> {
+        let (start_file_id, start_offset) = self.map_offset_down(range.start())?;
+        let (end_file_id, end_offset) = self.map_offset_down(range.end())?;
+        if start_file_id != end_file_id {
+            None
+        } else {
+            Some((start_file_id, TextRange::new(start_offset, end_offset)))
+        }
+    }
+
+    pub fn map_range_up(
+        &self,
+        virtual_file: FileId,
+        range: TextRange,
+    ) -> impl Iterator<Item = TextRange> {
+        // This could be `None` if the file is empty.
+        self.virtual_file_id_to_line(virtual_file)
+            .and_then(|line| self.line_offsets.get(line))
+            .into_iter()
+            .flat_map(move |&tmp_file_offset| {
+                // Resolve the offset relative to the virtual file to an offset relative to the combined indentation-trimmed file
+                let range = range + tmp_file_offset;
+                // Then resolve that to an offset relative to the real file.
+                self.mapper.map_range_up(range)
+            })
+            // And finally resolve the offset relative to the literal to relative to the file.
+            .filter_map(|range| self.literal.map_range_up(range))
+    }
+
+    pub fn map_offset_up(&self, virtual_file: FileId, offset: TextSize) -> Option<TextSize> {
+        self.map_range_up(virtual_file, TextRange::empty(offset)).next().map(|range| range.start())
+    }
+
+    pub fn is_sysroot_file(&self, file_id: FileId) -> bool {
+        self.sysroot_files.contains(&file_id)
+    }
+}
+
+pub trait UpmapFromRaFixture: Sized {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()>;
+}
+
+trait IsEmpty {
+    fn is_empty(&self) -> bool;
+}
+
+impl<T> IsEmpty for Vec<T> {
+    fn is_empty(&self) -> bool {
+        self.is_empty()
+    }
+}
+
+impl<T, const N: usize> IsEmpty for SmallVec<[T; N]> {
+    fn is_empty(&self) -> bool {
+        self.is_empty()
+    }
+}
+
+#[allow(clippy::disallowed_types)]
+impl<K, V, S> IsEmpty for std::collections::HashMap<K, V, S> {
+    fn is_empty(&self) -> bool {
+        self.is_empty()
+    }
+}
+
+fn upmap_collection<T, Collection>(
+    collection: Collection,
+    analysis: &RaFixtureAnalysis,
+    virtual_file_id: FileId,
+    real_file_id: FileId,
+) -> Result<Collection, ()>
+where
+    T: UpmapFromRaFixture,
+    Collection: IntoIterator<Item = T> + FromIterator<T> + IsEmpty,
+{
+    if collection.is_empty() {
+        // The collection was already empty, don't mark it as failing just because of that.
+        return Ok(collection);
+    }
+    let result = collection
+        .into_iter()
+        .filter_map(|item| item.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id).ok())
+        .collect::<Collection>();
+    if result.is_empty() {
+        // The collection was emptied by the upmapping - all items errored, therefore mark it as erroring as well.
+        Err(())
+    } else {
+        Ok(result)
+    }
+}
+
+impl<T: UpmapFromRaFixture> UpmapFromRaFixture for Option<T> {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        Ok(match self {
+            Some(it) => Some(it.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?),
+            None => None,
+        })
+    }
+}
+
+impl<T: UpmapFromRaFixture> UpmapFromRaFixture for Vec<T> {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        upmap_collection(self, analysis, virtual_file_id, real_file_id)
+    }
+}
+
+impl<T: UpmapFromRaFixture, const N: usize> UpmapFromRaFixture for SmallVec<[T; N]> {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        upmap_collection(self, analysis, virtual_file_id, real_file_id)
+    }
+}
+
+#[allow(clippy::disallowed_types)]
+impl<K: UpmapFromRaFixture + Hash + Eq, V: UpmapFromRaFixture, S: BuildHasher + Default>
+    UpmapFromRaFixture for std::collections::HashMap<K, V, S>
+{
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        upmap_collection(self, analysis, virtual_file_id, real_file_id)
+    }
+}
+
+// A map of `FileId`s is treated as associating the ranges in the values with the keys.
+#[allow(clippy::disallowed_types)]
+impl<V: UpmapFromRaFixture, S: BuildHasher + Default> UpmapFromRaFixture
+    for std::collections::HashMap<FileId, V, S>
+{
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        _virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        if self.is_empty() {
+            return Ok(self);
+        }
+        let result = self
+            .into_iter()
+            .filter_map(|(virtual_file_id, value)| {
+                Some((
+                    real_file_id,
+                    value.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id).ok()?,
+                ))
+            })
+            .collect::<std::collections::HashMap<_, _, _>>();
+        if result.is_empty() { Err(()) } else { Ok(result) }
+    }
+}
+
+macro_rules! impl_tuple {
+    () => {}; // Base case.
+    ( $first:ident, $( $rest:ident, )* ) => {
+        impl<
+            $first: UpmapFromRaFixture,
+            $( $rest: UpmapFromRaFixture, )*
+        > UpmapFromRaFixture for ( $first, $( $rest, )* ) {
+            fn upmap_from_ra_fixture(
+                self,
+                analysis: &RaFixtureAnalysis,
+                virtual_file_id: FileId,
+                real_file_id: FileId,
+            ) -> Result<Self, ()> {
+                #[allow(non_snake_case)]
+                let ( $first, $($rest,)* ) = self;
+                Ok((
+                    $first.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+                    $( $rest.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?, )*
+                ))
+            }
+        }
+
+        impl_tuple!( $($rest,)* );
+    };
+}
+impl_tuple!(A, B, C, D, E,);
+
+impl UpmapFromRaFixture for TextSize {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        _real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        analysis.map_offset_up(virtual_file_id, self).ok_or(())
+    }
+}
+
+impl UpmapFromRaFixture for TextRange {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        virtual_file_id: FileId,
+        _real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        analysis.map_range_up(virtual_file_id, self).next().ok_or(())
+    }
+}
+
+// Deliberately do not implement that, as it's easy to get things misbehave and be treated with the wrong FileId:
+//
+// impl UpmapFromRaFixture for FileId {
+//     fn upmap_from_ra_fixture(
+//         self,
+//         _analysis: &RaFixtureAnalysis,
+//         _virtual_file_id: FileId,
+//         real_file_id: FileId,
+//     ) -> Result<Self, ()> {
+//         Ok(real_file_id)
+//     }
+// }
+
+impl UpmapFromRaFixture for FilePositionWrapper<FileId> {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        _virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        Ok(FilePositionWrapper {
+            file_id: real_file_id,
+            offset: self.offset.upmap_from_ra_fixture(analysis, self.file_id, real_file_id)?,
+        })
+    }
+}
+
+impl UpmapFromRaFixture for FileRangeWrapper<FileId> {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &RaFixtureAnalysis,
+        _virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        Ok(FileRangeWrapper {
+            file_id: real_file_id,
+            range: self.range.upmap_from_ra_fixture(analysis, self.file_id, real_file_id)?,
+        })
+    }
+}
+
+#[macro_export]
+macro_rules! impl_empty_upmap_from_ra_fixture {
+    ( $( $ty:ty ),* $(,)? ) => {
+        $(
+            impl $crate::ra_fixture::UpmapFromRaFixture for $ty {
+                fn upmap_from_ra_fixture(
+                    self,
+                    _analysis: &$crate::ra_fixture::RaFixtureAnalysis,
+                    _virtual_file_id: $crate::ra_fixture::FileId,
+                    _real_file_id: $crate::ra_fixture::FileId,
+                ) -> Result<Self, ()> {
+                    Ok(self)
+                }
+            }
+        )*
+    };
+}
+
+impl_empty_upmap_from_ra_fixture!(
+    bool,
+    i8,
+    i16,
+    i32,
+    i64,
+    i128,
+    u8,
+    u16,
+    u32,
+    u64,
+    u128,
+    f32,
+    f64,
+    &str,
+    String,
+    SmolStr,
+    Documentation,
+    SymbolKind,
+    CfgExpr,
+    ReferenceCategory,
+);
diff --git a/crates/ide-db/src/range_mapper.rs b/crates/ide-db/src/range_mapper.rs
new file mode 100644
index 0000000..ef84888
--- /dev/null
+++ b/crates/ide-db/src/range_mapper.rs
@@ -0,0 +1,65 @@
+//! Maps between ranges in documents.
+
+use std::cmp::Ordering;
+
+use stdx::equal_range_by;
+use syntax::{TextRange, TextSize};
+
+#[derive(Default)]
+pub struct RangeMapper {
+    buf: String,
+    ranges: Vec<(TextRange, Option<TextRange>)>,
+}
+
+impl RangeMapper {
+    pub fn add(&mut self, text: &str, source_range: TextRange) {
+        let len = TextSize::of(text);
+        assert_eq!(len, source_range.len());
+        self.add_impl(text, Some(source_range.start()));
+    }
+
+    pub fn add_unmapped(&mut self, text: &str) {
+        self.add_impl(text, None);
+    }
+
+    fn add_impl(&mut self, text: &str, source: Option<TextSize>) {
+        let len = TextSize::of(text);
+        let target_range = TextRange::at(TextSize::of(&self.buf), len);
+        self.ranges.push((target_range, source.map(|it| TextRange::at(it, len))));
+        self.buf.push_str(text);
+    }
+
+    pub fn take_text(&mut self) -> String {
+        std::mem::take(&mut self.buf)
+    }
+
+    pub fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
+        equal_range_by(&self.ranges, |&(r, _)| {
+            if range.is_empty() && r.contains(range.start()) {
+                Ordering::Equal
+            } else {
+                TextRange::ordering(r, range)
+            }
+        })
+        .filter_map(move |i| {
+            let (target_range, source_range) = self.ranges[i];
+            let intersection = target_range.intersect(range).unwrap();
+            let source_range = source_range?;
+            Some(intersection - target_range.start() + source_range.start())
+        })
+    }
+
+    pub fn map_offset_down(&self, offset: TextSize) -> Option<TextSize> {
+        // Using a binary search here is a bit complicated because of the `None` entries.
+        // But the number of lines in fixtures is usually low.
+        let (target_range, source_range) =
+            self.ranges.iter().find_map(|&(target_range, source_range)| {
+                let source_range = source_range?;
+                if !source_range.contains(offset) {
+                    return None;
+                }
+                Some((target_range, source_range))
+            })?;
+        Some(offset - source_range.start() + target_range.start())
+    }
+}
diff --git a/crates/ide-db/src/source_change.rs b/crates/ide-db/src/source_change.rs
index 16c0d8d..57072bb 100644
--- a/crates/ide-db/src/source_change.rs
+++ b/crates/ide-db/src/source_change.rs
@@ -10,6 +10,7 @@
 use crate::{SnippetCap, assists::Command, syntax_helpers::tree_diff::diff};
 use base_db::AnchoredPathBuf;
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 use nohash_hasher::IntMap;
 use rustc_hash::FxHashMap;
 use span::FileId;
@@ -20,7 +21,7 @@
 };
 
 /// An annotation ID associated with an indel, to describe changes.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, UpmapFromRaFixture)]
 pub struct ChangeAnnotationId(u32);
 
 impl fmt::Display for ChangeAnnotationId {
diff --git a/crates/ide-db/src/text_edit.rs b/crates/ide-db/src/text_edit.rs
index 6e9bd7b..d2a7371 100644
--- a/crates/ide-db/src/text_edit.rs
+++ b/crates/ide-db/src/text_edit.rs
@@ -5,6 +5,7 @@
 //! rust-analyzer.
 
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 pub use span::{TextRange, TextSize};
 use std::cmp::max;
 
@@ -13,14 +14,14 @@
 /// `InsertDelete` -- a single "atomic" change to text
 ///
 /// Must not overlap with other `InDel`s
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash, UpmapFromRaFixture)]
 pub struct Indel {
     pub insert: String,
     /// Refers to offsets in the original text
     pub delete: TextRange,
 }
 
-#[derive(Default, Debug, Clone)]
+#[derive(Default, Debug, Clone, UpmapFromRaFixture)]
 pub struct TextEdit {
     /// Invariant: disjoint and sorted by `delete`.
     indels: Vec<Indel>,
diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs
index 37af05e..3dc155e 100644
--- a/crates/ide-diagnostics/src/tests.rs
+++ b/crates/ide-diagnostics/src/tests.rs
@@ -311,7 +311,7 @@
     }
 
     fn check(minicore: MiniCore) {
-        let source = minicore.source_code();
+        let source = minicore.source_code(MiniCore::RAW_SOURCE);
         let mut config = DiagnosticsConfig::test_sample();
         // This should be ignored since we conditionally remove code which creates single item use with braces
         config.disabled.insert("unused_braces".to_owned());
@@ -321,7 +321,7 @@
     }
 
     // Checks that there is no diagnostic in minicore for each flag.
-    for flag in MiniCore::available_flags() {
+    for flag in MiniCore::available_flags(MiniCore::RAW_SOURCE) {
         if flag == "clone" {
             // Clone without copy has `moved-out-of-ref`, so ignoring.
             // FIXME: Maybe we should merge copy and clone in a single flag?
@@ -332,5 +332,5 @@
     }
     // And one time for all flags, to check codes which are behind multiple flags + prevent name collisions
     eprintln!("Checking all minicore flags");
-    check(MiniCore::from_flags(MiniCore::available_flags()))
+    check(MiniCore::from_flags(MiniCore::available_flags(MiniCore::RAW_SOURCE)))
 }
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index 06d2776..08ffd39 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -42,6 +42,7 @@
 # ide should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
 hir.workspace = true
+macros.workspace = true
 
 [target.'cfg(not(any(target_arch = "wasm32", target_os = "emscripten")))'.dependencies]
 toolchain.workspace = true
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs
index dec1889..36c4404 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -1,6 +1,6 @@
 use hir::{HasSource, InFile, InRealFile, Semantics};
 use ide_db::{
-    FileId, FilePosition, FileRange, FxIndexSet, RootDatabase, defs::Definition,
+    FileId, FilePosition, FileRange, FxIndexSet, MiniCore, RootDatabase, defs::Definition,
     helpers::visit_file_defs,
 };
 use itertools::Itertools;
@@ -11,7 +11,7 @@
     annotations::fn_references::find_all_methods,
     goto_implementation::goto_implementation,
     navigation_target,
-    references::find_all_refs,
+    references::{FindAllRefsConfig, find_all_refs},
     runnables::{Runnable, runnables},
 };
 
@@ -36,7 +36,7 @@
     HasReferences { pos: FilePosition, data: Option<Vec<FileRange>> },
 }
 
-pub struct AnnotationConfig {
+pub struct AnnotationConfig<'a> {
     pub binary_target: bool,
     pub annotate_runnables: bool,
     pub annotate_impls: bool,
@@ -44,6 +44,7 @@
     pub annotate_method_references: bool,
     pub annotate_enum_variant_references: bool,
     pub location: AnnotationLocation,
+    pub minicore: MiniCore<'a>,
 }
 
 pub enum AnnotationLocation {
@@ -53,7 +54,7 @@
 
 pub(crate) fn annotations(
     db: &RootDatabase,
-    config: &AnnotationConfig,
+    config: &AnnotationConfig<'_>,
     file_id: FileId,
 ) -> Vec<Annotation> {
     let mut annotations = FxIndexSet::default();
@@ -196,13 +197,22 @@
         .collect()
 }
 
-pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation {
+pub(crate) fn resolve_annotation(
+    db: &RootDatabase,
+    config: &AnnotationConfig<'_>,
+    mut annotation: Annotation,
+) -> Annotation {
     match annotation.kind {
         AnnotationKind::HasImpls { pos, ref mut data } => {
             *data = goto_implementation(db, pos).map(|range| range.info);
         }
         AnnotationKind::HasReferences { pos, ref mut data } => {
-            *data = find_all_refs(&Semantics::new(db), pos, None).map(|result| {
+            *data = find_all_refs(
+                &Semantics::new(db),
+                pos,
+                &FindAllRefsConfig { search_scope: None, minicore: config.minicore },
+            )
+            .map(|result| {
                 result
                     .into_iter()
                     .flat_map(|res| res.references)
@@ -228,12 +238,13 @@
 #[cfg(test)]
 mod tests {
     use expect_test::{Expect, expect};
+    use ide_db::MiniCore;
 
     use crate::{Annotation, AnnotationConfig, fixture};
 
     use super::AnnotationLocation;
 
-    const DEFAULT_CONFIG: AnnotationConfig = AnnotationConfig {
+    const DEFAULT_CONFIG: AnnotationConfig<'_> = AnnotationConfig {
         binary_target: true,
         annotate_runnables: true,
         annotate_impls: true,
@@ -241,12 +252,13 @@
         annotate_method_references: true,
         annotate_enum_variant_references: true,
         location: AnnotationLocation::AboveName,
+        minicore: MiniCore::default(),
     };
 
     fn check_with_config(
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
         expect: Expect,
-        config: &AnnotationConfig,
+        config: &AnnotationConfig<'_>,
     ) {
         let (analysis, file_id) = fixture::file(ra_fixture);
 
@@ -254,7 +266,7 @@
             .annotations(config, file_id)
             .unwrap()
             .into_iter()
-            .map(|annotation| analysis.resolve_annotation(annotation).unwrap())
+            .map(|annotation| analysis.resolve_annotation(&DEFAULT_CONFIG, annotation).unwrap())
             .collect();
 
         expect.assert_debug_eq(&annotations);
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index f42cead..aded911 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -4,14 +4,16 @@
 
 use hir::Semantics;
 use ide_db::{
-    FileRange, FxIndexMap, RootDatabase,
+    FileRange, FxIndexMap, MiniCore, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
     helpers::pick_best_token,
     search::FileReference,
 };
 use syntax::{AstNode, SyntaxKind::IDENT, ast};
 
-use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav, goto_definition};
+use crate::{
+    FilePosition, GotoDefinitionConfig, NavigationTarget, RangeInfo, TryToNav, goto_definition,
+};
 
 #[derive(Debug, Clone)]
 pub struct CallItem {
@@ -19,22 +21,28 @@
     pub ranges: Vec<FileRange>,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct CallHierarchyConfig {
+#[derive(Debug, Clone, Copy)]
+pub struct CallHierarchyConfig<'a> {
     /// Whether to exclude tests from the call hierarchy
     pub exclude_tests: bool,
+    pub minicore: MiniCore<'a>,
 }
 
 pub(crate) fn call_hierarchy(
     db: &RootDatabase,
     position: FilePosition,
+    config: &CallHierarchyConfig<'_>,
 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
-    goto_definition::goto_definition(db, position)
+    goto_definition::goto_definition(
+        db,
+        position,
+        &GotoDefinitionConfig { minicore: config.minicore },
+    )
 }
 
 pub(crate) fn incoming_calls(
     db: &RootDatabase,
-    CallHierarchyConfig { exclude_tests }: CallHierarchyConfig,
+    config: &CallHierarchyConfig<'_>,
     FilePosition { file_id, offset }: FilePosition,
 ) -> Option<Vec<CallItem>> {
     let sema = &Semantics::new(db);
@@ -71,7 +79,7 @@
             });
 
             if let Some((def, nav)) = def_nav {
-                if exclude_tests && def.is_test(db) {
+                if config.exclude_tests && def.is_test(db) {
                     continue;
                 }
 
@@ -89,7 +97,7 @@
 
 pub(crate) fn outgoing_calls(
     db: &RootDatabase,
-    CallHierarchyConfig { exclude_tests }: CallHierarchyConfig,
+    config: &CallHierarchyConfig<'_>,
     FilePosition { file_id, offset }: FilePosition,
 ) -> Option<Vec<CallItem>> {
     let sema = Semantics::new(db);
@@ -119,7 +127,7 @@
                     let callable = sema.type_of_expr(&expr)?.original.as_callable(db)?;
                     match callable.kind() {
                         hir::CallableKind::Function(it) => {
-                            if exclude_tests && it.is_test(db) {
+                            if config.exclude_tests && it.is_test(db) {
                                 return None;
                             }
                             it.try_to_nav(&sema)
@@ -132,7 +140,7 @@
                 }
                 ast::CallableExpr::MethodCall(expr) => {
                     let function = sema.resolve_method_call(&expr)?;
-                    if exclude_tests && function.is_test(db) {
+                    if config.exclude_tests && function.is_test(db) {
                         return None;
                     }
                     function
@@ -166,7 +174,7 @@
 #[cfg(test)]
 mod tests {
     use expect_test::{Expect, expect};
-    use ide_db::FilePosition;
+    use ide_db::{FilePosition, MiniCore};
     use itertools::Itertools;
 
     use crate::fixture;
@@ -189,21 +197,20 @@
             )
         }
 
+        let config = crate::CallHierarchyConfig { exclude_tests, minicore: MiniCore::default() };
         let (analysis, pos) = fixture::position(ra_fixture);
 
-        let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info;
+        let mut navs = analysis.call_hierarchy(pos, &config).unwrap().unwrap().info;
         assert_eq!(navs.len(), 1);
         let nav = navs.pop().unwrap();
         expected_nav.assert_eq(&nav.debug_render());
 
-        let config = crate::CallHierarchyConfig { exclude_tests };
-
         let item_pos =
             FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
-        let incoming_calls = analysis.incoming_calls(config, item_pos).unwrap().unwrap();
+        let incoming_calls = analysis.incoming_calls(&config, item_pos).unwrap().unwrap();
         expected_incoming.assert_eq(&incoming_calls.into_iter().map(debug_render).join("\n"));
 
-        let outgoing_calls = analysis.outgoing_calls(config, item_pos).unwrap().unwrap();
+        let outgoing_calls = analysis.outgoing_calls(&config, item_pos).unwrap().unwrap();
         expected_outgoing.assert_eq(&outgoing_calls.into_iter().map(debug_render).join("\n"));
     }
 
diff --git a/crates/ide/src/goto_declaration.rs b/crates/ide/src/goto_declaration.rs
index 686dbe2..375ce94 100644
--- a/crates/ide/src/goto_declaration.rs
+++ b/crates/ide/src/goto_declaration.rs
@@ -6,8 +6,8 @@
 use syntax::{AstNode, SyntaxKind::*, T, ast, match_ast};
 
 use crate::{
-    FilePosition, NavigationTarget, RangeInfo, goto_definition::goto_definition,
-    navigation_target::TryToNav,
+    FilePosition, GotoDefinitionConfig, NavigationTarget, RangeInfo,
+    goto_definition::goto_definition, navigation_target::TryToNav,
 };
 
 // Feature: Go to Declaration
@@ -21,6 +21,7 @@
 pub(crate) fn goto_declaration(
     db: &RootDatabase,
     position @ FilePosition { file_id, offset }: FilePosition,
+    config: &GotoDefinitionConfig<'_>,
 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
     let sema = Semantics::new(db);
     let file = sema.parse_guess_edition(file_id).syntax().clone();
@@ -69,20 +70,27 @@
         .flatten()
         .collect();
 
-    if info.is_empty() { goto_definition(db, position) } else { Some(RangeInfo::new(range, info)) }
+    if info.is_empty() {
+        goto_definition(db, position, config)
+    } else {
+        Some(RangeInfo::new(range, info))
+    }
 }
 
 #[cfg(test)]
 mod tests {
-    use ide_db::FileRange;
+    use ide_db::{FileRange, MiniCore};
     use itertools::Itertools;
 
-    use crate::fixture;
+    use crate::{GotoDefinitionConfig, fixture};
+
+    const TEST_CONFIG: GotoDefinitionConfig<'_> =
+        GotoDefinitionConfig { minicore: MiniCore::default() };
 
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
         let navs = analysis
-            .goto_declaration(position)
+            .goto_declaration(position, &TEST_CONFIG)
             .unwrap()
             .expect("no declaration or definition found")
             .info;
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 2dcb13d..e335989 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,5 +1,6 @@
 use std::{iter, mem::discriminant};
 
+use crate::Analysis;
 use crate::{
     FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
     doc_links::token_as_doc_comment,
@@ -8,6 +9,7 @@
 use hir::{
     AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym,
 };
+use ide_db::{MiniCore, ra_fixture::UpmapFromRaFixture};
 use ide_db::{
     RootDatabase, SymbolKind,
     base_db::{AnchoredPath, SourceDatabase},
@@ -25,6 +27,11 @@
     match_ast,
 };
 
+#[derive(Debug)]
+pub struct GotoDefinitionConfig<'a> {
+    pub minicore: MiniCore<'a>,
+}
+
 // Feature: Go to Definition
 //
 // Navigates to the definition of an identifier.
@@ -39,6 +46,7 @@
 pub(crate) fn goto_definition(
     db: &RootDatabase,
     FilePosition { file_id, offset }: FilePosition,
+    config: &GotoDefinitionConfig<'_>,
 ) -> Option<RangeInfo<Vec<NavigationTarget>>> {
     let sema = &Semantics::new(db);
     let file = sema.parse_guess_edition(file_id).syntax().clone();
@@ -83,52 +91,64 @@
         return Some(RangeInfo::new(original_token.text_range(), navs));
     }
 
-    let navs = sema
-        .descend_into_macros_no_opaque(original_token.clone(), false)
-        .into_iter()
-        .filter_map(|token| {
-            if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {
-                return Some(navs);
-            }
+    let tokens = sema.descend_into_macros_no_opaque(original_token.clone(), false);
+    let mut navs = Vec::new();
+    for token in tokens {
+        if let Some(n) = find_definition_for_known_blanket_dual_impls(sema, &token.value) {
+            navs.extend(n);
+            continue;
+        }
 
-            let parent = token.value.parent()?;
+        if let Some(token) = ast::String::cast(token.value.clone())
+            && let Some(original_token) = ast::String::cast(original_token.clone())
+            && let Some((analysis, fixture_analysis)) =
+                Analysis::from_ra_fixture(sema, original_token, &token, config.minicore)
+            && let Some((virtual_file_id, file_offset)) = fixture_analysis.map_offset_down(offset)
+        {
+            return hir::attach_db_allow_change(&analysis.db, || {
+                goto_definition(
+                    &analysis.db,
+                    FilePosition { file_id: virtual_file_id, offset: file_offset },
+                    config,
+                )
+            })
+            .and_then(|navs| {
+                navs.upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id).ok()
+            });
+        }
 
-            let token_file_id = token.file_id;
-            if let Some(token) = ast::String::cast(token.value.clone())
-                && let Some(x) =
-                    try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id)
-            {
-                return Some(vec![x]);
-            }
+        let parent = token.value.parent()?;
 
-            if ast::TokenTree::can_cast(parent.kind())
-                && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value)
-            {
-                return Some(vec![x]);
-            }
+        let token_file_id = token.file_id;
+        if let Some(token) = ast::String::cast(token.value.clone())
+            && let Some(x) =
+                try_lookup_include_path(sema, InFile::new(token_file_id, token), file_id)
+        {
+            navs.push(x);
+            continue;
+        }
 
-            Some(
-                IdentClass::classify_node(sema, &parent)?
-                    .definitions()
+        if ast::TokenTree::can_cast(parent.kind())
+            && let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value)
+        {
+            navs.push(x);
+            continue;
+        }
+
+        let Some(ident_class) = IdentClass::classify_node(sema, &parent) else { continue };
+        navs.extend(ident_class.definitions().into_iter().flat_map(|(def, _)| {
+            if let Definition::ExternCrateDecl(crate_def) = def {
+                return crate_def
+                    .resolved_crate(db)
+                    .map(|it| it.root_module().to_nav(sema.db))
                     .into_iter()
-                    .flat_map(|(def, _)| {
-                        if let Definition::ExternCrateDecl(crate_def) = def {
-                            return crate_def
-                                .resolved_crate(db)
-                                .map(|it| it.root_module().to_nav(sema.db))
-                                .into_iter()
-                                .flatten()
-                                .collect();
-                        }
-                        try_filter_trait_item_definition(sema, &def)
-                            .unwrap_or_else(|| def_to_nav(sema, def))
-                    })
-                    .collect(),
-            )
-        })
-        .flatten()
-        .unique()
-        .collect::<Vec<NavigationTarget>>();
+                    .flatten()
+                    .collect();
+            }
+            try_filter_trait_item_definition(sema, &def).unwrap_or_else(|| def_to_nav(sema, def))
+        }));
+    }
+    let navs = navs.into_iter().unique().collect();
 
     Some(RangeInfo::new(original_token.text_range(), navs))
 }
@@ -584,15 +604,22 @@
 
 #[cfg(test)]
 mod tests {
-    use crate::fixture;
-    use ide_db::FileRange;
+    use crate::{GotoDefinitionConfig, fixture};
+    use ide_db::{FileRange, MiniCore};
     use itertools::Itertools;
     use syntax::SmolStr;
 
+    const TEST_CONFIG: GotoDefinitionConfig<'_> =
+        GotoDefinitionConfig { minicore: MiniCore::default() };
+
     #[track_caller]
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
-        let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+        let navs = analysis
+            .goto_definition(position, &TEST_CONFIG)
+            .unwrap()
+            .expect("no definition found")
+            .info;
 
         let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
         let navs = navs
@@ -611,14 +638,22 @@
 
     fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position) = fixture::position(ra_fixture);
-        let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+        let navs = analysis
+            .goto_definition(position, &TEST_CONFIG)
+            .unwrap()
+            .expect("no definition found")
+            .info;
 
         assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
     }
 
     fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) {
         let (analysis, position, _) = fixture::annotations(ra_fixture);
-        let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+        let navs = analysis
+            .goto_definition(position, &TEST_CONFIG)
+            .unwrap()
+            .expect("no definition found")
+            .info;
         assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());
         let Some(target) = navs.into_iter().next() else {
             panic!("expected single navigation target but encountered none");
@@ -3961,4 +3996,23 @@
 "#,
         );
     }
+
+    #[test]
+    fn ra_fixture() {
+        check(
+            r##"
+fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
+
+fn foo() {
+    fixture(r#"
+fn foo() {}
+// ^^^
+fn bar() {
+    f$0oo();
+}
+    "#)
+}
+        "##,
+        );
+    }
 }
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index c4fb6d1..e1d18b0 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -11,29 +11,32 @@
     db::DefDatabase,
 };
 use ide_db::{
-    FileRange, FxIndexSet, Ranker, RootDatabase,
+    FileRange, FxIndexSet, MiniCore, Ranker, RootDatabase,
     defs::{Definition, IdentClass, NameRefClass, OperatorClass},
     famous_defs::FamousDefs,
     helpers::pick_best_token,
+    ra_fixture::UpmapFromRaFixture,
 };
 use itertools::{Itertools, multizip};
-use span::Edition;
+use macros::UpmapFromRaFixture;
+use span::{Edition, TextRange};
 use syntax::{
-    AstNode,
+    AstNode, AstToken,
     SyntaxKind::{self, *},
     SyntaxNode, T, ast,
 };
 
 use crate::{
-    FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
+    Analysis, FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
     doc_links::token_as_doc_comment,
     markdown_remove::remove_markdown,
     markup::Markup,
     navigation_target::UpmappingResult,
     runnables::{runnable_fn, runnable_mod},
 };
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct HoverConfig {
+
+#[derive(Clone, Debug)]
+pub struct HoverConfig<'a> {
     pub links_in_hover: bool,
     pub memory_layout: Option<MemoryLayoutHoverConfig>,
     pub documentation: bool,
@@ -44,6 +47,7 @@
     pub max_enum_variants_count: Option<usize>,
     pub max_subst_ty_len: SubstTyLen,
     pub show_drop_glue: bool,
+    pub minicore: MiniCore<'a>,
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -75,7 +79,7 @@
     PlainText,
 }
 
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq, UpmapFromRaFixture)]
 pub enum HoverAction {
     Runnable(Runnable),
     Implementation(FilePosition),
@@ -108,14 +112,14 @@
     }
 }
 
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+#[derive(Debug, Clone, Eq, PartialEq, Hash, UpmapFromRaFixture)]
 pub struct HoverGotoTypeData {
     pub mod_path: String,
     pub nav: NavigationTarget,
 }
 
 /// Contains the results when hovering over an item
-#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
+#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, UpmapFromRaFixture)]
 pub struct HoverResult {
     pub markup: Markup,
     pub actions: Vec<HoverAction>,
@@ -130,7 +134,7 @@
 pub(crate) fn hover(
     db: &RootDatabase,
     frange @ FileRange { file_id, range }: FileRange,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
 ) -> Option<RangeInfo<HoverResult>> {
     let sema = &hir::Semantics::new(db);
     let file = sema.parse_guess_edition(file_id).syntax().clone();
@@ -161,7 +165,7 @@
     sema: &Semantics<'_, RootDatabase>,
     FilePosition { file_id, offset }: FilePosition,
     file: SyntaxNode,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> Option<RangeInfo<HoverResult>> {
@@ -219,6 +223,21 @@
         return Some(RangeInfo::new(range, res));
     }
 
+    if let Some(literal) = ast::String::cast(original_token.clone())
+        && let Some((analysis, fixture_analysis)) =
+            Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)
+    {
+        let (virtual_file_id, virtual_offset) = fixture_analysis.map_offset_down(offset)?;
+        return analysis
+            .hover(
+                config,
+                FileRange { file_id: virtual_file_id, range: TextRange::empty(virtual_offset) },
+            )
+            .ok()??
+            .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id)
+            .ok();
+    }
+
     // prefer descending the same token kind in attribute expansions, in normal macros text
     // equivalency is more important
     let mut descended = sema.descend_into_macros(original_token.clone());
@@ -383,9 +402,9 @@
 
 fn hover_ranged(
     sema: &Semantics<'_, RootDatabase>,
-    FileRange { range, .. }: FileRange,
+    FileRange { file_id, range }: FileRange,
     file: SyntaxNode,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> Option<RangeInfo<HoverResult>> {
@@ -404,6 +423,20 @@
         {
             render::deref_expr(sema, config, prefix_expr, edition, display_target)
         }
+        Either::Left(ast::Expr::Literal(literal)) => {
+            if let Some(literal) = ast::String::cast(literal.token())
+                && let Some((analysis, fixture_analysis)) =
+                    Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)
+            {
+                let (virtual_file_id, virtual_range) = fixture_analysis.map_range_down(range)?;
+                return analysis
+                    .hover(config, FileRange { file_id: virtual_file_id, range: virtual_range })
+                    .ok()??
+                    .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id)
+                    .ok();
+            }
+            None
+        }
         _ => None,
     };
     let res =
@@ -426,7 +459,7 @@
     scope_node: &SyntaxNode,
     macro_arm: Option<u32>,
     render_extras: bool,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> HoverResult {
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index f29ccc9..a1eff3a 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -35,7 +35,7 @@
 
 pub(super) fn type_info_of(
     sema: &Semantics<'_, RootDatabase>,
-    _config: &HoverConfig,
+    _config: &HoverConfig<'_>,
     expr_or_pat: &Either<ast::Expr, ast::Pat>,
     edition: Edition,
     display_target: DisplayTarget,
@@ -49,7 +49,7 @@
 
 pub(super) fn closure_expr(
     sema: &Semantics<'_, RootDatabase>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     c: ast::ClosureExpr,
     edition: Edition,
     display_target: DisplayTarget,
@@ -60,7 +60,7 @@
 
 pub(super) fn try_expr(
     sema: &Semantics<'_, RootDatabase>,
-    _config: &HoverConfig,
+    _config: &HoverConfig<'_>,
     try_expr: &ast::TryExpr,
     edition: Edition,
     display_target: DisplayTarget,
@@ -155,7 +155,7 @@
 
 pub(super) fn deref_expr(
     sema: &Semantics<'_, RootDatabase>,
-    _config: &HoverConfig,
+    _config: &HoverConfig<'_>,
     deref_expr: &ast::PrefixExpr,
     edition: Edition,
     display_target: DisplayTarget,
@@ -219,7 +219,7 @@
 
 pub(super) fn underscore(
     sema: &Semantics<'_, RootDatabase>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     token: &SyntaxToken,
     edition: Edition,
     display_target: DisplayTarget,
@@ -263,7 +263,7 @@
 
 pub(super) fn keyword(
     sema: &Semantics<'_, RootDatabase>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     token: &SyntaxToken,
     edition: Edition,
     display_target: DisplayTarget,
@@ -290,7 +290,7 @@
 /// i.e. `let S {a, ..} = S {a: 1, b: 2}`
 pub(super) fn struct_rest_pat(
     sema: &Semantics<'_, RootDatabase>,
-    _config: &HoverConfig,
+    _config: &HoverConfig<'_>,
     pattern: &ast::RecordPat,
     edition: Edition,
     display_target: DisplayTarget,
@@ -371,7 +371,7 @@
     def: Definition,
     markup: &Markup,
     markup_range_map: Option<DocsRangeMap>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
 ) -> Markup {
     let markup = markup.as_str();
     let markup = if config.links_in_hover {
@@ -481,7 +481,7 @@
     macro_arm: Option<u32>,
     render_extras: bool,
     subst_types: Option<&Vec<(Symbol, Type<'_>)>>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     edition: Edition,
     display_target: DisplayTarget,
 ) -> (Markup, Option<DocsRangeMap>) {
@@ -979,7 +979,7 @@
 
 fn type_info(
     sema: &Semantics<'_, RootDatabase>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     ty: TypeInfo<'_>,
     edition: Edition,
     display_target: DisplayTarget,
@@ -1038,7 +1038,7 @@
 
 fn closure_ty(
     sema: &Semantics<'_, RootDatabase>,
-    config: &HoverConfig,
+    config: &HoverConfig<'_>,
     TypeInfo { original, adjusted }: &TypeInfo<'_>,
     edition: Edition,
     display_target: DisplayTarget,
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index df18006..91fb4d0 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -1,5 +1,5 @@
 use expect_test::{Expect, expect};
-use ide_db::{FileRange, base_db::SourceDatabase};
+use ide_db::{FileRange, MiniCore, base_db::SourceDatabase};
 use syntax::TextRange;
 
 use crate::{
@@ -8,7 +8,7 @@
 
 use hir::setup_tracing;
 
-const HOVER_BASE_CONFIG: HoverConfig = HoverConfig {
+const HOVER_BASE_CONFIG: HoverConfig<'_> = HoverConfig {
     links_in_hover: false,
     memory_layout: Some(MemoryLayoutHoverConfig {
         size: Some(MemoryLayoutHoverRenderKind::Both),
@@ -25,6 +25,7 @@
     max_enum_variants_count: Some(5),
     max_subst_ty_len: super::SubstTyLen::Unlimited,
     show_drop_glue: true,
+    minicore: MiniCore::default(),
 };
 
 fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index f7b09b4..21550d5 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -8,9 +8,12 @@
     ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
     HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
 };
-use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder};
+use ide_db::{
+    FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder,
+};
 use ide_db::{FxHashSet, text_edit::TextEdit};
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 use smallvec::{SmallVec, smallvec};
 use stdx::never;
 use syntax::{
@@ -37,6 +40,7 @@
 mod implied_dyn_trait;
 mod lifetime;
 mod param_name;
+mod ra_fixture;
 mod range_exclusive;
 
 // Feature: Inlay Hints
@@ -80,7 +84,7 @@
     db: &RootDatabase,
     file_id: FileId,
     range_limit: Option<TextRange>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
 ) -> Vec<InlayHint> {
     let _p = tracing::info_span!("inlay_hints").entered();
     let sema = Semantics::new(db);
@@ -132,7 +136,7 @@
     file_id: FileId,
     resolve_range: TextRange,
     hash: u64,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     hasher: impl Fn(&InlayHint) -> u64,
 ) -> Option<InlayHint> {
     let _p = tracing::info_span!("inlay_hints_resolve").entered();
@@ -208,7 +212,7 @@
     hints: &mut Vec<InlayHint>,
     ctx: &mut InlayHintCtx,
     famous_defs @ FamousDefs(sema, _krate): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     file_id: EditionedFileId,
     display_target: DisplayTarget,
     node: SyntaxNode,
@@ -239,6 +243,7 @@
                         closure_ret::hints(hints, famous_defs, config, display_target, it)
                     },
                     ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, it),
+                    ast::Expr::Literal(it) => ra_fixture::hints(hints, famous_defs.0, file_id, config, it),
                     _ => Some(()),
                 }
             },
@@ -294,8 +299,8 @@
     };
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct InlayHintsConfig {
+#[derive(Clone, Debug)]
+pub struct InlayHintsConfig<'a> {
     pub render_colons: bool,
     pub type_hints: bool,
     pub sized_bound: bool,
@@ -321,9 +326,10 @@
     pub max_length: Option<usize>,
     pub closing_brace_hints_min_lines: Option<usize>,
     pub fields_to_resolve: InlayFieldsToResolve,
+    pub minicore: MiniCore<'a>,
 }
 
-impl InlayHintsConfig {
+impl InlayHintsConfig<'_> {
     fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty<TextEdit> {
         if self.fields_to_resolve.resolve_text_edits {
             LazyProperty::Lazy
@@ -466,7 +472,7 @@
     After,
 }
 
-#[derive(Debug)]
+#[derive(Debug, UpmapFromRaFixture)]
 pub struct InlayHint {
     /// The text range this inlay hint applies to.
     pub range: TextRange,
@@ -485,9 +491,10 @@
 }
 
 /// A type signaling that a value is either computed, or is available for computation.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Default, UpmapFromRaFixture)]
 pub enum LazyProperty<T> {
     Computed(T),
+    #[default]
     Lazy,
 }
 
@@ -537,7 +544,7 @@
     Markdown(String),
 }
 
-#[derive(Default, Hash)]
+#[derive(Default, Hash, UpmapFromRaFixture)]
 pub struct InlayHintLabel {
     pub parts: SmallVec<[InlayHintLabelPart; 1]>,
 }
@@ -623,6 +630,7 @@
     }
 }
 
+#[derive(UpmapFromRaFixture)]
 pub struct InlayHintLabelPart {
     pub text: String,
     /// Source location represented by this label part. The client will use this to fetch the part's
@@ -724,7 +732,7 @@
 
 fn label_of_ty(
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     ty: &hir::Type<'_>,
     display_target: DisplayTarget,
 ) -> Option<InlayHintLabel> {
@@ -734,7 +742,7 @@
         mut max_length: Option<usize>,
         ty: &hir::Type<'_>,
         label_builder: &mut InlayHintLabelBuilder<'_>,
-        config: &InlayHintsConfig,
+        config: &InlayHintsConfig<'_>,
         display_target: DisplayTarget,
     ) -> Result<(), HirDisplayError> {
         hir::attach_db(sema.db, || {
@@ -829,7 +837,7 @@
 
 fn ty_to_text_edit(
     sema: &Semantics<'_, RootDatabase>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     node_for_hint: &SyntaxNode,
     ty: &hir::Type<'_>,
     offset_to_insert_ty: TextSize,
@@ -860,6 +868,7 @@
 
     use expect_test::Expect;
     use hir::ClosureStyle;
+    use ide_db::MiniCore;
     use itertools::Itertools;
     use test_utils::extract_annotations;
 
@@ -869,7 +878,7 @@
 
     use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve};
 
-    pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
+    pub(super) const DISABLED_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
         discriminant_hints: DiscriminantHints::Never,
         render_colons: false,
         type_hints: false,
@@ -899,8 +908,9 @@
         fields_to_resolve: InlayFieldsToResolve::empty(),
         implicit_drop_hints: false,
         range_exclusive_hints: false,
+        minicore: MiniCore::default(),
     };
-    pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
+    pub(super) const TEST_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig {
         type_hints: true,
         parameter_hints: true,
         chaining_hints: true,
@@ -917,7 +927,7 @@
 
     #[track_caller]
     pub(super) fn check_with_config(
-        config: InlayHintsConfig,
+        config: InlayHintsConfig<'_>,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
     ) {
         let (analysis, file_id) = fixture::file(ra_fixture);
@@ -936,7 +946,7 @@
 
     #[track_caller]
     pub(super) fn check_expect(
-        config: InlayHintsConfig,
+        config: InlayHintsConfig<'_>,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
         expect: Expect,
     ) {
@@ -951,7 +961,7 @@
     /// expect test.
     #[track_caller]
     pub(super) fn check_edit(
-        config: InlayHintsConfig,
+        config: InlayHintsConfig<'_>,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
         expect: Expect,
     ) {
@@ -974,7 +984,7 @@
 
     #[track_caller]
     pub(super) fn check_no_edit(
-        config: InlayHintsConfig,
+        config: InlayHintsConfig<'_>,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
     ) {
         let (analysis, file_id) = fixture::file(ra_fixture);
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index 7231a31..ebb0d57 100644
--- a/crates/ide/src/inlay_hints/adjustment.rs
+++ b/crates/ide/src/inlay_hints/adjustment.rs
@@ -23,7 +23,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: DisplayTarget,
     expr: &ast::Expr,
 ) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs
index 121b16b..de207c7 100644
--- a/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/crates/ide/src/inlay_hints/bind_pat.rs
@@ -20,7 +20,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: DisplayTarget,
     pat: &ast::IdentPat,
 ) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs
index 169ab92..e8d305a 100644
--- a/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/crates/ide/src/inlay_hints/binding_mode.rs
@@ -15,7 +15,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     pat: &ast::Pat,
 ) -> Option<()> {
     if !config.binding_mode_hints {
diff --git a/crates/ide/src/inlay_hints/bounds.rs b/crates/ide/src/inlay_hints/bounds.rs
index 4abd67b..c9fbdf3 100644
--- a/crates/ide/src/inlay_hints/bounds.rs
+++ b/crates/ide/src/inlay_hints/bounds.rs
@@ -13,7 +13,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     params: ast::GenericParamList,
 ) -> Option<()> {
     if !config.sized_bound {
diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs
index a8bb652..cf3149c 100644
--- a/crates/ide/src/inlay_hints/chaining.rs
+++ b/crates/ide/src/inlay_hints/chaining.rs
@@ -13,7 +13,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: DisplayTarget,
     expr: &ast::Expr,
 ) -> Option<()> {
@@ -93,7 +93,7 @@
 
     #[track_caller]
     pub(super) fn check_expect_clear_loc(
-        config: InlayHintsConfig,
+        config: InlayHintsConfig<'_>,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
         expect: Expect,
     ) {
diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs
index 9d246ed..ab3ce5b 100644
--- a/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/crates/ide/src/inlay_hints/closing_brace.rs
@@ -19,7 +19,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     sema: &Semantics<'_, RootDatabase>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: DisplayTarget,
     InRealFile { file_id, value: node }: InRealFile<SyntaxNode>,
 ) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/closure_captures.rs b/crates/ide/src/inlay_hints/closure_captures.rs
index 3186a56..f8d4ddc 100644
--- a/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/crates/ide/src/inlay_hints/closure_captures.rs
@@ -13,7 +13,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     closure: ast::ClosureExpr,
 ) -> Option<()> {
     if !config.closure_capture_hints {
diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs
index fef1cb8..7765dc4 100644
--- a/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/crates/ide/src/inlay_hints/closure_ret.rs
@@ -13,7 +13,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: DisplayTarget,
     closure: ast::ClosureExpr,
 ) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs
index a2a7028..5b92671 100644
--- a/crates/ide/src/inlay_hints/discriminant.rs
+++ b/crates/ide/src/inlay_hints/discriminant.rs
@@ -17,7 +17,7 @@
 pub(super) fn enum_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     enum_: ast::Enum,
 ) -> Option<()> {
     if let DiscriminantHints::Never = config.discriminant_hints {
@@ -41,7 +41,7 @@
 
 fn variant_hints(
     acc: &mut Vec<InlayHint>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     sema: &Semantics<'_, RootDatabase>,
     enum_: &ast::Enum,
     variant: &ast::Variant,
diff --git a/crates/ide/src/inlay_hints/extern_block.rs b/crates/ide/src/inlay_hints/extern_block.rs
index 491018a..8dd6c4d 100644
--- a/crates/ide/src/inlay_hints/extern_block.rs
+++ b/crates/ide/src/inlay_hints/extern_block.rs
@@ -7,7 +7,7 @@
 pub(super) fn extern_block_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     extern_block: ast::ExternBlock,
 ) -> Option<()> {
     if extern_block.unsafe_token().is_some() {
@@ -33,7 +33,7 @@
 pub(super) fn fn_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     fn_: &ast::Fn,
     extern_block: &ast::ExternBlock,
 ) -> Option<()> {
@@ -51,7 +51,7 @@
 pub(super) fn static_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     static_: &ast::Static,
     extern_block: &ast::ExternBlock,
 ) -> Option<()> {
@@ -67,7 +67,7 @@
 }
 
 fn item_hint(
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     extern_block: &ast::ExternBlock,
     token: SyntaxToken,
 ) -> InlayHint {
diff --git a/crates/ide/src/inlay_hints/generic_param.rs b/crates/ide/src/inlay_hints/generic_param.rs
index 1fddb6f..27d14f7 100644
--- a/crates/ide/src/inlay_hints/generic_param.rs
+++ b/crates/ide/src/inlay_hints/generic_param.rs
@@ -16,7 +16,7 @@
 pub(crate) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, krate): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     node: AnyHasGenericArgs,
 ) -> Option<()> {
     let GenericParameterHints { type_hints, lifetime_hints, const_hints } =
diff --git a/crates/ide/src/inlay_hints/implicit_drop.rs b/crates/ide/src/inlay_hints/implicit_drop.rs
index 1e272fe..951a672 100644
--- a/crates/ide/src/inlay_hints/implicit_drop.rs
+++ b/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -23,7 +23,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     display_target: hir::DisplayTarget,
     node: &ast::Fn,
 ) -> Option<()> {
@@ -147,7 +147,7 @@
         inlay_hints::tests::{DISABLED_CONFIG, check_with_config},
     };
 
-    const ONLY_DROP_CONFIG: InlayHintsConfig =
+    const ONLY_DROP_CONFIG: InlayHintsConfig<'_> =
         InlayHintsConfig { implicit_drop_hints: true, ..DISABLED_CONFIG };
 
     #[test]
diff --git a/crates/ide/src/inlay_hints/implicit_static.rs b/crates/ide/src/inlay_hints/implicit_static.rs
index bddce90..0492991 100644
--- a/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/crates/ide/src/inlay_hints/implicit_static.rs
@@ -15,7 +15,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(_sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     statik_or_const: Either<ast::Static, ast::Const>,
 ) -> Option<()> {
     if config.lifetime_elision_hints != LifetimeElisionHints::Always {
diff --git a/crates/ide/src/inlay_hints/implied_dyn_trait.rs b/crates/ide/src/inlay_hints/implied_dyn_trait.rs
index 0da1785..562eb1e 100644
--- a/crates/ide/src/inlay_hints/implied_dyn_trait.rs
+++ b/crates/ide/src/inlay_hints/implied_dyn_trait.rs
@@ -11,7 +11,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     path: Either<ast::PathType, ast::DynTraitType>,
 ) -> Option<()> {
     let parent = path.syntax().parent()?;
diff --git a/crates/ide/src/inlay_hints/lifetime.rs b/crates/ide/src/inlay_hints/lifetime.rs
index a89c53e..4982b60 100644
--- a/crates/ide/src/inlay_hints/lifetime.rs
+++ b/crates/ide/src/inlay_hints/lifetime.rs
@@ -21,7 +21,7 @@
     acc: &mut Vec<InlayHint>,
     ctx: &mut InlayHintCtx,
     fd: &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     func: ast::Fn,
 ) -> Option<()> {
     if config.lifetime_elision_hints == LifetimeElisionHints::Never {
@@ -70,7 +70,7 @@
     acc: &mut Vec<InlayHint>,
     ctx: &mut InlayHintCtx,
     fd: &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     func: ast::FnPtrType,
 ) -> Option<()> {
     if config.lifetime_elision_hints == LifetimeElisionHints::Never {
@@ -135,7 +135,7 @@
     acc: &mut Vec<InlayHint>,
     ctx: &mut InlayHintCtx,
     fd: &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     func: &ast::PathType,
 ) -> Option<()> {
     if config.lifetime_elision_hints == LifetimeElisionHints::Never {
@@ -196,7 +196,7 @@
     acc: &mut Vec<InlayHint>,
     ctx: &mut InlayHintCtx,
     FamousDefs(_, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     params: impl Iterator<Item = (Option<ast::Name>, ast::Type)>,
     generic_param_list: Option<ast::GenericParamList>,
     ret_type: Option<ast::RetType>,
diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs
index 7547077..3e555e8 100644
--- a/crates/ide/src/inlay_hints/param_name.rs
+++ b/crates/ide/src/inlay_hints/param_name.rs
@@ -18,7 +18,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, krate): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     file_id: EditionedFileId,
     expr: ast::Expr,
 ) -> Option<()> {
diff --git a/crates/ide/src/inlay_hints/ra_fixture.rs b/crates/ide/src/inlay_hints/ra_fixture.rs
new file mode 100644
index 0000000..bee1841
--- /dev/null
+++ b/crates/ide/src/inlay_hints/ra_fixture.rs
@@ -0,0 +1,32 @@
+//! Injected inlay hints for `#[rust_analyzer::rust_fixture]`.
+
+use hir::{EditionedFileId, Semantics};
+use ide_db::{RootDatabase, impl_empty_upmap_from_ra_fixture, ra_fixture::UpmapFromRaFixture};
+use syntax::{AstToken, ast};
+
+use crate::{Analysis, InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip};
+
+pub(super) fn hints(
+    acc: &mut Vec<InlayHint>,
+    sema: &Semantics<'_, RootDatabase>,
+    file_id: EditionedFileId,
+    config: &InlayHintsConfig<'_>,
+    literal: ast::Literal,
+) -> Option<()> {
+    let file_id = file_id.file_id(sema.db);
+    let literal = ast::String::cast(literal.token())?;
+    let (analysis, fixture_analysis) =
+        Analysis::from_ra_fixture(sema, literal.clone(), &literal, config.minicore)?;
+    for virtual_file_id in fixture_analysis.files() {
+        acc.extend(
+            analysis
+                .inlay_hints(config, virtual_file_id, None)
+                .ok()?
+                .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, file_id)
+                .ok()?,
+        );
+    }
+    Some(())
+}
+
+impl_empty_upmap_from_ra_fixture!(InlayHintPosition, InlayKind, InlayTooltip);
diff --git a/crates/ide/src/inlay_hints/range_exclusive.rs b/crates/ide/src/inlay_hints/range_exclusive.rs
index 47bd6d7..a446908 100644
--- a/crates/ide/src/inlay_hints/range_exclusive.rs
+++ b/crates/ide/src/inlay_hints/range_exclusive.rs
@@ -11,7 +11,7 @@
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(_sema, _): &FamousDefs<'_, '_>,
-    config: &InlayHintsConfig,
+    config: &InlayHintsConfig<'_>,
     range: impl ast::RangeItem,
 ) -> Option<()> {
     (config.range_exclusive_hints && range.end().is_some())
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index f7d21c9..8572528 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -62,7 +62,7 @@
 
 use cfg::CfgOptions;
 use fetch_crates::CrateInfo;
-use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, db::HirDatabase, sym};
+use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, sym};
 use ide_db::{
     FxHashMap, FxIndexSet, LineIndexDatabase,
     base_db::{
@@ -71,7 +71,9 @@
     },
     prime_caches, symbol_index,
 };
-use syntax::SourceFile;
+use ide_db::{MiniCore, ra_fixture::RaFixtureAnalysis};
+use macros::UpmapFromRaFixture;
+use syntax::{SourceFile, ast};
 use triomphe::Arc;
 use view_memory_layout::{RecursiveMemoryLayout, view_memory_layout};
 
@@ -83,6 +85,7 @@
     expand_macro::ExpandedMacro,
     file_structure::{FileStructureConfig, StructureNode, StructureNodeKind},
     folding_ranges::{Fold, FoldKind},
+    goto_definition::GotoDefinitionConfig,
     highlight_related::{HighlightRelatedConfig, HighlightedRange},
     hover::{
         HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult,
@@ -102,7 +105,7 @@
     },
     move_item::Direction,
     navigation_target::{NavigationTarget, TryToNav, UpmappingResult},
-    references::ReferenceSearchResult,
+    references::{FindAllRefsConfig, ReferenceSearchResult},
     rename::RenameError,
     runnables::{Runnable, RunnableKind, TestId, UpdateTest},
     signature_help::SignatureHelp,
@@ -144,7 +147,7 @@
 pub type Cancellable<T> = Result<T, Cancelled>;
 
 /// Info associated with a text range.
-#[derive(Debug)]
+#[derive(Debug, UpmapFromRaFixture)]
 pub struct RangeInfo<T> {
     pub range: TextRange,
     pub info: T,
@@ -274,6 +277,28 @@
         (host.analysis(), file_id)
     }
 
+    pub(crate) fn from_ra_fixture(
+        sema: &Semantics<'_, RootDatabase>,
+        literal: ast::String,
+        expanded: &ast::String,
+        minicore: MiniCore<'_>,
+    ) -> Option<(Analysis, RaFixtureAnalysis)> {
+        Self::from_ra_fixture_with_on_cursor(sema, literal, expanded, minicore, &mut |_| {})
+    }
+
+    /// Like [`Analysis::from_ra_fixture()`], but also calls `on_cursor` with the cursor position.
+    pub(crate) fn from_ra_fixture_with_on_cursor(
+        sema: &Semantics<'_, RootDatabase>,
+        literal: ast::String,
+        expanded: &ast::String,
+        minicore: MiniCore<'_>,
+        on_cursor: &mut dyn FnMut(TextRange),
+    ) -> Option<(Analysis, RaFixtureAnalysis)> {
+        let analysis =
+            RaFixtureAnalysis::analyze_ra_fixture(sema, literal, expanded, minicore, on_cursor)?;
+        Some((Analysis { db: analysis.db.clone() }, analysis))
+    }
+
     /// Debug info about the current state of the analysis.
     pub fn status(&self, file_id: Option<FileId>) -> Cancellable<String> {
         self.with_db(|db| status::status(db, file_id))
@@ -446,7 +471,7 @@
     /// Returns a list of the places in the file where type hints can be displayed.
     pub fn inlay_hints(
         &self,
-        config: &InlayHintsConfig,
+        config: &InlayHintsConfig<'_>,
         file_id: FileId,
         range: Option<TextRange>,
     ) -> Cancellable<Vec<InlayHint>> {
@@ -454,7 +479,7 @@
     }
     pub fn inlay_hints_resolve(
         &self,
-        config: &InlayHintsConfig,
+        config: &InlayHintsConfig<'_>,
         file_id: FileId,
         resolve_range: TextRange,
         hash: u64,
@@ -495,16 +520,18 @@
     pub fn goto_definition(
         &self,
         position: FilePosition,
+        config: &GotoDefinitionConfig<'_>,
     ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
-        self.with_db(|db| goto_definition::goto_definition(db, position))
+        self.with_db(|db| goto_definition::goto_definition(db, position, config))
     }
 
     /// Returns the declaration from the symbol at `position`.
     pub fn goto_declaration(
         &self,
         position: FilePosition,
+        config: &GotoDefinitionConfig<'_>,
     ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
-        self.with_db(|db| goto_declaration::goto_declaration(db, position))
+        self.with_db(|db| goto_declaration::goto_declaration(db, position, config))
     }
 
     /// Returns the impls from the symbol at `position`.
@@ -526,19 +553,16 @@
     pub fn find_all_refs(
         &self,
         position: FilePosition,
-        search_scope: Option<SearchScope>,
+        config: &FindAllRefsConfig<'_>,
     ) -> Cancellable<Option<Vec<ReferenceSearchResult>>> {
-        let search_scope = AssertUnwindSafe(search_scope);
-        self.with_db(|db| {
-            let _ = &search_scope;
-            references::find_all_refs(&Semantics::new(db), position, search_scope.0)
-        })
+        let config = AssertUnwindSafe(config);
+        self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, &config))
     }
 
     /// Returns a short text describing element at position.
     pub fn hover(
         &self,
-        config: &HoverConfig,
+        config: &HoverConfig<'_>,
         range: FileRange,
     ) -> Cancellable<Option<RangeInfo<HoverResult>>> {
         self.with_db(|db| hover::hover(db, range, config))
@@ -576,14 +600,15 @@
     pub fn call_hierarchy(
         &self,
         position: FilePosition,
+        config: &CallHierarchyConfig<'_>,
     ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
-        self.with_db(|db| call_hierarchy::call_hierarchy(db, position))
+        self.with_db(|db| call_hierarchy::call_hierarchy(db, position, config))
     }
 
     /// Computes incoming calls for the given file position.
     pub fn incoming_calls(
         &self,
-        config: CallHierarchyConfig,
+        config: &CallHierarchyConfig<'_>,
         position: FilePosition,
     ) -> Cancellable<Option<Vec<CallItem>>> {
         self.with_db(|db| call_hierarchy::incoming_calls(db, config, position))
@@ -592,7 +617,7 @@
     /// Computes outgoing calls for the given file position.
     pub fn outgoing_calls(
         &self,
-        config: CallHierarchyConfig,
+        config: &CallHierarchyConfig<'_>,
         position: FilePosition,
     ) -> Cancellable<Option<Vec<CallItem>>> {
         self.with_db(|db| call_hierarchy::outgoing_calls(db, config, position))
@@ -675,28 +700,22 @@
     /// Computes syntax highlighting for the given file
     pub fn highlight(
         &self,
-        highlight_config: HighlightConfig,
+        highlight_config: HighlightConfig<'_>,
         file_id: FileId,
     ) -> Cancellable<Vec<HlRange>> {
-        // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
-        // highlighting instead sets up the attach hook where neceesary for the trait solver
-        Cancelled::catch(|| {
-            syntax_highlighting::highlight(&self.db, highlight_config, file_id, None)
-        })
+        self.with_db(|db| syntax_highlighting::highlight(db, &highlight_config, file_id, None))
     }
 
     /// Computes syntax highlighting for the given file range.
     pub fn highlight_range(
         &self,
-        highlight_config: HighlightConfig,
+        highlight_config: HighlightConfig<'_>,
         frange: FileRange,
     ) -> Cancellable<Vec<HlRange>> {
-        // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
-        // highlighting instead sets up the attach hook where neceesary for the trait solver
-        Cancelled::catch(|| {
+        self.with_db(|db| {
             syntax_highlighting::highlight(
-                &self.db,
-                highlight_config,
+                db,
+                &highlight_config,
                 frange.file_id,
                 Some(frange.range),
             )
@@ -706,22 +725,18 @@
     /// Computes syntax highlighting for the given file.
     pub fn highlight_as_html_with_config(
         &self,
-        config: HighlightConfig,
+        config: HighlightConfig<'_>,
         file_id: FileId,
         rainbow: bool,
     ) -> Cancellable<String> {
-        // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
-        // highlighting instead sets up the attach hook where neceesary for the trait solver
-        Cancelled::catch(|| {
-            syntax_highlighting::highlight_as_html_with_config(&self.db, config, file_id, rainbow)
+        self.with_db(|db| {
+            syntax_highlighting::highlight_as_html_with_config(db, &config, file_id, rainbow)
         })
     }
 
     /// Computes syntax highlighting for the given file.
     pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable<String> {
-        // highlighting may construct a new database for "speculative" execution, so we can't currently attach the database
-        // highlighting instead sets up the attach hook where neceesary for the trait solver
-        Cancelled::catch(|| syntax_highlighting::highlight_as_html(&self.db, file_id, rainbow))
+        self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow))
     }
 
     /// Computes completions at the given position.
@@ -853,14 +868,18 @@
 
     pub fn annotations(
         &self,
-        config: &AnnotationConfig,
+        config: &AnnotationConfig<'_>,
         file_id: FileId,
     ) -> Cancellable<Vec<Annotation>> {
         self.with_db(|db| annotations::annotations(db, config, file_id))
     }
 
-    pub fn resolve_annotation(&self, annotation: Annotation) -> Cancellable<Annotation> {
-        self.with_db(|db| annotations::resolve_annotation(db, annotation))
+    pub fn resolve_annotation(
+        &self,
+        config: &AnnotationConfig<'_>,
+        annotation: Annotation,
+    ) -> Cancellable<Annotation> {
+        self.with_db(|db| annotations::resolve_annotation(db, config, annotation))
     }
 
     pub fn move_item(
@@ -899,12 +918,8 @@
     where
         F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe,
     {
-        hir::attach_db(&self.db, || {
-            // the trait solver code may invoke `as_view<HirDatabase>` outside of queries,
-            // so technically we might run into a panic in salsa if the downcaster has not yet been registered.
-            HirDatabase::zalsa_register_downcaster(&self.db);
-            Cancelled::catch(|| f(&self.db))
-        })
+        // We use `attach_db_allow_change()` and not `attach_db()` because fixture injection can change the database.
+        hir::attach_db_allow_change(&self.db, || Cancelled::catch(|| f(&self.db)))
     }
 }
 
diff --git a/crates/ide/src/markup.rs b/crates/ide/src/markup.rs
index 750d125..3eb9986 100644
--- a/crates/ide/src/markup.rs
+++ b/crates/ide/src/markup.rs
@@ -5,6 +5,8 @@
 //! what is used by LSP, so let's keep it simple.
 use std::fmt;
 
+use ide_db::impl_empty_upmap_from_ra_fixture;
+
 #[derive(Clone, Default, Debug, Hash, PartialEq, Eq)]
 pub struct Markup {
     text: String,
@@ -39,3 +41,5 @@
         format!("```text\n{contents}\n```").into()
     }
 }
+
+impl_empty_upmap_from_ra_fixture!(Markup);
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index db12983..4058008 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -14,6 +14,7 @@
     defs::{Definition, find_std_module},
     documentation::{Documentation, HasDocs},
     famous_defs::FamousDefs,
+    ra_fixture::UpmapFromRaFixture,
 };
 use span::Edition;
 use stdx::never;
@@ -78,6 +79,44 @@
     }
 }
 
+impl UpmapFromRaFixture for NavigationTarget {
+    fn upmap_from_ra_fixture(
+        self,
+        analysis: &ide_db::ra_fixture::RaFixtureAnalysis,
+        _virtual_file_id: FileId,
+        real_file_id: FileId,
+    ) -> Result<Self, ()> {
+        let virtual_file_id = self.file_id;
+        Ok(NavigationTarget {
+            file_id: real_file_id,
+            full_range: self.full_range.upmap_from_ra_fixture(
+                analysis,
+                virtual_file_id,
+                real_file_id,
+            )?,
+            focus_range: self.focus_range.upmap_from_ra_fixture(
+                analysis,
+                virtual_file_id,
+                real_file_id,
+            )?,
+            name: self.name.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+            kind: self.kind.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+            container_name: self.container_name.upmap_from_ra_fixture(
+                analysis,
+                virtual_file_id,
+                real_file_id,
+            )?,
+            description: self.description.upmap_from_ra_fixture(
+                analysis,
+                virtual_file_id,
+                real_file_id,
+            )?,
+            docs: self.docs.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+            alias: self.alias.upmap_from_ra_fixture(analysis, virtual_file_id, real_file_id)?,
+        })
+    }
+}
+
 pub(crate) trait ToNav {
     fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget>;
 }
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 0189939..a53a192 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -19,14 +19,17 @@
 
 use hir::{PathResolution, Semantics};
 use ide_db::{
-    FileId, RootDatabase,
+    FileId, MiniCore, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
     helpers::pick_best_token,
+    ra_fixture::UpmapFromRaFixture,
     search::{ReferenceCategory, SearchScope, UsageSearchResult},
 };
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 use nohash_hasher::IntMap;
 use span::Edition;
+use syntax::AstToken;
 use syntax::{
     AstNode,
     SyntaxKind::*,
@@ -35,10 +38,12 @@
     match_ast,
 };
 
-use crate::{FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related};
+use crate::{
+    Analysis, FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related,
+};
 
 /// Result of a reference search operation.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, UpmapFromRaFixture)]
 pub struct ReferenceSearchResult {
     /// Information about the declaration site of the searched item.
     /// For ADTs (structs/enums), this points to the type definition.
@@ -54,7 +59,7 @@
 }
 
 /// Information about the declaration site of a searched item.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, UpmapFromRaFixture)]
 pub struct Declaration {
     /// Navigation information to jump to the declaration
     pub nav: NavigationTarget,
@@ -82,6 +87,12 @@
 //
 // ![Find All References](https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif)
 
+#[derive(Debug)]
+pub struct FindAllRefsConfig<'a> {
+    pub search_scope: Option<SearchScope>,
+    pub minicore: MiniCore<'a>,
+}
+
 /// Find all references to the item at the given position.
 ///
 /// # Arguments
@@ -110,14 +121,14 @@
 pub(crate) fn find_all_refs(
     sema: &Semantics<'_, RootDatabase>,
     position: FilePosition,
-    search_scope: Option<SearchScope>,
+    config: &FindAllRefsConfig<'_>,
 ) -> Option<Vec<ReferenceSearchResult>> {
     let _p = tracing::info_span!("find_all_refs").entered();
     let syntax = sema.parse_guess_edition(position.file_id).syntax().clone();
     let make_searcher = |literal_search: bool| {
         move |def: Definition| {
             let mut usages =
-                def.usages(sema).set_scope(search_scope.as_ref()).include_self_refs().all();
+                def.usages(sema).set_scope(config.search_scope.as_ref()).include_self_refs().all();
             if literal_search {
                 retain_adt_literal_usages(&mut usages, def, sema);
             }
@@ -165,6 +176,20 @@
         return Some(vec![res]);
     }
 
+    if let Some(token) = syntax.token_at_offset(position.offset).left_biased()
+        && let Some(token) = ast::String::cast(token.clone())
+        && let Some((analysis, fixture_analysis)) =
+            Analysis::from_ra_fixture(sema, token.clone(), &token, config.minicore)
+        && let Some((virtual_file_id, file_offset)) =
+            fixture_analysis.map_offset_down(position.offset)
+    {
+        return analysis
+            .find_all_refs(FilePosition { file_id: virtual_file_id, offset: file_offset }, config)
+            .ok()??
+            .upmap_from_ra_fixture(&fixture_analysis, virtual_file_id, position.file_id)
+            .ok();
+    }
+
     match name_for_constructor_search(&syntax, position) {
         Some(name) => {
             let def = match NameClass::classify(sema, &name)? {
@@ -433,10 +458,10 @@
 mod tests {
     use expect_test::{Expect, expect};
     use hir::EditionedFileId;
-    use ide_db::{FileId, RootDatabase};
+    use ide_db::{FileId, MiniCore, RootDatabase};
     use stdx::format_to;
 
-    use crate::{SearchScope, fixture};
+    use crate::{SearchScope, fixture, references::FindAllRefsConfig};
 
     #[test]
     fn exclude_tests() {
@@ -1513,8 +1538,11 @@
         expect: Expect,
     ) {
         let (analysis, pos) = fixture::position(ra_fixture);
-        let refs =
-            analysis.find_all_refs(pos, search_scope.map(|it| it(&analysis.db))).unwrap().unwrap();
+        let config = FindAllRefsConfig {
+            search_scope: search_scope.map(|it| it(&analysis.db)),
+            minicore: MiniCore::default(),
+        };
+        let refs = analysis.find_all_refs(pos, &config).unwrap().unwrap();
 
         let mut actual = String::new();
         for mut refs in refs {
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index cc1bbfb..494701d 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -8,6 +8,7 @@
     sym,
 };
 use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
+use ide_db::impl_empty_upmap_from_ra_fixture;
 use ide_db::{
     FilePosition, FxHashMap, FxIndexMap, FxIndexSet, RootDatabase, SymbolKind,
     base_db::RootQueryDb,
@@ -17,6 +18,7 @@
     search::{FileReferenceNode, SearchScope},
 };
 use itertools::Itertools;
+use macros::UpmapFromRaFixture;
 use smallvec::SmallVec;
 use span::{Edition, TextSize};
 use stdx::format_to;
@@ -28,7 +30,7 @@
 
 use crate::{FileId, NavigationTarget, ToNav, TryToNav, references};
 
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Clone, Hash, PartialEq, Eq, UpmapFromRaFixture)]
 pub struct Runnable {
     pub use_name_in_title: bool,
     pub nav: NavigationTarget,
@@ -37,6 +39,8 @@
     pub update_test: UpdateTest,
 }
 
+impl_empty_upmap_from_ra_fixture!(RunnableKind, UpdateTest);
+
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub enum TestId {
     Name(SmolStr),
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 453d6f5..e261928 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -4,7 +4,7 @@
 use arrayvec::ArrayVec;
 use hir::{Crate, Module, Semantics, db::HirDatabase};
 use ide_db::{
-    FileId, FileRange, FxHashMap, FxHashSet, RootDatabase,
+    FileId, FileRange, FxHashMap, FxHashSet, MiniCore, RootDatabase,
     base_db::{RootQueryDb, SourceDatabase, VfsPath},
     defs::{Definition, IdentClass},
     documentation::Documentation,
@@ -184,6 +184,7 @@
                     closing_brace_hints_min_lines: Some(25),
                     fields_to_resolve: InlayFieldsToResolve::empty(),
                     range_exclusive_hints: false,
+                    minicore: MiniCore::default(),
                 },
                 file_id,
                 None,
@@ -215,6 +216,7 @@
             max_enum_variants_count: Some(5),
             max_subst_ty_len: SubstTyLen::Unlimited,
             show_drop_glue: true,
+            minicore: MiniCore::default(),
         };
         let tokens = tokens.filter(|token| {
             matches!(
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 0da9ee0..66895cb 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -1,7 +1,6 @@
 pub(crate) mod tags;
 
 mod highlights;
-mod injector;
 
 mod escape;
 mod format;
@@ -16,7 +15,7 @@
 
 use either::Either;
 use hir::{DefWithBody, EditionedFileId, InFile, InRealFile, MacroKind, Name, Semantics};
-use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind};
+use ide_db::{FxHashMap, FxHashSet, MiniCore, Ranker, RootDatabase, SymbolKind};
 use syntax::{
     AstNode, AstToken, NodeOrToken,
     SyntaxKind::*,
@@ -44,8 +43,8 @@
     pub binding_hash: Option<u64>,
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct HighlightConfig {
+#[derive(Copy, Clone, Debug)]
+pub struct HighlightConfig<'a> {
     /// Whether to highlight strings
     pub strings: bool,
     /// Whether to highlight comments
@@ -64,6 +63,7 @@
     pub macro_bang: bool,
     /// Whether to highlight unresolved things be their syntax
     pub syntactic_name_ref_highlighting: bool,
+    pub minicore: MiniCore<'a>,
 }
 
 // Feature: Semantic Syntax Highlighting
@@ -191,7 +191,7 @@
 // ![Semantic Syntax Highlighting](https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png)
 pub(crate) fn highlight(
     db: &RootDatabase,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     file_id: FileId,
     range_to_highlight: Option<TextRange>,
 ) -> Vec<HlRange> {
@@ -226,7 +226,7 @@
 fn traverse(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     InRealFile { file_id, value: root }: InRealFile<&SyntaxNode>,
     krate: Option<hir::Crate>,
     range_to_highlight: TextRange,
@@ -426,12 +426,9 @@
         let edition = descended_element.file_id.edition(sema.db);
         let (unsafe_ops, bindings_shadow_count) = match current_body {
             Some(current_body) => {
-                let (ops, bindings) = per_body_cache.entry(current_body).or_insert_with(|| {
-                    (
-                        hir::attach_db(sema.db, || sema.get_unsafe_ops(current_body)),
-                        Default::default(),
-                    )
-                });
+                let (ops, bindings) = per_body_cache
+                    .entry(current_body)
+                    .or_insert_with(|| (sema.get_unsafe_ops(current_body), Default::default()));
                 (&*ops, Some(bindings))
             }
             None => (&empty, None),
@@ -494,7 +491,7 @@
 fn string_injections(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     file_id: EditionedFileId,
     krate: Option<hir::Crate>,
     token: SyntaxToken,
@@ -591,7 +588,7 @@
     })
 }
 
-fn filter_by_config(highlight: &mut Highlight, config: HighlightConfig) -> bool {
+fn filter_by_config(highlight: &mut Highlight, config: &HighlightConfig<'_>) -> bool {
     match &mut highlight.tag {
         HlTag::StringLiteral if !config.strings => return false,
         HlTag::Comment if !config.comments => return false,
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 358ac9b..75e46b8 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -1,6 +1,7 @@
 //! Renders a bit of code as HTML.
 
 use hir::{EditionedFileId, Semantics};
+use ide_db::MiniCore;
 use oorandom::Rand32;
 use stdx::format_to;
 use syntax::AstNode;
@@ -12,7 +13,7 @@
 
 pub(crate) fn highlight_as_html_with_config(
     db: &RootDatabase,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     file_id: FileId,
     rainbow: bool,
 ) -> String {
@@ -60,7 +61,7 @@
 pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String {
     highlight_as_html_with_config(
         db,
-        HighlightConfig {
+        &HighlightConfig {
             strings: true,
             comments: true,
             punctuation: true,
@@ -70,6 +71,7 @@
             inject_doc_comment: true,
             macro_bang: true,
             syntactic_name_ref_highlighting: false,
+            minicore: MiniCore::default(),
         },
         file_id,
         rainbow,
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index efc7782..7955f5a 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -4,9 +4,9 @@
 
 use either::Either;
 use hir::{EditionedFileId, HirFileId, InFile, Semantics, sym};
+use ide_db::range_mapper::RangeMapper;
 use ide_db::{
-    SymbolKind, active_parameter::ActiveParameter, defs::Definition,
-    documentation::docs_with_rangemap, rust_doc::is_rust_fence,
+    SymbolKind, defs::Definition, documentation::docs_with_rangemap, rust_doc::is_rust_fence,
 };
 use syntax::{
     AstToken, NodeOrToken, SyntaxNode, TextRange, TextSize,
@@ -16,85 +16,56 @@
 use crate::{
     Analysis, HlMod, HlRange, HlTag, RootDatabase,
     doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def},
-    syntax_highlighting::{HighlightConfig, highlights::Highlights, injector::Injector},
+    syntax_highlighting::{HighlightConfig, highlights::Highlights},
 };
 
 pub(super) fn ra_fixture(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     literal: &ast::String,
     expanded: &ast::String,
 ) -> Option<()> {
-    let active_parameter =
-        hir::attach_db(sema.db, || ActiveParameter::at_token(sema, expanded.syntax().clone()))?;
-    let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| {
-        attrs.filter_map(|attr| attr.as_simple_path()).any(|path| {
-            path.segments()
-                .zip(["rust_analyzer", "rust_fixture"])
-                .all(|(seg, name)| seg.name_ref().map_or(false, |nr| nr.text() == name))
-        })
-    });
-    if !has_rust_fixture_attr {
-        return None;
-    }
-    let value = literal.value().ok()?;
+    let (analysis, fixture_analysis) = Analysis::from_ra_fixture_with_on_cursor(
+        sema,
+        literal.clone(),
+        expanded,
+        config.minicore,
+        &mut |range| {
+            hl.add(HlRange {
+                range,
+                highlight: HlTag::Keyword | HlMod::Injected,
+                binding_hash: None,
+            });
+        },
+    )?;
 
     if let Some(range) = literal.open_quote_text_range() {
         hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None })
     }
 
-    let mut inj = Injector::default();
-
-    let mut text = &*value;
-    let mut offset: TextSize = 0.into();
-
-    while !text.is_empty() {
-        let marker = "$0";
-        let idx = text.find(marker).unwrap_or(text.len());
-        let (chunk, next) = text.split_at(idx);
-        inj.add(chunk, TextRange::at(offset, TextSize::of(chunk)));
-
-        text = next;
-        offset += TextSize::of(chunk);
-
-        if let Some(next) = text.strip_prefix(marker) {
-            if let Some(range) = literal.map_range_up(TextRange::at(offset, TextSize::of(marker))) {
-                hl.add(HlRange {
-                    range,
-                    highlight: HlTag::Keyword | HlMod::Injected,
-                    binding_hash: None,
-                });
-            }
-
-            text = next;
-
-            let marker_len = TextSize::of(marker);
-            offset += marker_len;
-        }
-    }
-
-    let (analysis, tmp_file_id) = Analysis::from_single_file(inj.take_text());
-
-    for mut hl_range in analysis
-        .highlight(
-            HighlightConfig {
-                syntactic_name_ref_highlighting: false,
-                comments: true,
-                punctuation: true,
-                operator: true,
-                strings: true,
-                specialize_punctuation: config.specialize_punctuation,
-                specialize_operator: config.operator,
-                inject_doc_comment: config.inject_doc_comment,
-                macro_bang: config.macro_bang,
-            },
-            tmp_file_id,
-        )
-        .unwrap()
-    {
-        for range in inj.map_range_up(hl_range.range) {
-            if let Some(range) = literal.map_range_up(range) {
+    for tmp_file_id in fixture_analysis.files() {
+        for mut hl_range in analysis
+            .highlight(
+                HighlightConfig {
+                    syntactic_name_ref_highlighting: false,
+                    comments: true,
+                    punctuation: true,
+                    operator: true,
+                    strings: true,
+                    specialize_punctuation: config.specialize_punctuation,
+                    specialize_operator: config.operator,
+                    inject_doc_comment: config.inject_doc_comment,
+                    macro_bang: config.macro_bang,
+                    // What if there is a fixture inside a fixture? It's fixtures all the way down.
+                    // (In fact, we have a fixture inside a fixture in our test suite!)
+                    minicore: config.minicore,
+                },
+                tmp_file_id,
+            )
+            .unwrap()
+        {
+            for range in fixture_analysis.map_range_up(tmp_file_id, hl_range.range) {
                 hl_range.range = range;
                 hl_range.highlight |= HlMod::Injected;
                 hl.add(hl_range);
@@ -116,7 +87,7 @@
 pub(super) fn doc_comment(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
-    config: HighlightConfig,
+    config: &HighlightConfig<'_>,
     src_file_id: EditionedFileId,
     node: &SyntaxNode,
 ) {
@@ -128,39 +99,37 @@
 
     // Extract intra-doc links and emit highlights for them.
     if let Some((docs, doc_mapping)) = docs_with_rangemap(sema.db, &attributes) {
-        hir::attach_db(sema.db, || {
-            extract_definitions_from_docs(&docs)
-                .into_iter()
-                .filter_map(|(range, link, ns)| {
-                    doc_mapping
-                        .map(range)
-                        .filter(|(mapping, _)| mapping.file_id == src_file_id)
-                        .and_then(|(InFile { value: mapped_range, .. }, attr_id)| {
-                            Some(mapped_range).zip(resolve_doc_path_for_def(
-                                sema.db,
-                                def,
-                                &link,
-                                ns,
-                                attr_id.is_inner_attr(),
-                            ))
-                        })
-                })
-                .for_each(|(range, def)| {
-                    hl.add(HlRange {
-                        range,
-                        highlight: module_def_to_hl_tag(def)
-                            | HlMod::Documentation
-                            | HlMod::Injected
-                            | HlMod::IntraDocLink,
-                        binding_hash: None,
+        extract_definitions_from_docs(&docs)
+            .into_iter()
+            .filter_map(|(range, link, ns)| {
+                doc_mapping
+                    .map(range)
+                    .filter(|(mapping, _)| mapping.file_id == src_file_id)
+                    .and_then(|(InFile { value: mapped_range, .. }, attr_id)| {
+                        Some(mapped_range).zip(resolve_doc_path_for_def(
+                            sema.db,
+                            def,
+                            &link,
+                            ns,
+                            attr_id.is_inner_attr(),
+                        ))
                     })
+            })
+            .for_each(|(range, def)| {
+                hl.add(HlRange {
+                    range,
+                    highlight: module_def_to_hl_tag(def)
+                        | HlMod::Documentation
+                        | HlMod::Injected
+                        | HlMod::IntraDocLink,
+                    binding_hash: None,
                 })
-        });
+            })
     }
 
     // Extract doc-test sources from the docs and calculate highlighting for them.
 
-    let mut inj = Injector::default();
+    let mut inj = RangeMapper::default();
     inj.add_unmapped("fn doctest() {\n");
 
     let attrs_source_map = attributes.source_map(sema.db);
@@ -249,7 +218,7 @@
     if let Ok(ranges) = analysis.with_db(|db| {
         super::highlight(
             db,
-            HighlightConfig {
+            &HighlightConfig {
                 syntactic_name_ref_highlighting: true,
                 comments: true,
                 punctuation: true,
@@ -259,6 +228,7 @@
                 specialize_operator: config.operator,
                 inject_doc_comment: config.inject_doc_comment,
                 macro_bang: config.macro_bang,
+                minicore: config.minicore,
             },
             tmp_file_id,
             None,
diff --git a/crates/ide/src/syntax_highlighting/injector.rs b/crates/ide/src/syntax_highlighting/injector.rs
deleted file mode 100644
index c30f797..0000000
--- a/crates/ide/src/syntax_highlighting/injector.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-//! Extracts a subsequence of a text document, remembering the mapping of ranges
-//! between original and extracted texts.
-use std::ops::{self, Sub};
-
-use stdx::equal_range_by;
-use syntax::{TextRange, TextSize};
-
-#[derive(Default)]
-pub(super) struct Injector {
-    buf: String,
-    ranges: Vec<(TextRange, Option<Delta<TextSize>>)>,
-}
-
-impl Injector {
-    pub(super) fn add(&mut self, text: &str, source_range: TextRange) {
-        let len = TextSize::of(text);
-        assert_eq!(len, source_range.len());
-        self.add_impl(text, Some(source_range.start()));
-    }
-
-    pub(super) fn add_unmapped(&mut self, text: &str) {
-        self.add_impl(text, None);
-    }
-
-    fn add_impl(&mut self, text: &str, source: Option<TextSize>) {
-        let len = TextSize::of(text);
-        let target_range = TextRange::at(TextSize::of(&self.buf), len);
-        self.ranges.push((target_range, source.map(|it| Delta::new(target_range.start(), it))));
-        self.buf.push_str(text);
-    }
-
-    pub(super) fn take_text(&mut self) -> String {
-        std::mem::take(&mut self.buf)
-    }
-
-    pub(super) fn map_range_up(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
-        equal_range_by(&self.ranges, |&(r, _)| TextRange::ordering(r, range)).filter_map(move |i| {
-            let (target_range, delta) = self.ranges[i];
-            let intersection = target_range.intersect(range).unwrap();
-            Some(intersection + delta?)
-        })
-    }
-}
-
-#[derive(Clone, Copy)]
-enum Delta<T> {
-    Add(T),
-    Sub(T),
-}
-
-impl<T> Delta<T> {
-    fn new(from: T, to: T) -> Delta<T>
-    where
-        T: Ord + Sub<Output = T>,
-    {
-        if to >= from { Delta::Add(to - from) } else { Delta::Sub(from - to) }
-    }
-}
-
-impl ops::Add<Delta<TextSize>> for TextSize {
-    type Output = TextSize;
-
-    fn add(self, rhs: Delta<TextSize>) -> TextSize {
-        match rhs {
-            Delta::Add(it) => self + it,
-            Delta::Sub(it) => self - it,
-        }
-    }
-}
-
-impl ops::Add<Delta<TextSize>> for TextRange {
-    type Output = TextRange;
-
-    fn add(self, rhs: Delta<TextSize>) -> TextRange {
-        TextRange::at(self.start() + rhs, self.len())
-    }
-}
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 3b468ab..579c6ce 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -43,18 +43,19 @@
 <pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute">rust_analyzer</span><span class="operator attribute">::</span><span class="tool_module attribute">rust_fixture</span><span class="attribute_bracket attribute">]</span> <span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
-    <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span><span class="none injected">
-</span><span class="keyword injected">trait</span><span class="none injected"> </span><span class="trait declaration injected">Foo</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
-    </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function associated declaration injected static trait">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
-        </span><span class="unresolved_reference injected">println</span><span class="macro_bang injected">!</span><span class="parenthesis injected">(</span><span class="string_literal injected">"2 + 2 = {}"</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">4</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="none injected">
-    </span><span class="brace injected">}</span><span class="none injected">
+    <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
+@@- minicore: sized
+<span class="keyword injected">trait</span><span class="none injected"> </span><span class="trait declaration injected">Foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="trait default_library injected library">Sized</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>    <span class="keyword injected">fn</span><span class="none injected"> </span><span class="function associated declaration injected static trait">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>        <span class="unresolved_reference injected">println</span><span class="macro_bang injected">!</span><span class="parenthesis injected">(</span><span class="string_literal injected">"2 + 2 = {}"</span><span class="comma injected">,</span><span class="none injected"> </span><span class="numeric_literal injected">4</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="none injected">
+</span>    <span class="brace injected">}</span><span class="none injected">
 </span><span class="brace injected">}</span><span class="string_literal">"#</span>
     <span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r"</span><span class="none injected">
-</span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
-    </span><span class="function injected">foo</span><span class="parenthesis injected">(</span><span class="keyword injected">$0</span><span class="brace injected">{</span><span class="none injected">
-        </span><span class="numeric_literal injected">92</span><span class="none injected">
-    </span><span class="brace injected">}</span><span class="keyword injected">$0</span><span class="parenthesis injected">)</span><span class="none injected">
+    <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r"</span>
+<span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>    <span class="function injected">foo</span><span class="parenthesis injected">(</span><span class="keyword injected">$0</span><span class="brace injected">{</span><span class="none injected">
+</span>        <span class="numeric_literal injected">92</span><span class="none injected">
+</span>    <span class="brace injected">}</span><span class="keyword injected">$0</span><span class="parenthesis injected">)</span><span class="none injected">
 </span><span class="brace injected">}</span><span class="string_literal">"</span>
     <span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html
new file mode 100644
index 0000000..fc2d9a3
--- /dev/null
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html
@@ -0,0 +1,61 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.proc_macro         { color: #94BFF3; text-decoration: underline; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
+
+.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute">rust_analyzer</span><span class="operator attribute">::</span><span class="tool_module attribute">rust_fixture</span><span class="attribute_bracket attribute">]</span> <span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
+
+<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
+    <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
+@@- /main.rs crate:main deps:other_crate
+<span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">test</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>    <span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">x</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="module crate_root injected library">other_crate</span><span class="operator injected">::</span><span class="module injected library">foo</span><span class="operator injected">::</span><span class="struct injected library">S</span><span class="operator injected">::</span><span class="function associated injected library static">thing</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span><span class="none injected">
+</span>    <span class="variable injected">x</span><span class="semicolon injected">;</span><span class="none injected">
+</span><span class="brace injected">}</span><span class="none injected"> </span><span class="comment injected">//^ i128</span><span class="none injected">
+</span><span class="none injected">
+</span>@@- /lib.rs crate:other_crate
+<span class="keyword injected">pub</span><span class="none injected"> </span><span class="keyword injected">mod</span><span class="none injected"> </span><span class="module declaration injected public">foo</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>    <span class="keyword injected">pub</span><span class="none injected"> </span><span class="keyword injected">struct</span><span class="none injected"> </span><span class="struct declaration injected public">S</span><span class="semicolon injected">;</span><span class="none injected">
+</span>    <span class="keyword injected">impl</span><span class="none injected"> </span><span class="struct injected public">S</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected">
+</span>        <span class="keyword injected">pub</span><span class="none injected"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function associated declaration injected public static">thing</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">-&gt;</span><span class="none injected"> </span><span class="builtin_type injected">i128</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="numeric_literal injected">0</span><span class="none injected"> </span><span class="brace injected">}</span><span class="none injected">
+</span>    <span class="brace injected">}</span><span class="none injected">
+</span><span class="brace injected">}</span><span class="none injected">
+</span>   <span class="none injected"> </span><span class="string_literal">"#</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+<span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 8198701..4e84127 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -1,13 +1,13 @@
 use std::time::Instant;
 
 use expect_test::{ExpectFile, expect_file};
-use ide_db::SymbolKind;
+use ide_db::{MiniCore, SymbolKind};
 use span::Edition;
 use test_utils::{AssertLinear, bench, bench_fixture, skip_slow_tests};
 
 use crate::{FileRange, HighlightConfig, HlTag, TextRange, fixture};
 
-const HL_CONFIG: HighlightConfig = HighlightConfig {
+const HL_CONFIG: HighlightConfig<'_> = HighlightConfig {
     strings: true,
     comments: true,
     punctuation: true,
@@ -17,6 +17,7 @@
     inject_doc_comment: true,
     macro_bang: true,
     syntactic_name_ref_highlighting: false,
+    minicore: MiniCore::default(),
 };
 
 #[test]
@@ -1017,6 +1018,35 @@
 }
 
 #[test]
+fn test_injection_2() {
+    check_highlighting(
+        r##"
+fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {}
+
+fn main() {
+    fixture(r#"
+@@- /main.rs crate:main deps:other_crate
+fn test() {
+    let x = other_crate::foo::S::thing();
+    x;
+} //^ i128
+
+@@- /lib.rs crate:other_crate
+pub mod foo {
+    pub struct S;
+    impl S {
+        pub fn thing() -> i128 { 0 }
+    }
+}
+    "#);
+}
+"##,
+        expect_file!["./test_data/highlight_injection_2.html"],
+        false,
+    );
+}
+
+#[test]
 fn test_injection() {
     check_highlighting(
         r##"
@@ -1024,7 +1054,8 @@
 
 fn main() {
     fixture(r#"
-trait Foo {
+@@- minicore: sized
+trait Foo: Sized {
     fn foo() {
         println!("2 + 2 = {}", 4);
     }
@@ -1223,7 +1254,7 @@
 /// Note that the `snapshot` file is overwritten by the rendered HTML.
 fn check_highlighting_with_config(
     #[rust_analyzer::rust_fixture] ra_fixture: &str,
-    config: HighlightConfig,
+    config: HighlightConfig<'_>,
     expect: ExpectFile,
     rainbow: bool,
 ) {
diff --git a/crates/macros/src/lib.rs b/crates/macros/src/lib.rs
index 8bafcf4..3f90ecc 100644
--- a/crates/macros/src/lib.rs
+++ b/crates/macros/src/lib.rs
@@ -162,3 +162,42 @@
 
     ignored
 }
+
+decl_derive!(
+    [UpmapFromRaFixture] => upmap_from_ra_fixture
+);
+
+fn upmap_from_ra_fixture(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    if let syn::Data::Union(_) = s.ast().data {
+        panic!("cannot derive on union")
+    }
+
+    s.add_bounds(synstructure::AddBounds::Generics);
+    s.bind_with(|_| synstructure::BindStyle::Move);
+    let body = s.each_variant(|vi| {
+        let bindings = vi.bindings();
+        vi.construct(|_, index| {
+            let bind = &bindings[index];
+
+            quote! {
+                ::ide_db::ra_fixture::UpmapFromRaFixture::upmap_from_ra_fixture(
+                    #bind, __analysis, __virtual_file_id, __real_file_id,
+                )?
+            }
+        })
+    });
+
+    s.bound_impl(
+        quote!(::ide_db::ra_fixture::UpmapFromRaFixture),
+        quote! {
+            fn upmap_from_ra_fixture(
+                self,
+                __analysis: &::ide_db::ra_fixture::RaFixtureAnalysis,
+                __virtual_file_id: ::ide_db::ra_fixture::FileId,
+                __real_file_id: ::ide_db::ra_fixture::FileId,
+            ) -> Result<Self, ()> {
+                Ok(match self { #body })
+            }
+        },
+    )
+}
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 2a9ef98..717bd23 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -25,7 +25,7 @@
     InlayHintsConfig, LineCol, RootDatabase,
 };
 use ide_db::{
-    EditionedFileId, LineIndexDatabase, SnippetCap,
+    EditionedFileId, LineIndexDatabase, MiniCore, SnippetCap,
     base_db::{SourceDatabase, salsa::Database},
 };
 use itertools::Itertools;
@@ -1194,6 +1194,7 @@
                     closing_brace_hints_min_lines: Some(20),
                     fields_to_resolve: InlayFieldsToResolve::empty(),
                     range_exclusive_hints: true,
+                    minicore: MiniCore::default(),
                 },
                 analysis.editioned_file_id_to_vfs(file_id),
                 None,
@@ -1203,26 +1204,25 @@
         bar.finish_and_clear();
 
         let mut bar = create_bar();
+        let annotation_config = AnnotationConfig {
+            binary_target: true,
+            annotate_runnables: true,
+            annotate_impls: true,
+            annotate_references: false,
+            annotate_method_references: false,
+            annotate_enum_variant_references: false,
+            location: ide::AnnotationLocation::AboveName,
+            minicore: MiniCore::default(),
+        };
         for &file_id in file_ids {
             let msg = format!("annotations: {}", vfs.file_path(file_id.file_id(db)));
             bar.set_message(move || msg.clone());
             analysis
-                .annotations(
-                    &AnnotationConfig {
-                        binary_target: true,
-                        annotate_runnables: true,
-                        annotate_impls: true,
-                        annotate_references: false,
-                        annotate_method_references: false,
-                        annotate_enum_variant_references: false,
-                        location: ide::AnnotationLocation::AboveName,
-                    },
-                    analysis.editioned_file_id_to_vfs(file_id),
-                )
+                .annotations(&annotation_config, analysis.editioned_file_id_to_vfs(file_id))
                 .unwrap()
                 .into_iter()
                 .for_each(|annotation| {
-                    _ = analysis.resolve_annotation(annotation);
+                    _ = analysis.resolve_annotation(&annotation_config, annotation);
                 });
             bar.inc(1);
         }
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 96b6583..652c2e3 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -8,14 +8,14 @@
 use cfg::{CfgAtom, CfgDiff};
 use hir::Symbol;
 use ide::{
-    AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
-    CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, HighlightConfig,
-    HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig,
-    JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope,
-    SourceRootId,
+    AnnotationConfig, AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig,
+    CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, GotoDefinitionConfig,
+    HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
+    InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
+    Snippet, SnippetScope, SourceRootId,
 };
 use ide_db::{
-    SnippetCap,
+    MiniCore, SnippetCap,
     assists::ExprFillDefaultMode,
     imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
 };
@@ -1454,6 +1454,23 @@
     pub fn references(&self) -> bool {
         self.method_refs || self.refs_adt || self.refs_trait || self.enum_variant_refs
     }
+
+    pub fn into_annotation_config<'a>(
+        self,
+        binary_target: bool,
+        minicore: MiniCore<'a>,
+    ) -> AnnotationConfig<'a> {
+        AnnotationConfig {
+            binary_target,
+            annotate_runnables: self.runnable(),
+            annotate_impls: self.implementations,
+            annotate_references: self.refs_adt,
+            annotate_method_references: self.method_refs,
+            annotate_enum_variant_references: self.enum_variant_refs,
+            location: self.location.into(),
+            minicore,
+        }
+    }
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
@@ -1688,11 +1705,15 @@
         }
     }
 
-    pub fn call_hierarchy(&self) -> CallHierarchyConfig {
-        CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned() }
+    pub fn call_hierarchy<'a>(&self, minicore: MiniCore<'a>) -> CallHierarchyConfig<'a> {
+        CallHierarchyConfig { exclude_tests: self.references_excludeTests().to_owned(), minicore }
     }
 
-    pub fn completion(&self, source_root: Option<SourceRootId>) -> CompletionConfig<'_> {
+    pub fn completion<'a>(
+        &'a self,
+        source_root: Option<SourceRootId>,
+        minicore: MiniCore<'a>,
+    ) -> CompletionConfig<'a> {
         let client_capability_fields = self.completion_resolve_support_properties();
         CompletionConfig {
             enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(),
@@ -1746,6 +1767,7 @@
                 })
                 .collect(),
             exclude_traits: self.completion_excludeTraits(source_root),
+            minicore,
         }
     }
 
@@ -1820,7 +1842,7 @@
         }
     }
 
-    pub fn hover(&self) -> HoverConfig {
+    pub fn hover<'a>(&self, minicore: MiniCore<'a>) -> HoverConfig<'a> {
         let mem_kind = |kind| match kind {
             MemoryLayoutHoverRenderKindDef::Both => MemoryLayoutHoverRenderKind::Both,
             MemoryLayoutHoverRenderKindDef::Decimal => MemoryLayoutHoverRenderKind::Decimal,
@@ -1853,10 +1875,15 @@
                 None => ide::SubstTyLen::Unlimited,
             },
             show_drop_glue: *self.hover_dropGlue_enable(),
+            minicore,
         }
     }
 
-    pub fn inlay_hints(&self) -> InlayHintsConfig {
+    pub fn goto_definition<'a>(&self, minicore: MiniCore<'a>) -> GotoDefinitionConfig<'a> {
+        GotoDefinitionConfig { minicore }
+    }
+
+    pub fn inlay_hints<'a>(&self, minicore: MiniCore<'a>) -> InlayHintsConfig<'a> {
         let client_capability_fields = self.inlay_hint_resolve_support_properties();
 
         InlayHintsConfig {
@@ -1938,6 +1965,7 @@
             ),
             implicit_drop_hints: self.inlayHints_implicitDrops_enable().to_owned(),
             range_exclusive_hints: self.inlayHints_rangeExclusiveHints_enable().to_owned(),
+            minicore,
         }
     }
 
@@ -1975,7 +2003,7 @@
         self.semanticHighlighting_nonStandardTokens().to_owned()
     }
 
-    pub fn highlighting_config(&self) -> HighlightConfig {
+    pub fn highlighting_config<'a>(&self, minicore: MiniCore<'a>) -> HighlightConfig<'a> {
         HighlightConfig {
             strings: self.semanticHighlighting_strings_enable().to_owned(),
             comments: self.semanticHighlighting_comments_enable().to_owned(),
@@ -1990,6 +2018,7 @@
                 .to_owned(),
             inject_doc_comment: self.semanticHighlighting_doc_comment_inject_enable().to_owned(),
             syntactic_name_ref_highlighting: false,
+            minicore,
         }
     }
 
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index ce6644f..f557dd5 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -13,7 +13,10 @@
 use crossbeam_channel::{Receiver, Sender, unbounded};
 use hir::ChangeWithProcMacros;
 use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
-use ide_db::base_db::{Crate, ProcMacroPaths, SourceDatabase};
+use ide_db::{
+    MiniCore,
+    base_db::{Crate, ProcMacroPaths, SourceDatabase},
+};
 use itertools::Itertools;
 use load_cargo::SourceRootConfig;
 use lsp_types::{SemanticTokens, Url};
@@ -188,6 +191,14 @@
     /// This is marked true if we failed to load a crate root file at crate graph creation,
     /// which will usually end up causing a bunch of incorrect diagnostics on startup.
     pub(crate) incomplete_crate_graph: bool,
+
+    pub(crate) minicore: MiniCoreRustAnalyzerInternalOnly,
+}
+
+// FIXME: This should move to the VFS once the rewrite is done.
+#[derive(Debug, Clone, Default)]
+pub(crate) struct MiniCoreRustAnalyzerInternalOnly {
+    pub(crate) minicore_text: Option<String>,
 }
 
 /// An immutable snapshot of the world's state at a point in time.
@@ -204,6 +215,7 @@
     // FIXME: Can we derive this from somewhere else?
     pub(crate) proc_macros_loaded: bool,
     pub(crate) flycheck: Arc<[FlycheckHandle]>,
+    minicore: MiniCoreRustAnalyzerInternalOnly,
 }
 
 impl std::panic::UnwindSafe for GlobalStateSnapshot {}
@@ -304,6 +316,8 @@
 
             deferred_task_queue: task_queue,
             incomplete_crate_graph: false,
+
+            minicore: MiniCoreRustAnalyzerInternalOnly::default(),
         };
         // Apply any required database inputs from the config.
         this.update_configuration(config);
@@ -550,6 +564,7 @@
             workspaces: Arc::clone(&self.workspaces),
             analysis: self.analysis_host.analysis(),
             vfs: Arc::clone(&self.vfs),
+            minicore: self.minicore.clone(),
             check_fixes: Arc::clone(&self.diagnostics.check_fixes),
             mem_docs: self.mem_docs.clone(),
             semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache),
@@ -838,6 +853,14 @@
     pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
         self.vfs.read().0.exists(file_id)
     }
+
+    #[inline]
+    pub(crate) fn minicore(&self) -> MiniCore<'_> {
+        match &self.minicore.minicore_text {
+            Some(minicore) => MiniCore::new(minicore),
+            None => MiniCore::default(),
+        }
+    }
 }
 
 pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url {
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 6cb28ae..55d092f 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -7,8 +7,8 @@
 
 use base64::{Engine, prelude::BASE64_STANDARD};
 use ide::{
-    AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve,
-    FilePosition, FileRange, FileStructureConfig, HoverAction, HoverGotoTypeData,
+    AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve, FilePosition,
+    FileRange, FileStructureConfig, FindAllRefsConfig, HoverAction, HoverGotoTypeData,
     InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
     SingleResolve, SourceChange, TextEdit,
 };
@@ -811,7 +811,8 @@
     let _p = tracing::info_span!("handle_goto_definition").entered();
     let position =
         try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
-    let nav_info = match snap.analysis.goto_definition(position)? {
+    let config = snap.config.goto_definition(snap.minicore());
+    let nav_info = match snap.analysis.goto_definition(position, &config)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -829,7 +830,8 @@
         &snap,
         params.text_document_position_params.clone()
     )?);
-    let nav_info = match snap.analysis.goto_declaration(position)? {
+    let config = snap.config.goto_definition(snap.minicore());
+    let nav_info = match snap.analysis.goto_declaration(position, &config)? {
         None => return handle_goto_definition(snap, params),
         Some(it) => it,
     };
@@ -1106,7 +1108,7 @@
         context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
 
     let source_root = snap.analysis.source_root_id(position.file_id)?;
-    let completion_config = &snap.config.completion(Some(source_root));
+    let completion_config = &snap.config.completion(Some(source_root), snap.minicore());
     // FIXME: We should fix up the position when retrying the cancelled request instead
     position.offset = position.offset.min(line_index.index.len());
     let items = match snap.analysis.completions(
@@ -1160,7 +1162,8 @@
     };
     let source_root = snap.analysis.source_root_id(file_id)?;
 
-    let mut forced_resolve_completions_config = snap.config.completion(Some(source_root));
+    let mut forced_resolve_completions_config =
+        snap.config.completion(Some(source_root), snap.minicore());
     forced_resolve_completions_config.fields_to_resolve = CompletionFieldsToResolve::empty();
 
     let position = FilePosition { file_id, offset };
@@ -1274,7 +1277,7 @@
     };
     let file_range = try_default!(from_proto::file_range(&snap, &params.text_document, range)?);
 
-    let hover = snap.config.hover();
+    let hover = snap.config.hover(snap.minicore());
     let info = match snap.analysis.hover(&hover, file_range)? {
         None => return Ok(None),
         Some(info) => info,
@@ -1360,7 +1363,11 @@
     let exclude_imports = snap.config.find_all_refs_exclude_imports();
     let exclude_tests = snap.config.find_all_refs_exclude_tests();
 
-    let Some(refs) = snap.analysis.find_all_refs(position, None)? else {
+    let Some(refs) = snap.analysis.find_all_refs(
+        position,
+        &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+    )?
+    else {
         return Ok(None);
     };
 
@@ -1615,8 +1622,8 @@
     let target_spec = TargetSpec::for_file(&snap, file_id)?;
 
     let annotations = snap.analysis.annotations(
-        &AnnotationConfig {
-            binary_target: target_spec
+        &lens_config.into_annotation_config(
+            target_spec
                 .map(|spec| {
                     matches!(
                         spec.target_kind(),
@@ -1624,13 +1631,8 @@
                     )
                 })
                 .unwrap_or(false),
-            annotate_runnables: lens_config.runnable(),
-            annotate_impls: lens_config.implementations,
-            annotate_references: lens_config.refs_adt,
-            annotate_method_references: lens_config.method_refs,
-            annotate_enum_variant_references: lens_config.enum_variant_refs,
-            location: lens_config.location.into(),
-        },
+            snap.minicore(),
+        ),
         file_id,
     )?;
 
@@ -1653,7 +1655,8 @@
     let Some(annotation) = from_proto::annotation(&snap, code_lens.range, resolve)? else {
         return Ok(code_lens);
     };
-    let annotation = snap.analysis.resolve_annotation(annotation)?;
+    let config = snap.config.lens().into_annotation_config(false, snap.minicore());
+    let annotation = snap.analysis.resolve_annotation(&config, annotation)?;
 
     let mut acc = Vec::new();
     to_proto::code_lens(&mut acc, &snap, annotation)?;
@@ -1736,7 +1739,7 @@
         range.end().min(line_index.index.len()),
     );
 
-    let inlay_hints_config = snap.config.inlay_hints();
+    let inlay_hints_config = snap.config.inlay_hints(snap.minicore());
     Ok(Some(
         snap.analysis
             .inlay_hints(&inlay_hints_config, file_id, Some(range))?
@@ -1777,7 +1780,7 @@
     let line_index = snap.file_line_index(file_id)?;
     let range = from_proto::text_range(&line_index, resolve_data.resolve_range)?;
 
-    let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
+    let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints(snap.minicore());
     forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
     let resolve_hints = snap.analysis.inlay_hints_resolve(
         &forced_resolve_inlay_hints_config,
@@ -1816,7 +1819,8 @@
     let position =
         try_default!(from_proto::file_position(&snap, params.text_document_position_params)?);
 
-    let nav_info = match snap.analysis.call_hierarchy(position)? {
+    let config = snap.config.call_hierarchy(snap.minicore());
+    let nav_info = match snap.analysis.call_hierarchy(position, &config)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -1842,8 +1846,8 @@
     let frange = try_default!(from_proto::file_range(&snap, &doc, item.selection_range)?);
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 
-    let config = snap.config.call_hierarchy();
-    let call_items = match snap.analysis.incoming_calls(config, fpos)? {
+    let config = snap.config.call_hierarchy(snap.minicore());
+    let call_items = match snap.analysis.incoming_calls(&config, fpos)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -1881,8 +1885,8 @@
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
     let line_index = snap.file_line_index(fpos.file_id)?;
 
-    let config = snap.config.call_hierarchy();
-    let call_items = match snap.analysis.outgoing_calls(config, fpos)? {
+    let config = snap.config.call_hierarchy(snap.minicore());
+    let call_items = match snap.analysis.outgoing_calls(&config, fpos)? {
         None => return Ok(None),
         Some(it) => it,
     };
@@ -1916,7 +1920,7 @@
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config();
+    let mut highlight_config = snap.config.highlighting_config(snap.minicore());
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1946,7 +1950,7 @@
     let text = snap.analysis.file_text(file_id)?;
     let line_index = snap.file_line_index(file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config();
+    let mut highlight_config = snap.config.highlighting_config(snap.minicore());
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1988,7 +1992,7 @@
     let text = snap.analysis.file_text(frange.file_id)?;
     let line_index = snap.file_line_index(frange.file_id)?;
 
-    let mut highlight_config = snap.config.highlighting_config();
+    let mut highlight_config = snap.config.highlighting_config(snap.minicore());
     // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
     highlight_config.syntactic_name_ref_highlighting =
         snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -2156,7 +2160,13 @@
 ) -> Option<lsp_ext::CommandLinkGroup> {
     if snap.config.hover_actions().references
         && snap.config.client_commands().show_reference
-        && let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None)
+        && let Some(ref_search_res) = snap
+            .analysis
+            .find_all_refs(
+                *position,
+                &FindAllRefsConfig { search_scope: None, minicore: snap.minicore() },
+            )
+            .unwrap_or(None)
     {
         let uri = to_proto::url(snap, position.file_id);
         let line_index = snap.file_line_index(position.file_id).ok()?;
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 84b7888..38ee9cb 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -16,7 +16,7 @@
     FilePosition, TextSize,
 };
 use ide_db::{
-    SnippetCap,
+    MiniCore, SnippetCap,
     imports::insert_use::{ImportGranularity, InsertUseConfig},
 };
 use project_model::CargoConfig;
@@ -186,6 +186,7 @@
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
+            minicore: MiniCore::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -240,6 +241,7 @@
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
+            minicore: MiniCore::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -292,6 +294,7 @@
             exclude_traits: &[],
             enable_auto_await: true,
             enable_auto_iter: true,
+            minicore: MiniCore::default(),
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index d51ddb8..cd384ca 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -16,7 +16,9 @@
     SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
     UpdateTest,
 };
-use ide_db::{FxHasher, assists, rust_doc::format_docs, source_change::ChangeAnnotationId};
+use ide_db::{
+    FxHasher, MiniCore, assists, rust_doc::format_docs, source_change::ChangeAnnotationId,
+};
 use itertools::Itertools;
 use paths::{Utf8Component, Utf8Prefix};
 use semver::VersionReq;
@@ -270,7 +272,7 @@
         );
     }
 
-    if let Some(limit) = config.completion(None).limit {
+    if let Some(limit) = config.completion(None, MiniCore::default()).limit {
         res.sort_by(|item1, item2| item1.sort_text.cmp(&item2.sort_text));
         res.truncate(limit);
     }
@@ -400,16 +402,17 @@
 
     set_score(&mut lsp_item, max_relevance, item.relevance);
 
-    let imports =
-        if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() {
-            item.import_to_add
-                .clone()
-                .into_iter()
-                .map(|import_path| lsp_ext::CompletionImport { full_import_path: import_path })
-                .collect()
-        } else {
-            Vec::new()
-        };
+    let imports = if config.completion(None, MiniCore::default()).enable_imports_on_the_fly
+        && !item.import_to_add.is_empty()
+    {
+        item.import_to_add
+            .clone()
+            .into_iter()
+            .map(|import_path| lsp_ext::CompletionImport { full_import_path: import_path })
+            .collect()
+    } else {
+        Vec::new()
+    };
     let (ref_resolve_data, resolve_data) = if something_to_resolve || !imports.is_empty() {
         let ref_resolve_data = if ref_match.is_some() {
             let ref_resolve_data = lsp_ext::CompletionResolveData {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 3e80e8b..c0947b2 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -847,6 +847,13 @@
                 self.debounce_workspace_fetch();
                 let vfs = &mut self.vfs.write().0;
                 for (path, contents) in files {
+                    if matches!(path.name_and_extension(), Some(("minicore", Some("rs")))) {
+                        // Not a lot of bad can happen from mistakenly identifying `minicore`, so proceed with that.
+                        self.minicore.minicore_text = contents
+                            .as_ref()
+                            .and_then(|contents| String::from_utf8(contents.clone()).ok());
+                    }
+
                     let path = VfsPath::from(path);
                     // if the file is in mem docs, it's managed by the client via notifications
                     // so only set it if its not in there
diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index d9223e8..e1a9f3a 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -201,6 +201,10 @@
             None
         }
     }
+    fn map_offset_down(&self, offset: TextSize) -> Option<TextSize> {
+        let contents_range = self.text_range_between_quotes()?;
+        offset.checked_sub(contents_range.start())
+    }
 }
 
 impl IsString for ast::String {
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index a454979..aefe81f 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -24,7 +24,7 @@
 use span::{Edition, FileId, Span};
 use stdx::itertools::Itertools;
 use test_utils::{
-    CURSOR_MARKER, ESCAPED_CURSOR_MARKER, Fixture, FixtureWithProjectMeta, RangeOrOffset,
+    CURSOR_MARKER, ESCAPED_CURSOR_MARKER, Fixture, FixtureWithProjectMeta, MiniCore, RangeOrOffset,
     extract_range_or_offset,
 };
 use triomphe::Arc;
@@ -69,7 +69,12 @@
         proc_macros: Vec<(String, ProcMacro)>,
     ) -> Self {
         let mut db = Self::default();
-        let fixture = ChangeFixture::parse_with_proc_macros(&db, ra_fixture, proc_macros);
+        let fixture = ChangeFixture::parse_with_proc_macros(
+            &db,
+            ra_fixture,
+            MiniCore::RAW_SOURCE,
+            proc_macros,
+        );
         fixture.change.apply(&mut db);
         assert!(fixture.file_position.is_none());
         db
@@ -112,8 +117,10 @@
 
 pub struct ChangeFixture {
     pub file_position: Option<(EditionedFileId, RangeOrOffset)>,
+    pub file_lines: Vec<usize>,
     pub files: Vec<EditionedFileId>,
     pub change: ChangeWithProcMacros,
+    pub sysroot_files: Vec<FileId>,
 }
 
 const SOURCE_ROOT_PREFIX: &str = "/";
@@ -123,12 +130,13 @@
         db: &dyn salsa::Database,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
     ) -> ChangeFixture {
-        Self::parse_with_proc_macros(db, ra_fixture, Vec::new())
+        Self::parse_with_proc_macros(db, ra_fixture, MiniCore::RAW_SOURCE, Vec::new())
     }
 
     pub fn parse_with_proc_macros(
         db: &dyn salsa::Database,
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        minicore_raw: &str,
         mut proc_macro_defs: Vec<(String, ProcMacro)>,
     ) -> ChangeFixture {
         let FixtureWithProjectMeta {
@@ -149,6 +157,8 @@
         let mut source_change = FileChange::default();
 
         let mut files = Vec::new();
+        let mut sysroot_files = Vec::new();
+        let mut file_lines = Vec::new();
         let mut crate_graph = CrateGraphBuilder::default();
         let mut crates = FxIndexMap::default();
         let mut crate_deps = Vec::new();
@@ -173,6 +183,8 @@
         let proc_macro_cwd = Arc::new(AbsPathBuf::assert_utf8(std::env::current_dir().unwrap()));
 
         for entry in fixture {
+            file_lines.push(entry.line);
+
             let mut range_or_offset = None;
             let text = if entry.text.contains(CURSOR_MARKER) {
                 if entry.text.contains(ESCAPED_CURSOR_MARKER) {
@@ -259,7 +271,9 @@
             fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_owned()));
             roots.push(SourceRoot::new_library(fs));
 
-            source_change.change_file(core_file, Some(mini_core.source_code()));
+            sysroot_files.push(core_file);
+
+            source_change.change_file(core_file, Some(mini_core.source_code(minicore_raw)));
 
             let core_crate = crate_graph.add_crate_root(
                 core_file,
@@ -348,6 +362,8 @@
             );
             roots.push(SourceRoot::new_library(fs));
 
+            sysroot_files.push(proc_lib_file);
+
             source_change.change_file(proc_lib_file, Some(source));
 
             let all_crates = crate_graph.iter().collect::<Vec<_>>();
@@ -396,7 +412,7 @@
         change.source_change.set_roots(roots);
         change.source_change.set_crate_graph(crate_graph);
 
-        ChangeFixture { file_position, files, change }
+        ChangeFixture { file_position, file_lines, files, change, sysroot_files }
     }
 }
 
diff --git a/crates/test-utils/src/fixture.rs b/crates/test-utils/src/fixture.rs
index c024089..559894e 100644
--- a/crates/test-utils/src/fixture.rs
+++ b/crates/test-utils/src/fixture.rs
@@ -132,13 +132,17 @@
     pub library: bool,
     /// Actual file contents. All meta comments are stripped.
     pub text: String,
+    /// The line number in the original fixture of the beginning of this fixture.
+    pub line: usize,
 }
 
+#[derive(Debug)]
 pub struct MiniCore {
     activated_flags: Vec<String>,
     valid_flags: Vec<String>,
 }
 
+#[derive(Debug)]
 pub struct FixtureWithProjectMeta {
     pub fixture: Vec<Fixture>,
     pub mini_core: Option<MiniCore>,
@@ -184,40 +188,49 @@
         let mut mini_core = None;
         let mut res: Vec<Fixture> = Vec::new();
         let mut proc_macro_names = vec![];
+        let mut first_row = 0;
 
         if let Some(meta) = fixture.strip_prefix("//- toolchain:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             toolchain = Some(meta.trim().to_owned());
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- target_data_layout:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             meta.trim().clone_into(&mut target_data_layout);
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- target_arch:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             meta.trim().clone_into(&mut target_arch);
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- proc_macros:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             proc_macro_names = meta.split(',').map(|it| it.trim().to_owned()).collect();
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- minicore:") {
+            first_row += 1;
             let (meta, remain) = meta.split_once('\n').unwrap();
             mini_core = Some(MiniCore::parse(meta));
             fixture = remain;
         }
 
-        let default = if fixture.contains("//-") { None } else { Some("//- /main.rs") };
+        let default =
+            if fixture.contains("//- /") { None } else { Some((first_row - 1, "//- /main.rs")) };
 
-        for (ix, line) in default.into_iter().chain(fixture.split_inclusive('\n')).enumerate() {
+        for (ix, line) in
+            default.into_iter().chain((first_row..).zip(fixture.split_inclusive('\n')))
+        {
             if line.contains("//-") {
                 assert!(
                     line.starts_with("//-"),
@@ -228,7 +241,7 @@
             }
 
             if let Some(line) = line.strip_prefix("//-") {
-                let meta = Self::parse_meta_line(line);
+                let meta = Self::parse_meta_line(line, (ix + 1).try_into().unwrap());
                 res.push(meta);
             } else {
                 if matches!(line.strip_prefix("// "), Some(l) if l.trim().starts_with('/')) {
@@ -252,7 +265,7 @@
     }
 
     //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
-    fn parse_meta_line(meta: &str) -> Fixture {
+    fn parse_meta_line(meta: &str, line: usize) -> Fixture {
         let meta = meta.trim();
         let mut components = meta.split_ascii_whitespace();
 
@@ -317,6 +330,7 @@
         Fixture {
             path,
             text: String::new(),
+            line,
             krate,
             deps,
             extern_prelude,
@@ -330,7 +344,7 @@
 }
 
 impl MiniCore {
-    const RAW_SOURCE: &'static str = include_str!("./minicore.rs");
+    pub const RAW_SOURCE: &'static str = include_str!("./minicore.rs");
 
     fn has_flag(&self, flag: &str) -> bool {
         self.activated_flags.iter().any(|it| it == flag)
@@ -363,8 +377,8 @@
         res
     }
 
-    pub fn available_flags() -> impl Iterator<Item = &'static str> {
-        let lines = MiniCore::RAW_SOURCE.split_inclusive('\n');
+    pub fn available_flags(raw_source: &str) -> impl Iterator<Item = &str> {
+        let lines = raw_source.split_inclusive('\n');
         lines
             .map_while(|x| x.strip_prefix("//!"))
             .skip_while(|line| !line.contains("Available flags:"))
@@ -375,9 +389,9 @@
     /// Strips parts of minicore.rs which are flagged by inactive flags.
     ///
     /// This is probably over-engineered to support flags dependencies.
-    pub fn source_code(mut self) -> String {
+    pub fn source_code(mut self, raw_source: &str) -> String {
         let mut buf = String::new();
-        let mut lines = MiniCore::RAW_SOURCE.split_inclusive('\n');
+        let mut lines = raw_source.split_inclusive('\n');
 
         let mut implications = Vec::new();