Repository: rust-lang/rust-analyzer
Pull request #16861 (2024-03-17 11:04:00)

fix: Ignore some warnings if they originate from within macro expansions
These tend to be annoying noise as we can't handle `allow`s for them properly for the time being. 


Patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index dc0a6c2d91..ac536d0fdd 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -36,6 +36,7 @@ jobs:
           - os: ubuntu-20.04
             target: x86_64-unknown-linux-gnu
             code-target: linux-x64
+            container: ubuntu:18.04
           - os: ubuntu-20.04
             target: aarch64-unknown-linux-gnu
             code-target: linux-arm64
@@ -62,6 +63,14 @@ jobs:
         with:
           fetch-depth: ${{ env.FETCH_DEPTH }}
 
+      - name: Install toolchain dependencies
+        if: matrix.container == 'ubuntu:18.04'
+        shell: bash
+        run: |
+          apt-get update && apt-get install -y build-essential curl
+          curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --profile minimal --default-toolchain none -y
+          echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH
+
       - name: Install Rust toolchain
         run: |
           rustup update --no-self-update stable
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index b815c9b73e..d4c1db8b95 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -715,7 +715,7 @@ impl<'a> AssocItemCollector<'a> {
             }
             AssocItem::MacroCall(call) => {
                 let file_id = self.expander.current_file_id();
-                let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call];
+                let MacroCall { ast_id, expand_to, call_site, ref path } = item_tree[call];
                 let module = self.expander.module.local_id;
 
                 let resolver = |path| {
@@ -734,7 +734,7 @@ impl<'a> AssocItemCollector<'a> {
                 match macro_call_as_call_id(
                     self.db.upcast(),
                     &AstIdWithPath::new(file_id, ast_id, Clone::clone(path)),
-                    ctxt,
+                    call_site,
                     expand_to,
                     self.expander.module.krate(),
                     resolver,
@@ -745,7 +745,6 @@ impl<'a> AssocItemCollector<'a> {
                         self.collect_macro_items(res, &|| hir_expand::MacroCallKind::FnLike {
                             ast_id: InFile::new(file_id, ast_id),
                             expand_to: hir_expand::ExpandTo::Items,
-                            eager: None,
                         });
                     }
                     Ok(None) => (),
@@ -755,7 +754,6 @@ impl<'a> AssocItemCollector<'a> {
                             MacroCallKind::FnLike {
                                 ast_id: InFile::new(file_id, ast_id),
                                 expand_to,
-                                eager: None,
                             },
                             Clone::clone(path),
                         ));
diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs
index a7461b78af..5790e600f6 100644
--- a/crates/hir-def/src/data/adt.rs
+++ b/crates/hir-def/src/data/adt.rs
@@ -191,9 +191,9 @@ impl StructData {
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
-        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
+        let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
 
-        let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
+        let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
 
         let mut flags = StructFlags::NO_FLAGS;
         if attrs.by_key("rustc_has_incoherent_inherent_impls").exists() {
@@ -248,9 +248,9 @@ impl StructData {
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
-        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
+        let cfg_options = db.crate_graph()[loc.container.krate].cfg_options.clone();
 
-        let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
+        let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
         let mut flags = StructFlags::NO_FLAGS;
         if attrs.by_key("rustc_has_incoherent_inherent_impls").exists() {
             flags |= StructFlags::IS_RUSTC_HAS_INCOHERENT_INHERENT_IMPL;
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 30d52d87f1..544ed6bc34 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -309,9 +309,13 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
                 kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()),
                 local_inner: false,
                 allow_internal_unsafe: loc.allow_internal_unsafe,
+                span: db
+                    .span_map(loc.id.file_id())
+                    .span_for_range(db.ast_id_map(loc.id.file_id()).get(makro.ast_id).text_range()),
                 edition: loc.edition,
             }
         }
+
         MacroId::MacroRulesId(it) => {
             let loc: MacroRulesLoc = it.lookup(db);
 
@@ -324,6 +328,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
                 allow_internal_unsafe: loc
                     .flags
                     .contains(MacroRulesLocFlags::ALLOW_INTERNAL_UNSAFE),
+                span: db
+                    .span_map(loc.id.file_id())
+                    .span_for_range(db.ast_id_map(loc.id.file_id()).get(makro.ast_id).text_range()),
                 edition: loc.edition,
             }
         }
@@ -341,6 +348,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
                 ),
                 local_inner: false,
                 allow_internal_unsafe: false,
+                span: db
+                    .span_map(loc.id.file_id())
+                    .span_for_range(db.ast_id_map(loc.id.file_id()).get(makro.ast_id).text_range()),
                 edition: loc.edition,
             }
         }
diff --git a/crates/hir-def/src/item_tree.rs b/crates/hir-def/src/item_tree.rs
index 585e93ce21..bd3d377ec0 100644
--- a/crates/hir-def/src/item_tree.rs
+++ b/crates/hir-def/src/item_tree.rs
@@ -49,7 +49,7 @@ use intern::Interned;
 use la_arena::{Arena, Idx, IdxRange, RawIdx};
 use rustc_hash::FxHashMap;
 use smallvec::SmallVec;
-use span::{AstIdNode, FileAstId, SyntaxContextId};
+use span::{AstIdNode, FileAstId, Span};
 use stdx::never;
 use syntax::{ast, match_ast, SyntaxKind};
 use triomphe::Arc;
@@ -790,7 +790,8 @@ pub struct MacroCall {
     pub path: Interned<ModPath>,
     pub ast_id: FileAstId<ast::MacroCall>,
     pub expand_to: ExpandTo,
-    pub ctxt: SyntaxContextId,
+    // FIXME: We need to move this out. It invalidates the item tree when typing inside the macro call.
+    pub call_site: Span,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs
index f02163cbe4..bf3d54f4ca 100644
--- a/crates/hir-def/src/item_tree/lower.rs
+++ b/crates/hir-def/src/item_tree/lower.rs
@@ -560,32 +560,35 @@ impl<'a> Ctx<'a> {
 
     fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
         let span_map = self.span_map();
-        let path = m.path()?;
-        let range = path.syntax().text_range();
-        let path = Interned::new(ModPath::from_src(self.db.upcast(), path, &mut |range| {
+        let path = Interned::new(ModPath::from_src(self.db.upcast(), m.path()?, &mut |range| {
             span_map.span_for_range(range).ctx
         })?);
         let ast_id = self.source_ast_id_map.ast_id(m);
         let expand_to = hir_expand::ExpandTo::from_call_site(m);
-        let res = MacroCall { path, ast_id, expand_to, ctxt: span_map.span_for_range(range).ctx };
+        let res = MacroCall {
+            path,
+            ast_id,
+            expand_to,
+            call_site: span_map.span_for_range(m.syntax().text_range()),
+        };
         Some(id(self.data().macro_calls.alloc(res)))
     }
 
     fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<FileItemTreeId<MacroRules>> {
-        let name = m.name()?;
+        let name = m.name().map(|it| it.as_name())?;
         let ast_id = self.source_ast_id_map.ast_id(m);
 
-        let res = MacroRules { name: name.as_name(), ast_id };
+        let res = MacroRules { name, ast_id };
         Some(id(self.data().macro_rules.alloc(res)))
     }
 
     fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<FileItemTreeId<Macro2>> {
-        let name = m.name()?;
+        let name = m.name().map(|it| it.as_name())?;
 
         let ast_id = self.source_ast_id_map.ast_id(m);
         let visibility = self.lower_visibility(m);
 
-        let res = Macro2 { name: name.as_name(), ast_id, visibility };
+        let res = Macro2 { name, ast_id, visibility };
         Some(id(self.data().macro_defs.alloc(res)))
     }
 
diff --git a/crates/hir-def/src/item_tree/pretty.rs b/crates/hir-def/src/item_tree/pretty.rs
index 953bf6b85d..87c90a4c6a 100644
--- a/crates/hir-def/src/item_tree/pretty.rs
+++ b/crates/hir-def/src/item_tree/pretty.rs
@@ -487,12 +487,12 @@ impl Printer<'_> {
                 }
             }
             ModItem::MacroCall(it) => {
-                let MacroCall { path, ast_id, expand_to, ctxt } = &self.tree[it];
+                let MacroCall { path, ast_id, expand_to, call_site } = &self.tree[it];
                 let _ = writeln!(
                     self,
-                    "// AstId: {:?}, SyntaxContext: {}, ExpandTo: {:?}",
+                    "// AstId: {:?}, Span: {}, ExpandTo: {:?}",
                     ast_id.erase().into_raw(),
-                    ctxt,
+                    call_site,
                     expand_to
                 );
                 wln!(self, "{}!(...);", path.display(self.db.upcast()));
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 828842de7e..d63f2268aa 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -90,7 +90,7 @@ use hir_expand::{
 use item_tree::ExternBlock;
 use la_arena::Idx;
 use nameres::DefMap;
-use span::{AstIdNode, FileAstId, FileId, SyntaxContextId};
+use span::{AstIdNode, FileAstId, FileId, Span};
 use stdx::impl_from;
 use syntax::{ast, AstNode};
 
@@ -1342,22 +1342,21 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
         let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
         let span_map = db.span_map(self.file_id);
         let path = self.value.path().and_then(|path| {
-            let range = path.syntax().text_range();
-            let mod_path = path::ModPath::from_src(db, path, &mut |range| {
+            path::ModPath::from_src(db, path, &mut |range| {
                 span_map.as_ref().span_for_range(range).ctx
-            })?;
-            let call_site = span_map.span_for_range(range);
-            Some((call_site, mod_path))
+            })
         });
 
-        let Some((call_site, path)) = path else {
+        let Some(path) = path else {
             return Ok(ExpandResult::only_err(ExpandError::other("malformed macro invocation")));
         };
 
+        let call_site = span_map.span_for_range(self.value.syntax().text_range());
+
         macro_call_as_call_id_with_eager(
             db,
             &AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
-            call_site.ctx,
+            call_site,
             expands_to,
             krate,
             resolver,
@@ -1382,7 +1381,7 @@ impl<T: AstIdNode> AstIdWithPath<T> {
 fn macro_call_as_call_id(
     db: &dyn ExpandDatabase,
     call: &AstIdWithPath<ast::MacroCall>,
-    call_site: SyntaxContextId,
+    call_site: Span,
     expand_to: ExpandTo,
     krate: CrateId,
     resolver: impl Fn(path::ModPath) -> Option<MacroDefId> + Copy,
@@ -1394,7 +1393,7 @@ fn macro_call_as_call_id(
 fn macro_call_as_call_id_with_eager(
     db: &dyn ExpandDatabase,
     call: &AstIdWithPath<ast::MacroCall>,
-    call_site: SyntaxContextId,
+    call_site: Span,
     expand_to: ExpandTo,
     krate: CrateId,
     resolver: impl FnOnce(path::ModPath) -> Option<MacroDefId>,
@@ -1404,20 +1403,17 @@ fn macro_call_as_call_id_with_eager(
         resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
 
     let res = match def.kind {
-        MacroDefKind::BuiltInEager(..) => expand_eager_macro_input(
-            db,
-            krate,
-            &call.ast_id.to_node(db),
-            call.ast_id,
-            def,
-            call_site,
-            &|path| eager_resolver(path).filter(MacroDefId::is_fn_like),
-        ),
+        MacroDefKind::BuiltInEager(..) => {
+            let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db));
+            expand_eager_macro_input(db, krate, macro_call, def, call_site, &|path| {
+                eager_resolver(path).filter(MacroDefId::is_fn_like)
+            })
+        }
         _ if def.is_fn_like() => ExpandResult {
-            value: Some(def.make_call(
+            value: Some(def.as_lazy_macro(
                 db,
                 krate,
-                MacroCallKind::FnLike { ast_id: call.ast_id, expand_to, eager: None },
+                MacroCallKind::FnLike { ast_id: call.ast_id, expand_to },
                 call_site,
             )),
             err: None,
diff --git a/crates/hir-def/src/nameres/attr_resolution.rs b/crates/hir-def/src/nameres/attr_resolution.rs
index 662c80edf3..1cadae8c87 100644
--- a/crates/hir-def/src/nameres/attr_resolution.rs
+++ b/crates/hir-def/src/nameres/attr_resolution.rs
@@ -5,7 +5,7 @@ use hir_expand::{
     attrs::{Attr, AttrId, AttrInput},
     MacroCallId, MacroCallKind, MacroDefId,
 };
-use span::SyntaxContextId;
+use span::Span;
 use syntax::{ast, SmolStr};
 use triomphe::Arc;
 
@@ -109,14 +109,14 @@ pub(super) fn attr_macro_as_call_id(
     let arg = match macro_attr.input.as_deref() {
         Some(AttrInput::TokenTree(tt)) => {
             let mut tt = tt.as_ref().clone();
-            tt.delimiter.kind = tt::DelimiterKind::Invisible;
+            tt.delimiter = tt::Delimiter::invisible_spanned(macro_attr.span);
             Some(tt)
         }
 
         _ => None,
     };
 
-    def.make_call(
+    def.as_lazy_macro(
         db.upcast(),
         krate,
         MacroCallKind::Attr {
@@ -124,7 +124,7 @@ pub(super) fn attr_macro_as_call_id(
             attr_args: arg.map(Arc::new),
             invoc_attr_index: macro_attr.id,
         },
-        macro_attr.ctxt,
+        macro_attr.span,
     )
 }
 
@@ -133,14 +133,14 @@ pub(super) fn derive_macro_as_call_id(
     item_attr: &AstIdWithPath<ast::Adt>,
     derive_attr_index: AttrId,
     derive_pos: u32,
-    call_site: SyntaxContextId,
+    call_site: Span,
     krate: CrateId,
     resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
 ) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
     let (macro_id, def_id) = resolver(item_attr.path.clone())
         .filter(|(_, def_id)| def_id.is_derive())
         .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
-    let call_id = def_id.make_call(
+    let call_id = def_id.as_lazy_macro(
         db.upcast(),
         krate,
         MacroCallKind::Derive {
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 3d026447fb..f9fe6d3b90 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -230,13 +230,13 @@ enum MacroDirectiveKind {
     FnLike {
         ast_id: AstIdWithPath<ast::MacroCall>,
         expand_to: ExpandTo,
-        ctxt: SyntaxContextId,
+        call_site: Span,
     },
     Derive {
         ast_id: AstIdWithPath<ast::Adt>,
         derive_attr: AttrId,
         derive_pos: usize,
-        ctxt: SyntaxContextId,
+        call_site: Span,
     },
     Attr {
         ast_id: AstIdWithPath<ast::Item>,
@@ -1126,7 +1126,7 @@ impl DefCollector<'_> {
             let resolver_def_id = |path| resolver(path).map(|(_, it)| it);
 
             match &directive.kind {
-                MacroDirectiveKind::FnLike { ast_id, expand_to, ctxt: call_site } => {
+                MacroDirectiveKind::FnLike { ast_id, expand_to, call_site } => {
                     let call_id = macro_call_as_call_id(
                         self.db.upcast(),
                         ast_id,
@@ -1146,7 +1146,7 @@ impl DefCollector<'_> {
                         return Resolved::Yes;
                     }
                 }
-                MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, ctxt: call_site } => {
+                MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, call_site } => {
                     let id = derive_macro_as_call_id(
                         self.db,
                         ast_id,
@@ -1266,7 +1266,7 @@ impl DefCollector<'_> {
                                             ast_id,
                                             derive_attr: attr.id,
                                             derive_pos: idx,
-                                            ctxt: call_site.ctx,
+                                            call_site,
                                         },
                                         container: directive.container,
                                     });
@@ -1428,7 +1428,7 @@ impl DefCollector<'_> {
 
         for directive in &self.unresolved_macros {
             match &directive.kind {
-                MacroDirectiveKind::FnLike { ast_id, expand_to, ctxt: call_site } => {
+                MacroDirectiveKind::FnLike { ast_id, expand_to, call_site } => {
                     // FIXME: we shouldn't need to re-resolve the macro here just to get the unresolved error!
                     let macro_call_as_call_id = macro_call_as_call_id(
                         self.db.upcast(),
@@ -1451,16 +1451,12 @@ impl DefCollector<'_> {
                     if let Err(UnresolvedMacro { path }) = macro_call_as_call_id {
                         self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
                             directive.module_id,
-                            MacroCallKind::FnLike {
-                                ast_id: ast_id.ast_id,
-                                expand_to: *expand_to,
-                                eager: None,
-                            },
+                            MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: *expand_to },
                             path,
                         ));
                     }
                 }
-                MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, ctxt: _ } => {
+                MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos, call_site: _ } => {
                     self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
                         directive.module_id,
                         MacroCallKind::Derive {
@@ -2289,7 +2285,7 @@ impl ModCollector<'_, '_> {
 
     fn collect_macro_call(
         &mut self,
-        &MacroCall { ref path, ast_id, expand_to, ctxt }: &MacroCall,
+        &MacroCall { ref path, ast_id, expand_to, call_site }: &MacroCall,
         container: ItemContainerId,
     ) {
         let ast_id = AstIdWithPath::new(self.file_id(), ast_id, ModPath::clone(path));
@@ -2303,7 +2299,7 @@ impl ModCollector<'_, '_> {
         if let Ok(res) = macro_call_as_call_id_with_eager(
             db.upcast(),
             &ast_id,
-            ctxt,
+            call_site,
             expand_to,
             self.def_collector.def_map.krate,
             |path| {
@@ -2361,7 +2357,7 @@ impl ModCollector<'_, '_> {
         self.def_collector.unresolved_macros.push(MacroDirective {
             module_id: self.module_id,
             depth: self.macro_depth + 1,
-            kind: MacroDirectiveKind::FnLike { ast_id, expand_to, ctxt },
+            kind: MacroDirectiveKind::FnLike { ast_id, expand_to, call_site },
             container,
         });
     }
diff --git a/crates/hir-expand/src/attrs.rs b/crates/hir-expand/src/attrs.rs
index af3ecdcd5e..7793e99532 100644
--- a/crates/hir-expand/src/attrs.rs
+++ b/crates/hir-expand/src/attrs.rs
@@ -7,7 +7,7 @@ use either::Either;
 use intern::Interned;
 use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
 use smallvec::{smallvec, SmallVec};
-use span::{Span, SyntaxContextId};
+use span::Span;
 use syntax::{ast, match_ast, AstNode, AstToken, SmolStr, SyntaxNode};
 use triomphe::Arc;
 
@@ -53,7 +53,7 @@ impl RawAttrs {
                 id,
                 input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))),
                 path: Interned::new(ModPath::from(crate::name!(doc))),
-                ctxt: span_map.span_for_range(comment.syntax().text_range()).ctx,
+                span: span_map.span_for_range(comment.syntax().text_range()),
             }),
         });
         let entries: Arc<[Attr]> = Arc::from_iter(entries);
@@ -173,7 +173,7 @@ pub struct Attr {
     pub id: AttrId,
     pub path: Interned<ModPath>,
     pub input: Option<Interned<AttrInput>>,
-    pub ctxt: SyntaxContextId,
+    pub span: Span,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -201,12 +201,10 @@ impl Attr {
         span_map: SpanMapRef<'_>,
         id: AttrId,
     ) -> Option<Attr> {
-        let path = ast.path()?;
-        let range = path.syntax().text_range();
-        let path = Interned::new(ModPath::from_src(db, path, &mut |range| {
+        let path = Interned::new(ModPath::from_src(db, ast.path()?, &mut |range| {
             span_map.span_for_range(range).ctx
         })?);
-        let span = span_map.span_for_range(range);
+        let span = span_map.span_for_range(ast.syntax().text_range());
         let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
             let value = match lit.kind() {
                 ast::LiteralKind::String(string) => string.value()?.into(),
@@ -219,11 +217,11 @@ impl Attr {
         } else {
             None
         };
-        Some(Attr { id, path, input, ctxt: span.ctx })
+        Some(Attr { id, path, input, span })
     }
 
     fn from_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree], id: AttrId) -> Option<Attr> {
-        let ctxt = tt.first()?.first_span().ctx;
+        let span = tt.first()?.first_span();
         let path_end = tt
             .iter()
             .position(|tt| {
@@ -255,7 +253,7 @@ impl Attr {
             }
             _ => None,
         };
-        Some(Attr { id, path, input, ctxt })
+        Some(Attr { id, path, input, span })
     }
 
     pub fn path(&self) -> &ModPath {
diff --git a/crates/hir-expand/src/builtin_attr_macro.rs b/crates/hir-expand/src/builtin_attr_macro.rs
index 9ff29b484d..a0102f36af 100644
--- a/crates/hir-expand/src/builtin_attr_macro.rs
+++ b/crates/hir-expand/src/builtin_attr_macro.rs
@@ -11,7 +11,7 @@ macro_rules! register_builtin {
         }
 
         impl BuiltinAttrExpander {
-            pub fn expander(&self) -> fn (&dyn ExpandDatabase, MacroCallId, &tt::Subtree, Span) -> ExpandResult<tt::Subtree>  {
+            pub fn expander(&self) -> fn (&dyn ExpandDatabase, MacroCallId, &tt::Subtree) -> ExpandResult<tt::Subtree>  {
                 match *self {
                     $( BuiltinAttrExpander::$variant => $expand, )*
                 }
@@ -34,9 +34,8 @@ impl BuiltinAttrExpander {
         db: &dyn ExpandDatabase,
         id: MacroCallId,
         tt: &tt::Subtree,
-        span: Span,
     ) -> ExpandResult<tt::Subtree> {
-        self.expander()(db, id, tt, span)
+        self.expander()(db, id, tt)
     }
 
     pub fn is_derive(self) -> bool {
@@ -72,7 +71,6 @@ fn dummy_attr_expand(
     _db: &dyn ExpandDatabase,
     _id: MacroCallId,
     tt: &tt::Subtree,
-    _span: Span,
 ) -> ExpandResult<tt::Subtree> {
     ExpandResult::ok(tt.clone())
 }
@@ -102,7 +100,6 @@ fn derive_expand(
     db: &dyn ExpandDatabase,
     id: MacroCallId,
     tt: &tt::Subtree,
-    span: Span,
 ) -> ExpandResult<tt::Subtree> {
     let loc = db.lookup_intern_macro_call(id);
     let derives = match &loc.kind {
@@ -110,14 +107,17 @@ fn derive_expand(
             attr_args
         }
         _ => {
-            return ExpandResult::ok(tt::Subtree::empty(tt::DelimSpan { open: span, close: span }))
+            return ExpandResult::ok(tt::Subtree::empty(tt::DelimSpan {
+                open: loc.call_site,
+                close: loc.call_site,
+            }))
         }
     };
-    pseudo_derive_attr_expansion(tt, derives, span)
+    pseudo_derive_attr_expansion(tt, derives, loc.call_site)
 }
 
 pub fn pseudo_derive_attr_expansion(
-    _: &tt::Subtree,
+    tt: &tt::Subtree,
     args: &tt::Subtree,
     call_site: Span,
 ) -> ExpandResult<tt::Subtree> {
@@ -141,7 +141,7 @@ pub fn pseudo_derive_attr_expansion(
         token_trees.push(mk_leaf(']'));
     }
     ExpandResult::ok(tt::Subtree {
-        delimiter: args.delimiter,
+        delimiter: tt.delimiter,
         token_trees: token_trees.into_boxed_slice(),
     })
 }
diff --git a/crates/hir-expand/src/builtin_derive_macro.rs b/crates/hir-expand/src/builtin_derive_macro.rs
index 528038a9cc..66dec7d89e 100644
--- a/crates/hir-expand/src/builtin_derive_macro.rs
+++ b/crates/hir-expand/src/builtin_derive_macro.rs
@@ -50,8 +50,8 @@ impl BuiltinDeriveExpander {
         db: &dyn ExpandDatabase,
         id: MacroCallId,
         tt: &tt::Subtree,
-        span: Span,
     ) -> ExpandResult<tt::Subtree> {
+        let span = db.lookup_intern_macro_call(id).call_site;
         let span = span_with_def_site_ctxt(db, span, id);
         self.expander()(span, tt)
     }
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index 9fb6a0b234..0fd0c25dcc 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -19,14 +19,14 @@ use crate::{
 };
 
 macro_rules! register_builtin {
-    ( $LAZY:ident: $(($name:ident, $kind: ident) => $expand:ident),* , $EAGER:ident: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),*  ) => {
+    ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),*  ) => {
         #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-        pub enum $LAZY {
+        pub enum BuiltinFnLikeExpander {
             $($kind),*
         }
 
         #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-        pub enum $EAGER {
+        pub enum EagerExpander {
             $($e_kind),*
         }
 
@@ -62,8 +62,8 @@ impl BuiltinFnLikeExpander {
         db: &dyn ExpandDatabase,
         id: MacroCallId,
         tt: &tt::Subtree,
-        span: Span,
     ) -> ExpandResult<tt::Subtree> {
+        let span = db.lookup_intern_macro_call(id).call_site;
         let span = span_with_def_site_ctxt(db, span, id);
         self.expander()(db, id, tt, span)
     }
@@ -75,8 +75,8 @@ impl EagerExpander {
         db: &dyn ExpandDatabase,
         id: MacroCallId,
         tt: &tt::Subtree,
-        span: Span,
     ) -> ExpandResult<tt::Subtree> {
+        let span = db.lookup_intern_macro_call(id).call_site;
         let span = span_with_def_site_ctxt(db, span, id);
         self.expander()(db, id, tt, span)
     }
@@ -84,17 +84,6 @@ impl EagerExpander {
     pub fn is_include(&self) -> bool {
         matches!(self, EagerExpander::Include)
     }
-
-    pub fn is_include_like(&self) -> bool {
-        matches!(
-            self,
-            EagerExpander::Include | EagerExpander::IncludeStr | EagerExpander::IncludeBytes
-        )
-    }
-
-    pub fn is_env_or_option_env(&self) -> bool {
-        matches!(self, EagerExpander::Env | EagerExpander::OptionEnv)
-    }
 }
 
 pub fn find_builtin_macro(
@@ -104,7 +93,7 @@ pub fn find_builtin_macro(
 }
 
 register_builtin! {
-    BuiltinFnLikeExpander:
+    LAZY:
     (column, Column) => line_expand,
     (file, File) => file_expand,
     (line, Line) => line_expand,
@@ -125,7 +114,7 @@ register_builtin! {
     (format_args_nl, FormatArgsNl) => format_args_nl_expand,
     (quote, Quote) => quote_expand,
 
-    EagerExpander:
+    EAGER:
     (compile_error, CompileError) => compile_error_expand,
     (concat, Concat) => concat_expand,
     (concat_idents, ConcatIdents) => concat_idents_expand,
@@ -437,25 +426,22 @@ fn use_panic_2021(db: &dyn ExpandDatabase, span: Span) -> bool {
     }
 }
 
-fn unquote_str(lit: &tt::Literal) -> Option<(String, Span)> {
-    let span = lit.span;
+fn unquote_str(lit: &tt::Literal) -> Option<String> {
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::String::cast(lit)?;
-    token.value().map(|it| (it.into_owned(), span))
+    token.value().map(|it| it.into_owned())
 }
 
-fn unquote_char(lit: &tt::Literal) -> Option<(char, Span)> {
-    let span = lit.span;
+fn unquote_char(lit: &tt::Literal) -> Option<char> {
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::Char::cast(lit)?;
-    token.value().zip(Some(span))
+    token.value()
 }
 
-fn unquote_byte_string(lit: &tt::Literal) -> Option<(Vec<u8>, Span)> {
-    let span = lit.span;
+fn unquote_byte_string(lit: &tt::Literal) -> Option<Vec<u8>> {
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::ByteString::cast(lit)?;
-    token.value().map(|it| (it.into_owned(), span))
+    token.value().map(|it| it.into_owned())
 }
 
 fn compile_error_expand(
@@ -466,7 +452,7 @@ fn compile_error_expand(
 ) -> ExpandResult<tt::Subtree> {
     let err = match &*tt.token_trees {
         [tt::TokenTree::Leaf(tt::Leaf::Literal(it))] => match unquote_str(it) {
-            Some((unquoted, _)) => ExpandError::other(unquoted.into_boxed_str()),
+            Some(unquoted) => ExpandError::other(unquoted.into_boxed_str()),
             None => ExpandError::other("`compile_error!` argument must be a string"),
         },
         _ => ExpandError::other("`compile_error!` argument must be a string"),
@@ -479,16 +465,10 @@ fn concat_expand(
     _db: &dyn ExpandDatabase,
     _arg_id: MacroCallId,
     tt: &tt::Subtree,
-    _: Span,
+    span: Span,
 ) -> ExpandResult<tt::Subtree> {
     let mut err = None;
     let mut text = String::new();
-    let mut span: Option<Span> = None;
-    let mut record_span = |s: Span| match &mut span {
-        Some(span) if span.anchor == s.anchor => span.range = span.range.cover(s.range),
-        Some(_) => (),
-        None => span = Some(s),
-    };
     for (i, mut t) in tt.token_trees.iter().enumerate() {
         // FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses
         // to ensure the right parsing order, so skip the parentheses here. Ideally we'd
@@ -506,14 +486,11 @@ fn concat_expand(
                 // concat works with string and char literals, so remove any quotes.
                 // It also works with integer, float and boolean literals, so just use the rest
                 // as-is.
-                if let Some((c, span)) = unquote_char(it) {
+                if let Some(c) = unquote_char(it) {
                     text.push(c);
-                    record_span(span);
                 } else {
-                    let (component, span) =
-                        unquote_str(it).unwrap_or_else(|| (it.text.to_string(), it.span));
+                    let component = unquote_str(it).unwrap_or_else(|| it.text.to_string());
                     text.push_str(&component);
-                    record_span(span);
                 }
             }
             // handle boolean literals
@@ -521,7 +498,6 @@ fn concat_expand(
                 if i % 2 == 0 && (id.text == "true" || id.text == "false") =>
             {
                 text.push_str(id.text.as_str());
-                record_span(id.span);
             }
             tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
             _ => {
@@ -529,7 +505,6 @@ fn concat_expand(
             }
         }
     }
-    let span = span.unwrap_or(tt.delimiter.open);
     ExpandResult { value: quote!(span =>#text), err }
 }
 
@@ -537,25 +512,18 @@ fn concat_bytes_expand(
     _db: &dyn ExpandDatabase,
     _arg_id: MacroCallId,
     tt: &tt::Subtree,
-    call_site: Span,
+    span: Span,
 ) -> ExpandResult<tt::Subtree> {
     let mut bytes = Vec::new();
     let mut err = None;
-    let mut span: Option<Span> = None;
-    let mut record_span = |s: Span| match &mut span {
-        Some(span) if span.anchor == s.anchor => span.range = span.range.cover(s.range),
-        Some(_) => (),
-        None => span = Some(s),
-    };
     for (i, t) in tt.token_trees.iter().enumerate() {
         match t {
             tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
                 let token = ast::make::tokens::literal(&lit.to_string());
-                record_span(lit.span);
                 match token.kind() {
                     syntax::SyntaxKind::BYTE => bytes.push(token.text().to_owned()),
                     syntax::SyntaxKind::BYTE_STRING => {
-                        let components = unquote_byte_string(lit).map_or(vec![], |(it, _)| it);
+                        let components = unquote_byte_string(lit).unwrap_or_default();
                         components.into_iter().for_each(|it| bytes.push(it.to_string()));
                     }
                     _ => {
@@ -566,7 +534,7 @@ fn concat_bytes_expand(
             }
             tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
             tt::TokenTree::Subtree(tree) if tree.delimiter.kind == tt::DelimiterKind::Bracket => {
-                if let Err(e) = concat_bytes_expand_subtree(tree, &mut bytes, &mut record_span) {
+                if let Err(e) = concat_bytes_expand_subtree(tree, &mut bytes) {
                     err.get_or_insert(e);
                     break;
                 }
@@ -578,24 +546,17 @@ fn concat_bytes_expand(
         }
     }
     let value = tt::Subtree {
-        delimiter: tt::Delimiter {
-            open: call_site,
-            close: call_site,
-            kind: tt::DelimiterKind::Bracket,
-        },
+        delimiter: tt::Delimiter { open: span, close: span, kind: tt::DelimiterKind::Bracket },
         token_trees: {
             Itertools::intersperse_with(
                 bytes.into_iter().map(|it| {
-                    tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
-                        text: it.into(),
-                        span: span.unwrap_or(call_site),
-                    }))
+                    tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { text: it.into(), span }))
                 }),
                 || {
                     tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
                         char: ',',
                         spacing: tt::Spacing::Alone,
-                        span: call_site,
+                        span,
                     }))
                 },
             )
@@ -608,15 +569,13 @@ fn concat_bytes_expand(
 fn concat_bytes_expand_subtree(
     tree: &tt::Subtree,
     bytes: &mut Vec<String>,
-    mut record_span: impl FnMut(Span),
 ) -> Result<(), ExpandError> {
     for (ti, tt) in tree.token_trees.iter().enumerate() {
         match tt {
-            tt::TokenTree::Leaf(tt::Leaf::Literal(it)) => {
-                let lit = ast::make::tokens::literal(&it.to_string());
+            tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
+                let lit = ast::make::tokens::literal(&lit.to_string());
                 match lit.kind() {
                     syntax::SyntaxKind::BYTE | syntax::SyntaxKind::INT_NUMBER => {
-                        record_span(it.span);
                         bytes.push(lit.text().to_owned())
                     }
                     _ => {
@@ -676,7 +635,7 @@ fn relative_file(
     }
 }
 
-fn parse_string(tt: &tt::Subtree) -> Result<(String, Span), ExpandError> {
+fn parse_string(tt: &tt::Subtree) -> Result<String, ExpandError> {
     tt.token_trees
         .first()
         .and_then(|tt| match tt {
@@ -716,7 +675,7 @@ pub fn include_input_to_file_id(
     arg_id: MacroCallId,
     arg: &tt::Subtree,
 ) -> Result<FileId, ExpandError> {
-    relative_file(db, arg_id, &parse_string(arg)?.0, false)
+    relative_file(db, arg_id, &parse_string(arg)?, false)
 }
 
 fn include_bytes_expand(
@@ -742,7 +701,7 @@ fn include_str_expand(
     tt: &tt::Subtree,
     span: Span,
 ) -> ExpandResult<tt::Subtree> {
-    let (path, span) = match parse_string(tt) {
+    let path = match parse_string(tt) {
         Ok(it) => it,
         Err(e) => {
             return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
@@ -777,7 +736,7 @@ fn env_expand(
     tt: &tt::Subtree,
     span: Span,
 ) -> ExpandResult<tt::Subtree> {
-    let (key, span) = match parse_string(tt) {
+    let key = match parse_string(tt) {
         Ok(it) => it,
         Err(e) => {
             return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
@@ -807,24 +766,18 @@ fn option_env_expand(
     db: &dyn ExpandDatabase,
     arg_id: MacroCallId,
     tt: &tt::Subtree,
-    call_site: Span,
+    span: Span,
 ) -> ExpandResult<tt::Subtree> {
-    let (key, span) = match parse_string(tt) {
+    let key = match parse_string(tt) {
         Ok(it) => it,
         Err(e) => {
-            return ExpandResult::new(
-                tt::Subtree::empty(DelimSpan { open: call_site, close: call_site }),
-                e,
-            )
+            return ExpandResult::new(tt::Subtree::empty(DelimSpan { open: span, close: span }), e)
         }
     };
-    let dollar_crate = dollar_crate(call_site);
+    let dollar_crate = dollar_crate(span);
     let expanded = match get_env_inner(db, arg_id, &key) {
-        None => quote! {call_site => #dollar_crate::option::Option::None::<&str> },
-        Some(s) => {
-            let s = quote! (span => #s);
-            quote! {call_site => #dollar_crate::option::Option::Some(#s) }
-        }
+        None => quote! {span => #dollar_crate::option::Option::None::<&str> },
+        Some(s) => quote! {span => #dollar_crate::option::Option::Some(#s) },
     };
 
     ExpandResult::ok(expanded)
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index ec68f2f96e..a7469ae5c8 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -3,19 +3,22 @@
 use base_db::{salsa, CrateId, FileId, SourceDatabase};
 use either::Either;
 use limit::Limit;
-use mbe::syntax_node_to_token_tree;
+use mbe::{syntax_node_to_token_tree, ValueResult};
 use rustc_hash::FxHashSet;
-use span::{AstIdMap, Span, SyntaxContextData, SyntaxContextId};
-use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T};
+use span::{AstIdMap, SyntaxContextData, SyntaxContextId};
+use syntax::{
+    ast::{self, HasAttrs},
+    AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T,
+};
 use triomphe::Arc;
 
 use crate::{
-    attrs::{collect_attrs, AttrId},
+    attrs::collect_attrs,
     builtin_attr_macro::pseudo_derive_attr_expansion,
     builtin_fn_macro::EagerExpander,
     cfg_process,
     declarative::DeclarativeMacroExpander,
-    fixup::{self, SyntaxFixupUndoInfo},
+    fixup::{self, reverse_fixups, SyntaxFixupUndoInfo},
     hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt},
     proc_macro::ProcMacros,
     span_map::{RealSpanMap, SpanMap, SpanMapRef},
@@ -98,7 +101,10 @@ pub trait ExpandDatabase: SourceDatabase {
     /// Lowers syntactic macro call to a token tree representation. That's a firewall
     /// query, only typing in the macro call itself changes the returned
     /// subtree.
-    fn macro_arg(&self, id: MacroCallId) -> (Arc<tt::Subtree>, SyntaxFixupUndoInfo, Span);
+    fn macro_arg(
+        &self,
+        id: MacroCallId,
+    ) -> ValueResult<(Arc<tt::Subtree>, SyntaxFixupUndoInfo), Arc<Box<[SyntaxError]>>>;
     /// Fetches the expander for this macro.
     #[salsa::transparent]
     #[salsa::invoke(TokenExpander::macro_expander)]
@@ -115,12 +121,6 @@ pub trait ExpandDatabase: SourceDatabase {
     /// non-determinism breaks salsa in a very, very, very bad way.
     /// @edwin0cheng heroically debugged this once! See #4315 for details
     fn expand_proc_macro(&self, call: MacroCallId) -> ExpandResult<Arc<tt::Subtree>>;
-    /// Retrieves the span to be used for a proc-macro expansions spans.
-    /// This is a firewall query as it requires parsing the file, which we don't want proc-macros to
-    /// directly depend on as that would cause to frequent invalidations, mainly because of the
-    /// parse queries being LRU cached. If they weren't the invalidations would only happen if the
-    /// user wrote in the file that defines the proc-macro.
-    fn proc_macro_span(&self, fun: AstId<ast::Fn>) -> Span;
     /// Firewall query that returns the errors from the `parse_macro_expansion` query.
     fn parse_macro_expansion_error(
         &self,
@@ -140,36 +140,20 @@ pub fn expand_speculative(
 ) -> Option<(SyntaxNode, SyntaxToken)> {
     let loc = db.lookup_intern_macro_call(actual_macro_call);
 
-    // FIXME: This BOGUS here is dangerous once the proc-macro server can call back into the database!
     let span_map = RealSpanMap::absolute(FileId::BOGUS);
     let span_map = SpanMapRef::RealSpanMap(&span_map);
 
-    let (_, _, span) = db.macro_arg(actual_macro_call);
-
     // Build the subtree and token mapping for the speculative args
     let (mut tt, undo_info) = match loc.kind {
         MacroCallKind::FnLike { .. } => (
-            mbe::syntax_node_to_token_tree(speculative_args, span_map, span),
-            SyntaxFixupUndoInfo::NONE,
-        ),
-        MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => (
-            mbe::syntax_node_to_token_tree(speculative_args, span_map, span),
+            mbe::syntax_node_to_token_tree(speculative_args, span_map, loc.call_site),
             SyntaxFixupUndoInfo::NONE,
         ),
-        MacroCallKind::Derive { derive_attr_index: index, .. }
-        | MacroCallKind::Attr { invoc_attr_index: index, .. } => {
-            let censor = if let MacroCallKind::Derive { .. } = loc.kind {
-                censor_derive_input(index, &ast::Adt::cast(speculative_args.clone())?)
-            } else {
-                attr_source(index, &ast::Item::cast(speculative_args.clone())?)
-                    .into_iter()
-                    .map(|it| it.syntax().clone().into())
-                    .collect()
-            };
-
+        MacroCallKind::Derive { .. } | MacroCallKind::Attr { .. } => {
+            let censor = censor_for_macro_input(&loc, speculative_args);
             let censor_cfg =
                 cfg_process::process_cfg_attrs(speculative_args, &loc, db).unwrap_or_default();
-            let mut fixups = fixup::fixup_syntax(span_map, speculative_args, span);
+            let mut fixups = fixup::fixup_syntax(span_map, speculative_args, loc.call_site);
             fixups.append.retain(|it, _| match it {
                 syntax::NodeOrToken::Token(_) => true,
                 it => !censor.contains(it) && !censor_cfg.contains(it),
@@ -183,7 +167,7 @@ pub fn expand_speculative(
                     span_map,
                     fixups.append,
                     fixups.remove,
-                    span,
+                    loc.call_site,
                 ),
                 fixups.undo_info,
             )
@@ -205,8 +189,9 @@ pub fn expand_speculative(
             }?;
             match attr.token_tree() {
                 Some(token_tree) => {
-                    let mut tree = syntax_node_to_token_tree(token_tree.syntax(), span_map, span);
-                    tree.delimiter = tt::Delimiter::invisible_spanned(span);
+                    let mut tree =
+                        syntax_node_to_token_tree(token_tree.syntax(), span_map, loc.call_site);
+                    tree.delimiter = tt::Delimiter::invisible_spanned(loc.call_site);
 
                     Some(tree)
                 }
@@ -219,36 +204,36 @@ pub fn expand_speculative(
     // Do the actual expansion, we need to directly expand the proc macro due to the attribute args
     // Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
     let mut speculative_expansion = match loc.def.kind {
-        MacroDefKind::ProcMacro(expander, _, ast) => {
-            let span = db.proc_macro_span(ast);
-            tt.delimiter = tt::Delimiter::invisible_spanned(span);
+        MacroDefKind::ProcMacro(expander, ..) => {
+            tt.delimiter = tt::Delimiter::invisible_spanned(loc.call_site);
             expander.expand(
                 db,
                 loc.def.krate,
                 loc.krate,
                 &tt,
                 attr_arg.as_ref(),
-                span_with_def_site_ctxt(db, span, actual_macro_call),
-                span_with_call_site_ctxt(db, span, actual_macro_call),
-                span_with_mixed_site_ctxt(db, span, actual_macro_call),
+                span_with_def_site_ctxt(db, loc.def.span, actual_macro_call),
+                span_with_call_site_ctxt(db, loc.def.span, actual_macro_call),
+                span_with_mixed_site_ctxt(db, loc.def.span, actual_macro_call),
             )
         }
         MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
-            pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span)
-        }
-        MacroDefKind::Declarative(it) => {
-            db.decl_macro_expander(loc.krate, it).expand_unhygienic(db, tt, loc.def.krate, span)
-        }
-        MacroDefKind::BuiltIn(it, _) => {
-            it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
+            pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, loc.call_site)
         }
+        MacroDefKind::Declarative(it) => db.decl_macro_expander(loc.krate, it).expand_unhygienic(
+            db,
+            tt,
+            loc.def.krate,
+            loc.call_site,
+        ),
+        MacroDefKind::BuiltIn(it, _) => it.expand(db, actual_macro_call, &tt).map_err(Into::into),
         MacroDefKind::BuiltInDerive(it, ..) => {
-            it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
+            it.expand(db, actual_macro_call, &tt).map_err(Into::into)
         }
         MacroDefKind::BuiltInEager(it, _) => {
-            it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
+            it.expand(db, actual_macro_call, &tt).map_err(Into::into)
         }
-        MacroDefKind::BuiltInAttr(it, _) => it.expand(db, actual_macro_call, &tt, span),
+        MacroDefKind::BuiltInAttr(it, _) => it.expand(db, actual_macro_call, &tt),
     };
 
     let expand_to = loc.expand_to();
@@ -339,161 +324,185 @@ pub(crate) fn parse_with_map(
     }
 }
 
-// FIXME: for derive attributes, this will return separate copies of the same structures! Though
-// they may differ in spans due to differing call sites...
+// FIXME: for derive attributes, this will return separate copies of the same structures!
 fn macro_arg(
     db: &dyn ExpandDatabase,
     id: MacroCallId,
-) -> (Arc<tt::Subtree>, SyntaxFixupUndoInfo, Span) {
+    // FIXME: consider the following by putting fixup info into eager call info args
+    // ) -> ValueResult<Arc<(tt::Subtree, SyntaxFixupUndoInfo)>, Arc<Box<[SyntaxError]>>> {
+) -> ValueResult<(Arc<tt::Subtree>, SyntaxFixupUndoInfo), Arc<Box<[SyntaxError]>>> {
     let loc = db.lookup_intern_macro_call(id);
-
-    if let MacroCallLoc {
-        def: MacroDefId { kind: MacroDefKind::BuiltInEager(..), .. },
-        kind: MacroCallKind::FnLike { eager: Some(eager), .. },
-        ..
-    } = &loc
+    if let Some(EagerCallInfo { arg, .. }) = matches!(loc.def.kind, MacroDefKind::BuiltInEager(..))
+        .then(|| loc.eager.as_deref())
+        .flatten()
     {
-        return (eager.arg.clone(), SyntaxFixupUndoInfo::NONE, eager.span);
-    }
-
-    let (parse, map) = parse_with_map(db, loc.kind.file_id());
-    let root = parse.syntax_node();
-
-    let (censor, item_node, span) = match loc.kind {
-        MacroCallKind::FnLike { ast_id, .. } => {
-            let node = &ast_id.to_ptr(db).to_node(&root);
-            let path_range = node
-                .path()
-                .map_or_else(|| node.syntax().text_range(), |path| path.syntax().text_range());
-            let span = map.span_for_range(path_range);
+        ValueResult::ok((arg.clone(), SyntaxFixupUndoInfo::NONE))
+    } else {
+        let (parse, map) = parse_with_map(db, loc.kind.file_id());
+        let root = parse.syntax_node();
+
+        let syntax = match loc.kind {
+            MacroCallKind::FnLike { ast_id, .. } => {
+                let dummy_tt = |kind| {
+                    (
+                        Arc::new(tt::Subtree {
+                            delimiter: tt::Delimiter {
+                                open: loc.call_site,
+                                close: loc.call_site,
+                                kind,
+                            },
+                            token_trees: Box::default(),
+                        }),
+                        SyntaxFixupUndoInfo::default(),
+                    )
+                };
 
-            let dummy_tt = |kind| {
+                let node = &ast_id.to_ptr(db).to_node(&root);
+                let offset = node.syntax().text_range().start();
+                let Some(tt) = node.token_tree() else {
+                    return ValueResult::new(
+                        dummy_tt(tt::DelimiterKind::Invisible),
+                        Arc::new(Box::new([SyntaxError::new_at_offset(
+                            "missing token tree".to_owned(),
+                            offset,
+                        )])),
+                    );
+                };
+                let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']);
+                let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]);
+
+                let mismatched_delimiters = !matches!(
+                    (first, last),
+                    (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}'])
+                );
+                if mismatched_delimiters {
+                    // Don't expand malformed (unbalanced) macro invocations. This is
+                    // less than ideal, but trying to expand unbalanced  macro calls
+                    // sometimes produces pathological, deeply nested code which breaks
+                    // all kinds of things.
+                    //
+                    // So instead, we'll return an empty subtree here
+                    cov_mark::hit!(issue9358_bad_macro_stack_overflow);
+
+                    let kind = match first {
+                        _ if loc.def.is_proc_macro() => tt::DelimiterKind::Invisible,
+                        T!['('] => tt::DelimiterKind::Parenthesis,
+                        T!['['] => tt::DelimiterKind::Bracket,
+                        T!['{'] => tt::DelimiterKind::Brace,
+                        _ => tt::DelimiterKind::Invisible,
+                    };
+                    return ValueResult::new(
+                        dummy_tt(kind),
+                        Arc::new(Box::new([SyntaxError::new_at_offset(
+                            "mismatched delimiters".to_owned(),
+                            offset,
+                        )])),
+                    );
+                }
+                tt.syntax().clone()
+            }
+            MacroCallKind::Derive { ast_id, .. } => {
+                ast_id.to_ptr(db).to_node(&root).syntax().clone()
+            }
+            MacroCallKind::Attr { ast_id, .. } => ast_id.to_ptr(db).to_node(&root).syntax().clone(),
+        };
+        let (mut tt, undo_info) = match loc.kind {
+            MacroCallKind::FnLike { .. } => (
+                mbe::syntax_node_to_token_tree(&syntax, map.as_ref(), loc.call_site),
+                SyntaxFixupUndoInfo::NONE,
+            ),
+            MacroCallKind::Derive { .. } | MacroCallKind::Attr { .. } => {
+                let censor = censor_for_macro_input(&loc, &syntax);
+                let censor_cfg =
+                    cfg_process::process_cfg_attrs(&syntax, &loc, db).unwrap_or_default();
+                let mut fixups = fixup::fixup_syntax(map.as_ref(), &syntax, loc.call_site);
+                fixups.append.retain(|it, _| match it {
+                    syntax::NodeOrToken::Token(_) => true,
+                    it => !censor.contains(it) && !censor_cfg.contains(it),
+                });
+                fixups.remove.extend(censor);
+                fixups.remove.extend(censor_cfg);
+
+                {
+                    let mut tt = mbe::syntax_node_to_token_tree_modified(
+                        &syntax,
+                        map.as_ref(),
+                        fixups.append.clone(),
+                        fixups.remove.clone(),
+                        loc.call_site,
+                    );
+                    reverse_fixups(&mut tt, &fixups.undo_info);
+                }
                 (
-                    Arc::new(tt::Subtree {
-                        delimiter: tt::Delimiter { open: span, close: span, kind },
-                        token_trees: Box::default(),
-                    }),
-                    SyntaxFixupUndoInfo::default(),
-                    span,
+                    mbe::syntax_node_to_token_tree_modified(
+                        &syntax,
+                        map,
+                        fixups.append,
+                        fixups.remove,
+                        loc.call_site,
+                    ),
+                    fixups.undo_info,
                 )
-            };
-
-            let Some(tt) = node.token_tree() else {
-                return dummy_tt(tt::DelimiterKind::Invisible);
-            };
-            let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']);
-            let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]);
-
-            let mismatched_delimiters = !matches!(
-                (first, last),
-                (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}'])
-            );
-            if mismatched_delimiters {
-                // Don't expand malformed (unbalanced) macro invocations. This is
-                // less than ideal, but trying to expand unbalanced  macro calls
-                // sometimes produces pathological, deeply nested code which breaks
-                // all kinds of things.
-                //
-                // So instead, we'll return an empty subtree here
-                cov_mark::hit!(issue9358_bad_macro_stack_overflow);
-
-                let kind = match first {
-                    _ if loc.def.is_proc_macro() => tt::DelimiterKind::Invisible,
-                    T!['('] => tt::DelimiterKind::Parenthesis,
-                    T!['['] => tt::DelimiterKind::Bracket,
-                    T!['{'] => tt::DelimiterKind::Brace,
-                    _ => tt::DelimiterKind::Invisible,
-                };
-                return dummy_tt(kind);
             }
+        };
 
-            let mut tt = mbe::syntax_node_to_token_tree(tt.syntax(), map.as_ref(), span);
-            if loc.def.is_proc_macro() {
-                // proc macros expect their inputs without parentheses, MBEs expect it with them included
-                tt.delimiter.kind = tt::DelimiterKind::Invisible;
-            }
-            return (Arc::new(tt), SyntaxFixupUndoInfo::NONE, span);
-        }
-        MacroCallKind::Derive { ast_id, derive_attr_index, .. } => {
-            let node = ast_id.to_ptr(db).to_node(&root);
-            let censor_derive_input = censor_derive_input(derive_attr_index, &node);
-            let item_node = node.into();
-            let attr_source = attr_source(derive_attr_index, &item_node);
-            // FIXME: This is wrong, this should point to the path of the derive attribute`
-            let span =
-                map.span_for_range(attr_source.as_ref().and_then(|it| it.path()).map_or_else(
-                    || item_node.syntax().text_range(),
-                    |it| it.syntax().text_range(),
-                ));
-            (censor_derive_input, item_node, span)
+        if loc.def.is_proc_macro() {
+            // proc macros expect their inputs without parentheses, MBEs expect it with them included
+            tt.delimiter.kind = tt::DelimiterKind::Invisible;
         }
-        MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => {
-            let node = ast_id.to_ptr(db).to_node(&root);
-            let attr_source = attr_source(invoc_attr_index, &node);
-            let span = map.span_for_range(
-                attr_source
-                    .as_ref()
-                    .and_then(|it| it.path())
-                    .map_or_else(|| node.syntax().text_range(), |it| it.syntax().text_range()),
-            );
-            (attr_source.into_iter().map(|it| it.syntax().clone().into()).collect(), node, span)
-        }
-    };
 
-    let (mut tt, undo_info) = {
-        let syntax = item_node.syntax();
-        let censor_cfg = cfg_process::process_cfg_attrs(syntax, &loc, db).unwrap_or_default();
-        let mut fixups = fixup::fixup_syntax(map.as_ref(), syntax, span);
-        fixups.append.retain(|it, _| match it {
-            syntax::NodeOrToken::Token(_) => true,
-            it => !censor.contains(it) && !censor_cfg.contains(it),
-        });
-        fixups.remove.extend(censor);
-        fixups.remove.extend(censor_cfg);
-
-        (
-            mbe::syntax_node_to_token_tree_modified(
-                syntax,
-                map,
-                fixups.append,
-                fixups.remove,
-                span,
-            ),
-            fixups.undo_info,
-        )
-    };
-
-    if loc.def.is_proc_macro() {
-        // proc macros expect their inputs without parentheses, MBEs expect it with them included
-        tt.delimiter.kind = tt::DelimiterKind::Invisible;
+        if matches!(loc.def.kind, MacroDefKind::BuiltInEager(..)) {
+            match parse.errors() {
+                errors if errors.is_empty() => ValueResult::ok((Arc::new(tt), undo_info)),
+                errors => ValueResult::new(
+                    (Arc::new(tt), undo_info),
+                    // Box::<[_]>::from(res.errors()), not stable yet
+                    Arc::new(errors.to_vec().into_boxed_slice()),
+                ),
+            }
+        } else {
+            ValueResult::ok((Arc::new(tt), undo_info))
+        }
     }
-
-    (Arc::new(tt), undo_info, span)
 }
 
 // FIXME: Censoring info should be calculated by the caller! Namely by name resolution
-/// Derives expect all `#[derive(..)]` invocations up to (and including) the currently invoked one to be stripped
-fn censor_derive_input(derive_attr_index: AttrId, node: &ast::Adt) -> FxHashSet<SyntaxElement> {
+/// Certain macro calls expect some nodes in the input to be preprocessed away, namely:
+/// - derives expect all `#[derive(..)]` invocations up to the currently invoked one to be stripped
+/// - attributes expect the invoking attribute to be stripped
+fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<SyntaxElement> {
     // FIXME: handle `cfg_attr`
-    cov_mark::hit!(derive_censoring);
-    collect_attrs(node)
-        .take(derive_attr_index.ast_index() + 1)
-        .filter_map(|(_, attr)| Either::left(attr))
-        // FIXME, this resolution should not be done syntactically
-        // derive is a proper macro now, no longer builtin
-        // But we do not have resolution at this stage, this means
-        // we need to know about all macro calls for the given ast item here
-        // so we require some kind of mapping...
-        .filter(|attr| attr.simple_name().as_deref() == Some("derive"))
-        .map(|it| it.syntax().clone().into())
-        .collect()
-}
-
-/// Attributes expect the invoking attribute to be stripped
-fn attr_source(invoc_attr_index: AttrId, node: &ast::Item) -> Option<ast::Attr> {
-    // FIXME: handle `cfg_attr`
-    cov_mark::hit!(attribute_macro_attr_censoring);
-    collect_attrs(node).nth(invoc_attr_index.ast_index()).and_then(|(_, attr)| Either::left(attr))
+    (|| {
+        let censor = match loc.kind {
+            MacroCallKind::FnLike { .. } => return None,
+            MacroCallKind::Derive { derive_attr_index, .. } => {
+                cov_mark::hit!(derive_censoring);
+                ast::Item::cast(node.clone())?
+                    .attrs()
+                    .take(derive_attr_index.ast_index() + 1)
+                    // FIXME, this resolution should not be done syntactically
+                    // derive is a proper macro now, no longer builtin
+                    // But we do not have resolution at this stage, this means
+                    // we need to know about all macro calls for the given ast item here
+                    // so we require some kind of mapping...
+                    .filter(|attr| attr.simple_name().as_deref() == Some("derive"))
+                    .map(|it| it.syntax().clone().into())
+                    .collect()
+            }
+            MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => return None,
+            MacroCallKind::Attr { invoc_attr_index, .. } => {
+                cov_mark::hit!(attribute_macro_attr_censoring);
+                collect_attrs(&ast::Item::cast(node.clone())?)
+                    .nth(invoc_attr_index.ast_index())
+                    .and_then(|x| Either::left(x.1))
+                    .map(|attr| attr.syntax().clone().into())
+                    .into_iter()
+                    .collect()
+            }
+        };
+        Some(censor)
+    })()
+    .unwrap_or_default()
 }
 
 impl TokenExpander {
@@ -523,64 +532,74 @@ fn macro_expand(
 ) -> ExpandResult<CowArc<tt::Subtree>> {
     let _p = tracing::span!(tracing::Level::INFO, "macro_expand").entered();
 
-    let (ExpandResult { value: tt, err }, span) = match loc.def.kind {
+    let ExpandResult { value: tt, mut err } = match loc.def.kind {
         MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc),
         _ => {
-            let (macro_arg, undo_info, span) = db.macro_arg(macro_call_id);
+            let ValueResult { value: (macro_arg, undo_info), err } = db.macro_arg(macro_call_id);
+            let format_parse_err = |err: Arc<Box<[SyntaxError]>>| {
+                let mut buf = String::new();
+                for err in &**err {
+                    use std::fmt::Write;
+                    _ = write!(buf, "{}, ", err);
+                }
+                buf.pop();
+                buf.pop();
+                ExpandError::other(buf)
+            };
 
             let arg = &*macro_arg;
-            let res =
-                match loc.def.kind {
-                    MacroDefKind::Declarative(id) => db
-                        .decl_macro_expander(loc.def.krate, id)
-                        .expand(db, arg.clone(), macro_call_id, span),
-                    MacroDefKind::BuiltIn(it, _) => {
-                        it.expand(db, macro_call_id, arg, span).map_err(Into::into)
-                    }
-                    MacroDefKind::BuiltInDerive(it, _) => {
-                        it.expand(db, macro_call_id, arg, span).map_err(Into::into)
-                    }
-                    MacroDefKind::BuiltInEager(it, _) => {
-                        // This might look a bit odd, but we do not expand the inputs to eager macros here.
-                        // Eager macros inputs are expanded, well, eagerly when we collect the macro calls.
-                        // That kind of expansion uses the ast id map of an eager macros input though which goes through
-                        // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query
-                        // will end up going through here again, whereas we want to just want to inspect the raw input.
-                        // As such we just return the input subtree here.
-                        let eager = match &loc.kind {
-                            MacroCallKind::FnLike { eager: None, .. } => {
-                                return ExpandResult::ok(CowArc::Arc(macro_arg.clone()));
-                            }
-                            MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
-                            _ => None,
-                        };
-
-                        let mut res = it.expand(db, macro_call_id, arg, span).map_err(Into::into);
-
-                        if let Some(EagerCallInfo { error, .. }) = eager {
-                            // FIXME: We should report both errors!
-                            res.err = error.clone().or(res.err);
-                        }
-                        res
-                    }
-                    MacroDefKind::BuiltInAttr(it, _) => {
-                        let mut res = it.expand(db, macro_call_id, arg, span);
-                        fixup::reverse_fixups(&mut res.value, &undo_info);
-                        res
-                    }
-                    _ => unreachable!(),
-                };
-            (ExpandResult { value: res.value, err: res.err }, span)
+            let res = match loc.def.kind {
+                MacroDefKind::Declarative(id) => {
+                    db.decl_macro_expander(loc.def.krate, id).expand(db, arg.clone(), macro_call_id)
+                }
+                MacroDefKind::BuiltIn(it, _) => {
+                    it.expand(db, macro_call_id, arg).map_err(Into::into)
+                }
+                // This might look a bit odd, but we do not expand the inputs to eager macros here.
+                // Eager macros inputs are expanded, well, eagerly when we collect the macro calls.
+                // That kind of expansion uses the ast id map of an eager macros input though which goes through
+                // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query
+                // will end up going through here again, whereas we want to just want to inspect the raw input.
+                // As such we just return the input subtree here.
+                MacroDefKind::BuiltInEager(..) if loc.eager.is_none() => {
+                    return ExpandResult {
+                        value: CowArc::Arc(macro_arg.clone()),
+                        err: err.map(format_parse_err),
+                    };
+                }
+                MacroDefKind::BuiltInDerive(it, _) => {
+                    it.expand(db, macro_call_id, arg).map_err(Into::into)
+                }
+                MacroDefKind::BuiltInEager(it, _) => {
+                    it.expand(db, macro_call_id, arg).map_err(Into::into)
+                }
+                MacroDefKind::BuiltInAttr(it, _) => {
+                    let mut res = it.expand(db, macro_call_id, arg);
+                    fixup::reverse_fixups(&mut res.value, &undo_info);
+                    res
+                }
+                _ => unreachable!(),
+            };
+            ExpandResult {
+                value: res.value,
+                // if the arg had parse errors, show them instead of the expansion errors
+                err: err.map(format_parse_err).or(res.err),
+            }
         }
     };
 
+    if let Some(EagerCallInfo { error, .. }) = loc.eager.as_deref() {
+        // FIXME: We should report both errors!
+        err = error.clone().or(err);
+    }
+
     // Skip checking token tree limit for include! macro call
     if !loc.def.is_include() {
         // Set a hard limit for the expanded tt
         if let Err(value) = check_tt_count(&tt) {
             return value.map(|()| {
                 CowArc::Owned(tt::Subtree {
-                    delimiter: tt::Delimiter::invisible_spanned(span),
+                    delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
                     token_trees: Box::new([]),
                 })
             });
@@ -590,23 +609,12 @@ fn macro_expand(
     ExpandResult { value: CowArc::Owned(tt), err }
 }
 
-fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
-    let root = db.parse_or_expand(ast.file_id);
-    let ast_id_map = &db.ast_id_map(ast.file_id);
-    let span_map = &db.span_map(ast.file_id);
-
-    let node = ast_id_map.get(ast.value).to_node(&root);
-    let range = ast::HasName::name(&node)
-        .map_or_else(|| node.syntax().text_range(), |name| name.syntax().text_range());
-    span_map.span_for_range(range)
-}
-
 fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> {
     let loc = db.lookup_intern_macro_call(id);
-    let (macro_arg, undo_info, span) = db.macro_arg(id);
+    let (macro_arg, undo_info) = db.macro_arg(id).value;
 
-    let (expander, ast) = match loc.def.kind {
-        MacroDefKind::ProcMacro(expander, _, ast) => (expander, ast),
+    let expander = match loc.def.kind {
+        MacroDefKind::ProcMacro(expander, ..) => expander,
         _ => unreachable!(),
     };
 
@@ -615,25 +623,22 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<A
         _ => None,
     };
 
-    let ExpandResult { value: mut tt, err } = {
-        let span = db.proc_macro_span(ast);
-        expander.expand(
-            db,
-            loc.def.krate,
-            loc.krate,
-            &macro_arg,
-            attr_arg,
-            span_with_def_site_ctxt(db, span, id),
-            span_with_call_site_ctxt(db, span, id),
-            span_with_mixed_site_ctxt(db, span, id),
-        )
-    };
+    let ExpandResult { value: mut tt, err } = expander.expand(
+        db,
+        loc.def.krate,
+        loc.krate,
+        &macro_arg,
+        attr_arg,
+        span_with_def_site_ctxt(db, loc.def.span, id),
+        span_with_call_site_ctxt(db, loc.def.span, id),
+        span_with_mixed_site_ctxt(db, loc.def.span, id),
+    );
 
     // Set a hard limit for the expanded tt
     if let Err(value) = check_tt_count(&tt) {
         return value.map(|()| {
             Arc::new(tt::Subtree {
-                delimiter: tt::Delimiter::invisible_spanned(span),
+                delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
                 token_trees: Box::new([]),
             })
         });
diff --git a/crates/hir-expand/src/declarative.rs b/crates/hir-expand/src/declarative.rs
index 33643c0272..6874336cd2 100644
--- a/crates/hir-expand/src/declarative.rs
+++ b/crates/hir-expand/src/declarative.rs
@@ -29,7 +29,6 @@ impl DeclarativeMacroExpander {
         db: &dyn ExpandDatabase,
         tt: tt::Subtree,
         call_id: MacroCallId,
-        span: Span,
     ) -> ExpandResult<tt::Subtree> {
         let loc = db.lookup_intern_macro_call(call_id);
         let toolchain = db.toolchain(loc.def.krate);
@@ -46,7 +45,7 @@ impl DeclarativeMacroExpander {
         });
         match self.mac.err() {
             Some(_) => ExpandResult::new(
-                tt::Subtree::empty(tt::DelimSpan { open: span, close: span }),
+                tt::Subtree::empty(tt::DelimSpan { open: loc.call_site, close: loc.call_site }),
                 ExpandError::MacroDefinition,
             ),
             None => self
@@ -55,7 +54,7 @@ impl DeclarativeMacroExpander {
                     &tt,
                     |s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency),
                     new_meta_vars,
-                    span,
+                    loc.call_site,
                 )
                 .map_err(Into::into),
         }
diff --git a/crates/hir-expand/src/eager.rs b/crates/hir-expand/src/eager.rs
index 8b147c88c1..5337a5bb02 100644
--- a/crates/hir-expand/src/eager.rs
+++ b/crates/hir-expand/src/eager.rs
@@ -19,7 +19,7 @@
 //!
 //! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
 use base_db::CrateId;
-use span::SyntaxContextId;
+use span::Span;
 use syntax::{ted, Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent};
 use triomphe::Arc;
 
@@ -27,20 +27,22 @@ use crate::{
     ast::{self, AstNode},
     db::ExpandDatabase,
     mod_path::ModPath,
-    AstId, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap, InFile, Intern,
+    EagerCallInfo, ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap, InFile, Intern,
     MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
 };
 
 pub fn expand_eager_macro_input(
     db: &dyn ExpandDatabase,
     krate: CrateId,
-    macro_call: &ast::MacroCall,
-    ast_id: AstId<ast::MacroCall>,
+    macro_call: InFile<ast::MacroCall>,
     def: MacroDefId,
-    call_site: SyntaxContextId,
+    call_site: Span,
     resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
 ) -> ExpandResult<Option<MacroCallId>> {
-    let expand_to = ExpandTo::from_call_site(macro_call);
+    let ast_map = db.ast_id_map(macro_call.file_id);
+    // the expansion which the ast id map is built upon has no whitespace, so the offsets are wrong as macro_call is from the token tree that has whitespace!
+    let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(&macro_call.value));
+    let expand_to = ExpandTo::from_call_site(&macro_call.value);
 
     // Note:
     // When `lazy_expand` is called, its *parent* file must already exist.
@@ -49,11 +51,11 @@ pub fn expand_eager_macro_input(
     let arg_id = MacroCallLoc {
         def,
         krate,
-        kind: MacroCallKind::FnLike { ast_id, expand_to: ExpandTo::Expr, eager: None },
-        ctxt: call_site,
+        eager: None,
+        kind: MacroCallKind::FnLike { ast_id: call_id, expand_to: ExpandTo::Expr },
+        call_site,
     }
     .intern(db);
-    let (_, _, span) = db.macro_arg(arg_id);
     let ExpandResult { value: (arg_exp, arg_exp_map), err: parse_err } =
         db.parse_macro_expansion(arg_id.as_macro_file());
 
@@ -80,24 +82,16 @@ pub fn expand_eager_macro_input(
         return ExpandResult { value: None, err };
     };
 
-    let mut subtree = mbe::syntax_node_to_token_tree(&expanded_eager_input, arg_map, span);
+    let mut subtree = mbe::syntax_node_to_token_tree(&expanded_eager_input, arg_map, call_site);
 
     subtree.delimiter.kind = crate::tt::DelimiterKind::Invisible;
 
     let loc = MacroCallLoc {
         def,
         krate,
-        kind: MacroCallKind::FnLike {
-            ast_id,
-            expand_to,
-            eager: Some(Arc::new(EagerCallInfo {
-                arg: Arc::new(subtree),
-                arg_id,
-                error: err.clone(),
-                span,
-            })),
-        },
-        ctxt: call_site,
+        eager: Some(Arc::new(EagerCallInfo { arg: Arc::new(subtree), arg_id, error: err.clone() })),
+        kind: MacroCallKind::FnLike { ast_id: call_id, expand_to },
+        call_site,
     };
 
     ExpandResult { value: Some(loc.intern(db)), err }
@@ -106,18 +100,15 @@ pub fn expand_eager_macro_input(
 fn lazy_expand(
     db: &dyn ExpandDatabase,
     def: &MacroDefId,
-    macro_call: &ast::MacroCall,
-    ast_id: AstId<ast::MacroCall>,
+    macro_call: InFile<ast::MacroCall>,
     krate: CrateId,
-    call_site: SyntaxContextId,
+    call_site: Span,
 ) -> ExpandResult<(InFile<Parse<SyntaxNode>>, Arc<ExpansionSpanMap>)> {
-    let expand_to = ExpandTo::from_call_site(macro_call);
-    let id = def.make_call(
-        db,
-        krate,
-        MacroCallKind::FnLike { ast_id, expand_to, eager: None },
-        call_site,
-    );
+    let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
+
+    let expand_to = ExpandTo::from_call_site(&macro_call.value);
+    let ast_id = macro_call.with_value(ast_id);
+    let id = def.as_lazy_macro(db, krate, MacroCallKind::FnLike { ast_id, expand_to }, call_site);
     let macro_file = id.as_macro_file();
 
     db.parse_macro_expansion(macro_file)
@@ -131,7 +122,7 @@ fn eager_macro_recur(
     mut offset: TextSize,
     curr: InFile<SyntaxNode>,
     krate: CrateId,
-    call_site: SyntaxContextId,
+    call_site: Span,
     macro_resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
 ) -> ExpandResult<Option<(SyntaxNode, TextSize)>> {
     let original = curr.value.clone_for_update();
@@ -181,14 +172,12 @@ fn eager_macro_recur(
                 continue;
             }
         };
-        let ast_id = db.ast_id_map(curr.file_id).ast_id(&call);
         let ExpandResult { value, err } = match def.kind {
             MacroDefKind::BuiltInEager(..) => {
                 let ExpandResult { value, err } = expand_eager_macro_input(
                     db,
                     krate,
-                    &call,
-                    curr.with_value(ast_id),
+                    curr.with_value(call.clone()),
                     def,
                     call_site,
                     macro_resolver,
@@ -218,7 +207,7 @@ fn eager_macro_recur(
             | MacroDefKind::BuiltInDerive(..)
             | MacroDefKind::ProcMacro(..) => {
                 let ExpandResult { value: (parse, tm), err } =
-                    lazy_expand(db, &def, &call, curr.with_value(ast_id), krate, call_site);
+                    lazy_expand(db, &def, curr.with_value(call.clone()), krate, call_site);
 
                 // replace macro inside
                 let ExpandResult { value, err: error } = eager_macro_recur(
diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs
index 959595afb5..b44feb5ebe 100644
--- a/crates/hir-expand/src/fixup.rs
+++ b/crates/hir-expand/src/fixup.rs
@@ -3,7 +3,7 @@
 
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::SmallVec;
-use span::{ErasedFileAstId, Span, SpanAnchor, FIXUP_ERASED_FILE_AST_ID_MARKER};
+use span::{ErasedFileAstId, Span, SpanAnchor, SpanData, FIXUP_ERASED_FILE_AST_ID_MARKER};
 use stdx::never;
 use syntax::{
     ast::{self, AstNode, HasLoopBody},
@@ -57,7 +57,7 @@ pub(crate) fn fixup_syntax(
     let dummy_range = FIXUP_DUMMY_RANGE;
     let fake_span = |range| {
         let span = span_map.span_for_range(range);
-        Span {
+        SpanData {
             range: dummy_range,
             anchor: SpanAnchor { ast_id: FIXUP_DUMMY_AST_ID, ..span.anchor },
             ctx: span.ctx,
@@ -76,7 +76,7 @@ pub(crate) fn fixup_syntax(
             let span = span_map.span_for_range(node_range);
             let replacement = Leaf::Ident(Ident {
                 text: "__ra_fixup".into(),
-                span: Span {
+                span: SpanData {
                     range: TextRange::new(TextSize::new(idx), FIXUP_DUMMY_RANGE_END),
                     anchor: SpanAnchor { ast_id: FIXUP_DUMMY_AST_ID, ..span.anchor },
                     ctx: span.ctx,
@@ -305,8 +305,8 @@ pub(crate) fn reverse_fixups(tt: &mut Subtree, undo_info: &SyntaxFixupUndoInfo)
         tt.delimiter.close.anchor.ast_id == FIXUP_DUMMY_AST_ID
             || tt.delimiter.open.anchor.ast_id == FIXUP_DUMMY_AST_ID
     ) {
-        tt.delimiter.close = Span::DUMMY;
-        tt.delimiter.open = Span::DUMMY;
+        tt.delimiter.close = SpanData::DUMMY;
+        tt.delimiter.open = SpanData::DUMMY;
     }
     reverse_fixups_(tt, undo_info);
 }
diff --git a/crates/hir-expand/src/hygiene.rs b/crates/hir-expand/src/hygiene.rs
index 097e760c70..ac2bab280d 100644
--- a/crates/hir-expand/src/hygiene.rs
+++ b/crates/hir-expand/src/hygiene.rs
@@ -65,7 +65,7 @@ pub(super) fn apply_mark(
         return apply_mark_internal(db, ctxt, call_id, transparency);
     }
 
-    let call_site_ctxt = db.lookup_intern_macro_call(call_id).ctxt;
+    let call_site_ctxt = db.lookup_intern_macro_call(call_id).call_site.ctx;
     let mut call_site_ctxt = if transparency == Transparency::SemiTransparent {
         call_site_ctxt.normalize_to_macros_2_0(db)
     } else {
@@ -205,10 +205,11 @@ pub(crate) fn dump_syntax_contexts(db: &dyn ExpandDatabase) -> String {
         let id = e.key;
         let expn_data = e.value.as_ref().unwrap();
         s.push_str(&format!(
-            "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, kind: {:?}",
+            "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}",
             id,
             expn_data.kind.file_id(),
-            expn_data.ctxt,
+            expn_data.call_site,
+            SyntaxContextId::ROOT, // FIXME expn_data.def_site,
             expn_data.kind.descr(),
         ));
     }
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index 5d4f7dc146..924f0da6bd 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -170,8 +170,13 @@ impl fmt::Display for ExpandError {
 pub struct MacroCallLoc {
     pub def: MacroDefId,
     pub krate: CrateId,
+    /// Some if this is a macro call for an eager macro. Note that this is `None`
+    /// for the eager input macro file.
+    // FIXME: This is being interned, subtrees can vary quickly differ just slightly causing
+    // leakage problems here
+    eager: Option<Arc<EagerCallInfo>>,
     pub kind: MacroCallKind,
-    pub ctxt: SyntaxContextId,
+    pub call_site: Span,
 }
 impl_intern_value_trivial!(MacroCallLoc);
 
@@ -182,6 +187,7 @@ pub struct MacroDefId {
     pub kind: MacroDefKind,
     pub local_inner: bool,
     pub allow_internal_unsafe: bool,
+    pub span: Span,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -201,8 +207,6 @@ pub struct EagerCallInfo {
     /// Call id of the eager macro's input file (this is the macro file for its fully expanded input).
     arg_id: MacroCallId,
     error: Option<ExpandError>,
-    /// TODO: Doc
-    span: Span,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -210,11 +214,6 @@ pub enum MacroCallKind {
     FnLike {
         ast_id: AstId<ast::MacroCall>,
         expand_to: ExpandTo,
-        /// Some if this is a macro call for an eager macro. Note that this is `None`
-        /// for the eager input macro file.
-        // FIXME: This is being interned, subtrees can vary quickly differ just slightly causing
-        // leakage problems here
-        eager: Option<Arc<EagerCallInfo>>,
     },
     Derive {
         ast_id: AstId<ast::Adt>,
@@ -276,7 +275,7 @@ impl HirFileIdExt for HirFileId {
                 HirFileIdRepr::MacroFile(file) => {
                     let loc = db.lookup_intern_macro_call(file.macro_call_id);
                     if loc.def.is_include() {
-                        if let MacroCallKind::FnLike { eager: Some(eager), .. } = &loc.kind {
+                        if let Some(eager) = &loc.eager {
                             if let Ok(it) = builtin_fn_macro::include_input_to_file_id(
                                 db,
                                 file.macro_call_id,
@@ -323,9 +322,6 @@ impl HirFileIdExt for HirFileId {
 }
 
 pub trait MacroFileIdExt {
-    fn is_env_or_option_env(&self, db: &dyn ExpandDatabase) -> bool;
-    fn is_include_like_macro(&self, db: &dyn ExpandDatabase) -> bool;
-    fn eager_arg(&self, db: &dyn ExpandDatabase) -> Option<MacroCallId>;
     fn expansion_level(self, db: &dyn ExpandDatabase) -> u32;
     /// If this is a macro call, returns the syntax node of the call.
     fn call_node(self, db: &dyn ExpandDatabase) -> InFile<SyntaxNode>;
@@ -392,47 +388,31 @@ impl MacroFileIdExt for MacroFileId {
         db.lookup_intern_macro_call(self.macro_call_id).def.is_include()
     }
 
-    fn is_include_like_macro(&self, db: &dyn ExpandDatabase) -> bool {
-        db.lookup_intern_macro_call(self.macro_call_id).def.is_include_like()
-    }
-
-    fn is_env_or_option_env(&self, db: &dyn ExpandDatabase) -> bool {
-        db.lookup_intern_macro_call(self.macro_call_id).def.is_env_or_option_env()
-    }
-
     fn is_eager(&self, db: &dyn ExpandDatabase) -> bool {
-        let loc = db.lookup_intern_macro_call(self.macro_call_id);
+        let loc: MacroCallLoc = db.lookup_intern_macro_call(self.macro_call_id);
         matches!(loc.def.kind, MacroDefKind::BuiltInEager(..))
     }
 
-    fn eager_arg(&self, db: &dyn ExpandDatabase) -> Option<MacroCallId> {
-        let loc = db.lookup_intern_macro_call(self.macro_call_id);
-        match &loc.kind {
-            MacroCallKind::FnLike { eager, .. } => eager.as_ref().map(|it| it.arg_id),
-            _ => None,
-        }
-    }
-
     fn is_attr_macro(&self, db: &dyn ExpandDatabase) -> bool {
-        let loc = db.lookup_intern_macro_call(self.macro_call_id);
+        let loc: MacroCallLoc = db.lookup_intern_macro_call(self.macro_call_id);
         matches!(loc.kind, MacroCallKind::Attr { .. })
     }
 
     fn is_derive_attr_pseudo_expansion(&self, db: &dyn ExpandDatabase) -> bool {
-        let loc = db.lookup_intern_macro_call(self.macro_call_id);
+        let loc: MacroCallLoc = db.lookup_intern_macro_call(self.macro_call_id);
         loc.def.is_attribute_derive()
     }
 }
 
 impl MacroDefId {
-    pub fn make_call(
+    pub fn as_lazy_macro(
         self,
         db: &dyn ExpandDatabase,
         krate: CrateId,
         kind: MacroCallKind,
-        ctxt: SyntaxContextId,
+        call_site: Span,
     ) -> MacroCallId {
-        MacroCallLoc { def: self, krate, kind, ctxt }.intern(db)
+        MacroCallLoc { def: self, krate, eager: None, kind, call_site }.intern(db)
     }
 
     pub fn definition_range(&self, db: &dyn ExpandDatabase) -> InFile<TextRange> {
@@ -497,14 +477,6 @@ impl MacroDefId {
     pub fn is_include(&self) -> bool {
         matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_include())
     }
-
-    pub fn is_include_like(&self) -> bool {
-        matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_include_like())
-    }
-
-    pub fn is_env_or_option_env(&self) -> bool {
-        matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_env_or_option_env())
-    }
 }
 
 impl MacroCallLoc {
@@ -562,7 +534,7 @@ impl MacroCallLoc {
         macro_call_id: MacroCallId,
     ) -> Option<FileId> {
         if self.def.is_include() {
-            if let MacroCallKind::FnLike { eager: Some(eager), .. } = &self.kind {
+            if let Some(eager) = &self.eager {
                 if let Ok(it) =
                     builtin_fn_macro::include_input_to_file_id(db, macro_call_id, &eager.arg)
                 {
@@ -686,7 +658,7 @@ impl MacroCallKind {
 /// ExpansionInfo mainly describes how to map text range between src and expanded macro
 // FIXME: can be expensive to create, we should check the use sites and maybe replace them with
 // simpler function calls if the map is only used once
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct ExpansionInfo {
     pub expanded: InMacroFile<SyntaxNode>,
     /// The argument TokenTree or item for attributes
@@ -716,22 +688,6 @@ impl ExpansionInfo {
     /// Maps the passed in file range down into a macro expansion if it is the input to a macro call.
     ///
     /// Note this does a linear search through the entire backing vector of the spanmap.
-    pub fn map_range_down_exact(
-        &self,
-        span: Span,
-    ) -> Option<InMacroFile<impl Iterator<Item = SyntaxToken> + '_>> {
-        let tokens = self
-            .exp_map
-            .ranges_with_span_exact(span)
-            .flat_map(move |range| self.expanded.value.covering_element(range).into_token());
-
-        Some(InMacroFile::new(self.expanded.file_id, tokens))
-    }
-
-    /// Maps the passed in file range down into a macro expansion if it is the input to a macro call.
-    /// Unlike [`map_range_down_exact`], this will consider spans that contain the given span.
-    ///
-    /// Note this does a linear search through the entire backing vector of the spanmap.
     pub fn map_range_down(
         &self,
         span: Span,
@@ -788,7 +744,7 @@ impl ExpansionInfo {
                 InFile::new(
                     self.arg.file_id,
                     arg_map
-                        .ranges_with_span_exact(span)
+                        .ranges_with_span(span)
                         .filter(|range| range.intersect(arg_range).is_some())
                         .collect(),
                 )
@@ -806,7 +762,7 @@ impl ExpansionInfo {
         let (parse, exp_map) = db.parse_macro_expansion(macro_file).value;
         let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() };
 
-        let (macro_arg, _, _) = db.macro_arg(macro_file.macro_call_id);
+        let (macro_arg, _) = db.macro_arg(macro_file.macro_call_id).value;
 
         let def = loc.def.ast_id().left().and_then(|id| {
             let def_tt = match id.to_node(db) {
diff --git a/crates/hir-expand/src/quote.rs b/crates/hir-expand/src/quote.rs
index a31a111c91..c1930c94f5 100644
--- a/crates/hir-expand/src/quote.rs
+++ b/crates/hir-expand/src/quote.rs
@@ -266,11 +266,10 @@ mod tests {
 
         let quoted = quote!(DUMMY =>#a);
         assert_eq!(quoted.to_string(), "hello");
-        let t = format!("{quoted:#?}");
+        let t = format!("{quoted:?}");
         expect![[r#"
-            SUBTREE $$ 937550:0@0..0#0 937550:0@0..0#0
-              IDENT   hello 937550:0@0..0#0"#]]
-        .assert_eq(&t);
+            SUBTREE $$ SpanData { range: 0..0, anchor: SpanAnchor(FileId(937550), 0), ctx: SyntaxContextId(0) } SpanData { range: 0..0, anchor: SpanAnchor(FileId(937550), 0), ctx: SyntaxContextId(0) }
+              IDENT   hello SpanData { range: 0..0, anchor: SpanAnchor(FileId(937550), 0), ctx: SyntaxContextId(0) }"#]].assert_eq(&t);
     }
 
     #[test]
diff --git a/crates/hir-expand/src/span_map.rs b/crates/hir-expand/src/span_map.rs
index eae2c8fb63..29fec16334 100644
--- a/crates/hir-expand/src/span_map.rs
+++ b/crates/hir-expand/src/span_map.rs
@@ -1,13 +1,11 @@
 //! Span maps for real files and macro expansions.
-
 use span::{FileId, HirFileId, HirFileIdRepr, MacroFileId, Span, SyntaxContextId};
-use stdx::TupleExt;
-use syntax::{ast, AstNode, TextRange};
+use syntax::{AstNode, TextRange};
 use triomphe::Arc;
 
 pub use span::RealSpanMap;
 
-use crate::{attrs::collect_attrs, db::ExpandDatabase};
+use crate::db::ExpandDatabase;
 
 pub type ExpansionSpanMap = span::SpanMap<SyntaxContextId>;
 
@@ -84,54 +82,13 @@ pub(crate) fn real_span_map(db: &dyn ExpandDatabase, file_id: FileId) -> Arc<Rea
     let mut pairs = vec![(syntax::TextSize::new(0), span::ROOT_ERASED_FILE_AST_ID)];
     let ast_id_map = db.ast_id_map(file_id.into());
     let tree = db.parse(file_id).tree();
-    // This is an incrementality layer. Basically we can't use absolute ranges for our spans as that
-    // would mean we'd invalidate everything whenever we type. So instead we make the text ranges
-    // relative to some AstIds reducing the risk of invalidation as typing somewhere no longer
-    // affects all following spans in the file.
-    // There is some stuff to bear in mind here though, for one, the more "anchors" we create, the
-    // easier it gets to invalidate things again as spans are as stable as their anchor's ID.
-    // The other problem is proc-macros. Proc-macros have a `Span::join` api that allows them
-    // to join two spans that come from the same file. rust-analyzer's proc-macro server
-    // can only join two spans if they belong to the same anchor though, as the spans are relative
-    // to that anchor. To do cross anchor joining we'd need to access to the ast id map to resolve
-    // them again, something we might get access to in the future. But even then, proc-macros doing
-    // this kind of joining makes them as stable as the AstIdMap (which is basically changing on
-    // every input of the file)…
-
-    let item_to_entry =
-        |item: ast::Item| (item.syntax().text_range().start(), ast_id_map.ast_id(&item).erase());
-    // Top level items make for great anchors as they are the most stable and a decent boundary
-    pairs.extend(tree.items().map(item_to_entry));
-    // Unfortunately, assoc items are very common in Rust, so descend into those as well and make
-    // them anchors too, but only if they have no attributes attached, as those might be proc-macros
-    // and using different anchors inside of them will prevent spans from being joinable.
-    tree.items().for_each(|item| match &item {
-        ast::Item::ExternBlock(it)
-            if !collect_attrs(it).map(TupleExt::tail).any(|it| it.is_left()) =>
-        {
-            if let Some(extern_item_list) = it.extern_item_list() {
-                pairs.extend(
-                    extern_item_list.extern_items().map(ast::Item::from).map(item_to_entry),
-                );
-            }
-        }
-        ast::Item::Impl(it) if !collect_attrs(it).map(TupleExt::tail).any(|it| it.is_left()) => {
-            if let Some(assoc_item_list) = it.assoc_item_list() {
-                pairs.extend(assoc_item_list.assoc_items().map(ast::Item::from).map(item_to_entry));
-            }
-        }
-        ast::Item::Module(it) if !collect_attrs(it).map(TupleExt::tail).any(|it| it.is_left()) => {
-            if let Some(item_list) = it.item_list() {
-                pairs.extend(item_list.items().map(item_to_entry));
-            }
-        }
-        ast::Item::Trait(it) if !collect_attrs(it).map(TupleExt::tail).any(|it| it.is_left()) => {
-            if let Some(assoc_item_list) = it.assoc_item_list() {
-                pairs.extend(assoc_item_list.assoc_items().map(ast::Item::from).map(item_to_entry));
-            }
-        }
-        _ => (),
-    });
+    // FIXME: Descend into modules and other item containing items that are not annotated with attributes
+    // and allocate pairs for those as well. This gives us finer grained span anchors resulting in
+    // better incrementality
+    pairs.extend(
+        tree.items()
+            .map(|item| (item.syntax().text_range().start(), ast_id_map.ast_id(&item).erase())),
+    );
 
     Arc::new(RealSpanMap::from_file(
         file_id,
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index c5d44c11f2..cdc0db8653 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -159,7 +159,6 @@ impl HirDisplay for Adt {
 impl HirDisplay for Struct {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         let module_id = self.module(f.db).id;
-        // FIXME: Render repr if its set explicitly?
         write_visibility(module_id, self.visibility(f.db), f)?;
         f.write_str("struct ")?;
         write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
@@ -167,40 +166,37 @@ impl HirDisplay for Struct {
         write_generic_params(def_id, f)?;
 
         let variant_data = self.variant_data(f.db);
-        match variant_data.kind() {
-            StructKind::Tuple => {
-                f.write_char('(')?;
-                let mut it = variant_data.fields().iter().peekable();
-
-                while let Some((id, _)) = it.next() {
-                    let field = Field { parent: (*self).into(), id };
-                    write_visibility(module_id, field.visibility(f.db), f)?;
-                    field.ty(f.db).hir_fmt(f)?;
-                    if it.peek().is_some() {
-                        f.write_str(", ")?;
-                    }
+        if let StructKind::Tuple = variant_data.kind() {
+            f.write_char('(')?;
+            let mut it = variant_data.fields().iter().peekable();
+
+            while let Some((id, _)) = it.next() {
+                let field = Field { parent: (*self).into(), id };
+                write_visibility(module_id, field.visibility(f.db), f)?;
+                field.ty(f.db).hir_fmt(f)?;
+                if it.peek().is_some() {
+                    f.write_str(", ")?;
                 }
-
-                f.write_char(')')?;
-                write_where_clause(def_id, f)?;
             }
-            StructKind::Record => {
-                let has_where_clause = write_where_clause(def_id, f)?;
-                let fields = self.fields(f.db);
-                f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
-                if fields.is_empty() {
-                    f.write_str("{}")?;
-                } else {
-                    f.write_str("{\n")?;
-                    for field in self.fields(f.db) {
-                        f.write_str("    ")?;
-                        field.hir_fmt(f)?;
-                        f.write_str(",\n")?;
-                    }
-                    f.write_str("}")?;
+
+            f.write_str(");")?;
+        }
+
+        write_where_clause(def_id, f)?;
+
+        if let StructKind::Record = variant_data.kind() {
+            let fields = self.fields(f.db);
+            if fields.is_empty() {
+                f.write_str(" {}")?;
+            } else {
+                f.write_str(" {\n")?;
+                for field in self.fields(f.db) {
+                    f.write_str("    ")?;
+                    field.hir_fmt(f)?;
+                    f.write_str(",\n")?;
                 }
+                f.write_str("}")?;
             }
-            StructKind::Unit => _ = write_where_clause(def_id, f)?,
         }
 
         Ok(())
@@ -214,12 +210,11 @@ impl HirDisplay for Enum {
         write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
         let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
         write_generic_params(def_id, f)?;
-        let has_where_clause = write_where_clause(def_id, f)?;
+        write_where_clause(def_id, f)?;
 
         let variants = self.variants(f.db);
         if !variants.is_empty() {
-            f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
-            f.write_str("{\n")?;
+            f.write_str(" {\n")?;
             for variant in variants {
                 f.write_str("    ")?;
                 variant.hir_fmt(f)?;
@@ -239,12 +234,11 @@ impl HirDisplay for Union {
         write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
         let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
         write_generic_params(def_id, f)?;
-        let has_where_clause = write_where_clause(def_id, f)?;
+        write_where_clause(def_id, f)?;
 
         let fields = self.fields(f.db);
         if !fields.is_empty() {
-            f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
-            f.write_str("{\n")?;
+            f.write_str(" {\n")?;
             for field in self.fields(f.db) {
                 f.write_str("    ")?;
                 field.hir_fmt(f)?;
@@ -452,10 +446,7 @@ fn write_generic_params(
     Ok(())
 }
 
-fn write_where_clause(
-    def: GenericDefId,
-    f: &mut HirFormatter<'_>,
-) -> Result<bool, HirDisplayError> {
+fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
     let params = f.db.generic_params(def);
 
     // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
@@ -474,7 +465,7 @@ fn write_where_clause(
         });
 
     if !has_displayable_predicate {
-        return Ok(false);
+        return Ok(());
     }
 
     let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
@@ -552,7 +543,7 @@ fn write_where_clause(
     // End of final predicate. There must be at least one predicate here.
     f.write_char(',')?;
 
-    Ok(true)
+    Ok(())
 }
 
 impl HirDisplay for Const {
@@ -603,20 +594,19 @@ impl HirDisplay for Trait {
         write!(f, "trait {}", data.name.display(f.db.upcast()))?;
         let def_id = GenericDefId::TraitId(self.id);
         write_generic_params(def_id, f)?;
-        let has_where_clause = write_where_clause(def_id, f)?;
+        write_where_clause(def_id, f)?;
 
         if let Some(limit) = f.entity_limit {
             let assoc_items = self.items(f.db);
             let count = assoc_items.len().min(limit);
-            f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
             if count == 0 {
                 if assoc_items.is_empty() {
-                    f.write_str("{}")?;
+                    f.write_str(" {}")?;
                 } else {
-                    f.write_str("{ /* … */ }")?;
+                    f.write_str(" { /* … */ }")?;
                 }
             } else {
-                f.write_str("{\n")?;
+                f.write_str(" {\n")?;
                 for item in &assoc_items[..count] {
                     f.write_str("    ")?;
                     match item {
@@ -661,6 +651,7 @@ impl HirDisplay for TypeAlias {
         write!(f, "type {}", data.name.display(f.db.upcast()))?;
         let def_id = GenericDefId::TypeAliasId(self.id);
         write_generic_params(def_id, f)?;
+        write_where_clause(def_id, f)?;
         if !data.bounds.is_empty() {
             f.write_str(": ")?;
             f.write_joined(data.bounds.iter(), " + ")?;
@@ -669,7 +660,6 @@ impl HirDisplay for TypeAlias {
             f.write_str(" = ")?;
             ty.hir_fmt(f)?;
         }
-        write_where_clause(def_id, f)?;
         Ok(())
     }
 }
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b922aa8e46..b16ec5540c 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2617,15 +2617,6 @@ impl Macro {
         }
     }
 
-    pub fn is_env_or_option_env(&self, db: &dyn HirDatabase) -> bool {
-        match self.id {
-            MacroId::Macro2Id(it) => {
-                matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInEager(eager) if eager.is_env_or_option_env())
-            }
-            MacroId::MacroRulesId(_) | MacroId::ProcMacroId(_) => false,
-        }
-    }
-
     pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
         matches!(self.kind(db), MacroKind::Attr)
     }
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 9796009cb4..ca47b37d68 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -681,29 +681,28 @@ impl<'db> SemanticsImpl<'db> {
             .filter(|&(_, include_file_id)| include_file_id == file_id)
         {
             let macro_file = invoc.as_macro_file();
-            let expansion_info = cache.entry(macro_file).or_insert_with(|| {
-                let exp_info = macro_file.expansion_info(self.db.upcast());
-
-                let InMacroFile { file_id, value } = exp_info.expanded();
-                self.cache(value, file_id.into());
-
-                exp_info
-            });
+            let expansion_info = cache
+                .entry(macro_file)
+                .or_insert_with(|| macro_file.expansion_info(self.db.upcast()));
 
             // Create the source analyzer for the macro call scope
             let Some(sa) = self.analyze_no_infer(&self.parse_or_expand(expansion_info.call_file()))
             else {
                 continue;
             };
+            {
+                let InMacroFile { file_id: macro_file, value } = expansion_info.expanded();
+                self.cache(value, macro_file.into());
+            }
 
             // get mapped token in the include! macro file
-            let span = span::Span {
+            let span = span::SpanData {
                 range: token.text_range(),
                 anchor: span::SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID },
                 ctx: SyntaxContextId::ROOT,
             };
             let Some(InMacroFile { file_id, value: mut mapped_tokens }) =
-                expansion_info.map_range_down_exact(span)
+                expansion_info.map_range_down(span)
             else {
                 continue;
             };
@@ -754,20 +753,22 @@ impl<'db> SemanticsImpl<'db> {
         let def_map = sa.resolver.def_map();
 
         let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![(file_id, smallvec![token])];
+
         let mut process_expansion_for_token = |stack: &mut Vec<_>, macro_file| {
-            let exp_info = cache.entry(macro_file).or_insert_with(|| {
-                let exp_info = macro_file.expansion_info(self.db.upcast());
+            let expansion_info = cache
+                .entry(macro_file)
+                .or_insert_with(|| macro_file.expansion_info(self.db.upcast()));
 
-                let InMacroFile { file_id, value } = exp_info.expanded();
+            {
+                let InMacroFile { file_id, value } = expansion_info.expanded();
                 self.cache(value, file_id.into());
+            }
 
-                exp_info
-            });
-
-            let InMacroFile { file_id, value: mapped_tokens } = exp_info.map_range_down(span)?;
+            let InMacroFile { file_id, value: mapped_tokens } =
+                expansion_info.map_range_down(span)?;
             let mapped_tokens: SmallVec<[_; 2]> = mapped_tokens.collect();
 
-            // we have found a mapping for the token if the vec is non-empty
+            // if the length changed we have found a mapping for the token
             let res = mapped_tokens.is_empty().not().then_some(());
             // requeue the tokens we got from mapping our current token down
             stack.push((HirFileId::from(file_id), mapped_tokens));
@@ -850,13 +851,7 @@ impl<'db> SemanticsImpl<'db> {
                         // remove any other token in this macro input, all their mappings are the
                         // same as this one
                         tokens.retain(|t| !text_range.contains_range(t.text_range()));
-
-                        process_expansion_for_token(&mut stack, file_id).or(file_id
-                            .eager_arg(self.db.upcast())
-                            .and_then(|arg| {
-                                // also descend into eager expansions
-                                process_expansion_for_token(&mut stack, arg.as_macro_file())
-                            }))
+                        process_expansion_for_token(&mut stack, file_id)
                     } else if let Some(meta) = ast::Meta::cast(parent) {
                         // attribute we failed expansion for earlier, this might be a derive invocation
                         // or derive helper attribute
diff --git a/crates/ide-assists/src/handlers/extract_module.rs b/crates/ide-assists/src/handlers/extract_module.rs
index 42f935651c..af834c8a53 100644
--- a/crates/ide-assists/src/handlers/extract_module.rs
+++ b/crates/ide-assists/src/handlers/extract_module.rs
@@ -1,6 +1,5 @@
 use std::iter;
 
-use either::Either;
 use hir::{HasSource, HirFileIdExt, ModuleSource};
 use ide_db::{
     assists::{AssistId, AssistKind},
@@ -11,16 +10,17 @@ use ide_db::{
 };
 use itertools::Itertools;
 use smallvec::SmallVec;
+use stdx::format_to;
 use syntax::{
     algo::find_node_at_range,
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
-        make, HasVisibility,
+        make, HasName, HasVisibility,
     },
-    match_ast, ted, AstNode,
+    match_ast, ted, AstNode, SourceFile,
     SyntaxKind::{self, WHITESPACE},
-    SyntaxNode, TextRange, TextSize,
+    SyntaxNode, TextRange,
 };
 
 use crate::{AssistContext, Assists};
@@ -109,35 +109,76 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
 
             //We are getting item usages and record_fields together, record_fields
             //for change_visibility and usages for first point mentioned above in the process
-
-            let (usages_to_be_processed, record_fields, use_stmts_to_be_inserted) =
-                module.get_usages_and_record_fields(ctx);
-
-            builder.edit_file(ctx.file_id());
-            use_stmts_to_be_inserted.into_iter().for_each(|(_, use_stmt)| {
-                builder.insert(ctx.selection_trimmed().end(), format!("\n{use_stmt}"));
-            });
+            let (usages_to_be_processed, record_fields) = module.get_usages_and_record_fields(ctx);
 
             let import_paths_to_be_removed = module.resolve_imports(curr_parent_module, ctx);
             module.change_visibility(record_fields);
 
-            let module_def = generate_module_def(&impl_parent, &mut module, old_item_indent);
+            let mut body_items: Vec<String> = Vec::new();
+            let mut items_to_be_processed: Vec<ast::Item> = module.body_items.clone();
+
+            let new_item_indent = if impl_parent.is_some() {
+                old_item_indent + 2
+            } else {
+                items_to_be_processed = [module.use_items.clone(), items_to_be_processed].concat();
+                old_item_indent + 1
+            };
+
+            for item in items_to_be_processed {
+                let item = item.indent(IndentLevel(1));
+                let mut indented_item = String::new();
+                format_to!(indented_item, "{new_item_indent}{item}");
+                body_items.push(indented_item);
+            }
+
+            let mut body = body_items.join("\n\n");
+
+            if let Some(impl_) = &impl_parent {
+                let mut impl_body_def = String::new();
 
-            let mut usages_to_be_processed_for_cur_file = vec![];
-            for (file_id, usages) in usages_to_be_processed {
-                if file_id == ctx.file_id() {
-                    usages_to_be_processed_for_cur_file = usages;
+                if let Some(self_ty) = impl_.self_ty() {
+                    {
+                        let impl_indent = old_item_indent + 1;
+                        format_to!(
+                            impl_body_def,
+                            "{impl_indent}impl {self_ty} {{\n{body}\n{impl_indent}}}",
+                        );
+                    }
+                    body = impl_body_def;
+
+                    // Add the import for enum/struct corresponding to given impl block
+                    module.make_use_stmt_of_node_with_super(self_ty.syntax());
+                    for item in module.use_items {
+                        let item_indent = old_item_indent + 1;
+                        body = format!("{item_indent}{item}\n\n{body}");
+                    }
+                }
+            }
+
+            let mut module_def = String::new();
+
+            let module_name = module.name;
+            format_to!(module_def, "mod {module_name} {{\n{body}\n{old_item_indent}}}");
+
+            let mut usages_to_be_updated_for_curr_file = vec![];
+            for usages_to_be_updated_for_file in usages_to_be_processed {
+                if usages_to_be_updated_for_file.0 == ctx.file_id() {
+                    usages_to_be_updated_for_curr_file = usages_to_be_updated_for_file.1;
                     continue;
                 }
-                builder.edit_file(file_id);
-                for (text_range, usage) in usages {
-                    builder.replace(text_range, usage)
+                builder.edit_file(usages_to_be_updated_for_file.0);
+                for usage_to_be_processed in usages_to_be_updated_for_file.1 {
+                    builder.replace(usage_to_be_processed.0, usage_to_be_processed.1)
                 }
             }
 
             builder.edit_file(ctx.file_id());
-            for (text_range, usage) in usages_to_be_processed_for_cur_file {
-                builder.replace(text_range, usage);
+            for usage_to_be_processed in usages_to_be_updated_for_curr_file {
+                builder.replace(usage_to_be_processed.0, usage_to_be_processed.1)
+            }
+
+            for import_path_text_range in import_paths_to_be_removed {
+                builder.delete(import_path_text_range);
             }
 
             if let Some(impl_) = impl_parent {
@@ -158,51 +199,12 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
 
                 builder.insert(impl_.syntax().text_range().end(), format!("\n\n{module_def}"));
             } else {
-                for import_path_text_range in import_paths_to_be_removed {
-                    if module.text_range.intersect(import_path_text_range).is_some() {
-                        module.text_range = module.text_range.cover(import_path_text_range);
-                    } else {
-                        builder.delete(import_path_text_range);
-                    }
-                }
-
                 builder.replace(module.text_range, module_def)
             }
         },
     )
 }
 
-fn generate_module_def(
-    parent_impl: &Option<ast::Impl>,
-    module: &mut Module,
-    old_indent: IndentLevel,
-) -> String {
-    let (items_to_be_processed, new_item_indent) = if parent_impl.is_some() {
-        (Either::Left(module.body_items.iter()), old_indent + 2)
-    } else {
-        (Either::Right(module.use_items.iter().chain(module.body_items.iter())), old_indent + 1)
-    };
-
-    let mut body = items_to_be_processed
-        .map(|item| item.indent(IndentLevel(1)))
-        .map(|item| format!("{new_item_indent}{item}"))
-        .join("\n\n");
-
-    if let Some(self_ty) = parent_impl.as_ref().and_then(|imp| imp.self_ty()) {
-        let impl_indent = old_indent + 1;
-        body = format!("{impl_indent}impl {self_ty} {{\n{body}\n{impl_indent}}}");
-
-        // Add the import for enum/struct corresponding to given impl block
-        module.make_use_stmt_of_node_with_super(self_ty.syntax());
-        for item in module.use_items.iter() {
-            body = format!("{impl_indent}{item}\n\n{body}");
-        }
-    }
-
-    let module_name = module.name;
-    format!("mod {module_name} {{\n{body}\n{old_indent}}}")
-}
-
 #[derive(Debug)]
 struct Module {
     text_range: TextRange,
@@ -231,24 +233,20 @@ impl Module {
     fn get_usages_and_record_fields(
         &self,
         ctx: &AssistContext<'_>,
-    ) -> (FxHashMap<FileId, Vec<(TextRange, String)>>, Vec<SyntaxNode>, FxHashMap<TextSize, ast::Use>)
-    {
+    ) -> (FxHashMap<FileId, Vec<(TextRange, String)>>, Vec<SyntaxNode>) {
         let mut adt_fields = Vec::new();
         let mut refs: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
-        // use `TextSize` as key to avoid repeated use stmts
-        let mut use_stmts_to_be_inserted = FxHashMap::default();
 
         //Here impl is not included as each item inside impl will be tied to the parent of
         //implementing block(a struct, enum, etc), if the parent is in selected module, it will
         //get updated by ADT section given below or if it is not, then we dont need to do any operation
-
         for item in &self.body_items {
             match_ast! {
                 match (item.syntax()) {
                     ast::Adt(it) => {
                         if let Some( nod ) = ctx.sema.to_def(&it) {
                             let node_def = Definition::Adt(nod);
-                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
 
                             //Enum Fields are not allowed to explicitly specify pub, it is implied
                             match it {
@@ -282,30 +280,30 @@ impl Module {
                     ast::TypeAlias(it) => {
                         if let Some( nod ) = ctx.sema.to_def(&it) {
                             let node_def = Definition::TypeAlias(nod);
-                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
                         }
                     },
                     ast::Const(it) => {
                         if let Some( nod ) = ctx.sema.to_def(&it) {
                             let node_def = Definition::Const(nod);
-                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
                         }
                     },
                     ast::Static(it) => {
                         if let Some( nod ) = ctx.sema.to_def(&it) {
                             let node_def = Definition::Static(nod);
-                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
                         }
                     },
                     ast::Fn(it) => {
                         if let Some( nod ) = ctx.sema.to_def(&it) {
                             let node_def = Definition::Function(nod);
-                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs);
                         }
                     },
                     ast::Macro(it) => {
                         if let Some(nod) = ctx.sema.to_def(&it) {
-                            self.expand_and_group_usages_file_wise(ctx, Definition::Macro(nod), &mut refs, &mut use_stmts_to_be_inserted);
+                            self.expand_and_group_usages_file_wise(ctx, Definition::Macro(nod), &mut refs);
                         }
                     },
                     _ => (),
@@ -313,7 +311,7 @@ impl Module {
             }
         }
 
-        (refs, adt_fields, use_stmts_to_be_inserted)
+        (refs, adt_fields)
     }
 
     fn expand_and_group_usages_file_wise(
@@ -321,62 +319,49 @@ impl Module {
         ctx: &AssistContext<'_>,
         node_def: Definition,
         refs_in_files: &mut FxHashMap<FileId, Vec<(TextRange, String)>>,
-        use_stmts_to_be_inserted: &mut FxHashMap<TextSize, ast::Use>,
     ) {
-        let mod_name = self.name;
-        let covering_node = match ctx.covering_element() {
-            syntax::NodeOrToken::Node(node) => node,
-            syntax::NodeOrToken::Token(tok) => tok.parent().unwrap(), // won't panic
-        };
-        let out_of_sel = |node: &SyntaxNode| !self.text_range.contains_range(node.text_range());
-        let mut use_stmts_set = FxHashSet::default();
-
-        for (file_id, refs) in node_def.usages(&ctx.sema).all() {
+        for (file_id, references) in node_def.usages(&ctx.sema).all() {
             let source_file = ctx.sema.parse(file_id);
-            let usages = refs.into_iter().filter_map(|FileReference { range, .. }| {
-                // handle normal usages
-                let name_ref = find_node_at_range::<ast::NameRef>(source_file.syntax(), range)?;
-
-                if out_of_sel(name_ref.syntax()) {
-                    let new_ref = format!("{mod_name}::{name_ref}");
-                    return Some((range, new_ref));
-                } else if let Some(use_) = name_ref.syntax().ancestors().find_map(ast::Use::cast) {
-                    // handle usages in use_stmts which is in_sel
-                    // check if `use` is top stmt in selection
-                    if use_.syntax().parent().is_some_and(|parent| parent == covering_node)
-                        && use_stmts_set.insert(use_.syntax().text_range().start())
-                    {
-                        let use_ = use_stmts_to_be_inserted
-                            .entry(use_.syntax().text_range().start())
-                            .or_insert_with(|| use_.clone_subtree().clone_for_update());
-                        for seg in use_
-                            .syntax()
-                            .descendants()
-                            .filter_map(ast::NameRef::cast)
-                            .filter(|seg| seg.syntax().to_string() == name_ref.to_string())
-                        {
-                            let new_ref = make::path_from_text(&format!("{mod_name}::{seg}"))
-                                .clone_for_update();
-                            ted::replace(seg.syntax().parent()?, new_ref.syntax());
-                        }
-                    }
-                }
+            let usages_in_file = references
+                .into_iter()
+                .filter_map(|usage| self.get_usage_to_be_processed(&source_file, usage));
+            refs_in_files.entry(file_id).or_default().extend(usages_in_file);
+        }
+    }
 
-                None
-            });
-            refs_in_files.entry(file_id).or_default().extend(usages);
+    fn get_usage_to_be_processed(
+        &self,
+        source_file: &SourceFile,
+        FileReference { range, name, .. }: FileReference,
+    ) -> Option<(TextRange, String)> {
+        let path: ast::Path = find_node_at_range(source_file.syntax(), range)?;
+
+        for desc in path.syntax().descendants() {
+            if desc.to_string() == name.syntax().to_string()
+                && !self.text_range.contains_range(desc.text_range())
+            {
+                if let Some(name_ref) = ast::NameRef::cast(desc) {
+                    let mod_name = self.name;
+                    return Some((
+                        name_ref.syntax().text_range(),
+                        format!("{mod_name}::{name_ref}"),
+                    ));
+                }
+            }
         }
+
+        None
     }
 
     fn change_visibility(&mut self, record_fields: Vec<SyntaxNode>) {
         let (mut replacements, record_field_parents, impls) =
             get_replacements_for_visibility_change(&mut self.body_items, false);
 
-        let mut impl_items = impls
+        let mut impl_items: Vec<ast::Item> = impls
             .into_iter()
             .flat_map(|impl_| impl_.syntax().descendants())
             .filter_map(ast::Item::cast)
-            .collect_vec();
+            .collect();
 
         let (mut impl_item_replacements, _, _) =
             get_replacements_for_visibility_change(&mut impl_items, true);
@@ -409,88 +394,133 @@ impl Module {
 
     fn resolve_imports(
         &mut self,
-        module: Option<ast::Module>,
+        curr_parent_module: Option<ast::Module>,
         ctx: &AssistContext<'_>,
     ) -> Vec<TextRange> {
-        let mut imports_to_remove = vec![];
-        let mut node_set = FxHashSet::default();
+        let mut import_paths_to_be_removed: Vec<TextRange> = vec![];
+        let mut node_set: FxHashSet<String> = FxHashSet::default();
 
         for item in self.body_items.clone() {
-            item.syntax()
-                .descendants()
-                .filter_map(|x| {
-                    if let Some(name) = ast::Name::cast(x.clone()) {
-                        NameClass::classify(&ctx.sema, &name).and_then(|nc| match nc {
-                            NameClass::Definition(def) => Some((name.syntax().clone(), def)),
-                            _ => None,
-                        })
-                    } else if let Some(name_ref) = ast::NameRef::cast(x) {
-                        NameRefClass::classify(&ctx.sema, &name_ref).and_then(|nc| match nc {
-                            NameRefClass::Definition(def) => Some((name_ref.syntax().clone(), def)),
-                            _ => None,
-                        })
-                    } else {
-                        None
+            for x in item.syntax().descendants() {
+                if let Some(name) = ast::Name::cast(x.clone()) {
+                    if let Some(name_classify) = NameClass::classify(&ctx.sema, &name) {
+                        //Necessary to avoid two same names going through
+                        if !node_set.contains(&name.syntax().to_string()) {
+                            node_set.insert(name.syntax().to_string());
+                            let def_opt: Option<Definition> = match name_classify {
+                                NameClass::Definition(def) => Some(def),
+                                _ => None,
+                            };
+
+                            if let Some(def) = def_opt {
+                                if let Some(import_path) = self
+                                    .process_names_and_namerefs_for_import_resolve(
+                                        def,
+                                        name.syntax(),
+                                        &curr_parent_module,
+                                        ctx,
+                                    )
+                                {
+                                    check_intersection_and_push(
+                                        &mut import_paths_to_be_removed,
+                                        import_path,
+                                    );
+                                }
+                            }
+                        }
                     }
-                })
-                .for_each(|(node, def)| {
-                    if node_set.insert(node.to_string()) {
-                        if let Some(import) = self.process_def_in_sel(def, &node, &module, ctx) {
-                            check_intersection_and_push(&mut imports_to_remove, import);
+                }
+
+                if let Some(name_ref) = ast::NameRef::cast(x) {
+                    if let Some(name_classify) = NameRefClass::classify(&ctx.sema, &name_ref) {
+                        //Necessary to avoid two same names going through
+                        if !node_set.contains(&name_ref.syntax().to_string()) {
+                            node_set.insert(name_ref.syntax().to_string());
+                            let def_opt: Option<Definition> = match name_classify {
+                                NameRefClass::Definition(def) => Some(def),
+                                _ => None,
+                            };
+
+                            if let Some(def) = def_opt {
+                                if let Some(import_path) = self
+                                    .process_names_and_namerefs_for_import_resolve(
+                                        def,
+                                        name_ref.syntax(),
+                                        &curr_parent_module,
+                                        ctx,
+                                    )
+                                {
+                                    check_intersection_and_push(
+                                        &mut import_paths_to_be_removed,
+                                        import_path,
+                                    );
+                                }
+                            }
                         }
                     }
-                })
+                }
+            }
         }
 
-        imports_to_remove
+        import_paths_to_be_removed
     }
 
-    fn process_def_in_sel(
+    fn process_names_and_namerefs_for_import_resolve(
         &mut self,
         def: Definition,
-        use_node: &SyntaxNode,
+        node_syntax: &SyntaxNode,
         curr_parent_module: &Option<ast::Module>,
         ctx: &AssistContext<'_>,
     ) -> Option<TextRange> {
         //We only need to find in the current file
         let selection_range = ctx.selection_trimmed();
-        let file_id = ctx.file_id();
-        let usage_res = def.usages(&ctx.sema).in_scope(&SearchScope::single_file(file_id)).all();
-        let file = ctx.sema.parse(file_id);
-
-        // track uses which does not exists in `Use`
-        let mut uses_exist_in_sel = false;
-        let mut uses_exist_out_sel = false;
-        'outside: for (_, refs) in usage_res.iter() {
-            for x in refs
-                .iter()
-                .filter(|x| find_node_at_range::<ast::Use>(file.syntax(), x.range).is_none())
-                .filter_map(|x| find_node_at_range::<ast::Path>(file.syntax(), x.range))
-            {
-                let in_selection = selection_range.contains_range(x.syntax().text_range());
-                uses_exist_in_sel |= in_selection;
-                uses_exist_out_sel |= !in_selection;
-
-                if uses_exist_in_sel && uses_exist_out_sel {
-                    break 'outside;
+        let curr_file_id = ctx.file_id();
+        let search_scope = SearchScope::single_file(curr_file_id);
+        let usage_res = def.usages(&ctx.sema).in_scope(&search_scope).all();
+        let file = ctx.sema.parse(curr_file_id);
+
+        let mut exists_inside_sel = false;
+        let mut exists_outside_sel = false;
+        for (_, refs) in usage_res.iter() {
+            let mut non_use_nodes_itr = refs.iter().filter_map(|x| {
+                if find_node_at_range::<ast::Use>(file.syntax(), x.range).is_none() {
+                    let path_opt = find_node_at_range::<ast::Path>(file.syntax(), x.range);
+                    return path_opt;
                 }
+
+                None
+            });
+
+            if non_use_nodes_itr
+                .clone()
+                .any(|x| !selection_range.contains_range(x.syntax().text_range()))
+            {
+                exists_outside_sel = true;
+            }
+            if non_use_nodes_itr.any(|x| selection_range.contains_range(x.syntax().text_range())) {
+                exists_inside_sel = true;
             }
         }
 
-        let (def_in_mod, def_out_sel) =
-            check_def_in_mod_and_out_sel(def, ctx, curr_parent_module, selection_range, file_id);
+        let source_exists_outside_sel_in_same_mod = does_source_exists_outside_sel_in_same_mod(
+            def,
+            ctx,
+            curr_parent_module,
+            selection_range,
+            curr_file_id,
+        );
 
-        // Find use stmt that use def in current file
-        let use_stmt: Option<ast::Use> = usage_res
-            .into_iter()
-            .filter(|(use_file_id, _)| *use_file_id == file_id)
-            .flat_map(|(_, refs)| refs.into_iter().rev())
-            .find_map(|fref| find_node_at_range(file.syntax(), fref.range));
-        let use_stmt_not_in_sel = use_stmt.as_ref().is_some_and(|use_stmt| {
-            !selection_range.contains_range(use_stmt.syntax().text_range())
+        let use_stmt_opt: Option<ast::Use> = usage_res.into_iter().find_map(|(file_id, refs)| {
+            if file_id == curr_file_id {
+                refs.into_iter()
+                    .rev()
+                    .find_map(|fref| find_node_at_range(file.syntax(), fref.range))
+            } else {
+                None
+            }
         });
 
-        let mut use_tree_paths: Option<Vec<ast::Path>> = None;
+        let mut use_tree_str_opt: Option<Vec<ast::Path>> = None;
         //Exists inside and outside selection
         // - Use stmt for item is present -> get the use_tree_str and reconstruct the path in new
         // module
@@ -504,37 +534,37 @@ impl Module {
         //get the use_tree_str, reconstruct the use stmt in new module
 
         let mut import_path_to_be_removed: Option<TextRange> = None;
-        if uses_exist_in_sel && uses_exist_out_sel {
+        if exists_inside_sel && exists_outside_sel {
             //Changes to be made only inside new module
 
             //If use_stmt exists, find the use_tree_str, reconstruct it inside new module
             //If not, insert a use stmt with super and the given nameref
-            match self.process_use_stmt_for_import_resolve(use_stmt, use_node) {
-                Some((use_tree_str, _)) => use_tree_paths = Some(use_tree_str),
-                None if def_in_mod && def_out_sel => {
-                    //Considered only after use_stmt is not present
-                    //def_in_mod && def_out_sel | exists_outside_sel(exists_inside_sel =
-                    //true for all cases)
-                    // false | false -> Do nothing
-                    // false | true -> If source is in selection -> nothing to do, If source is outside
-                    // mod -> ust_stmt transversal
-                    // true  | false -> super import insertion
-                    // true  | true -> super import insertion
-                    self.make_use_stmt_of_node_with_super(use_node);
-                }
-                None => {}
+            if let Some((use_tree_str, _)) =
+                self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
+            {
+                use_tree_str_opt = Some(use_tree_str);
+            } else if source_exists_outside_sel_in_same_mod {
+                //Considered only after use_stmt is not present
+                //source_exists_outside_sel_in_same_mod | exists_outside_sel(exists_inside_sel =
+                //true for all cases)
+                // false | false -> Do nothing
+                // false | true -> If source is in selection -> nothing to do, If source is outside
+                // mod -> ust_stmt transversal
+                // true  | false -> super import insertion
+                // true  | true -> super import insertion
+                self.make_use_stmt_of_node_with_super(node_syntax);
             }
-        } else if uses_exist_in_sel && !uses_exist_out_sel {
+        } else if exists_inside_sel && !exists_outside_sel {
             //Changes to be made inside new module, and remove import from outside
 
             if let Some((mut use_tree_str, text_range_opt)) =
-                self.process_use_stmt_for_import_resolve(use_stmt, use_node)
+                self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
             {
                 if let Some(text_range) = text_range_opt {
                     import_path_to_be_removed = Some(text_range);
                 }
 
-                if def_in_mod && def_out_sel {
+                if source_exists_outside_sel_in_same_mod {
                     if let Some(first_path_in_use_tree) = use_tree_str.last() {
                         let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
                         if !first_path_in_use_tree_str.contains("super")
@@ -546,43 +576,31 @@ impl Module {
                     }
                 }
 
-                use_tree_paths = Some(use_tree_str);
-            } else if def_in_mod && def_out_sel {
-                self.make_use_stmt_of_node_with_super(use_node);
+                use_tree_str_opt = Some(use_tree_str);
+            } else if source_exists_outside_sel_in_same_mod {
+                self.make_use_stmt_of_node_with_super(node_syntax);
             }
         }
 
-        if let Some(mut use_tree_paths) = use_tree_paths {
-            use_tree_paths.reverse();
+        if let Some(use_tree_str) = use_tree_str_opt {
+            let mut use_tree_str = use_tree_str;
+            use_tree_str.reverse();
 
-            if uses_exist_out_sel || !uses_exist_in_sel || !def_in_mod || !def_out_sel {
-                if let Some(first_path_in_use_tree) = use_tree_paths.first() {
-                    if first_path_in_use_tree.to_string().contains("super") {
-                        use_tree_paths.insert(0, make::ext::ident_path("super"));
+            if !(!exists_outside_sel && exists_inside_sel && source_exists_outside_sel_in_same_mod)
+            {
+                if let Some(first_path_in_use_tree) = use_tree_str.first() {
+                    let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
+                    if first_path_in_use_tree_str.contains("super") {
+                        let super_path = make::ext::ident_path("super");
+                        use_tree_str.insert(0, super_path)
                     }
                 }
             }
 
-            let is_item = matches!(
-                def,
-                Definition::Macro(_)
-                    | Definition::Module(_)
-                    | Definition::Function(_)
-                    | Definition::Adt(_)
-                    | Definition::Const(_)
-                    | Definition::Static(_)
-                    | Definition::Trait(_)
-                    | Definition::TraitAlias(_)
-                    | Definition::TypeAlias(_)
-            );
-
-            if (def_out_sel || !is_item) && use_stmt_not_in_sel {
-                let use_ = make::use_(
-                    None,
-                    make::use_tree(make::join_paths(use_tree_paths), None, None, false),
-                );
-                self.use_items.insert(0, ast::Item::from(use_));
-            }
+            let use_ =
+                make::use_(None, make::use_tree(make::join_paths(use_tree_str), None, None, false));
+            let item = ast::Item::from(use_);
+            self.use_items.insert(0, item);
         }
 
         import_path_to_be_removed
@@ -603,26 +621,33 @@ impl Module {
 
     fn process_use_stmt_for_import_resolve(
         &self,
-        use_stmt: Option<ast::Use>,
+        use_stmt_opt: Option<ast::Use>,
         node_syntax: &SyntaxNode,
     ) -> Option<(Vec<ast::Path>, Option<TextRange>)> {
-        let use_stmt = use_stmt?;
-        for path_seg in use_stmt.syntax().descendants().filter_map(ast::PathSegment::cast) {
-            if path_seg.syntax().to_string() == node_syntax.to_string() {
-                let mut use_tree_str = vec![path_seg.parent_path()];
-                get_use_tree_paths_from_path(path_seg.parent_path(), &mut use_tree_str);
-
-                //Here we are looking for use_tree with same string value as node
-                //passed above as the range_to_remove function looks for a comma and
-                //then includes it in the text range to remove it. But the comma only
-                //appears at the use_tree level
-                for use_tree in path_seg.syntax().ancestors().filter_map(ast::UseTree::cast) {
-                    if use_tree.syntax().to_string() == node_syntax.to_string() {
-                        return Some((use_tree_str, Some(range_to_remove(use_tree.syntax()))));
+        if let Some(use_stmt) = use_stmt_opt {
+            for desc in use_stmt.syntax().descendants() {
+                if let Some(path_seg) = ast::PathSegment::cast(desc) {
+                    if path_seg.syntax().to_string() == node_syntax.to_string() {
+                        let mut use_tree_str = vec![path_seg.parent_path()];
+                        get_use_tree_paths_from_path(path_seg.parent_path(), &mut use_tree_str);
+                        for ancs in path_seg.syntax().ancestors() {
+                            //Here we are looking for use_tree with same string value as node
+                            //passed above as the range_to_remove function looks for a comma and
+                            //then includes it in the text range to remove it. But the comma only
+                            //appears at the use_tree level
+                            if let Some(use_tree) = ast::UseTree::cast(ancs) {
+                                if use_tree.syntax().to_string() == node_syntax.to_string() {
+                                    return Some((
+                                        use_tree_str,
+                                        Some(range_to_remove(use_tree.syntax())),
+                                    ));
+                                }
+                            }
+                        }
+
+                        return Some((use_tree_str, None));
                     }
                 }
-
-                return Some((use_tree_str, None));
             }
         }
 
@@ -651,58 +676,145 @@ fn check_intersection_and_push(
     import_paths_to_be_removed.push(import_path);
 }
 
-fn check_def_in_mod_and_out_sel(
+fn does_source_exists_outside_sel_in_same_mod(
     def: Definition,
     ctx: &AssistContext<'_>,
     curr_parent_module: &Option<ast::Module>,
     selection_range: TextRange,
     curr_file_id: FileId,
-) -> (bool, bool) {
-    macro_rules! check_item {
-        ($x:ident) => {
-            if let Some(source) = $x.source(ctx.db()) {
-                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
-                    ctx.sema.to_module_def(ast_module).is_some_and(|it| it == $x.module(ctx.db()))
-                } else {
-                    source.file_id.original_file(ctx.db()) == curr_file_id
-                };
-
-                let in_sel = !selection_range.contains_range(source.value.syntax().text_range());
-                return (have_same_parent, in_sel);
-            }
-        };
-    }
-
+) -> bool {
+    let mut source_exists_outside_sel_in_same_mod = false;
     match def {
         Definition::Module(x) => {
             let source = x.definition_source(ctx.db());
-            let have_same_parent = match (&curr_parent_module, x.parent(ctx.db())) {
-                (Some(ast_module), Some(hir_module)) => {
-                    ctx.sema.to_module_def(ast_module).is_some_and(|it| it == hir_module)
+            let have_same_parent = if let Some(ast_module) = &curr_parent_module {
+                if let Some(hir_module) = x.parent(ctx.db()) {
+                    compare_hir_and_ast_module(ast_module, hir_module, ctx).is_some()
+                } else {
+                    let source_file_id = source.file_id.original_file(ctx.db());
+                    source_file_id == curr_file_id
                 }
-                _ => source.file_id.original_file(ctx.db()) == curr_file_id,
+            } else {
+                let source_file_id = source.file_id.original_file(ctx.db());
+                source_file_id == curr_file_id
             };
 
             if have_same_parent {
                 if let ModuleSource::Module(module_) = source.value {
-                    let in_sel = !selection_range.contains_range(module_.syntax().text_range());
-                    return (have_same_parent, in_sel);
+                    source_exists_outside_sel_in_same_mod =
+                        !selection_range.contains_range(module_.syntax().text_range());
+                }
+            }
+        }
+        Definition::Function(x) => {
+            if let Some(source) = x.source(ctx.db()) {
+                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
+                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
+                } else {
+                    let source_file_id = source.file_id.original_file(ctx.db());
+                    source_file_id == curr_file_id
+                };
+
+                if have_same_parent {
+                    source_exists_outside_sel_in_same_mod =
+                        !selection_range.contains_range(source.value.syntax().text_range());
+                }
+            }
+        }
+        Definition::Adt(x) => {
+            if let Some(source) = x.source(ctx.db()) {
+                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
+                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
+                } else {
+                    let source_file_id = source.file_id.original_file(ctx.db());
+                    source_file_id == curr_file_id
+                };
+
+                if have_same_parent {
+                    source_exists_outside_sel_in_same_mod =
+                        !selection_range.contains_range(source.value.syntax().text_range());
+                }
+            }
+        }
+        Definition::Variant(x) => {
+            if let Some(source) = x.source(ctx.db()) {
+                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
+                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
+                } else {
+                    let source_file_id = source.file_id.original_file(ctx.db());
+                    source_file_id == curr_file_id
+                };
+
+                if have_same_parent {
+                    source_exists_outside_sel_in_same_mod =
+                        !selection_range.contains_range(source.value.syntax().text_range());
+                }
+            }
+        }
+        Definition::Const(x) => {
+            if let Some(source) = x.source(ctx.db()) {
+                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
+                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
+                } else {
+                    let source_file_id = source.file_id.original_file(ctx.db());
+                    source_file_id == curr_file_id
+                };
+
+                if have_same_parent {
+                    source_exists_outside_sel_in_same_mod =
+                        !selection_range.contains_range(source.value.syntax().text_range());
+                }
+            }
+        }
+        Definition::Static(x) => {
+            if let Some(source) = x.source(ctx.db()) {
+                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
+                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
+                } else {
+                    let source_file_id = source.file_id.original_file(ctx.db());
+                    source_file_id == curr_file_id
+                };
+
+                if have_same_parent {
+                    source_exists_outside_sel_in_same_mod =
+                        !selection_range.contains_range(source.value.syntax().text_range());
                 }
             }
+        }
+        Definition::Trait(x) => {
+            if let Some(source) = x.source(ctx.db()) {
+                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
+                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
+                } else {
+                    let source_file_id = source.file_id.original_file(ctx.db());
+                    source_file_id == curr_file_id
+                };
 
-            return (have_same_parent, false);
+                if have_same_parent {
+                    source_exists_outside_sel_in_same_mod =
+                        !selection_range.contains_range(source.value.syntax().text_range());
+                }
+            }
+        }
+        Definition::TypeAlias(x) => {
+            if let Some(source) = x.source(ctx.db()) {
+                let have_same_parent = if let Some(ast_module) = &curr_parent_module {
+                    compare_hir_and_ast_module(ast_module, x.module(ctx.db()), ctx).is_some()
+                } else {
+                    let source_file_id = source.file_id.original_file(ctx.db());
+                    source_file_id == curr_file_id
+                };
+
+                if have_same_parent {
+                    source_exists_outside_sel_in_same_mod =
+                        !selection_range.contains_range(source.value.syntax().text_range());
+                }
+            }
         }
-        Definition::Function(x) => check_item!(x),
-        Definition::Adt(x) => check_item!(x),
-        Definition::Variant(x) => check_item!(x),
-        Definition::Const(x) => check_item!(x),
-        Definition::Static(x) => check_item!(x),
-        Definition::Trait(x) => check_item!(x),
-        Definition::TypeAlias(x) => check_item!(x),
         _ => {}
     }
 
-    (false, false)
+    source_exists_outside_sel_in_same_mod
 }
 
 fn get_replacements_for_visibility_change(
@@ -722,30 +834,24 @@ fn get_replacements_for_visibility_change(
             *item = item.clone_for_update();
         }
         //Use stmts are ignored
-        macro_rules! push_to_replacement {
-            ($it:ident) => {
-                replacements.push(($it.visibility(), $it.syntax().clone()))
-            };
-        }
-
         match item {
-            ast::Item::Const(it) => push_to_replacement!(it),
-            ast::Item::Enum(it) => push_to_replacement!(it),
-            ast::Item::ExternCrate(it) => push_to_replacement!(it),
-            ast::Item::Fn(it) => push_to_replacement!(it),
+            ast::Item::Const(it) => replacements.push((it.visibility(), it.syntax().clone())),
+            ast::Item::Enum(it) => replacements.push((it.visibility(), it.syntax().clone())),
+            ast::Item::ExternCrate(it) => replacements.push((it.visibility(), it.syntax().clone())),
+            ast::Item::Fn(it) => replacements.push((it.visibility(), it.syntax().clone())),
             //Associated item's visibility should not be changed
             ast::Item::Impl(it) if it.for_token().is_none() => impls.push(it.clone()),
-            ast::Item::MacroDef(it) => push_to_replacement!(it),
-            ast::Item::Module(it) => push_to_replacement!(it),
-            ast::Item::Static(it) => push_to_replacement!(it),
+            ast::Item::MacroDef(it) => replacements.push((it.visibility(), it.syntax().clone())),
+            ast::Item::Module(it) => replacements.push((it.visibility(), it.syntax().clone())),
+            ast::Item::Static(it) => replacements.push((it.visibility(), it.syntax().clone())),
             ast::Item::Struct(it) => {
-                push_to_replacement!(it);
+                replacements.push((it.visibility(), it.syntax().clone()));
                 record_field_parents.push((it.visibility(), it.syntax().clone()));
             }
-            ast::Item::Trait(it) => push_to_replacement!(it),
-            ast::Item::TypeAlias(it) => push_to_replacement!(it),
+            ast::Item::Trait(it) => replacements.push((it.visibility(), it.syntax().clone())),
+            ast::Item::TypeAlias(it) => replacements.push((it.visibility(), it.syntax().clone())),
             ast::Item::Union(it) => {
-                push_to_replacement!(it);
+                replacements.push((it.visibility(), it.syntax().clone()));
                 record_field_parents.push((it.visibility(), it.syntax().clone()));
             }
             _ => (),
@@ -759,11 +865,8 @@ fn get_use_tree_paths_from_path(
     path: ast::Path,
     use_tree_str: &mut Vec<ast::Path>,
 ) -> Option<&mut Vec<ast::Path>> {
-    path.syntax()
-        .ancestors()
-        .filter(|x| x.to_string() != path.to_string())
-        .filter_map(ast::UseTree::cast)
-        .find_map(|use_tree| {
+    path.syntax().ancestors().filter(|x| x.to_string() != path.to_string()).find_map(|x| {
+        if let Some(use_tree) = ast::UseTree::cast(x) {
             if let Some(upper_tree_path) = use_tree.path() {
                 if upper_tree_path.to_string() != path.to_string() {
                     use_tree_str.push(upper_tree_path.clone());
@@ -771,8 +874,9 @@ fn get_use_tree_paths_from_path(
                     return Some(use_tree);
                 }
             }
-            None
-        })?;
+        }
+        None
+    })?;
 
     Some(use_tree_str)
 }
@@ -786,6 +890,20 @@ fn add_change_vis(vis: Option<ast::Visibility>, node_or_token_opt: Option<syntax
     }
 }
 
+fn compare_hir_and_ast_module(
+    ast_module: &ast::Module,
+    hir_module: hir::Module,
+    ctx: &AssistContext<'_>,
+) -> Option<()> {
+    let hir_mod_name = hir_module.name(ctx.db())?;
+    let ast_mod_name = ast_module.name()?;
+    if hir_mod_name.display(ctx.db()).to_string() != ast_mod_name.to_string() {
+        return None;
+    }
+
+    Some(())
+}
+
 fn indent_range_before_given_node(node: &SyntaxNode) -> Option<TextRange> {
     node.siblings_with_tokens(syntax::Direction::Prev)
         .find(|x| x.kind() == WHITESPACE)
@@ -1681,54 +1799,6 @@ mod modname {
         pub(crate) condvar: B,
     }
 }
-"#,
-        );
-    }
-
-    #[test]
-    fn test_remove_import_path_inside_selection() {
-        check_assist(
-            extract_module,
-            r#"
-$0struct Point;
-impl Point {
-    pub const fn direction(self, other: Self) -> Option<Direction> {
-        Some(Vertical)
-    }
-}
-
-pub enum Direction {
-    Horizontal,
-    Vertical,
-}
-use Direction::{Horizontal, Vertical};$0
-
-fn main() {
-    let x = Vertical;
-}
-"#,
-            r#"
-mod modname {
-    use Direction::{Horizontal, Vertical};
-
-    pub(crate) struct Point;
-
-    impl Point {
-        pub const fn direction(self, other: Self) -> Option<Direction> {
-            Some(Vertical)
-        }
-    }
-
-    pub enum Direction {
-        Horizontal,
-        Vertical,
-    }
-}
-use modname::Direction::{Horizontal, Vertical};
-
-fn main() {
-    let x = Vertical;
-}
 "#,
         );
     }
diff --git a/crates/ide-completion/src/completions/env_vars.rs b/crates/ide-completion/src/completions/env_vars.rs
index 4005753773..35e6b97eb7 100644
--- a/crates/ide-completion/src/completions/env_vars.rs
+++ b/crates/ide-completion/src/completions/env_vars.rs
@@ -1,10 +1,7 @@
 //! Completes environment variables defined by Cargo (https://doc.rust-lang.org/cargo/reference/environment-variables.html)
-use hir::MacroFileIdExt;
-use ide_db::syntax_helpers::node_ext::macro_call_for_string_token;
-use syntax::{
-    ast::{self, IsString},
-    AstToken,
-};
+use hir::Semantics;
+use ide_db::{syntax_helpers::node_ext::macro_call_for_string_token, RootDatabase};
+use syntax::ast::{self, IsString};
 
 use crate::{
     completions::Completions, context::CompletionContext, CompletionItem, CompletionItemKind,
@@ -35,24 +32,10 @@ const CARGO_DEFINED_VARS: &[(&str, &str)] = &[
 pub(crate) fn complete_cargo_env_vars(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
-    original: &ast::String,
     expanded: &ast::String,
 ) -> Option<()> {
-    let is_in_env_expansion = ctx
-        .sema
-        .hir_file_for(&expanded.syntax().parent()?)
-        .macro_file()
-        .map_or(false, |it| it.is_env_or_option_env(ctx.sema.db));
-    if !is_in_env_expansion {
-        let call = macro_call_for_string_token(expanded)?;
-        let makro = ctx.sema.resolve_macro_call(&call)?;
-        // We won't map into `option_env` as that generates `None` for non-existent env vars
-        // so fall back to this lookup
-        if !makro.is_env_or_option_env(ctx.sema.db) {
-            return None;
-        }
-    }
-    let range = original.text_range_between_quotes()?;
+    guard_env_macro(expanded, &ctx.sema)?;
+    let range = expanded.text_range_between_quotes()?;
 
     CARGO_DEFINED_VARS.iter().for_each(|&(var, detail)| {
         let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var);
@@ -63,6 +46,18 @@ pub(crate) fn complete_cargo_env_vars(
     Some(())
 }
 
+fn guard_env_macro(string: &ast::String, semantics: &Semantics<'_, RootDatabase>) -> Option<()> {
+    let call = macro_call_for_string_token(string)?;
+    let name = call.path()?.segment()?.name_ref()?;
+    let makro = semantics.resolve_macro_call(&call)?;
+    let db = semantics.db;
+
+    match name.text().as_str() {
+        "env" | "option_env" if makro.kind(db) == hir::MacroKind::BuiltIn => Some(()),
+        _ => None,
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_edit, completion_list};
@@ -73,7 +68,7 @@ mod tests {
             &format!(
                 r#"
             #[rustc_builtin_macro]
-            macro {macro_name} {{
+            macro_rules! {macro_name} {{
                 ($var:literal) => {{ 0 }}
             }}
 
@@ -85,7 +80,7 @@ mod tests {
             &format!(
                 r#"
             #[rustc_builtin_macro]
-            macro {macro_name} {{
+            macro_rules! {macro_name} {{
                 ($var:literal) => {{ 0 }}
             }}
 
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index d89cfc8b6c..912f2fba2b 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -207,7 +207,7 @@ pub fn completions(
             CompletionAnalysis::String { original, expanded: Some(expanded) } => {
                 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::env_vars::complete_cargo_env_vars(acc, ctx, expanded);
             }
             CompletionAnalysis::UnexpandedAttrTT {
                 colon_prefix,
diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs
index c0f0faba35..33970de1e4 100644
--- a/crates/ide-db/src/defs.rs
+++ b/crates/ide-db/src/defs.rs
@@ -407,7 +407,7 @@ impl NameClass {
     }
 
     pub fn classify(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<NameClass> {
-        let _p = tracing::span!(tracing::Level::INFO, "NameClass::classify").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "classify_name").entered();
 
         let parent = name.syntax().parent()?;
 
@@ -499,8 +499,7 @@ impl NameClass {
         sema: &Semantics<'_, RootDatabase>,
         lifetime: &ast::Lifetime,
     ) -> Option<NameClass> {
-        let _p = tracing::span!(tracing::Level::INFO, "NameClass::classify_lifetime", ?lifetime)
-            .entered();
+        let _p = tracing::span!(tracing::Level::INFO, "classify_lifetime", ?lifetime).entered();
         let parent = lifetime.syntax().parent()?;
 
         if let Some(it) = ast::LifetimeParam::cast(parent.clone()) {
@@ -591,8 +590,7 @@ impl NameRefClass {
         sema: &Semantics<'_, RootDatabase>,
         name_ref: &ast::NameRef,
     ) -> Option<NameRefClass> {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "NameRefClass::classify", ?name_ref).entered();
+        let _p = tracing::span!(tracing::Level::INFO, "classify_name_ref", ?name_ref).entered();
 
         let parent = name_ref.syntax().parent()?;
 
@@ -691,8 +689,7 @@ impl NameRefClass {
         sema: &Semantics<'_, RootDatabase>,
         lifetime: &ast::Lifetime,
     ) -> Option<NameRefClass> {
-        let _p = tracing::span!(tracing::Level::INFO, "NameRefClass::classify_lifetime", ?lifetime)
-            .entered();
+        let _p = tracing::span!(tracing::Level::INFO, "classify_lifetime_ref", ?lifetime).entered();
         let parent = lifetime.syntax().parent()?;
         match parent.kind() {
             SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => {
diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 34a0038295..6602aca2fa 100644
--- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -7,7 +7,11 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 // Diagnostic: need-mut
 //
 // This diagnostic is triggered on mutating an immutable variable.
-pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Diagnostic {
+pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option<Diagnostic> {
+    if d.span.file_id.macro_file().is_some() {
+        // FIXME: Our infra can't handle allow from within macro expansions rn
+        return None;
+    }
     let fixes = (|| {
         if d.local.is_ref(ctx.sema.db) {
             // There is no simple way to add `mut` to `ref x` and `ref mut x`
@@ -29,17 +33,19 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Diagno
             use_range,
         )])
     })();
-    Diagnostic::new_with_syntax_node_ptr(
-        ctx,
-        // FIXME: `E0384` is not the only error that this diagnostic handles
-        DiagnosticCode::RustcHardError("E0384"),
-        format!(
-            "cannot mutate immutable variable `{}`",
-            d.local.name(ctx.sema.db).display(ctx.sema.db)
-        ),
-        d.span,
+    Some(
+        Diagnostic::new_with_syntax_node_ptr(
+            ctx,
+            // FIXME: `E0384` is not the only error that this diagnostic handles
+            DiagnosticCode::RustcHardError("E0384"),
+            format!(
+                "cannot mutate immutable variable `{}`",
+                d.local.name(ctx.sema.db).display(ctx.sema.db)
+            ),
+            d.span,
+        )
+        .with_fixes(fixes),
     )
-    .with_fixes(fixes)
 }
 
 // Diagnostic: unused-mut
diff --git a/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
index 7a040e46e3..d831878044 100644
--- a/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
+++ b/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
@@ -12,7 +12,12 @@ use crate::{adjusted_display_range, fix, Diagnostic, DiagnosticCode, Diagnostics
 pub(crate) fn remove_trailing_return(
     ctx: &DiagnosticsContext<'_>,
     d: &RemoveTrailingReturn,
-) -> Diagnostic {
+) -> Option<Diagnostic> {
+    if d.return_expr.file_id.macro_file().is_some() {
+        // FIXME: Our infra can't handle allow from within macro expansions rn
+        return None;
+    }
+
     let display_range = adjusted_display_range(ctx, d.return_expr, &|return_expr| {
         return_expr
             .syntax()
@@ -20,12 +25,14 @@ pub(crate) fn remove_trailing_return(
             .and_then(ast::ExprStmt::cast)
             .map(|stmt| stmt.syntax().text_range())
     });
-    Diagnostic::new(
-        DiagnosticCode::Clippy("needless_return"),
-        "replace return <expr>; with <expr>",
-        display_range,
+    Some(
+        Diagnostic::new(
+            DiagnosticCode::Clippy("needless_return"),
+            "replace return <expr>; with <expr>",
+            display_range,
+        )
+        .with_fixes(fixes(ctx, d)),
     )
-    .with_fixes(fixes(ctx, d))
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveTrailingReturn) -> Option<Vec<Assist>> {
diff --git a/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
index f68e698238..073287d902 100644
--- a/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
+++ b/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
@@ -21,17 +21,24 @@ use crate::{
 pub(crate) fn remove_unnecessary_else(
     ctx: &DiagnosticsContext<'_>,
     d: &RemoveUnnecessaryElse,
-) -> Diagnostic {
+) -> Option<Diagnostic> {
+    if d.if_expr.file_id.macro_file().is_some() {
+        // FIXME: Our infra can't handle allow from within macro expansions rn
+        return None;
+    }
+
     let display_range = adjusted_display_range(ctx, d.if_expr, &|if_expr| {
         if_expr.else_token().as_ref().map(SyntaxToken::text_range)
     });
-    Diagnostic::new(
-        DiagnosticCode::Ra("remove-unnecessary-else", Severity::WeakWarning),
-        "remove unnecessary else block",
-        display_range,
+    Some(
+        Diagnostic::new(
+            DiagnosticCode::Ra("remove-unnecessary-else", Severity::WeakWarning),
+            "remove unnecessary else block",
+            display_range,
+        )
+        .experimental()
+        .with_fixes(fixes(ctx, d)),
     )
-    .experimental()
-    .with_fixes(fixes(ctx, d))
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveUnnecessaryElse) -> Option<Vec<Assist>> {
diff --git a/crates/ide-diagnostics/src/handlers/unused_variables.rs b/crates/ide-diagnostics/src/handlers/unused_variables.rs
index a9e1d07d7c..cd251faab9 100644
--- a/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -14,18 +14,24 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 pub(crate) fn unused_variables(
     ctx: &DiagnosticsContext<'_>,
     d: &hir::UnusedVariable,
-) -> Diagnostic {
+) -> Option<Diagnostic> {
     let ast = d.local.primary_source(ctx.sema.db).syntax_ptr();
+    if ast.file_id.macro_file().is_some() {
+        // FIXME: Our infra can't handle allow from within macro expansions rn
+        return None;
+    }
     let diagnostic_range = ctx.sema.diagnostics_display_range(ast);
     let var_name = d.local.primary_source(ctx.sema.db).syntax().to_string();
-    Diagnostic::new_with_syntax_node_ptr(
-        ctx,
-        DiagnosticCode::RustcLint("unused_variables"),
-        "unused variable",
-        ast,
+    Some(
+        Diagnostic::new_with_syntax_node_ptr(
+            ctx,
+            DiagnosticCode::RustcLint("unused_variables"),
+            "unused variable",
+            ast,
+        )
+        .with_fixes(fixes(&var_name, diagnostic_range, ast.file_id.is_macro()))
+        .experimental(),
     )
-    .with_fixes(fixes(&var_name, diagnostic_range, ast.file_id.is_macro()))
-    .experimental()
 }
 
 fn fixes(var_name: &String, diagnostic_range: FileRange, is_in_marco: bool) -> Option<Vec<Assist>> {
@@ -47,7 +53,7 @@ fn fixes(var_name: &String, diagnostic_range: FileRange, is_in_marco: bool) -> O
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::{check_diagnostics, check_fix, check_no_fix};
+    use crate::tests::{check_diagnostics, check_fix};
 
     #[test]
     fn unused_variables_simple() {
@@ -193,7 +199,7 @@ fn main() {
 
     #[test]
     fn no_fix_for_marco() {
-        check_no_fix(
+        check_diagnostics(
             r#"
 macro_rules! my_macro {
     () => {
@@ -202,7 +208,7 @@ macro_rules! my_macro {
 }
 
 fn main() {
-    $0my_macro!();
+    my_macro!();
 }
 "#,
         );
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 0df6f0e037..c5e52d104d 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -330,7 +330,6 @@ pub fn diagnostics(
     }
 
     for diag in diags {
-        #[rustfmt::skip]
         let d = match diag {
             AnyDiagnostic::ExpectedFunction(d) => handlers::expected_function::expected_function(&ctx, &d),
             AnyDiagnostic::InactiveCode(d) => match handlers::inactive_code::inactive_code(&ctx, &d) {
@@ -361,7 +360,10 @@ pub fn diagnostics(
             AnyDiagnostic::MissingMatchArms(d) => handlers::missing_match_arms::missing_match_arms(&ctx, &d),
             AnyDiagnostic::MissingUnsafe(d) => handlers::missing_unsafe::missing_unsafe(&ctx, &d),
             AnyDiagnostic::MovedOutOfRef(d) => handlers::moved_out_of_ref::moved_out_of_ref(&ctx, &d),
-            AnyDiagnostic::NeedMut(d) => handlers::mutability_errors::need_mut(&ctx, &d),
+            AnyDiagnostic::NeedMut(d) => match handlers::mutability_errors::need_mut(&ctx, &d) {
+                Some(it) => it,
+                None => continue,
+            },
             AnyDiagnostic::NonExhaustiveLet(d) => handlers::non_exhaustive_let::non_exhaustive_let(&ctx, &d),
             AnyDiagnostic::NoSuchField(d) => handlers::no_such_field::no_such_field(&ctx, &d),
             AnyDiagnostic::PrivateAssocItem(d) => handlers::private_assoc_item::private_assoc_item(&ctx, &d),
@@ -386,11 +388,20 @@ pub fn diagnostics(
             AnyDiagnostic::UnresolvedModule(d) => handlers::unresolved_module::unresolved_module(&ctx, &d),
             AnyDiagnostic::UnresolvedProcMacro(d) => handlers::unresolved_proc_macro::unresolved_proc_macro(&ctx, &d, config.proc_macros_enabled, config.proc_attr_macros_enabled),
             AnyDiagnostic::UnusedMut(d) => handlers::mutability_errors::unused_mut(&ctx, &d),
-            AnyDiagnostic::UnusedVariable(d) => handlers::unused_variables::unused_variables(&ctx, &d),
+            AnyDiagnostic::UnusedVariable(d) => match handlers::unused_variables::unused_variables(&ctx, &d) {
+                Some(it) => it,
+                None => continue,
+            },
             AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
             AnyDiagnostic::MismatchedTupleStructPatArgCount(d) => handlers::mismatched_arg_count::mismatched_tuple_struct_pat_arg_count(&ctx, &d),
-            AnyDiagnostic::RemoveTrailingReturn(d) => handlers::remove_trailing_return::remove_trailing_return(&ctx, &d),
-            AnyDiagnostic::RemoveUnnecessaryElse(d) => handlers::remove_unnecessary_else::remove_unnecessary_else(&ctx, &d),
+            AnyDiagnostic::RemoveTrailingReturn(d) => match handlers::remove_trailing_return::remove_trailing_return(&ctx, &d) {
+                Some(it) => it,
+                None => continue,
+            },
+            AnyDiagnostic::RemoveUnnecessaryElse(d) => match handlers::remove_unnecessary_else::remove_unnecessary_else(&ctx, &d) {
+                Some(it) => it,
+                None => continue,
+            },
         };
         res.push(d)
     }
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index ddeeca5f7b..1bda15255d 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,10 +1,10 @@
-use std::{iter, mem::discriminant};
+use std::mem::discriminant;
 
 use crate::{
     doc_links::token_as_doc_comment, navigation_target::ToNav, FilePosition, NavigationTarget,
     RangeInfo, TryToNav,
 };
-use hir::{AsAssocItem, AssocItem, DescendPreference, MacroFileIdExt, ModuleDef, Semantics};
+use hir::{AsAssocItem, AssocItem, DescendPreference, ModuleDef, Semantics};
 use ide_db::{
     base_db::{AnchoredPath, FileId, FileLoader},
     defs::{Definition, IdentClass},
@@ -74,13 +74,11 @@ pub(crate) fn goto_definition(
         .filter_map(|token| {
             let parent = token.parent()?;
 
-            if let Some(token) = ast::String::cast(token.clone()) {
-                if let Some(x) = try_lookup_include_path(sema, token, file_id) {
+            if let Some(tt) = ast::TokenTree::cast(parent.clone()) {
+                if let Some(x) = try_lookup_include_path(sema, tt, token.clone(), file_id) {
                     return Some(vec![x]);
                 }
-            }
 
-            if ast::TokenTree::can_cast(parent.kind()) {
                 if let Some(x) = try_lookup_macro_def_in_macro_use(sema, token) {
                     return Some(vec![x]);
                 }
@@ -113,17 +111,24 @@ pub(crate) fn goto_definition(
 
 fn try_lookup_include_path(
     sema: &Semantics<'_, RootDatabase>,
-    token: ast::String,
+    tt: ast::TokenTree,
+    token: SyntaxToken,
     file_id: FileId,
 ) -> Option<NavigationTarget> {
-    let file = sema.hir_file_for(&token.syntax().parent()?).macro_file()?;
-    if !iter::successors(Some(file), |file| file.parent(sema.db).macro_file())
-        // Check that we are in the eager argument expansion of an include macro
-        .any(|file| file.is_include_like_macro(sema.db) && file.eager_arg(sema.db).is_none())
-    {
+    let token = ast::String::cast(token)?;
+    let path = token.value()?.into_owned();
+    let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
+    let name = macro_call.path()?.segment()?.name_ref()?;
+    if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
         return None;
     }
-    let path = token.value()?;
+
+    // Ignore non-built-in macros to account for shadowing
+    if let Some(it) = sema.resolve_macro_call(&macro_call) {
+        if !matches!(it.kind(sema.db), hir::MacroKind::BuiltIn) {
+            return None;
+        }
+    }
 
     let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
     let size = sema.db.file_text(file_id).len().try_into().ok()?;
@@ -1526,26 +1531,6 @@ fn main() {
         );
     }
 
-    #[test]
-    fn goto_include_has_eager_input() {
-        check(
-            r#"
-//- /main.rs
-#[rustc_builtin_macro]
-macro_rules! include_str {}
-#[rustc_builtin_macro]
-macro_rules! concat {}
-
-fn main() {
-    let str = include_str!(concat!("foo", ".tx$0t"));
-}
-//- /foo.txt
-// empty
-//^file
-"#,
-        );
-    }
-
     #[test]
     fn goto_doc_include_str() {
         check(
diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs
index ac7f071178..d946ecc1ca 100644
--- a/crates/mbe/src/benchmark.rs
+++ b/crates/mbe/src/benchmark.rs
@@ -1,7 +1,6 @@
 //! This module add real world mbe example for benchmark tests
 
 use rustc_hash::FxHashMap;
-use span::Span;
 use syntax::{
     ast::{self, HasName},
     AstNode, SmolStr,
@@ -10,7 +9,7 @@ use test_utils::{bench, bench_fixture, skip_slow_tests};
 
 use crate::{
     parser::{MetaVarKind, Op, RepeatKind, Separator},
-    syntax_node_to_token_tree, DeclarativeMacro, DummyTestSpanMap, DUMMY,
+    syntax_node_to_token_tree, DeclarativeMacro, DummyTestSpanData, DummyTestSpanMap, DUMMY,
 };
 
 #[test]
@@ -51,14 +50,14 @@ fn benchmark_expand_macro_rules() {
     assert_eq!(hash, 69413);
 }
 
-fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro<Span>> {
+fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro<DummyTestSpanData>> {
     macro_rules_fixtures_tt()
         .into_iter()
         .map(|(id, tt)| (id, DeclarativeMacro::parse_macro_rules(&tt, true, true)))
         .collect()
 }
 
-fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::Subtree<Span>> {
+fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::Subtree<DummyTestSpanData>> {
     let fixture = bench_fixture::numerous_macro_rules();
     let source_file = ast::SourceFile::parse(&fixture).ok().unwrap();
 
@@ -80,8 +79,8 @@ fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::Subtree<Span>> {
 
 /// Generate random invocation fixtures from rules
 fn invocation_fixtures(
-    rules: &FxHashMap<String, DeclarativeMacro<Span>>,
-) -> Vec<(String, tt::Subtree<Span>)> {
+    rules: &FxHashMap<String, DeclarativeMacro<DummyTestSpanData>>,
+) -> Vec<(String, tt::Subtree<DummyTestSpanData>)> {
     let mut seed = 123456789;
     let mut res = Vec::new();
 
@@ -129,8 +128,8 @@ fn invocation_fixtures(
     return res;
 
     fn collect_from_op(
-        op: &Op<Span>,
-        token_trees: &mut Vec<tt::TokenTree<Span>>,
+        op: &Op<DummyTestSpanData>,
+        token_trees: &mut Vec<tt::TokenTree<DummyTestSpanData>>,
         seed: &mut usize,
     ) {
         return match op {
@@ -222,19 +221,19 @@ fn invocation_fixtures(
             *seed = usize::wrapping_add(usize::wrapping_mul(*seed, a), c);
             *seed
         }
-        fn make_ident(ident: &str) -> tt::TokenTree<Span> {
+        fn make_ident(ident: &str) -> tt::TokenTree<DummyTestSpanData> {
             tt::Leaf::Ident(tt::Ident { span: DUMMY, text: SmolStr::new(ident) }).into()
         }
-        fn make_punct(char: char) -> tt::TokenTree<Span> {
+        fn make_punct(char: char) -> tt::TokenTree<DummyTestSpanData> {
             tt::Leaf::Punct(tt::Punct { span: DUMMY, char, spacing: tt::Spacing::Alone }).into()
         }
-        fn make_literal(lit: &str) -> tt::TokenTree<Span> {
+        fn make_literal(lit: &str) -> tt::TokenTree<DummyTestSpanData> {
             tt::Leaf::Literal(tt::Literal { span: DUMMY, text: SmolStr::new(lit) }).into()
         }
         fn make_subtree(
             kind: tt::DelimiterKind,
-            token_trees: Option<Vec<tt::TokenTree<Span>>>,
-        ) -> tt::TokenTree<Span> {
+            token_trees: Option<Vec<tt::TokenTree<DummyTestSpanData>>>,
+        ) -> tt::TokenTree<DummyTestSpanData> {
             tt::Subtree {
                 delimiter: tt::Delimiter { open: DUMMY, close: DUMMY, kind },
                 token_trees: token_trees.map(Vec::into_boxed_slice).unwrap_or_default(),
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 57d6082dd7..cb8f8dff50 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -41,30 +41,32 @@ impl<S: Span, SM: SpanMapper<S>> SpanMapper<S> for &SM {
 /// Dummy things for testing where spans don't matter.
 pub(crate) mod dummy_test_span_utils {
 
-    use span::{Span, SyntaxContextId};
-
     use super::*;
 
-    pub const DUMMY: Span = Span {
+    pub type DummyTestSpanData = span::SpanData<DummyTestSyntaxContext>;
+    pub const DUMMY: DummyTestSpanData = span::SpanData {
         range: TextRange::empty(TextSize::new(0)),
         anchor: span::SpanAnchor {
             file_id: span::FileId::BOGUS,
             ast_id: span::ROOT_ERASED_FILE_AST_ID,
         },
-        ctx: SyntaxContextId::ROOT,
+        ctx: DummyTestSyntaxContext,
     };
 
+    #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+    pub struct DummyTestSyntaxContext;
+
     pub struct DummyTestSpanMap;
 
-    impl SpanMapper<Span> for DummyTestSpanMap {
-        fn span_for(&self, range: syntax::TextRange) -> Span {
-            Span {
+    impl SpanMapper<span::SpanData<DummyTestSyntaxContext>> for DummyTestSpanMap {
+        fn span_for(&self, range: syntax::TextRange) -> span::SpanData<DummyTestSyntaxContext> {
+            span::SpanData {
                 range,
                 anchor: span::SpanAnchor {
                     file_id: span::FileId::BOGUS,
                     ast_id: span::ROOT_ERASED_FILE_AST_ID,
                 },
-                ctx: SyntaxContextId::ROOT,
+                ctx: DummyTestSyntaxContext,
             }
         }
     }
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 1c5a862c70..ae58e6b9b2 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -56,6 +56,8 @@ fn integrated_highlighting_benchmark() {
         vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {path}"))
     };
 
+    let _g = crate::tracing::hprof::init("*>150");
+
     {
         let _it = stdx::timeit("initial");
         let analysis = host.analysis();
@@ -65,16 +67,13 @@ fn integrated_highlighting_benchmark() {
     {
         let _it = stdx::timeit("change");
         let mut text = host.analysis().file_text(file_id).unwrap().to_string();
-        text = text.replace(
-            "self.data.cargo_buildScripts_rebuildOnSave",
-            "self. data. cargo_buildScripts_rebuildOnSave",
-        );
+        text.push_str("\npub fn _dummy() {}\n");
         let mut change = ChangeWithProcMacros::new();
         change.change_file(file_id, Some(text));
         host.apply_change(change);
     }
 
-    let _g = crate::tracing::hprof::init("*>20");
+    let _g = crate::tracing::hprof::init("*>50");
 
     {
         let _it = stdx::timeit("after change");
diff --git a/crates/rust-analyzer/src/lsp/ext.rs b/crates/rust-analyzer/src/lsp/ext.rs
index 710ce7f8ac..86ab652f8e 100644
--- a/crates/rust-analyzer/src/lsp/ext.rs
+++ b/crates/rust-analyzer/src/lsp/ext.rs
@@ -234,13 +234,6 @@ impl Notification for EndRunTest {
     const METHOD: &'static str = "experimental/endRunTest";
 }
 
-pub enum AppendOutputToRunTest {}
-
-impl Notification for AppendOutputToRunTest {
-    type Params = String;
-    const METHOD: &'static str = "experimental/appendOutputToRunTest";
-}
-
 pub enum AbortRunTest {}
 
 impl Notification for AbortRunTest {
diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index e77d0c13bf..0423b2f4da 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -1519,28 +1519,13 @@ pub(crate) fn test_item(
         id: test_item.id,
         label: test_item.label,
         kind: match test_item.kind {
-            ide::TestItemKind::Crate(id) => 'b: {
-                let Some((cargo_ws, target)) = snap.cargo_target_for_crate_root(id) else {
-                    break 'b lsp_ext::TestItemKind::Package;
-                };
-                let target = &cargo_ws[target];
-                match target.kind {
-                    project_model::TargetKind::Bin
-                    | project_model::TargetKind::Lib { .. }
-                    | project_model::TargetKind::Example
-                    | project_model::TargetKind::BuildScript
-                    | project_model::TargetKind::Other => lsp_ext::TestItemKind::Package,
-                    project_model::TargetKind::Test | project_model::TargetKind::Bench => {
-                        lsp_ext::TestItemKind::Test
-                    }
-                }
-            }
+            ide::TestItemKind::Crate => lsp_ext::TestItemKind::Package,
             ide::TestItemKind::Module => lsp_ext::TestItemKind::Module,
             ide::TestItemKind::Function => lsp_ext::TestItemKind::Test,
         },
         can_resolve_children: matches!(
             test_item.kind,
-            ide::TestItemKind::Crate(_) | ide::TestItemKind::Module
+            ide::TestItemKind::Crate | ide::TestItemKind::Module
         ),
         parent: test_item.parent,
         text_document: test_item
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index ffe56e4143..e106a85c6e 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -799,9 +799,6 @@ impl GlobalState {
                 self.send_notification::<lsp_ext::EndRunTest>(());
                 self.test_run_session = None;
             }
-            flycheck::CargoTestMessage::Custom { text } => {
-                self.send_notification::<lsp_ext::AppendOutputToRunTest>(text);
-            }
         }
     }
 
diff --git a/crates/span/src/hygiene.rs b/crates/span/src/hygiene.rs
index e4b0a26a6f..4f6d792201 100644
--- a/crates/span/src/hygiene.rs
+++ b/crates/span/src/hygiene.rs
@@ -26,19 +26,9 @@ use salsa::{InternId, InternValue};
 use crate::MacroCallId;
 
 /// Interned [`SyntaxContextData`].
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct SyntaxContextId(InternId);
 
-impl fmt::Debug for SyntaxContextId {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if f.alternate() {
-            write!(f, "{}", self.0.as_u32())
-        } else {
-            f.debug_tuple("SyntaxContextId").field(&self.0).finish()
-        }
-    }
-}
-
 impl salsa::InternKey for SyntaxContextId {
     fn from_intern_id(v: salsa::InternId) -> Self {
         SyntaxContextId(v)
diff --git a/crates/span/src/lib.rs b/crates/span/src/lib.rs
index 6b849ce373..b2624762df 100644
--- a/crates/span/src/lib.rs
+++ b/crates/span/src/lib.rs
@@ -44,10 +44,7 @@ pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId =
 
 pub type Span = SpanData<SyntaxContextId>;
 
-/// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs
-/// together. Positions in spans are relative to some [`SpanAnchor`] to make them more incremental
-/// friendly.
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub struct SpanData<Ctx> {
     /// The text range of this span, relative to the anchor.
     /// We need the anchor for incrementality, as storing absolute ranges will require
@@ -59,26 +56,6 @@ pub struct SpanData<Ctx> {
     pub ctx: Ctx,
 }
 
-impl<Ctx: fmt::Debug> fmt::Debug for SpanData<Ctx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if f.alternate() {
-            fmt::Debug::fmt(&self.anchor.file_id.index(), f)?;
-            f.write_char(':')?;
-            fmt::Debug::fmt(&self.anchor.ast_id.into_raw(), f)?;
-            f.write_char('@')?;
-            fmt::Debug::fmt(&self.range, f)?;
-            f.write_char('#')?;
-            self.ctx.fmt(f)
-        } else {
-            f.debug_struct("SpanData")
-                .field("range", &self.range)
-                .field("anchor", &self.anchor)
-                .field("ctx", &self.ctx)
-                .finish()
-        }
-    }
-}
-
 impl<Ctx: Copy> SpanData<Ctx> {
     pub fn eq_ignoring_ctx(self, other: Self) -> bool {
         self.anchor == other.anchor && self.range == other.range
@@ -87,7 +64,7 @@ impl<Ctx: Copy> SpanData<Ctx> {
 
 impl Span {
     #[deprecated = "dummy spans will panic if surfaced incorrectly, as such they should be replaced appropriately"]
-    pub const DUMMY: Self = Self {
+    pub const DUMMY: Self = SpanData {
         range: TextRange::empty(TextSize::new(0)),
         anchor: SpanAnchor { file_id: FileId::BOGUS, ast_id: ROOT_ERASED_FILE_AST_ID },
         ctx: SyntaxContextId::ROOT,
diff --git a/crates/span/src/map.rs b/crates/span/src/map.rs
index 1f396a1e97..7b42551099 100644
--- a/crates/span/src/map.rs
+++ b/crates/span/src/map.rs
@@ -1,7 +1,7 @@
 //! A map that maps a span to every position in a file. Usually maps a span to some range of positions.
 //! Allows bidirectional lookup.
 
-use std::{fmt, hash::Hash};
+use std::hash::Hash;
 
 use stdx::{always, itertools::Itertools};
 use syntax::{TextRange, TextSize};
@@ -52,31 +52,12 @@ where
     /// Returns all [`TextRange`]s that correspond to the given span.
     ///
     /// Note this does a linear search through the entire backing vector.
-    pub fn ranges_with_span_exact(&self, span: SpanData<S>) -> impl Iterator<Item = TextRange> + '_
-    where
-        S: Copy,
-    {
-        self.spans.iter().enumerate().filter_map(move |(idx, &(end, s))| {
-            if !s.eq_ignoring_ctx(span) {
-                return None;
-            }
-            let start = idx.checked_sub(1).map_or(TextSize::new(0), |prev| self.spans[prev].0);
-            Some(TextRange::new(start, end))
-        })
-    }
-
-    /// Returns all [`TextRange`]s whose spans contain the given span.
-    ///
-    /// Note this does a linear search through the entire backing vector.
     pub fn ranges_with_span(&self, span: SpanData<S>) -> impl Iterator<Item = TextRange> + '_
     where
         S: Copy,
     {
         self.spans.iter().enumerate().filter_map(move |(idx, &(end, s))| {
-            if s.anchor != span.anchor {
-                return None;
-            }
-            if !s.range.contains_range(span.range) {
+            if !s.eq_ignoring_ctx(span) {
                 return None;
             }
             let start = idx.checked_sub(1).map_or(TextSize::new(0), |prev| self.spans[prev].0);
@@ -113,16 +94,6 @@ pub struct RealSpanMap {
     end: TextSize,
 }
 
-impl fmt::Display for RealSpanMap {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        writeln!(f, "RealSpanMap({:?}):", self.file_id)?;
-        for span in self.pairs.iter() {
-            writeln!(f, "{}: {}", u32::from(span.0), span.1.into_raw().into_u32())?;
-        }
-        Ok(())
-    }
-}
-
 impl RealSpanMap {
     /// Creates a real file span map that returns absolute ranges (relative ranges to the root ast id).
     pub fn absolute(file_id: FileId) -> Self {
diff --git a/crates/stdx/src/anymap.rs b/crates/stdx/src/anymap.rs
index d47b3d1647..899cd8ac6b 100644
--- a/crates/stdx/src/anymap.rs
+++ b/crates/stdx/src/anymap.rs
@@ -194,6 +194,21 @@ impl<'a, A: ?Sized + Downcast, V: IntoBox<A>> VacantEntry<'a, A, V> {
 mod tests {
     use super::*;
 
+    #[derive(Clone, Debug, PartialEq)]
+    struct A(i32);
+    #[derive(Clone, Debug, PartialEq)]
+    struct B(i32);
+    #[derive(Clone, Debug, PartialEq)]
+    struct C(i32);
+    #[derive(Clone, Debug, PartialEq)]
+    struct D(i32);
+    #[derive(Clone, Debug, PartialEq)]
+    struct E(i32);
+    #[derive(Clone, Debug, PartialEq)]
+    struct F(i32);
+    #[derive(Clone, Debug, PartialEq)]
+    struct J(i32);
+
     #[test]
     fn test_varieties() {
         fn assert_send<T: Send>() {}
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index c3d6f50e6b..1bc1ef8434 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -139,17 +139,6 @@ impl From<ast::AssocItem> for ast::Item {
     }
 }
 
-impl From<ast::ExternItem> for ast::Item {
-    fn from(extern_item: ast::ExternItem) -> Self {
-        match extern_item {
-            ast::ExternItem::Static(it) => ast::Item::Static(it),
-            ast::ExternItem::Fn(it) => ast::Item::Fn(it),
-            ast::ExternItem::MacroCall(it) => ast::Item::MacroCall(it),
-            ast::ExternItem::TypeAlias(it) => ast::Item::TypeAlias(it),
-        }
-    }
-}
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum AttrKind {
     Inner,
diff --git a/crates/tt/src/lib.rs b/crates/tt/src/lib.rs
index 28289a6431..eec88f8068 100644
--- a/crates/tt/src/lib.rs
+++ b/crates/tt/src/lib.rs
@@ -177,19 +177,17 @@ fn print_debug_subtree<S: fmt::Debug>(
     let align = "  ".repeat(level);
 
     let Delimiter { kind, open, close } = &subtree.delimiter;
-    let delim = match kind {
-        DelimiterKind::Invisible => "$$",
-        DelimiterKind::Parenthesis => "()",
-        DelimiterKind::Brace => "{}",
-        DelimiterKind::Bracket => "[]",
+    let aux = match kind {
+        DelimiterKind::Invisible => format!("$$ {:?} {:?}", open, close),
+        DelimiterKind::Parenthesis => format!("() {:?} {:?}", open, close),
+        DelimiterKind::Brace => format!("{{}} {:?} {:?}", open, close),
+        DelimiterKind::Bracket => format!("[] {:?} {:?}", open, close),
     };
 
-    write!(f, "{align}SUBTREE {delim} ",)?;
-    fmt::Debug::fmt(&open, f)?;
-    write!(f, " ")?;
-    fmt::Debug::fmt(&close, f)?;
-    if !subtree.token_trees.is_empty() {
-        writeln!(f)?;
+    if subtree.token_trees.is_empty() {
+        write!(f, "{align}SUBTREE {aux}")?;
+    } else {
+        writeln!(f, "{align}SUBTREE {aux}")?;
         for (idx, child) in subtree.token_trees.iter().enumerate() {
             print_debug_token(f, child, level + 1)?;
             if idx != subtree.token_trees.len() - 1 {
@@ -210,24 +208,16 @@ fn print_debug_token<S: fmt::Debug>(
 
     match tkn {
         TokenTree::Leaf(leaf) => match leaf {
-            Leaf::Literal(lit) => {
-                write!(f, "{}LITERAL {}", align, lit.text)?;
-                fmt::Debug::fmt(&lit.span, f)?;
-            }
-            Leaf::Punct(punct) => {
-                write!(
-                    f,
-                    "{}PUNCH   {} [{}] ",
-                    align,
-                    punct.char,
-                    if punct.spacing == Spacing::Alone { "alone" } else { "joint" },
-                )?;
-                fmt::Debug::fmt(&punct.span, f)?;
-            }
-            Leaf::Ident(ident) => {
-                write!(f, "{}IDENT   {} ", align, ident.text)?;
-                fmt::Debug::fmt(&ident.span, f)?;
-            }
+            Leaf::Literal(lit) => write!(f, "{}LITERAL {} {:?}", align, lit.text, lit.span)?,
+            Leaf::Punct(punct) => write!(
+                f,
+                "{}PUNCH   {} [{}] {:?}",
+                align,
+                punct.char,
+                if punct.spacing == Spacing::Alone { "alone" } else { "joint" },
+                punct.span
+            )?,
+            Leaf::Ident(ident) => write!(f, "{}IDENT   {} {:?}", align, ident.text, ident.span)?,
         },
         TokenTree::Subtree(subtree) => {
             print_debug_subtree(f, subtree, level)?;
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index cf9ad5fe04..af5b4e51ef 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp/ext.rs hash: 61f485497d6e8e88
+lsp/ext.rs hash: 6bc140531b403717
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
@@ -509,13 +509,6 @@ interface ChangeTestStateParams {
 }
 ```
 
-**Method:** `experimental/appendOutputToRunTest`
-
-**Notification:** `string`
-
-This notification is used for reporting messages independent of any single test and related to the run session
-in general, e.g. cargo compiling progress messages or warnings.
-
 ## Open External Documentation
 
 This request is sent from the client to the server to obtain web and local URL(s) for documentation related to the symbol under the cursor, if available.
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index bd8b0e9c4e..291cef926f 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -2290,9 +2290,9 @@
             "dev": true
         },
         "node_modules/follow-redirects": {
-            "version": "1.15.6",
-            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
-            "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
+            "version": "1.15.4",
+            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
+            "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
             "dev": true,
             "funding": [
                 {
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index ca8106371b..31ac3d9413 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -100,9 +100,6 @@ export const discoveredTests = new lc.NotificationType<DiscoverTestResults>(
 export const runTest = new lc.RequestType<RunTestParams, void, void>("experimental/runTest");
 export const abortRunTest = new lc.NotificationType0("experimental/abortRunTest");
 export const endRunTest = new lc.NotificationType0("experimental/endRunTest");
-export const appendOutputToRunTest = new lc.NotificationType<string>(
-    "experimental/appendOutputToRunTest",
-);
 export const changeTestState = new lc.NotificationType<ChangeTestStateParams>(
     "experimental/changeTestState",
 );


Test patch:
diff --git a/crates/flycheck/src/test_runner.rs b/crates/flycheck/src/test_runner.rs
index 31378716b3..6dac5899ee 100644
--- a/crates/flycheck/src/test_runner.rs
+++ b/crates/flycheck/src/test_runner.rs
@@ -28,20 +28,19 @@ pub enum CargoTestMessage {
     },
     Suite,
     Finished,
-    Custom {
-        text: String,
-    },
 }
 
 impl ParseFromLine for CargoTestMessage {
-    fn from_line(line: &str, _: &mut String) -> Option<Self> {
+    fn from_line(line: &str, error: &mut String) -> Option<Self> {
         let mut deserializer = serde_json::Deserializer::from_str(line);
         deserializer.disable_recursion_limit();
         if let Ok(message) = CargoTestMessage::deserialize(&mut deserializer) {
             return Some(message);
         }
 
-        Some(CargoTestMessage::Custom { text: line.to_owned() })
+        error.push_str(line);
+        error.push('\n');
+        None
     }
 
     fn from_eof() -> Option<Self> {
diff --git a/crates/hir-def/src/item_tree/tests.rs b/crates/hir-def/src/item_tree/tests.rs
index 48da876ac1..26f7b41c77 100644
--- a/crates/hir-def/src/item_tree/tests.rs
+++ b/crates/hir-def/src/item_tree/tests.rs
@@ -278,7 +278,7 @@ m!();
             // AstId: 2
             pub macro m2 { ... }
 
-            // AstId: 3, SyntaxContext: 0, ExpandTo: Items
+            // AstId: 3, Span: 0:3@0..5#0, ExpandTo: Items
             m!(...);
         "#]],
     );
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe.rs b/crates/hir-def/src/macro_expansion_tests/mbe.rs
index 965f329acb..edc8247f16 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -171,7 +171,7 @@ fn main(foo: ()) {
     }
 
     fn main(foo: ()) {
-        /* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#0#;
+        /* error: unresolved macro unresolved */"helloworld!"#0:3@207..323#2#;
     }
 }
 
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
index 23d8b023b8..63f211022c 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
@@ -33,7 +33,7 @@ m!(&k");
 "#,
         expect![[r#"
 macro_rules! m { ($i:literal) => {}; }
-/* error: expected literal */"#]],
+/* error: mismatched delimiters */"#]],
     );
 }
 
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs b/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
index fb5797d6e5..362c189f6a 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/tt_conversion.rs
@@ -98,7 +98,7 @@ macro_rules! m1 { ($x:ident) => { ($x } }
 macro_rules! m2 { ($x:ident) => {} }
 
 /* error: macro definition has parse errors */
-/* error: expected ident */
+/* error: mismatched delimiters */
 "#]],
     )
 }
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 4451e31870..051a96233a 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -819,7 +819,7 @@ fn foo(foo: Foo) {
 fn hover_tuple_struct() {
     check(
         r#"
-struct Foo$0(pub u32) where u32: Copy;
+struct Foo$0(pub u32)
 "#,
         expect![[r#"
             *Foo*
@@ -830,99 +830,7 @@ struct Foo$0(pub u32) where u32: Copy;
 
             ```rust
             // size = 4, align = 4
-            struct Foo(pub u32)
-            where
-                u32: Copy,
-            ```
-        "#]],
-    );
-}
-
-#[test]
-fn hover_record_struct() {
-    check(
-        r#"
-struct Foo$0 { field: u32 }
-"#,
-        expect![[r#"
-            *Foo*
-
-            ```rust
-            test
-            ```
-
-            ```rust
-            // size = 4, align = 4
-            struct Foo {
-                field: u32,
-            }
-            ```
-        "#]],
-    );
-    check(
-        r#"
-struct Foo$0 where u32: Copy { field: u32 }
-"#,
-        expect![[r#"
-            *Foo*
-
-            ```rust
-            test
-            ```
-
-            ```rust
-            // size = 4, align = 4
-            struct Foo
-            where
-                u32: Copy,
-            {
-                field: u32,
-            }
-            ```
-        "#]],
-    );
-}
-
-#[test]
-fn hover_unit_struct() {
-    check(
-        r#"
-struct Foo$0 where u32: Copy;
-"#,
-        expect![[r#"
-            *Foo*
-
-            ```rust
-            test
-            ```
-
-            ```rust
-            // size = 0, align = 1
-            struct Foo
-            where
-                u32: Copy,
-            ```
-        "#]],
-    );
-}
-
-#[test]
-fn hover_type_alias() {
-    check(
-        r#"
-type Fo$0o: Trait = S where T: Trait;
-"#,
-        expect![[r#"
-            *Foo*
-
-            ```rust
-            test
-            ```
-
-            ```rust
-            type Foo: Trait = S
-            where
-                T: Trait,
+            struct Foo(pub u32);
             ```
         "#]],
     );
@@ -2632,7 +2540,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; }
                                 focus_range: 7..10,
                                 name: "Arg",
                                 kind: Struct,
-                                description: "struct Arg(u32)",
+                                description: "struct Arg(u32);",
                             },
                         },
                         HoverGotoTypeData {
@@ -2691,7 +2599,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
                                 focus_range: 7..10,
                                 name: "Arg",
                                 kind: Struct,
-                                description: "struct Arg(u32)",
+                                description: "struct Arg(u32);",
                             },
                         },
                         HoverGotoTypeData {
@@ -2740,7 +2648,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
                                 focus_range: 7..8,
                                 name: "A",
                                 kind: Struct,
-                                description: "struct A(u32)",
+                                description: "struct A(u32);",
                             },
                         },
                         HoverGotoTypeData {
@@ -2753,7 +2661,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
                                 focus_range: 22..23,
                                 name: "B",
                                 kind: Struct,
-                                description: "struct B(u32)",
+                                description: "struct B(u32);",
                             },
                         },
                         HoverGotoTypeData {
@@ -2767,7 +2675,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); }
                                 name: "C",
                                 kind: Struct,
                                 container_name: "M",
-                                description: "pub struct C(u32)",
+                                description: "pub struct C(u32);",
                             },
                         },
                     ],
@@ -3423,26 +3331,26 @@ struct Foo<const BAR: Bar>;
 impl<const BAR: Bar> Foo<BAR$0> {}
 "#,
         expect![[r#"
-            [
-                GoToType(
-                    [
-                        HoverGotoTypeData {
-                            mod_path: "test::Bar",
-                            nav: NavigationTarget {
-                                file_id: FileId(
-                                    0,
-                                ),
-                                full_range: 0..11,
-                                focus_range: 7..10,
-                                name: "Bar",
-                                kind: Struct,
-                                description: "struct Bar",
+                [
+                    GoToType(
+                        [
+                            HoverGotoTypeData {
+                                mod_path: "test::Bar",
+                                nav: NavigationTarget {
+                                    file_id: FileId(
+                                        0,
+                                    ),
+                                    full_range: 0..11,
+                                    focus_range: 7..10,
+                                    name: "Bar",
+                                    kind: Struct,
+                                    description: "struct Bar",
+                                },
                             },
-                        },
-                    ],
-                ),
-            ]
-        "#]],
+                        ],
+                    ),
+                ]
+            "#]],
     );
 }
 
@@ -3488,26 +3396,26 @@ impl Foo {
 }
 "#,
         expect![[r#"
-            [
-                GoToType(
-                    [
-                        HoverGotoTypeData {
-                            mod_path: "test::Foo",
-                            nav: NavigationTarget {
-                                file_id: FileId(
-                                    0,
-                                ),
-                                full_range: 0..11,
-                                focus_range: 7..10,
-                                name: "Foo",
-                                kind: Struct,
-                                description: "struct Foo",
+                [
+                    GoToType(
+                        [
+                            HoverGotoTypeData {
+                                mod_path: "test::Foo",
+                                nav: NavigationTarget {
+                                    file_id: FileId(
+                                        0,
+                                    ),
+                                    full_range: 0..11,
+                                    focus_range: 7..10,
+                                    name: "Foo",
+                                    kind: Struct,
+                                    description: "struct Foo",
+                                },
                             },
-                        },
-                    ],
-                ),
-            ]
-        "#]],
+                        ],
+                    ),
+                ]
+            "#]],
     );
 }
 
@@ -3590,7 +3498,7 @@ struct S$0T<const C: usize = 1, T = Foo>(T);
             ```
 
             ```rust
-            struct ST<const C: usize = 1, T = Foo>(T)
+            struct ST<const C: usize = 1, T = Foo>(T);
             ```
         "#]],
     );
@@ -3611,7 +3519,7 @@ struct S$0T<const C: usize = {40 + 2}, T = Foo>(T);
             ```
 
             ```rust
-            struct ST<const C: usize = {const}, T = Foo>(T)
+            struct ST<const C: usize = {const}, T = Foo>(T);
             ```
         "#]],
     );
@@ -3633,7 +3541,7 @@ struct S$0T<const C: usize = VAL, T = Foo>(T);
             ```
 
             ```rust
-            struct ST<const C: usize = VAL, T = Foo>(T)
+            struct ST<const C: usize = VAL, T = Foo>(T);
             ```
         "#]],
     );
@@ -6023,26 +5931,26 @@ fn foo() {
 }
 "#,
         expect![[r#"
-            [
-                GoToType(
-                    [
-                        HoverGotoTypeData {
-                            mod_path: "test::Foo",
-                            nav: NavigationTarget {
-                                file_id: FileId(
-                                    0,
-                                ),
-                                full_range: 0..11,
-                                focus_range: 7..10,
-                                name: "Foo",
-                                kind: Struct,
-                                description: "struct Foo",
+                [
+                    GoToType(
+                        [
+                            HoverGotoTypeData {
+                                mod_path: "test::Foo",
+                                nav: NavigationTarget {
+                                    file_id: FileId(
+                                        0,
+                                    ),
+                                    full_range: 0..11,
+                                    focus_range: 7..10,
+                                    name: "Foo",
+                                    kind: Struct,
+                                    description: "struct Foo",
+                                },
                             },
-                        },
-                    ],
-                ),
-            ]
-        "#]],
+                        ],
+                    ),
+                ]
+            "#]],
     );
 }
 
@@ -6258,7 +6166,7 @@ pub struct Foo(i32);
 
             ```rust
             // size = 4, align = 4
-            pub struct Foo(i32)
+            pub struct Foo(i32);
             ```
 
             ---
@@ -6283,7 +6191,7 @@ pub struct Foo<T>(T);
             ```
 
             ```rust
-            pub struct Foo<T>(T)
+            pub struct Foo<T>(T);
             ```
 
             ---
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
index 32ac6a94d8..bcfe542410 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
@@ -94,7 +94,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="brace">}</span>
 
 
-<span class="macro default_library library">include</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro default_library library macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"foo/"</span><span class="string_literal macro">,</span> <span class="string_literal macro">"foo.rs"</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+<span class="macro default_library library">include</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"foo/"</span><span class="comma macro">,</span> <span class="string_literal macro">"foo.rs"</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</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="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">92</span><span class="comma macro">,</span><span class="parenthesis macro">)</span><span class="operator macro">.</span><span class="field library macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/test_explorer.rs b/crates/ide/src/test_explorer.rs
index ca47139970..2e741021ea 100644
--- a/crates/ide/src/test_explorer.rs
+++ b/crates/ide/src/test_explorer.rs
@@ -11,7 +11,7 @@ use crate::{navigation_target::ToNav, runnables::runnable_fn, Runnable, TryToNav
 
 #[derive(Debug)]
 pub enum TestItemKind {
-    Crate(CrateId),
+    Crate,
     Module,
     Function,
 }
@@ -32,17 +32,15 @@ pub(crate) fn discover_test_roots(db: &RootDatabase) -> Vec<TestItem> {
     crate_graph
         .iter()
         .filter(|&id| crate_graph[id].origin.is_local())
-        .filter_map(|id| {
-            let test_id = crate_graph[id].display_name.as_ref()?.to_string();
-            Some(TestItem {
-                kind: TestItemKind::Crate(id),
-                label: test_id.clone(),
-                id: test_id,
-                parent: None,
-                file: None,
-                text_range: None,
-                runnable: None,
-            })
+        .filter_map(|id| Some(crate_graph[id].display_name.as_ref()?.to_string()))
+        .map(|id| TestItem {
+            kind: TestItemKind::Crate,
+            label: id.clone(),
+            id,
+            parent: None,
+            file: None,
+            text_range: None,
+            runnable: None,
         })
         .collect()
 }
@@ -120,13 +118,12 @@ pub(crate) fn discover_tests_in_crate(db: &RootDatabase, crate_id: CrateId) -> V
     let Some(crate_test_id) = &crate_graph[crate_id].display_name else {
         return vec![];
     };
-    let kind = TestItemKind::Crate(crate_id);
     let crate_test_id = crate_test_id.to_string();
     let crate_id: Crate = crate_id.into();
     let module = crate_id.root_module();
     let mut r = vec![TestItem {
         id: crate_test_id.clone(),
-        kind,
+        kind: TestItemKind::Crate,
         label: crate_test_id.clone(),
         parent: None,
         file: None,
diff --git a/crates/mbe/src/syntax_bridge/tests.rs b/crates/mbe/src/syntax_bridge/tests.rs
index a261b1d431..11d1a72879 100644
--- a/crates/mbe/src/syntax_bridge/tests.rs
+++ b/crates/mbe/src/syntax_bridge/tests.rs
@@ -1,5 +1,4 @@
 use rustc_hash::FxHashMap;
-use span::Span;
 use syntax::{ast, AstNode};
 use test_utils::extract_annotations;
 use tt::{
@@ -7,7 +6,7 @@ use tt::{
     Leaf, Punct, Spacing,
 };
 
-use crate::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY};
+use crate::{syntax_node_to_token_tree, DummyTestSpanData, DummyTestSpanMap, DUMMY};
 
 fn check_punct_spacing(fixture: &str) {
     let source_file = ast::SourceFile::parse(fixture).ok().unwrap();
@@ -29,7 +28,7 @@ fn check_punct_spacing(fixture: &str) {
     while !cursor.eof() {
         while let Some(token_tree) = cursor.token_tree() {
             if let TokenTreeRef::Leaf(
-                Leaf::Punct(Punct { spacing, span: Span { range, .. }, .. }),
+                Leaf::Punct(Punct { spacing, span: DummyTestSpanData { range, .. }, .. }),
                 _,
             ) = token_tree
             {
diff --git a/crates/proc-macro-srv/src/tests/mod.rs b/crates/proc-macro-srv/src/tests/mod.rs
index 11b008fc0b..54a20357d2 100644
--- a/crates/proc-macro-srv/src/tests/mod.rs
+++ b/crates/proc-macro-srv/src/tests/mod.rs
@@ -8,12 +8,7 @@ use expect_test::expect;
 
 #[test]
 fn test_derive_empty() {
-    assert_expand(
-        "DeriveEmpty",
-        r#"struct S;"#,
-        expect!["SUBTREE $$ 1 1"],
-        expect!["SUBTREE $$ 42:2@0..100#0 42:2@0..100#0"],
-    );
+    assert_expand("DeriveEmpty", r#"struct S;"#, expect!["SUBTREE $$ 1 1"], expect!["SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"]);
 }
 
 #[test]
@@ -26,15 +21,15 @@ fn test_derive_error() {
               IDENT   compile_error 1
               PUNCH   ! [alone] 1
               SUBTREE () 1 1
-                LITERAL "#[derive(DeriveError)] struct S ;"1
+                LITERAL "#[derive(DeriveError)] struct S ;" 1
               PUNCH   ; [alone] 1"##]],
         expect![[r##"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   compile_error 42:2@0..100#0
-              PUNCH   ! [alone] 42:2@0..100#0
-              SUBTREE () 42:2@0..100#0 42:2@0..100#0
-                LITERAL "#[derive(DeriveError)] struct S ;"42:2@0..100#0
-              PUNCH   ; [alone] 42:2@0..100#0"##]],
+            SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              IDENT   compile_error SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   ! [alone] SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              SUBTREE () SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+                LITERAL "#[derive(DeriveError)] struct S ;" SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   ; [alone] SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"##]],
     );
 }
 
@@ -47,20 +42,20 @@ fn test_fn_like_macro_noop() {
             SUBTREE $$ 1 1
               IDENT   ident 1
               PUNCH   , [alone] 1
-              LITERAL 01
+              LITERAL 0 1
               PUNCH   , [alone] 1
-              LITERAL 11
+              LITERAL 1 1
               PUNCH   , [alone] 1
               SUBTREE [] 1 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   ident 42:2@0..5#0
-              PUNCH   , [alone] 42:2@5..6#0
-              LITERAL 042:2@7..8#0
-              PUNCH   , [alone] 42:2@8..9#0
-              LITERAL 142:2@10..11#0
-              PUNCH   , [alone] 42:2@11..12#0
-              SUBTREE [] 42:2@13..14#0 42:2@14..15#0"#]],
+            SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              IDENT   ident SpanData { range: 0..5, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 5..6, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 0 SpanData { range: 7..8, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 8..9, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 1 SpanData { range: 10..11, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 11..12, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              SUBTREE [] SpanData { range: 13..14, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 14..15, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"#]],
     );
 }
 
@@ -75,10 +70,10 @@ fn test_fn_like_macro_clone_ident_subtree() {
               PUNCH   , [alone] 1
               SUBTREE [] 1 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   ident 42:2@0..5#0
-              PUNCH   , [alone] 42:2@5..6#0
-              SUBTREE [] 42:2@7..8#0 42:2@7..8#0"#]],
+            SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              IDENT   ident SpanData { range: 0..5, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 5..6, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              SUBTREE [] SpanData { range: 7..8, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 7..8, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"#]],
     );
 }
 
@@ -91,8 +86,8 @@ fn test_fn_like_macro_clone_raw_ident() {
             SUBTREE $$ 1 1
               IDENT   r#async 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   r#async 42:2@0..7#0"#]],
+            SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              IDENT   r#async SpanData { range: 0..7, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"#]],
     );
 }
 
@@ -105,8 +100,8 @@ fn test_fn_like_fn_like_span_join() {
             SUBTREE $$ 1 1
               IDENT   r#joined 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   r#joined 42:2@0..11#0"#]],
+            SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              IDENT   r#joined SpanData { range: 0..11, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"#]],
     );
 }
 
@@ -121,10 +116,10 @@ fn test_fn_like_fn_like_span_ops() {
               IDENT   resolved_at_def_site 1
               IDENT   start_span 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   set_def_site 41:1@0..150#0
-              IDENT   resolved_at_def_site 42:2@13..33#0
-              IDENT   start_span 42:2@34..34#0"#]],
+            SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              IDENT   set_def_site SpanData { range: 0..150, anchor: SpanAnchor(FileId(41), 1), ctx: SyntaxContextId(0) }
+              IDENT   resolved_at_def_site SpanData { range: 13..33, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              IDENT   start_span SpanData { range: 34..34, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"#]],
     );
 }
 
@@ -135,22 +130,22 @@ fn test_fn_like_mk_literals() {
         r#""#,
         expect![[r#"
             SUBTREE $$ 1 1
-              LITERAL b"byte_string"1
-              LITERAL 'c'1
-              LITERAL "string"1
-              LITERAL 3.14f641
-              LITERAL 3.141
-              LITERAL 123i641
-              LITERAL 1231"#]],
+              LITERAL b"byte_string" 1
+              LITERAL 'c' 1
+              LITERAL "string" 1
+              LITERAL 3.14f64 1
+              LITERAL 3.14 1
+              LITERAL 123i64 1
+              LITERAL 123 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              LITERAL b"byte_string"42:2@0..100#0
-              LITERAL 'c'42:2@0..100#0
-              LITERAL "string"42:2@0..100#0
-              LITERAL 3.14f6442:2@0..100#0
-              LITERAL 3.1442:2@0..100#0
-              LITERAL 123i6442:2@0..100#0
-              LITERAL 12342:2@0..100#0"#]],
+            SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL b"byte_string" SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 'c' SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL "string" SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 3.14f64 SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 3.14 SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 123i64 SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 123 SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"#]],
     );
 }
 
@@ -164,9 +159,9 @@ fn test_fn_like_mk_idents() {
               IDENT   standard 1
               IDENT   r#raw 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   standard 42:2@0..100#0
-              IDENT   r#raw 42:2@0..100#0"#]],
+            SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              IDENT   standard SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              IDENT   r#raw SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"#]],
     );
 }
 
@@ -177,48 +172,48 @@ fn test_fn_like_macro_clone_literals() {
         r###"1u16, 2_u32, -4i64, 3.14f32, "hello bridge", "suffixed"suffix, r##"raw"##, 'a', b'b', c"null""###,
         expect![[r###"
             SUBTREE $$ 1 1
-              LITERAL 1u161
+              LITERAL 1u16 1
               PUNCH   , [alone] 1
-              LITERAL 2_u321
+              LITERAL 2_u32 1
               PUNCH   , [alone] 1
               PUNCH   - [alone] 1
-              LITERAL 4i641
+              LITERAL 4i64 1
               PUNCH   , [alone] 1
-              LITERAL 3.14f321
+              LITERAL 3.14f32 1
               PUNCH   , [alone] 1
-              LITERAL "hello bridge"1
+              LITERAL "hello bridge" 1
               PUNCH   , [alone] 1
-              LITERAL "suffixed"suffix1
+              LITERAL "suffixed"suffix 1
               PUNCH   , [alone] 1
-              LITERAL r##"raw"##1
+              LITERAL r##"raw"## 1
               PUNCH   , [alone] 1
-              LITERAL 'a'1
+              LITERAL 'a' 1
               PUNCH   , [alone] 1
-              LITERAL b'b'1
+              LITERAL b'b' 1
               PUNCH   , [alone] 1
-              LITERAL c"null"1"###]],
+              LITERAL c"null" 1"###]],
         expect![[r###"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              LITERAL 1u1642:2@0..4#0
-              PUNCH   , [alone] 42:2@4..5#0
-              LITERAL 2_u3242:2@6..11#0
-              PUNCH   , [alone] 42:2@11..12#0
-              PUNCH   - [alone] 42:2@13..14#0
-              LITERAL 4i6442:2@14..18#0
-              PUNCH   , [alone] 42:2@18..19#0
-              LITERAL 3.14f3242:2@20..27#0
-              PUNCH   , [alone] 42:2@27..28#0
-              LITERAL "hello bridge"42:2@29..43#0
-              PUNCH   , [alone] 42:2@43..44#0
-              LITERAL "suffixed"suffix42:2@45..61#0
-              PUNCH   , [alone] 42:2@61..62#0
-              LITERAL r##"raw"##42:2@63..73#0
-              PUNCH   , [alone] 42:2@73..74#0
-              LITERAL 'a'42:2@75..78#0
-              PUNCH   , [alone] 42:2@78..79#0
-              LITERAL b'b'42:2@80..84#0
-              PUNCH   , [alone] 42:2@84..85#0
-              LITERAL c"null"42:2@86..93#0"###]],
+            SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 1u16 SpanData { range: 0..4, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 4..5, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 2_u32 SpanData { range: 6..11, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 11..12, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   - [alone] SpanData { range: 13..14, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 4i64 SpanData { range: 14..18, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 18..19, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 3.14f32 SpanData { range: 20..27, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 27..28, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL "hello bridge" SpanData { range: 29..43, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 43..44, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL "suffixed"suffix SpanData { range: 45..61, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 61..62, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL r##"raw"## SpanData { range: 63..73, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 73..74, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL 'a' SpanData { range: 75..78, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 78..79, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL b'b' SpanData { range: 80..84, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   , [alone] SpanData { range: 84..85, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              LITERAL c"null" SpanData { range: 86..93, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"###]],
     );
 }
 
@@ -236,15 +231,15 @@ fn test_attr_macro() {
               IDENT   compile_error 1
               PUNCH   ! [alone] 1
               SUBTREE () 1 1
-                LITERAL "#[attr_error(some arguments)] mod m {}"1
+                LITERAL "#[attr_error(some arguments)] mod m {}" 1
               PUNCH   ; [alone] 1"##]],
         expect![[r##"
-            SUBTREE $$ 42:2@0..100#0 42:2@0..100#0
-              IDENT   compile_error 42:2@0..100#0
-              PUNCH   ! [alone] 42:2@0..100#0
-              SUBTREE () 42:2@0..100#0 42:2@0..100#0
-                LITERAL "#[attr_error(some arguments)] mod m {}"42:2@0..100#0
-              PUNCH   ; [alone] 42:2@0..100#0"##]],
+            SUBTREE $$ SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              IDENT   compile_error SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   ! [alone] SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              SUBTREE () SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) } SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+                LITERAL "#[attr_error(some arguments)] mod m {}" SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }
+              PUNCH   ; [alone] SpanData { range: 0..100, anchor: SpanAnchor(FileId(42), 2), ctx: SyntaxContextId(0) }"##]],
     );
 }
 
diff --git a/crates/proc-macro-srv/src/tests/utils.rs b/crates/proc-macro-srv/src/tests/utils.rs
index 6050bc9e36..9a1311d955 100644
--- a/crates/proc-macro-srv/src/tests/utils.rs
+++ b/crates/proc-macro-srv/src/tests/utils.rs
@@ -91,7 +91,7 @@ fn assert_expand_impl(
     let res = expander
         .expand(macro_name, fixture.into_subtree(call_site), attr, def_site, call_site, mixed_site)
         .unwrap();
-    expect_s.assert_eq(&format!("{res:#?}"));
+    expect_s.assert_eq(&format!("{res:?}"));
 }
 
 pub(crate) fn list() -> Vec<String> {
diff --git a/editors/code/src/test_explorer.ts b/editors/code/src/test_explorer.ts
index ac4ffb1926..2f0b4d5b5c 100644
--- a/editors/code/src/test_explorer.ts
+++ b/editors/code/src/test_explorer.ts
@@ -141,12 +141,6 @@ export const prepareTestExplorer = (
         }),
     );
 
-    ctx.pushClientCleanup(
-        client.onNotification(ra.appendOutputToRunTest, (output) => {
-            currentTestRun!.appendOutput(`${output}\r\n`);
-        }),
-    );
-
     ctx.pushClientCleanup(
         client.onNotification(ra.changeTestState, (results) => {
             const test = idToTestMap.get(results.testId)!;