about summary refs log tree commit diff
path: root/src/tools/rust-analyzer/crates/ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/ide/src')
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/annotations.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/annotations/fn_references.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/child_modules.rs123
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links/intra_doc_links.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/expand_macro.rs69
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/extend_selection.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs23
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/file_structure.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/fixture.rs34
-rwxr-xr-xsrc/tools/rust-analyzer/crates/ide/src/folding_ranges.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs268
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/highlight_related.rs120
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs117
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs646
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs95
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs41
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs50
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs60
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs233
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/interpret.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/join_lines.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs140
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/matching_brace.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/moniker.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/move_item.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/parent_module.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/references.rs44
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs57
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs47
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs213
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/ssr.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs146
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/status.rs254
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs62
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_19357.html46
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/test_explorer.rs39
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs63
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_hir.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_mir.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs4
72 files changed, 2011 insertions, 1555 deletions
diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
index e47891bbdfe..3d71da985b2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
@@ -1,17 +1,17 @@
 use hir::{HasSource, InFile, InRealFile, Semantics};
 use ide_db::{
-    defs::Definition, helpers::visit_file_defs, FileId, FilePosition, FileRange, FxIndexSet,
-    RootDatabase,
+    FileId, FilePosition, FileRange, FxIndexSet, RootDatabase, defs::Definition,
+    helpers::visit_file_defs,
 };
 use itertools::Itertools;
-use syntax::{ast::HasName, AstNode, TextRange};
+use syntax::{AstNode, TextRange, ast::HasName};
 
 use crate::{
+    NavigationTarget, RunnableKind,
     annotations::fn_references::find_all_methods,
     goto_implementation::goto_implementation,
     references::find_all_refs,
-    runnables::{runnables, Runnable},
-    NavigationTarget, RunnableKind,
+    runnables::{Runnable, runnables},
 };
 
 mod fn_references;
@@ -149,7 +149,7 @@ pub(crate) fn annotations(
             source_file_id: FileId,
         ) -> Option<(TextRange, Option<TextRange>)> {
             if let Some(InRealFile { file_id, value }) = node.original_ast_node_rooted(db) {
-                if file_id == source_file_id {
+                if file_id.file_id(db) == source_file_id {
                     return Some((
                         value.syntax().text_range(),
                         value.name().map(|name| name.syntax().text_range()),
@@ -209,9 +209,9 @@ fn should_skip_runnable(kind: &RunnableKind, binary_target: bool) -> bool {
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::{Expect, expect};
 
-    use crate::{fixture, Annotation, AnnotationConfig};
+    use crate::{Annotation, AnnotationConfig, fixture};
 
     use super::AnnotationLocation;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations/fn_references.rs b/src/tools/rust-analyzer/crates/ide/src/annotations/fn_references.rs
index 08cc10509cb..427a2eff820 100644
--- a/src/tools/rust-analyzer/crates/ide/src/annotations/fn_references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/annotations/fn_references.rs
@@ -4,7 +4,7 @@
 use hir::Semantics;
 use ide_assists::utils::test_related_attribute_syn;
 use ide_db::RootDatabase;
-use syntax::{ast, ast::HasName, AstNode, SyntaxNode, TextRange};
+use syntax::{AstNode, SyntaxNode, TextRange, ast, ast::HasName};
 
 use crate::FileId;
 
@@ -34,8 +34,8 @@ fn method_range(item: SyntaxNode) -> Option<(TextRange, Option<TextRange>)> {
 mod tests {
     use syntax::TextRange;
 
-    use crate::fixture;
     use crate::TextSize;
+    use crate::fixture;
     use std::ops::RangeInclusive;
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
index afd6f740c42..4b8d07a2533 100644
--- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
@@ -4,14 +4,14 @@ use std::iter;
 
 use hir::Semantics;
 use ide_db::{
+    FileRange, FxIndexMap, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
     helpers::pick_best_token,
     search::FileReference,
-    FileRange, FxIndexMap, RootDatabase,
 };
-use syntax::{ast, AstNode, SyntaxKind::IDENT};
+use syntax::{AstNode, SyntaxKind::IDENT, ast};
 
-use crate::{goto_definition, FilePosition, NavigationTarget, RangeInfo, TryToNav};
+use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav, goto_definition};
 
 #[derive(Debug, Clone)]
 pub struct CallItem {
@@ -76,9 +76,9 @@ pub(crate) fn incoming_calls(
                 }
 
                 let range = sema.original_range(name.syntax());
-                calls.add(nav.call_site, range.into());
+                calls.add(nav.call_site, range.into_file_id(db));
                 if let Some(other) = nav.def_site {
-                    calls.add(other, range.into());
+                    calls.add(other, range.into_file_id(db));
                 }
             }
         }
@@ -143,7 +143,7 @@ pub(crate) fn outgoing_calls(
             Some(nav_target.into_iter().zip(iter::repeat(range)))
         })
         .flatten()
-        .for_each(|(nav, range)| calls.add(nav, range.into()));
+        .for_each(|(nav, range)| calls.add(nav, range.into_file_id(db)));
 
     Some(calls.into_items())
 }
@@ -165,7 +165,7 @@ impl CallLocations {
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::{Expect, expect};
     use ide_db::FilePosition;
     use itertools::Itertools;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/child_modules.rs b/src/tools/rust-analyzer/crates/ide/src/child_modules.rs
new file mode 100644
index 00000000000..b781596187b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide/src/child_modules.rs
@@ -0,0 +1,123 @@
+use hir::Semantics;
+use ide_db::{FilePosition, RootDatabase};
+use syntax::{
+    algo::find_node_at_offset,
+    ast::{self, AstNode},
+};
+
+use crate::NavigationTarget;
+
+// Feature: Child Modules
+//
+// Navigates to the child modules of the current module.
+//
+// | Editor  | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: Locate child modules** |
+
+/// This returns `Vec` because a module may be included from several places.
+pub(crate) fn child_modules(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> {
+    let sema = Semantics::new(db);
+    let source_file = sema.parse_guess_edition(position.file_id);
+    // First go to the parent module which contains the cursor
+    let module = find_node_at_offset::<ast::Module>(source_file.syntax(), position.offset);
+
+    match module {
+        Some(module) => {
+            // Return all child modules inside the ItemList of the parent module
+            sema.to_def(&module)
+                .into_iter()
+                .flat_map(|module| module.children(db))
+                .map(|module| NavigationTarget::from_module_to_decl(db, module).call_site())
+                .collect()
+        }
+        None => {
+            // Return all the child modules inside the source file
+            sema.file_to_module_defs(position.file_id)
+                .flat_map(|module| module.children(db))
+                .map(|module| NavigationTarget::from_module_to_decl(db, module).call_site())
+                .collect()
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use ide_db::FileRange;
+
+    use crate::fixture;
+
+    fn check_child_module(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
+        let (analysis, position, expected) = fixture::annotations(ra_fixture);
+        let navs = analysis.child_modules(position).unwrap();
+        let navs = navs
+            .iter()
+            .map(|nav| FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
+            .collect::<Vec<_>>();
+        assert_eq!(expected.into_iter().map(|(fr, _)| fr).collect::<Vec<_>>(), navs);
+    }
+
+    #[test]
+    fn test_resolve_child_module() {
+        check_child_module(
+            r#"
+//- /lib.rs
+$0
+mod foo;
+  //^^^
+
+//- /foo.rs
+// empty
+"#,
+        );
+    }
+
+    #[test]
+    fn test_resolve_child_module_on_module_decl() {
+        check_child_module(
+            r#"
+//- /lib.rs
+mod $0foo;
+//- /foo.rs
+mod bar;
+  //^^^
+
+//- /foo/bar.rs
+// empty
+"#,
+        );
+    }
+
+    #[test]
+    fn test_resolve_child_module_for_inline() {
+        check_child_module(
+            r#"
+//- /lib.rs
+mod foo {
+    mod $0bar {
+        mod baz {}
+    }     //^^^
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_resolve_multi_child_module() {
+        check_child_module(
+            r#"
+//- /main.rs
+$0
+mod foo;
+  //^^^
+mod bar;
+  //^^^
+//- /foo.rs
+// empty
+
+//- /bar.rs
+// empty
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index 8d2ca33bf25..ebbd68bcdf7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -6,28 +6,29 @@ mod tests;
 mod intra_doc_links;
 
 use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
-use pulldown_cmark_to_cmark::{cmark_resume_with_options, Options as CMarkOptions};
+use pulldown_cmark_to_cmark::{Options as CMarkOptions, cmark_resume_with_options};
 use stdx::format_to;
 use url::Url;
 
-use hir::{db::HirDatabase, sym, Adt, AsAssocItem, AssocItem, AssocItemContainer, HasAttrs};
+use hir::{Adt, AsAssocItem, AssocItem, AssocItemContainer, HasAttrs, db::HirDatabase, sym};
 use ide_db::{
-    base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, SourceDatabase},
+    RootDatabase,
+    base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, RootQueryDb},
     defs::{Definition, NameClass, NameRefClass},
-    documentation::{docs_with_rangemap, Documentation, HasDocs},
+    documentation::{Documentation, HasDocs, docs_with_rangemap},
     helpers::pick_best_token,
-    RootDatabase,
 };
 use syntax::{
-    ast::{self, IsString},
-    match_ast, AstNode, AstToken,
+    AstNode, AstToken,
     SyntaxKind::*,
-    SyntaxNode, SyntaxToken, TextRange, TextSize, T,
+    SyntaxNode, SyntaxToken, T, TextRange, TextSize,
+    ast::{self, IsString},
+    match_ast,
 };
 
 use crate::{
-    doc_links::intra_doc_links::{parse_intra_doc_link, strip_prefixes_suffixes},
     FilePosition, Semantics,
+    doc_links::intra_doc_links::{parse_intra_doc_link, strip_prefixes_suffixes},
 };
 
 /// Web and local links to an item's documentation.
@@ -504,9 +505,7 @@ fn get_doc_base_urls(
 
     let Some(krate) = krate else { return Default::default() };
     let Some(display_name) = krate.display_name(db) else { return Default::default() };
-    let crate_data = &db.crate_graph()[krate.into()];
-
-    let (web_base, local_base) = match &crate_data.origin {
+    let (web_base, local_base) = match krate.origin(db) {
         // std and co do not specify `html_root_url` any longer so we gotta handwrite this ourself.
         // FIXME: Use the toolchains channel instead of nightly
         CrateOrigin::Lang(
@@ -598,7 +597,7 @@ fn filename_and_frag_for_def(
         Definition::Module(m) => match m.name(db) {
             // `#[doc(keyword = "...")]` is internal used only by rust compiler
             Some(name) => {
-                match m.attrs(db).by_key(&sym::doc).find_string_value_in_tt(&sym::keyword) {
+                match m.attrs(db).by_key(sym::doc).find_string_value_in_tt(sym::keyword) {
                     Some(kw) => {
                         format!("keyword.{}.html", kw)
                     }
@@ -628,7 +627,7 @@ fn filename_and_frag_for_def(
             return Some((def, file, Some(format!("variant.{}", ev.name(db).as_str()))));
         }
         Definition::Const(c) => {
-            format!("const.{}.html", c.name(db)?.as_str())
+            format!("constant.{}.html", c.name(db)?.as_str())
         }
         Definition::Static(s) => {
             format!("static.{}.html", s.name(db).as_str())
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/intra_doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/intra_doc_links.rs
index 6cc240d6524..c331734c785 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links/intra_doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/intra_doc_links.rs
@@ -53,7 +53,7 @@ pub(super) fn strip_prefixes_suffixes(s: &str) -> &str {
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::{Expect, expect};
 
     use super::*;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
index b09e3a3c804..91785be8d8b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
@@ -1,18 +1,19 @@
 use std::iter;
 
-use expect_test::{expect, Expect};
+use expect_test::{Expect, expect};
 use hir::Semantics;
 use ide_db::{
+    FilePosition, FileRange, RootDatabase,
     defs::Definition,
     documentation::{Documentation, HasDocs},
-    FilePosition, FileRange, RootDatabase,
 };
 use itertools::Itertools;
-use syntax::{ast, match_ast, AstNode, SyntaxNode};
+use syntax::{AstNode, SyntaxNode, ast, match_ast};
 
 use crate::{
+    TryToNav,
     doc_links::{extract_definitions_from_docs, resolve_doc_path_for_def, rewrite_links},
-    fixture, TryToNav,
+    fixture,
 };
 
 fn check_external_docs(
@@ -43,7 +44,7 @@ fn check_external_docs(
 
 fn check_rewrite(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
     let (analysis, position) = fixture::position(ra_fixture);
-    let sema = &Semantics::new(&*analysis.db);
+    let sema = &Semantics::new(&analysis.db);
     let (cursor_def, docs) = def_under_cursor(sema, &position);
     let res = rewrite_links(sema.db, docs.as_str(), cursor_def);
     expect.assert_eq(&res)
@@ -54,7 +55,7 @@ fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
 
     let (analysis, position, mut expected) = fixture::annotations(ra_fixture);
     expected.sort_by_key(key_fn);
-    let sema = &Semantics::new(&*analysis.db);
+    let sema = &Semantics::new(&analysis.db);
     let (cursor_def, docs) = def_under_cursor(sema, &position);
     let defs = extract_definitions_from_docs(&docs);
     let actual: Vec<_> = defs
@@ -683,7 +684,9 @@ fn rewrite_intra_doc_link_with_anchor() {
         //! $0[PartialEq#derivable]
         fn main() {}
         "#,
-        expect!["[PartialEq#derivable](https://doc.rust-lang.org/stable/core/cmp/trait.PartialEq.html#derivable)"],
+        expect![
+            "[PartialEq#derivable](https://doc.rust-lang.org/stable/core/cmp/trait.PartialEq.html#derivable)"
+        ],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index ad4308e06a1..241a702038d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -1,12 +1,12 @@
 use hir::db::ExpandDatabase;
-use hir::{ExpandResult, InFile, MacroFileIdExt, Semantics};
-use ide_db::base_db::CrateId;
+use hir::{ExpandResult, InFile, Semantics};
 use ide_db::{
-    helpers::pick_best_token, syntax_helpers::prettify_macro_expansion, FileId, RootDatabase,
+    FileId, RootDatabase, base_db::Crate, helpers::pick_best_token,
+    syntax_helpers::prettify_macro_expansion,
 };
-use span::{Edition, SpanMap, SyntaxContextId, TextRange, TextSize};
+use span::{Edition, SpanMap, SyntaxContext, TextRange, TextSize};
 use stdx::format_to;
-use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T};
+use syntax::{AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T, ast, ted};
 
 use crate::FilePosition;
 
@@ -99,7 +99,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
                         .display(
                             db,
                             sema.attach_first_edition(position.file_id)
-                                .map(|it| it.edition())
+                                .map(|it| it.edition(db))
                                 .unwrap_or(Edition::CURRENT),
                         )
                         .to_string(),
@@ -142,7 +142,7 @@ fn expand_macro_recur(
     sema: &Semantics<'_, RootDatabase>,
     macro_call: &ast::Item,
     error: &mut String,
-    result_span_map: &mut SpanMap<SyntaxContextId>,
+    result_span_map: &mut SpanMap<SyntaxContext>,
     offset_in_original_node: TextSize,
 ) -> Option<SyntaxNode> {
     let ExpandResult { value: expanded, err } = match macro_call {
@@ -170,7 +170,7 @@ fn expand(
     sema: &Semantics<'_, RootDatabase>,
     expanded: SyntaxNode,
     error: &mut String,
-    result_span_map: &mut SpanMap<SyntaxContextId>,
+    result_span_map: &mut SpanMap<SyntaxContext>,
     mut offset_in_original_node: i32,
 ) -> SyntaxNode {
     let children = expanded.descendants().filter_map(ast::Item::cast);
@@ -207,8 +207,8 @@ fn format(
     kind: SyntaxKind,
     file_id: FileId,
     expanded: SyntaxNode,
-    span_map: &SpanMap<SyntaxContextId>,
-    krate: CrateId,
+    span_map: &SpanMap<SyntaxContext>,
+    krate: Crate,
 ) -> String {
     let expansion = prettify_macro_expansion(db, expanded, span_map, krate).to_string();
 
@@ -234,7 +234,8 @@ fn _format(
     file_id: FileId,
     expansion: &str,
 ) -> Option<String> {
-    use ide_db::base_db::{FileLoader, SourceDatabase};
+    use ide_db::base_db::RootQueryDb;
+
     // hack until we get hygiene working (same character amount to preserve formatting as much as possible)
     const DOLLAR_CRATE_REPLACE: &str = "__r_a_";
     const BUILTIN_REPLACE: &str = "builtin__POUND";
@@ -249,7 +250,7 @@ fn _format(
     let expansion = format!("{prefix}{expansion}{suffix}");
 
     let &crate_id = db.relevant_crates(file_id).iter().next()?;
-    let edition = db.crate_graph()[crate_id].edition;
+    let edition = crate_id.data(db).edition;
 
     #[allow(clippy::disallowed_methods)]
     let mut cmd = std::process::Command::new(toolchain::Tool::Rustfmt.path());
@@ -289,7 +290,7 @@ fn _format(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::{Expect, expect};
 
     use crate::fixture;
 
@@ -550,7 +551,7 @@ macro_rules! foo {
 }
 
 fn main() {
-    let res = fo$0o!();
+    fo$0o!()
 }
 "#,
             expect![[r#"
@@ -560,6 +561,24 @@ fn main() {
     }
 
     #[test]
+    fn macro_expand_item_expansion_in_expression_call() {
+        check(
+            r#"
+macro_rules! foo {
+    () => {fn f<T>() {}};
+}
+
+fn main() {
+    let res = fo$0o!();
+}
+"#,
+            expect![[r#"
+                foo!
+                fn f<T>(){}"#]],
+        );
+    }
+
+    #[test]
     fn macro_expand_derive() {
         check(
             r#"
@@ -677,4 +696,26 @@ crate::Foo;
 crate::Foo;"#]],
         );
     }
+
+    #[test]
+    fn semi_glueing() {
+        check(
+            r#"
+macro_rules! __log_value {
+    ($key:ident :$capture:tt =) => {};
+}
+
+macro_rules! __log {
+    ($key:tt $(:$capture:tt)? $(= $value:expr)?; $($arg:tt)+) => {
+        __log_value!($key $(:$capture)* = $($value)*);
+    };
+}
+
+__log!(written:%; "Test"$0);
+    "#,
+            expect![[r#"
+                __log!
+            "#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
index 76414854e91..a374f9752fc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
@@ -3,11 +3,11 @@ use std::iter::successors;
 use hir::Semantics;
 use ide_db::RootDatabase;
 use syntax::{
-    algo::{self, skip_trivia_token},
-    ast::{self, AstNode, AstToken},
     Direction, NodeOrToken,
     SyntaxKind::{self, *},
-    SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, T,
+    SyntaxNode, SyntaxToken, T, TextRange, TextSize, TokenAtOffset,
+    algo::{self, skip_trivia_token},
+    ast::{self, AstNode, AstToken},
 };
 
 use crate::FileRange;
@@ -178,11 +178,7 @@ fn extend_tokens_from_range(
     .last()?;
 
     let range = first.text_range().cover(last.text_range());
-    if range.contains_range(original_range) && original_range != range {
-        Some(range)
-    } else {
-        None
-    }
+    if range.contains_range(original_range) && original_range != range { Some(range) } else { None }
 }
 
 /// Find the shallowest node with same range, which allows us to traverse siblings.
@@ -216,11 +212,7 @@ fn extend_single_word_in_comment_or_string(
     let to: TextSize = (cursor_position + end_idx).into();
 
     let range = TextRange::new(from, to);
-    if range.is_empty() {
-        None
-    } else {
-        Some(range + leaf.text_range().start())
-    }
+    if range.is_empty() { None } else { Some(range + leaf.text_range().start()) }
 }
 
 fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextSize) -> TextRange {
diff --git a/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs b/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
index 5ed21444307..956379e722d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
@@ -1,6 +1,6 @@
 use ide_db::{
-    base_db::{CrateOrigin, SourceDatabase},
     FileId, FxIndexSet, RootDatabase,
+    base_db::{CrateOrigin, RootQueryDb},
 };
 
 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -20,21 +20,24 @@ pub struct CrateInfo {
 //
 // ![Show Dependency Tree](https://user-images.githubusercontent.com/5748995/229394139-2625beab-f4c9-484b-84ed-ad5dee0b1e1a.png)
 pub(crate) fn fetch_crates(db: &RootDatabase) -> FxIndexSet<CrateInfo> {
-    let crate_graph = db.crate_graph();
-    crate_graph
+    db.all_crates()
         .iter()
-        .map(|crate_id| &crate_graph[crate_id])
-        .filter(|&data| !matches!(data.origin, CrateOrigin::Local { .. }))
-        .map(crate_info)
+        .copied()
+        .map(|crate_id| (crate_id.data(db), crate_id.extra_data(db)))
+        .filter(|(data, _)| !matches!(data.origin, CrateOrigin::Local { .. }))
+        .map(|(data, extra_data)| crate_info(data, extra_data))
         .collect()
 }
 
-fn crate_info(data: &ide_db::base_db::CrateData) -> CrateInfo {
-    let crate_name = crate_name(data);
-    let version = data.version.clone();
+fn crate_info(
+    data: &ide_db::base_db::BuiltCrateData,
+    extra_data: &ide_db::base_db::ExtraCrateData,
+) -> CrateInfo {
+    let crate_name = crate_name(extra_data);
+    let version = extra_data.version.clone();
     CrateInfo { name: crate_name, version, root_file_id: data.root_file_id }
 }
 
-fn crate_name(data: &ide_db::base_db::CrateData) -> Option<String> {
+fn crate_name(data: &ide_db::base_db::ExtraCrateData) -> Option<String> {
     data.display_name.as_ref().map(|it| it.canonical_name().as_str().to_owned())
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
index 52fbab6fa12..347da4e85b4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
@@ -1,8 +1,8 @@
 use ide_db::SymbolKind;
 use syntax::{
+    AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, TextRange, WalkEvent,
     ast::{self, HasAttrs, HasGenericParams, HasName},
-    match_ast, AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, TextRange,
-    WalkEvent,
+    match_ast,
 };
 
 #[derive(Debug, Clone)]
@@ -250,7 +250,7 @@ fn structure_token(token: SyntaxToken) -> Option<StructureNode> {
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::{Expect, expect};
 
     use super::*;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/fixture.rs b/src/tools/rust-analyzer/crates/ide/src/fixture.rs
index a0612f48d37..fbf89042fae 100644
--- a/src/tools/rust-analyzer/crates/ide/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/fixture.rs
@@ -1,16 +1,16 @@
 //! Utilities for creating `Analysis` instances for tests.
 use test_fixture::ChangeFixture;
-use test_utils::{extract_annotations, RangeOrOffset};
+use test_utils::{RangeOrOffset, extract_annotations};
 
 use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange};
 
 /// Creates analysis for a single file.
 pub(crate) fn file(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Analysis, FileId) {
     let mut host = AnalysisHost::default();
-    let change_fixture = ChangeFixture::parse(ra_fixture);
+    let change_fixture = ChangeFixture::parse(&host.db, ra_fixture);
     host.db.enable_proc_attr_macros();
     host.db.apply_change(change_fixture.change);
-    (host.analysis(), change_fixture.files[0].into())
+    (host.analysis(), change_fixture.files[0].file_id(&host.db))
 }
 
 /// Creates analysis from a multi-file fixture, returns positions marked with $0.
@@ -18,23 +18,23 @@ pub(crate) fn position(
     #[rust_analyzer::rust_fixture] ra_fixture: &str,
 ) -> (Analysis, FilePosition) {
     let mut host = AnalysisHost::default();
-    let change_fixture = ChangeFixture::parse(ra_fixture);
+    let change_fixture = ChangeFixture::parse(&host.db, ra_fixture);
     host.db.enable_proc_attr_macros();
     host.db.apply_change(change_fixture.change);
     let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
     let offset = range_or_offset.expect_offset();
-    (host.analysis(), FilePosition { file_id: file_id.into(), offset })
+    (host.analysis(), FilePosition { file_id: file_id.file_id(&host.db), offset })
 }
 
 /// Creates analysis for a single file, returns range marked with a pair of $0.
 pub(crate) fn range(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Analysis, FileRange) {
     let mut host = AnalysisHost::default();
-    let change_fixture = ChangeFixture::parse(ra_fixture);
+    let change_fixture = ChangeFixture::parse(&host.db, ra_fixture);
     host.db.enable_proc_attr_macros();
     host.db.apply_change(change_fixture.change);
     let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
     let range = range_or_offset.expect_range();
-    (host.analysis(), FileRange { file_id: file_id.into(), range })
+    (host.analysis(), FileRange { file_id: file_id.file_id(&host.db), range })
 }
 
 /// Creates analysis for a single file, returns range marked with a pair of $0 or a position marked with $0.
@@ -42,11 +42,11 @@ pub(crate) fn range_or_position(
     #[rust_analyzer::rust_fixture] ra_fixture: &str,
 ) -> (Analysis, FileId, RangeOrOffset) {
     let mut host = AnalysisHost::default();
-    let change_fixture = ChangeFixture::parse(ra_fixture);
+    let change_fixture = ChangeFixture::parse(&host.db, ra_fixture);
     host.db.enable_proc_attr_macros();
     host.db.apply_change(change_fixture.change);
     let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
-    (host.analysis(), file_id.into(), range_or_offset)
+    (host.analysis(), file_id.file_id(&host.db), range_or_offset)
 }
 
 /// Creates analysis from a multi-file fixture, returns positions marked with $0.
@@ -54,24 +54,25 @@ pub(crate) fn annotations(
     #[rust_analyzer::rust_fixture] ra_fixture: &str,
 ) -> (Analysis, FilePosition, Vec<(FileRange, String)>) {
     let mut host = AnalysisHost::default();
-    let change_fixture = ChangeFixture::parse(ra_fixture);
+    let change_fixture = ChangeFixture::parse(&host.db, ra_fixture);
     host.db.enable_proc_attr_macros();
     host.db.apply_change(change_fixture.change);
     let (file_id, range_or_offset) = change_fixture.file_position.expect("expected a marker ($0)");
     let offset = range_or_offset.expect_offset();
 
+    let db = &host.db;
     let annotations = change_fixture
         .files
         .iter()
         .flat_map(|&file_id| {
-            let file_text = host.analysis().file_text(file_id.into()).unwrap();
+            let file_text = host.analysis().file_text(file_id.file_id(&host.db)).unwrap();
             let annotations = extract_annotations(&file_text);
             annotations
                 .into_iter()
-                .map(move |(range, data)| (FileRange { file_id: file_id.into(), range }, data))
+                .map(move |(range, data)| (FileRange { file_id: file_id.file_id(db), range }, data))
         })
         .collect();
-    (host.analysis(), FilePosition { file_id: file_id.into(), offset }, annotations)
+    (host.analysis(), FilePosition { file_id: file_id.file_id(&host.db), offset }, annotations)
 }
 
 /// Creates analysis from a multi-file fixture with annotations without $0
@@ -79,19 +80,20 @@ pub(crate) fn annotations_without_marker(
     #[rust_analyzer::rust_fixture] ra_fixture: &str,
 ) -> (Analysis, Vec<(FileRange, String)>) {
     let mut host = AnalysisHost::default();
-    let change_fixture = ChangeFixture::parse(ra_fixture);
+    let change_fixture = ChangeFixture::parse(&host.db, ra_fixture);
     host.db.enable_proc_attr_macros();
     host.db.apply_change(change_fixture.change);
 
+    let db = &host.db;
     let annotations = change_fixture
         .files
         .iter()
         .flat_map(|&file_id| {
-            let file_text = host.analysis().file_text(file_id.into()).unwrap();
+            let file_text = host.analysis().file_text(file_id.file_id(db)).unwrap();
             let annotations = extract_annotations(&file_text);
             annotations
                 .into_iter()
-                .map(move |(range, data)| (FileRange { file_id: file_id.into(), range }, data))
+                .map(move |(range, data)| (FileRange { file_id: file_id.file_id(db), range }, data))
         })
         .collect();
     (host.analysis(), annotations)
diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
index e5a94ff9fe9..194e8c968f7 100755
--- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs
@@ -1,9 +1,10 @@
-use ide_db::{syntax_helpers::node_ext::vis_eq, FxHashSet};
+use ide_db::{FxHashSet, syntax_helpers::node_ext::vis_eq};
 use syntax::{
-    ast::{self, AstNode, AstToken},
-    match_ast, Direction, NodeOrToken, SourceFile,
+    Direction, NodeOrToken, SourceFile,
     SyntaxKind::{self, *},
     TextRange, TextSize,
+    ast::{self, AstNode, AstToken},
+    match_ast,
 };
 
 use std::hash::Hash;
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
index 3742edc8db8..38c032d382e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
@@ -1,13 +1,13 @@
 use hir::{AsAssocItem, Semantics};
 use ide_db::{
-    defs::{Definition, NameClass, NameRefClass},
     RootDatabase,
+    defs::{Definition, NameClass, NameRefClass},
 };
-use syntax::{ast, match_ast, AstNode, SyntaxKind::*, T};
+use syntax::{AstNode, SyntaxKind::*, T, ast, match_ast};
 
 use crate::{
-    goto_definition::goto_definition, navigation_target::TryToNav, FilePosition, NavigationTarget,
-    RangeInfo,
+    FilePosition, NavigationTarget, RangeInfo, goto_definition::goto_definition,
+    navigation_target::TryToNav,
 };
 
 // Feature: Go to Declaration
@@ -32,7 +32,7 @@ pub(crate) fn goto_declaration(
         .descend_into_macros_no_opaque(original_token)
         .iter()
         .filter_map(|token| {
-            let parent = token.parent()?;
+            let parent = token.value.parent()?;
             let def = match_ast! {
                 match parent {
                     ast::NameRef(name_ref) => match NameRefClass::classify(&sema, &name_ref)? {
@@ -52,7 +52,7 @@ pub(crate) fn goto_declaration(
             };
             let assoc = match def? {
                 Definition::Module(module) => {
-                    return Some(NavigationTarget::from_module_to_decl(db, module))
+                    return Some(NavigationTarget::from_module_to_decl(db, module));
                 }
                 Definition::Const(c) => c.as_assoc_item(db),
                 Definition::TypeAlias(ta) => ta.as_assoc_item(db),
@@ -69,11 +69,7 @@ pub(crate) fn goto_declaration(
         .flatten()
         .collect();
 
-    if info.is_empty() {
-        goto_definition(db, position)
-    } else {
-        Some(RangeInfo::new(range, info))
-    }
+    if info.is_empty() { goto_definition(db, position) } else { Some(RangeInfo::new(range, info)) }
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index 60a904233a9..b894e857522 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -1,28 +1,28 @@
 use std::{iter, mem::discriminant};
 
 use crate::{
+    FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
     doc_links::token_as_doc_comment,
     navigation_target::{self, ToNav},
-    FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
 };
 use hir::{
-    sym, AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, MacroFileIdExt,
-    ModuleDef, Semantics,
+    AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, ModuleDef, Semantics, sym,
 };
 use ide_db::{
-    base_db::{AnchoredPath, FileLoader, SourceDatabase},
+    RootDatabase, SymbolKind,
+    base_db::{AnchoredPath, SourceDatabase},
     defs::{Definition, IdentClass},
     famous_defs::FamousDefs,
     helpers::pick_best_token,
-    RootDatabase, SymbolKind,
 };
 use itertools::Itertools;
 use span::{Edition, FileId};
 use syntax::{
-    ast::{self, HasLoopBody},
-    match_ast, AstNode, AstToken,
+    AstNode, AstToken,
     SyntaxKind::*,
-    SyntaxNode, SyntaxToken, TextRange, T,
+    SyntaxNode, SyntaxToken, T, TextRange,
+    ast::{self, HasLoopBody},
+    match_ast,
 };
 
 // Feature: Go to Definition
@@ -43,7 +43,7 @@ pub(crate) fn goto_definition(
     let sema = &Semantics::new(db);
     let file = sema.parse_guess_edition(file_id).syntax().clone();
     let edition =
-        sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
+        sema.attach_first_edition(file_id).map(|it| it.edition(db)).unwrap_or(Edition::CURRENT);
     let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
         IDENT
         | INT_NUMBER
@@ -91,16 +91,19 @@ pub(crate) fn goto_definition(
         .descend_into_macros_no_opaque(original_token.clone())
         .into_iter()
         .filter_map(|token| {
-            let parent = token.parent()?;
+            let parent = token.value.parent()?;
 
-            if let Some(token) = ast::String::cast(token.clone()) {
-                if let Some(x) = try_lookup_include_path(sema, token, file_id) {
+            let token_file_id = token.file_id;
+            if let Some(token) = ast::String::cast(token.value.clone()) {
+                if let Some(x) =
+                    try_lookup_include_path(sema, InFile::new(token_file_id, token), 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) {
+                if let Some(x) = try_lookup_macro_def_in_macro_use(sema, token.value) {
                     return Some(vec![x]);
                 }
             }
@@ -204,20 +207,22 @@ fn find_definition_for_known_blanket_dual_impls(
 
 fn try_lookup_include_path(
     sema: &Semantics<'_, RootDatabase>,
-    token: ast::String,
+    token: InFile<ast::String>,
     file_id: FileId,
 ) -> Option<NavigationTarget> {
-    let file = sema.hir_file_for(&token.syntax().parent()?).macro_file()?;
+    let file = token.file_id.macro_file()?;
+
+    // Check that we are in the eager argument expansion of an include macro
+    // that is we are the string input of it
     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())
     {
         return None;
     }
-    let path = token.value().ok()?;
+    let path = token.value.value().ok()?;
 
     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()?;
+    let size = sema.db.file_text(file_id).text(sema.db).len().try_into().ok()?;
     Some(NavigationTarget {
         file_id,
         full_range: TextRange::new(0.into(), size),
@@ -358,7 +363,7 @@ fn nav_for_exit_points(
 
                         if let Some(FileRange { file_id, range }) = focus_frange {
                             let contains_frange = |nav: &NavigationTarget| {
-                                nav.file_id == file_id && nav.full_range.contains_range(range)
+                                nav.file_id == file_id.file_id(db) && nav.full_range.contains_range(range)
                             };
 
                             if let Some(def_site) = nav.def_site.as_mut() {
@@ -2047,7 +2052,10 @@ fn main() {
         );
     }
 
+    // macros in this position are not yet supported
     #[test]
+    // FIXME
+    #[should_panic]
     fn goto_doc_include_str() {
         check(
             r#"
@@ -2190,8 +2198,8 @@ where T : Bound
 struct A;
 impl Bound for A{}
 fn f() {
-    let gen = Gen::<A>(A);
-    gen.g$0();
+    let g = Gen::<A>(A);
+    g.g$0();
 }
                 "#,
             );
@@ -2216,8 +2224,8 @@ where T : Bound
 struct A;
 impl Bound for A{}
 fn f() {
-    let gen = Gen::<A>(A);
-    gen.g$0();
+    let g = Gen::<A>(A);
+    g.g$0();
 }
 "#,
             );
@@ -3324,4 +3332,218 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn struct_shadow_by_module() {
+        check(
+            r#"
+mod foo {
+    pub mod bar {
+         // ^^^
+        pub type baz = usize;
+    }
+}
+struct bar;
+fn main() {
+    use foo::bar;
+    let x: ba$0r::baz = 5;
+
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn type_alias_shadow_by_module() {
+        check(
+            r#"
+mod foo {
+    pub mod bar {
+         // ^^^
+        pub fn baz() {}
+    }
+}
+
+trait Qux {}
+
+fn item<bar: Qux>() {
+    use foo::bar;
+    ba$0r::baz();
+}
+}
+"#,
+        );
+
+        check(
+            r#"
+mod foo {
+    pub mod bar {
+         // ^^^
+        pub fn baz() {}
+    }
+}
+
+fn item<bar>(x: bar) {
+    use foo::bar;
+    let x: bar$0 = x;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn trait_shadow_by_module() {
+        check(
+            r#"
+pub mod foo {
+    pub mod Bar {}
+         // ^^^
+}
+
+trait Bar {}
+
+fn main() {
+    use foo::Bar;
+    fn f<Qux: B$0ar>() {}
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn const_shadow_by_module() {
+        check(
+            r#"
+pub mod foo {
+    pub struct u8 {}
+    pub mod bar {
+        pub mod u8 {}
+    }
+}
+
+fn main() {
+    use foo::u8;
+    {
+        use foo::bar::u8;
+
+        fn f1<const N: u$08>() {}
+    }
+    fn f2<const N: u8>() {}
+}
+"#,
+        );
+
+        check(
+            r#"
+pub mod foo {
+    pub struct u8 {}
+            // ^^
+    pub mod bar {
+        pub mod u8 {}
+    }
+}
+
+fn main() {
+    use foo::u8;
+    {
+        use foo::bar::u8;
+
+        fn f1<const N: u8>() {}
+    }
+    fn f2<const N: u$08>() {}
+}
+"#,
+        );
+
+        check(
+            r#"
+pub mod foo {
+    pub struct buz {}
+    pub mod bar {
+        pub mod buz {}
+             // ^^^
+    }
+}
+
+fn main() {
+    use foo::buz;
+    {
+        use foo::bar::buz;
+
+        fn f1<const N: buz$0>() {}
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn offset_of() {
+        check(
+            r#"
+//- minicore: offset_of
+struct Foo {
+    field: i32,
+ // ^^^^^
+}
+
+fn foo() {
+    let _ = core::mem::offset_of!(Foo, fiel$0d);
+}
+        "#,
+        );
+
+        check(
+            r#"
+//- minicore: offset_of
+struct Bar(Foo);
+struct Foo {
+    field: i32,
+ // ^^^^^
+}
+
+fn foo() {
+    let _ = core::mem::offset_of!(Bar, 0.fiel$0d);
+}
+        "#,
+        );
+
+        check(
+            r#"
+//- minicore: offset_of
+struct Bar(Baz);
+enum Baz {
+    Abc(Foo),
+    None,
+}
+struct Foo {
+    field: i32,
+ // ^^^^^
+}
+
+fn foo() {
+    let _ = core::mem::offset_of!(Bar, 0.Abc.0.fiel$0d);
+}
+        "#,
+        );
+
+        check(
+            r#"
+//- minicore: offset_of
+struct Bar(Baz);
+enum Baz {
+    Abc(Foo),
+ // ^^^
+    None,
+}
+struct Foo {
+    field: i32,
+}
+
+fn foo() {
+    let _ = core::mem::offset_of!(Bar, 0.Ab$0c.0.field);
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
index e1d834b5d1c..1bc28f28b6f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
@@ -1,10 +1,10 @@
 use hir::{AsAssocItem, Impl, Semantics};
 use ide_db::{
+    RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
     helpers::pick_best_token,
-    RootDatabase,
 };
-use syntax::{ast, AstNode, SyntaxKind::*, T};
+use syntax::{AstNode, SyntaxKind::*, T, ast};
 
 use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav};
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
index ddc274a8303..a78f5cdc9d0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
@@ -1,6 +1,6 @@
 use hir::GenericParam;
-use ide_db::{base_db::Upcast, defs::Definition, helpers::pick_best_token, RootDatabase};
-use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, T};
+use ide_db::{RootDatabase, defs::Definition, helpers::pick_best_token};
+use syntax::{AstNode, SyntaxKind::*, SyntaxToken, T, ast, match_ast};
 
 use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav};
 
@@ -71,8 +71,8 @@ pub(crate) fn goto_type_definition(
     sema.descend_into_macros_no_opaque(token)
         .into_iter()
         .filter_map(|token| {
-            let ty = sema
-                .token_ancestors_with_macros(token)
+            sema
+                .token_ancestors_with_macros(token.value)
                 // When `token` is within a macro call, we can't determine its type. Don't continue
                 // this traversal because otherwise we'll end up returning the type of *that* macro
                 // call, which is not what we want in general.
@@ -87,7 +87,7 @@ pub(crate) fn goto_type_definition(
                             ast::Pat(it) => sema.type_of_pat(&it)?.original,
                             ast::SelfParam(it) => sema.type_of_self(&it)?,
                             ast::Type(it) => sema.resolve_type(&it)?,
-                            ast::RecordField(it) => sema.to_def(&it)?.ty(db.upcast()),
+                            ast::RecordField(it) => sema.to_def(&it)?.ty(db),
                             // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise
                             ast::NameRef(it) => {
                                 if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) {
@@ -103,8 +103,7 @@ pub(crate) fn goto_type_definition(
                     };
 
                     Some(ty)
-                });
-            ty
+                })
         })
         .for_each(process_ty);
     Some(RangeInfo::new(range, res))
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index 6463206596a..80624eeae80 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -1,7 +1,8 @@
 use std::iter;
 
-use hir::{db, FilePosition, FileRange, HirFileId, InFile, Semantics};
+use hir::{EditionedFileId, FilePosition, FileRange, HirFileId, InFile, Semantics, db};
 use ide_db::{
+    FxHashMap, FxHashSet, RootDatabase,
     defs::{Definition, IdentClass},
     helpers::pick_best_token,
     search::{FileReference, ReferenceCategory, SearchScope},
@@ -9,17 +10,17 @@ use ide_db::{
         eq_label_lt, for_each_tail_expr, full_path_of_name_ref, is_closure_or_blk_with_modif,
         preorder_expr_with_ctx_checker,
     },
-    FxHashMap, FxHashSet, RootDatabase,
 };
-use span::EditionedFileId;
+use span::FileId;
 use syntax::{
-    ast::{self, HasLoopBody},
-    match_ast, AstNode,
+    AstNode,
     SyntaxKind::{self, IDENT, INT_NUMBER},
-    SyntaxToken, TextRange, WalkEvent, T,
+    SyntaxToken, T, TextRange, WalkEvent,
+    ast::{self, HasLoopBody},
+    match_ast,
 };
 
-use crate::{goto_definition, navigation_target::ToNav, NavigationTarget, TryToNav};
+use crate::{NavigationTarget, TryToNav, goto_definition, navigation_target::ToNav};
 
 #[derive(PartialEq, Eq, Hash)]
 pub struct HighlightedRange {
@@ -59,13 +60,14 @@ pub(crate) fn highlight_related(
     let _p = tracing::info_span!("highlight_related").entered();
     let file_id = sema
         .attach_first_edition(file_id)
-        .unwrap_or_else(|| EditionedFileId::current_edition(file_id));
+        .unwrap_or_else(|| EditionedFileId::current_edition(sema.db, file_id));
+    let span_file_id = file_id.editioned_file_id(sema.db);
     let syntax = sema.parse(file_id).syntax().clone();
 
     let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind {
         T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?`
         T![->] => 4,
-        kind if kind.is_keyword(file_id.edition()) => 3,
+        kind if kind.is_keyword(span_file_id.edition()) => 3,
         IDENT | INT_NUMBER => 2,
         T![|] => 1,
         _ => 0,
@@ -87,11 +89,18 @@ pub(crate) fn highlight_related(
         T![break] | T![loop] | T![while] | T![continue] if config.break_points => {
             highlight_break_points(sema, token).remove(&file_id)
         }
-        T![|] if config.closure_captures => highlight_closure_captures(sema, token, file_id),
-        T![move] if config.closure_captures => highlight_closure_captures(sema, token, file_id),
-        _ if config.references => {
-            highlight_references(sema, token, FilePosition { file_id, offset })
+        T![|] if config.closure_captures => {
+            highlight_closure_captures(sema, token, file_id, span_file_id.file_id())
+        }
+        T![move] if config.closure_captures => {
+            highlight_closure_captures(sema, token, file_id, span_file_id.file_id())
         }
+        _ if config.references => highlight_references(
+            sema,
+            token,
+            FilePosition { file_id, offset },
+            span_file_id.file_id(),
+        ),
         _ => None,
     }
 }
@@ -100,6 +109,7 @@ fn highlight_closure_captures(
     sema: &Semantics<'_, RootDatabase>,
     token: SyntaxToken,
     file_id: EditionedFileId,
+    vfs_file_id: FileId,
 ) -> Option<Vec<HighlightedRange>> {
     let closure = token.parent_ancestors().take(2).find_map(ast::ClosureExpr::cast)?;
     let search_range = closure.body()?.syntax().text_range();
@@ -132,7 +142,7 @@ fn highlight_closure_captures(
                     .sources(sema.db)
                     .into_iter()
                     .flat_map(|x| x.to_nav(sema.db))
-                    .filter(|decl| decl.file_id == file_id)
+                    .filter(|decl| decl.file_id == vfs_file_id)
                     .filter_map(|decl| decl.focus_range)
                     .map(move |range| HighlightedRange { range, category })
                     .chain(usages)
@@ -145,6 +155,7 @@ fn highlight_references(
     sema: &Semantics<'_, RootDatabase>,
     token: SyntaxToken,
     FilePosition { file_id, offset }: FilePosition,
+    vfs_file_id: FileId,
 ) -> Option<Vec<HighlightedRange>> {
     let defs = if let Some((range, resolution)) =
         sema.check_for_format_args_template(token.clone(), offset)
@@ -152,7 +163,10 @@ fn highlight_references(
         match resolution.map(Definition::from) {
             Some(def) => iter::once(def).collect(),
             None => {
-                return Some(vec![HighlightedRange { range, category: ReferenceCategory::empty() }])
+                return Some(vec![HighlightedRange {
+                    range,
+                    category: ReferenceCategory::empty(),
+                }]);
             }
         }
     } else {
@@ -224,6 +238,23 @@ fn highlight_references(
             }
         }
 
+        // highlight the tail expr of the labelled block
+        if matches!(def, Definition::Label(_)) {
+            let label = token.parent_ancestors().nth(1).and_then(ast::Label::cast);
+            if let Some(block) =
+                label.and_then(|label| label.syntax().parent()).and_then(ast::BlockExpr::cast)
+            {
+                for_each_tail_expr(&block.into(), &mut |tail| {
+                    if !matches!(tail, ast::Expr::BreakExpr(_)) {
+                        res.insert(HighlightedRange {
+                            range: tail.syntax().text_range(),
+                            category: ReferenceCategory::empty(),
+                        });
+                    }
+                });
+            }
+        }
+
         // highlight the defs themselves
         match def {
             Definition::Local(local) => {
@@ -236,7 +267,7 @@ fn highlight_references(
                     .sources(sema.db)
                     .into_iter()
                     .flat_map(|x| x.to_nav(sema.db))
-                    .filter(|decl| decl.file_id == file_id)
+                    .filter(|decl| decl.file_id == vfs_file_id)
                     .filter_map(|decl| decl.focus_range)
                     .map(|range| HighlightedRange { range, category })
                     .for_each(|x| {
@@ -254,7 +285,7 @@ fn highlight_references(
                     },
                 };
                 for nav in navs {
-                    if nav.file_id != file_id {
+                    if nav.file_id != vfs_file_id {
                         continue;
                     }
                     let hl_range = nav.focus_range.map(|range| {
@@ -274,11 +305,7 @@ fn highlight_references(
     }
 
     res.extend(usages);
-    if res.is_empty() {
-        None
-    } else {
-        Some(res.into_iter().collect())
-    }
+    if res.is_empty() { None } else { Some(res.into_iter().collect()) }
 }
 
 fn hl_exit_points(
@@ -442,6 +469,18 @@ pub(crate) fn highlight_break_points(
                 push_to_highlights(file_id, text_range);
             });
 
+        if matches!(expr, ast::Expr::BlockExpr(_)) {
+            for_each_tail_expr(&expr, &mut |tail| {
+                if matches!(tail, ast::Expr::BreakExpr(_)) {
+                    return;
+                }
+
+                let file_id = sema.hir_file_for(tail.syntax());
+                let range = tail.syntax().text_range();
+                push_to_highlights(file_id, Some(range));
+            });
+        }
+
         Some(highlights)
     }
 
@@ -2068,4 +2107,41 @@ pub unsafe fn bootstrap() -> ! {
 "#,
         )
     }
+
+    #[test]
+    fn labeled_block_tail_expr() {
+        check(
+            r#"
+fn foo() {
+    'a: {
+ // ^^^
+        if true { break$0 'a 0; }
+               // ^^^^^^^^
+        5
+     // ^
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn labeled_block_tail_expr_2() {
+        check(
+            r#"
+fn foo() {
+    let _ = 'b$0lk: {
+         // ^^^^
+        let x = 1;
+        if true { break 'blk 42; }
+                     // ^^^^
+        if false { break 'blk 24; }
+                      // ^^^^
+        100
+     // ^^^
+    };
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index b00de6ba408..2f2d2252f84 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -7,26 +7,30 @@ use std::{iter, ops::Not};
 
 use either::Either;
 use hir::{
-    db::DefDatabase, DisplayTarget, GenericDef, GenericSubstitution, HasCrate, HasSource, LangItem,
-    Semantics,
+    DisplayTarget, GenericDef, GenericSubstitution, HasCrate, HasSource, LangItem, Semantics,
+    db::DefDatabase,
 };
 use ide_db::{
+    FileRange, FxIndexSet, Ranker, RootDatabase,
     defs::{Definition, IdentClass, NameRefClass, OperatorClass},
     famous_defs::FamousDefs,
     helpers::pick_best_token,
-    FileRange, FxIndexSet, Ranker, RootDatabase,
 };
-use itertools::{multizip, Itertools};
+use itertools::{Itertools, multizip};
 use span::Edition;
-use syntax::{ast, AstNode, SyntaxKind::*, SyntaxNode, T};
+use syntax::{
+    AstNode,
+    SyntaxKind::{self, *},
+    SyntaxNode, T, ast,
+};
 
 use crate::{
+    FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
     doc_links::token_as_doc_comment,
     markdown_remove::remove_markdown,
     markup::Markup,
     navigation_target::UpmappingResult,
     runnables::{runnable_fn, runnable_mod},
-    FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, TryToNav,
 };
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct HoverConfig {
@@ -129,8 +133,8 @@ pub(crate) fn hover(
     let sema = &hir::Semantics::new(db);
     let file = sema.parse_guess_edition(file_id).syntax().clone();
     let edition =
-        sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
-    let display_target = sema.first_crate_or_default(file_id).to_display_target(db);
+        sema.attach_first_edition(file_id).map(|it| it.edition(db)).unwrap_or(Edition::CURRENT);
+    let display_target = sema.first_crate(file_id)?.to_display_target(db);
     let mut res = if range.is_empty() {
         hover_offset(
             sema,
@@ -274,11 +278,13 @@ fn hover_offset(
                         }
 
                         class => {
-                            let is_def = matches!(class, IdentClass::NameClass(_));
+                            let render_extras = matches!(class, IdentClass::NameClass(_))
+                                // Render extra information for `Self` keyword as well
+                                || ast::NameRef::cast(node.clone()).is_some_and(|name_ref| name_ref.token_kind() == SyntaxKind::SELF_TYPE_KW);
                             multizip((
                                 class.definitions(),
                                 iter::repeat(None),
-                                iter::repeat(is_def),
+                                iter::repeat(render_extras),
                                 iter::repeat(node),
                             ))
                             .collect::<Vec<_>>()
@@ -422,7 +428,7 @@ pub(crate) fn hover_for_definition(
     subst: Option<GenericSubstitution>,
     scope_node: &SyntaxNode,
     macro_arm: Option<u32>,
-    hovered_definition: bool,
+    render_extras: bool,
     config: &HoverConfig,
     edition: Edition,
     display_target: DisplayTarget,
@@ -456,7 +462,7 @@ pub(crate) fn hover_for_definition(
         famous_defs.as_ref(),
         &notable_traits,
         macro_arm,
-        hovered_definition,
+        render_extras,
         subst_types.as_ref(),
         config,
         edition,
@@ -499,6 +505,7 @@ fn notable_traits(
                 )
             })
         })
+        .sorted_by_cached_key(|(trait_, _)| trait_.name(db))
         .collect::<Vec<_>>()
 }
 
@@ -512,7 +519,7 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
 
     let adt = match def {
         Definition::Trait(it) => {
-            return it.try_to_nav(db).map(UpmappingResult::call_site).map(to_action)
+            return it.try_to_nav(db).map(UpmappingResult::call_site).map(to_action);
         }
         Definition::Adt(it) => Some(it),
         Definition::SelfType(it) => it.self_ty(db).as_adt(),
@@ -544,7 +551,7 @@ fn runnable_action(
         Definition::Module(it) => runnable_mod(sema, it).map(HoverAction::Runnable),
         Definition::Function(func) => {
             let src = func.source(sema.db)?;
-            if src.file_id != file_id {
+            if src.file_id.file_id().is_none_or(|f| f.file_id(sema.db) != file_id) {
                 cov_mark::hit!(hover_macro_generated_struct_fn_doc_comment);
                 cov_mark::hit!(hover_macro_generated_struct_fn_doc_attr);
                 return None;
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 31ef89a07cd..69b83f3b12d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -3,34 +3,34 @@ use std::{env, mem, ops::Not};
 
 use either::Either;
 use hir::{
-    db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind, DisplayTarget, DropGlue,
+    Adt, AsAssocItem, AsExternAssocItem, CaptureKind, DisplayTarget, DropGlue,
     DynCompatibilityViolation, HasCrate, HasSource, HirDisplay, Layout, LayoutError,
     MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, VariantDef,
+    db::ExpandDatabase,
 };
 use ide_db::{
-    base_db::SourceDatabase,
+    RootDatabase,
     defs::Definition,
     documentation::HasDocs,
     famous_defs::FamousDefs,
     generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
     syntax_helpers::prettify_macro_expansion,
-    RootDatabase,
 };
 use itertools::Itertools;
 use rustc_apfloat::{
-    ieee::{Half as f16, Quad as f128},
     Float,
+    ieee::{Half as f16, Quad as f128},
 };
 use span::Edition;
 use stdx::format_to;
-use syntax::{algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxToken, T};
+use syntax::{AstNode, AstToken, Direction, SyntaxToken, T, algo, ast, match_ast};
 
 use crate::{
-    doc_links::{remove_links, rewrite_links},
-    hover::{notable_traits, walk_and_push_ty, SubstTyLen},
-    interpret::render_const_eval_error,
     HoverAction, HoverConfig, HoverResult, Markup, MemoryLayoutHoverConfig,
     MemoryLayoutHoverRenderKind,
+    doc_links::{remove_links, rewrite_links},
+    hover::{SubstTyLen, notable_traits, walk_and_push_ty},
+    interpret::render_const_eval_error,
 };
 
 pub(super) fn type_info_of(
@@ -346,11 +346,7 @@ pub(super) fn try_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option<Hove
                 .is_some_and(|t| {
                     t.kind() == T![ident] && t.into_token().is_some_and(|t| t.text() == "clippy")
                 });
-            if is_clippy {
-                (true, CLIPPY_LINTS)
-            } else {
-                (false, DEFAULT_LINTS)
-            }
+            if is_clippy { (true, CLIPPY_LINTS) } else { (false, DEFAULT_LINTS) }
         }
         _ => return None,
     };
@@ -418,7 +414,7 @@ fn definition_owner_name(db: &RootDatabase, def: Definition, edition: Edition) -
                             "{}::{}",
                             name.display(db, edition),
                             it.name(db).display(db, edition)
-                        ))
+                        ));
                     }
                     None => Some(it.name(db)),
                 }
@@ -436,7 +432,7 @@ fn definition_owner_name(db: &RootDatabase, def: Definition, edition: Edition) -
                             "{}::{}",
                             name.display(db, edition),
                             it.name(db)?.display(db, edition)
-                        ))
+                        ));
                     }
                     None => it.name(db),
                 }
@@ -466,8 +462,7 @@ pub(super) fn path(
     item_name: Option<String>,
     edition: Edition,
 ) -> String {
-    let crate_name =
-        db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string());
+    let crate_name = module.krate().display_name(db).as_ref().map(|it| it.to_string());
     let module_path = module
         .path_to_root(db)
         .into_iter()
@@ -482,7 +477,7 @@ pub(super) fn definition(
     famous_defs: Option<&FamousDefs<'_, '_>>,
     notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
     macro_arm: Option<u32>,
-    hovered_definition: bool,
+    render_extras: bool,
     subst_types: Option<&Vec<(Symbol, Type)>>,
     config: &HoverConfig,
     edition: Edition,
@@ -645,6 +640,12 @@ pub(super) fn definition(
         Definition::Local(it) => {
             render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None)
         }
+        Definition::SelfType(it) => render_memory_layout(
+            config.memory_layout,
+            || it.self_ty(db).layout(db),
+            |_| None,
+            |_| None,
+        ),
         _ => None,
     };
 
@@ -717,18 +718,17 @@ pub(super) fn definition(
             }
             _ => return None,
         };
-        let rendered_drop_glue = match drop_info.drop_glue {
-            DropGlue::None => "does not contain types with destructors (drop glue)",
-            DropGlue::DependOnParams => {
-                "may contain types with destructors (drop glue) depending on type parameters"
+        let rendered_drop_glue = if drop_info.has_dtor == Some(true) {
+            "impl Drop"
+        } else {
+            match drop_info.drop_glue {
+                DropGlue::HasDropGlue => "needs Drop",
+                DropGlue::None => "no Drop",
+                DropGlue::DependOnParams => "type param may need Drop",
             }
-            DropGlue::HasDropGlue => "contain types with destructors (drop glue)",
         };
-        Some(match drop_info.has_dtor {
-            Some(true) => format!("{}; has a destructor", rendered_drop_glue),
-            Some(false) => format!("{}; doesn't have a destructor", rendered_drop_glue),
-            None => rendered_drop_glue.to_owned(),
-        })
+
+        Some(rendered_drop_glue.to_owned())
     };
 
     let dyn_compatibility_info = || match def {
@@ -746,7 +746,7 @@ pub(super) fn definition(
     };
 
     let mut extra = String::new();
-    if hovered_definition {
+    if render_extras {
         if let Some(notable_traits) =
             render_notable_trait(db, notable_traits, edition, display_target)
         {
@@ -760,15 +760,18 @@ pub(super) fn definition(
         if let Some(layout_info) = layout_info() {
             extra.push_str("\n___\n");
             extra.push_str(&layout_info);
+            if let Some(drop_info) = drop_info() {
+                extra.push_str(", ");
+                extra.push_str(&drop_info)
+            }
+        } else if let Some(drop_info) = drop_info() {
+            extra.push_str("\n___\n");
+            extra.push_str(&drop_info);
         }
         if let Some(dyn_compatibility_info) = dyn_compatibility_info() {
             extra.push_str("\n___\n");
             extra.push_str(&dyn_compatibility_info);
         }
-        if let Some(drop_info) = drop_info() {
-            extra.push_str("\n___\n");
-            extra.push_str(&drop_info);
-        }
     }
     let mut desc = String::new();
     desc.push_str(&label);
@@ -906,9 +909,9 @@ fn render_notable_trait(
     let mut needs_impl_header = true;
     for (trait_, assoc_types) in notable_traits {
         desc.push_str(if mem::take(&mut needs_impl_header) {
-            "Implements notable traits: "
+            "Implements notable traits: `"
         } else {
-            ", "
+            "`, `"
         });
         format_to!(desc, "{}", trait_.name(db).display(db, edition));
         if !assoc_types.is_empty() {
@@ -928,7 +931,12 @@ fn render_notable_trait(
             desc.push('>');
         }
     }
-    desc.is_empty().not().then_some(desc)
+    if desc.is_empty() {
+        None
+    } else {
+        desc.push('`');
+        Some(desc)
+    }
 }
 
 fn type_info(
@@ -955,37 +963,12 @@ fn type_info(
     res.markup = if let Some(adjusted_ty) = adjusted {
         walk_and_push_ty(db, &adjusted_ty, &mut push_new_def);
 
-        let notable = {
-            let mut desc = String::new();
-            let mut needs_impl_header = true;
-            for (trait_, assoc_types) in notable_traits(db, &original) {
-                desc.push_str(if mem::take(&mut needs_impl_header) {
-                    "Implements Notable Traits: "
-                } else {
-                    ", "
-                });
-                format_to!(desc, "{}", trait_.name(db).display(db, edition));
-                if !assoc_types.is_empty() {
-                    desc.push('<');
-                    format_to!(
-                        desc,
-                        "{}",
-                        assoc_types.into_iter().format_with(", ", |(ty, name), f| {
-                            f(&name.display(db, edition))?;
-                            f(&" = ")?;
-                            match ty {
-                                Some(ty) => f(&ty.display(db, display_target)),
-                                None => f(&"?"),
-                            }
-                        })
-                    );
-                    desc.push('>');
-                }
-            }
-            if !desc.is_empty() {
-                desc.push('\n');
-            }
-            desc
+        let notable = if let Some(notable) =
+            render_notable_trait(db, &notable_traits(db, &original), edition, display_target)
+        {
+            format!("{notable}\n")
+        } else {
+            String::new()
         };
 
         let original = original.display(db, display_target).to_string();
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 80a2d4690d4..d469cd7c0cd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -1,9 +1,9 @@
-use expect_test::{expect, Expect};
-use ide_db::{base_db::SourceDatabase, FileRange};
+use expect_test::{Expect, expect};
+use ide_db::{FileRange, base_db::SourceDatabase};
 use syntax::TextRange;
 
 use crate::{
-    fixture, HoverConfig, HoverDocFormat, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
+    HoverConfig, HoverDocFormat, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, fixture,
 };
 
 const HOVER_BASE_CONFIG: HoverConfig = HoverConfig {
@@ -47,7 +47,7 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
         .unwrap();
 
     let content = analysis.db.file_text(position.file_id);
-    let hovered_element = &content[hover.range];
+    let hovered_element = &content.text(&analysis.db)[hover.range];
 
     let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup);
     expect.assert_eq(&actual)
@@ -72,7 +72,7 @@ fn check_hover_fields_limit(
         .unwrap()
         .unwrap();
 
-    let content = analysis.db.file_text(position.file_id);
+    let content = analysis.db.file_text(position.file_id).text(&analysis.db);
     let hovered_element = &content[hover.range];
 
     let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup);
@@ -98,7 +98,7 @@ fn check_hover_enum_variants_limit(
         .unwrap()
         .unwrap();
 
-    let content = analysis.db.file_text(position.file_id);
+    let content = analysis.db.file_text(position.file_id).text(&analysis.db);
     let hovered_element = &content[hover.range];
 
     let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup);
@@ -124,7 +124,7 @@ fn check_assoc_count(
         .unwrap()
         .unwrap();
 
-    let content = analysis.db.file_text(position.file_id);
+    let content = analysis.db.file_text(position.file_id).text(&analysis.db);
     let hovered_element = &content[hover.range];
 
     let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup);
@@ -141,7 +141,7 @@ fn check_hover_no_links(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect:
         .unwrap()
         .unwrap();
 
-    let content = analysis.db.file_text(position.file_id);
+    let content = analysis.db.file_text(position.file_id).text(&analysis.db);
     let hovered_element = &content[hover.range];
 
     let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup);
@@ -158,7 +158,7 @@ fn check_hover_no_memory_layout(#[rust_analyzer::rust_fixture] ra_fixture: &str,
         .unwrap()
         .unwrap();
 
-    let content = analysis.db.file_text(position.file_id);
+    let content = analysis.db.file_text(position.file_id).text(&analysis.db);
     let hovered_element = &content[hover.range];
 
     let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup);
@@ -179,7 +179,7 @@ fn check_hover_no_markdown(#[rust_analyzer::rust_fixture] ra_fixture: &str, expe
         .unwrap()
         .unwrap();
 
-    let content = analysis.db.file_text(position.file_id);
+    let content = analysis.db.file_text(position.file_id).text(&analysis.db);
     let hovered_element = &content[hover.range];
 
     let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup);
@@ -567,11 +567,7 @@ fn main() {
 
             ---
 
-            size = 8, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 8, align = 4, no Drop
         "#]],
     );
 }
@@ -816,11 +812,7 @@ struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 }
 
             ---
 
-            size = 1, align = 1, offset = 6
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 1, align = 1, offset = 6, no Drop
         "#]],
     );
 }
@@ -871,11 +863,7 @@ fn main() {
 
             ---
 
-            size = 4, align = 4, offset = 0
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 4, offset = 0, no Drop
         "#]],
     );
 }
@@ -945,11 +933,7 @@ struct Foo$0(pub u32) where u32: Copy;
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 4, align = 4, no Drop
         "#]],
     );
 }
@@ -975,11 +959,7 @@ struct Foo$0 { field: u32 }
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 4, align = 4, no Drop
         "#]],
     );
     check(
@@ -1004,11 +984,7 @@ struct Foo$0 where u32: Copy { field: u32 }
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 4, align = 4, no Drop
         "#]],
     );
 }
@@ -1037,11 +1013,7 @@ fn hover_record_struct_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 12 (0xC), align = 4, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1064,11 +1036,7 @@ fn hover_record_struct_limit() {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 4, align = 4, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1094,11 +1062,7 @@ fn hover_record_struct_limit() {
 
             ---
 
-            size = 16 (0x10), align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 16 (0x10), align = 4, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1119,11 +1083,7 @@ fn hover_record_struct_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 12 (0xC), align = 4, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1144,11 +1104,7 @@ fn hover_record_struct_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 12 (0xC), align = 4, no Drop
         "#]],
     );
 
@@ -1171,11 +1127,7 @@ fn hover_record_struct_limit() {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -1200,11 +1152,7 @@ fn hover_record_variant_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 12 (0xC), align = 4, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1225,11 +1173,7 @@ fn hover_record_variant_limit() {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 4, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1250,11 +1194,7 @@ fn hover_record_variant_limit() {
 
             ---
 
-            size = 16 (0x10), align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 16 (0x10), align = 4, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1275,11 +1215,7 @@ fn hover_record_variant_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 12 (0xC), align = 4, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1300,11 +1236,7 @@ fn hover_record_variant_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 12 (0xC), align = 4, no Drop
         "#]],
     );
 }
@@ -1330,11 +1262,7 @@ fn hover_enum_limit() {
 
             ---
 
-            size = 1, align = 1, niches = 254
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 1, align = 1, niches = 254, no Drop
         "#]],
     );
     check_hover_enum_variants_limit(
@@ -1356,11 +1284,7 @@ fn hover_enum_limit() {
 
             ---
 
-            size = 1, align = 1, niches = 254
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 1, align = 1, niches = 254, no Drop
         "#]],
     );
     check_hover_enum_variants_limit(
@@ -1379,11 +1303,7 @@ fn hover_enum_limit() {
 
             ---
 
-            size = 1, align = 1, niches = 254
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 1, align = 1, niches = 254, no Drop
         "#]],
     );
     check_hover_enum_variants_limit(
@@ -1402,11 +1322,7 @@ fn hover_enum_limit() {
 
             ---
 
-            size = 1, align = 1, niches = 254
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 1, align = 1, niches = 254, no Drop
         "#]],
     );
     check_hover_enum_variants_limit(
@@ -1443,11 +1359,7 @@ fn hover_enum_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4, niches = a lot
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 12 (0xC), align = 4, niches = a lot, no Drop
         "#]],
     );
 }
@@ -1473,11 +1385,7 @@ fn hover_union_limit() {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 4, align = 4, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1499,11 +1407,7 @@ fn hover_union_limit() {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 4, align = 4, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1522,11 +1426,7 @@ fn hover_union_limit() {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 4, align = 4, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1545,11 +1445,7 @@ fn hover_union_limit() {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 4, align = 4, no Drop
         "#]],
     );
 }
@@ -1575,11 +1471,7 @@ struct Foo$0 where u32: Copy;
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -1605,7 +1497,7 @@ type Fo$0o: Trait = S where T: Trait;
 
             ---
 
-            does not contain types with destructors (drop glue)
+            no Drop
         "#]],
     );
 }
@@ -1754,11 +1646,7 @@ fn main() {
 
             ---
 
-            size = 8, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 8, align = 4, no Drop
         "#]],
     );
     check_hover_range(
@@ -1813,11 +1701,7 @@ fn main() { let b$0ar = Some(12); }
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 4, no Drop
         "#]],
     );
 }
@@ -1845,7 +1729,7 @@ enum Option<T> {
 
             ---
 
-            does not contain types with destructors (drop glue)
+            no Drop
 
             ---
 
@@ -1908,11 +1792,7 @@ fn hover_for_local_variable_pat() {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 4, no Drop
         "#]],
     )
 }
@@ -1944,11 +1824,7 @@ fn hover_for_param_edge() {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 4, no Drop
         "#]],
     )
 }
@@ -1974,7 +1850,7 @@ fn hover_for_param_with_multiple_traits() {
 
             ---
 
-            may contain types with destructors (drop glue) depending on type parameters
+            type param may need Drop
         "#]],
     )
 }
@@ -2000,11 +1876,7 @@ fn main() { let foo_$0test = Thing::new(); }
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 4, no Drop
         "#]],
     )
 }
@@ -2089,6 +1961,10 @@ impl Thing {
                 x: u32,
             }
             ```
+
+            ---
+
+            size = 4, align = 4
         "#]],
     );
     check_hover_fields_limit(
@@ -2109,6 +1985,10 @@ impl Thing {
             ```rust
             struct Thing
             ```
+
+            ---
+
+            size = 4, align = 4
         "#]],
     );
     check(
@@ -2130,6 +2010,10 @@ impl Thing {
                 x: u32,
             }
             ```
+
+            ---
+
+            size = 4, align = 4
         "#]],
     );
     check(
@@ -2151,6 +2035,10 @@ impl Thing {
                 A,
             }
             ```
+
+            ---
+
+            size = 0, align = 1
         "#]],
     );
     check(
@@ -2172,6 +2060,10 @@ impl Thing {
                 A,
             }
             ```
+
+            ---
+
+            size = 0, align = 1
         "#]],
     );
     check(
@@ -2190,6 +2082,10 @@ impl usize {
             ```rust
             usize
             ```
+
+            ---
+
+            size = 8, align = 8
         "#]],
     );
     check(
@@ -2208,6 +2104,32 @@ impl fn() -> usize {
             ```rust
             fn() -> usize
             ```
+
+            ---
+
+            size = 8, align = 8, niches = 1
+        "#]],
+    );
+    check(
+        r#"
+pub struct Foo
+where
+    Self$0:;
+"#,
+        expect![[r#"
+            *Self*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            pub struct Foo
+            ```
+
+            ---
+
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -2753,11 +2675,7 @@ fn test_hover_function_pointer_show_identifiers() {
 
             ---
 
-            size = 8, align = 8, niches = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 8, align = 8, niches = 1, no Drop
         "#]],
     );
 }
@@ -2779,11 +2697,7 @@ fn test_hover_function_pointer_no_identifier() {
 
             ---
 
-            size = 8, align = 8, niches = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 8, align = 8, niches = 1, no Drop
         "#]],
     );
 }
@@ -3026,11 +2940,7 @@ pub struct B$0ar
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 0, align = 1, no Drop
 
             ---
 
@@ -3061,11 +2971,7 @@ pub struct B$0ar
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 0, align = 1, no Drop
 
             ---
 
@@ -3158,11 +3064,7 @@ fn test_hover_layout_of_variant() {
 
             ---
 
-            size = 4, align = 2
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 2, no Drop
         "#]],
     );
 }
@@ -3187,7 +3089,7 @@ fn test_hover_layout_of_variant_generic() {
 
             ---
 
-            does not contain types with destructors (drop glue)
+            no Drop
         "#]],
     );
 }
@@ -3212,11 +3114,7 @@ struct S$0<T>(core::marker::PhantomData<T>);
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -3244,11 +3142,7 @@ fn test_hover_layout_of_enum() {
 
             ---
 
-            size = 16 (0x10), align = 8, niches = 254
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 16 (0x10), align = 8, niches = 254, no Drop
         "#]],
     );
 }
@@ -3270,7 +3164,7 @@ fn test_hover_no_memory_layout() {
 
             ---
 
-            does not contain types with destructors (drop glue)
+            no Drop
         "#]],
     );
 
@@ -4578,11 +4472,7 @@ fn main() {
 
             ---
 
-            size = 8, align = 8, niches = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 8, align = 8, niches = 1, no Drop
 
             ---
 
@@ -4596,11 +4486,7 @@ fn main() {
 
             ---
 
-            size = 4, align = 4, offset = 0
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 4, offset = 0, no Drop
         "#]],
     );
 }
@@ -4620,16 +4506,12 @@ 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 = {const}, T = Foo>(T)
             ```
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            may contain types with destructors (drop glue) depending on type parameters; doesn't have a destructor
+            size = 0, align = 1, type param may need Drop
         "#]],
     );
 }
@@ -4654,11 +4536,7 @@ struct S$0T<const C: usize = {40 + 2}, T = Foo>(T);
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            may contain types with destructors (drop glue) depending on type parameters; doesn't have a destructor
+            size = 0, align = 1, type param may need Drop
         "#]],
     );
 }
@@ -4679,16 +4557,12 @@ 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 = {const}, T = Foo>(T)
             ```
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            may contain types with destructors (drop glue) depending on type parameters; doesn't have a destructor
+            size = 0, align = 1, type param may need Drop
         "#]],
     );
 }
@@ -4712,11 +4586,7 @@ fn main() {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -4740,11 +4610,7 @@ fn main() {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -4763,16 +4629,12 @@ fn main() {
             *value*
 
             ```rust
-            let value: Const<-1>
+            let value: Const<_>
             ```
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -4796,11 +4658,7 @@ fn main() {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -4824,11 +4682,7 @@ fn main() {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -4851,11 +4705,7 @@ impl Foo {
 
             ---
 
-            size = 8, align = 8, niches = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 8, align = 8, niches = 1, no Drop
         "#]],
     );
 }
@@ -4879,11 +4729,7 @@ impl Foo {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -5368,16 +5214,12 @@ type Fo$0o2 = Foo<2>;
             ```
 
             ```rust
-            type Foo2 = Foo<2>
+            type Foo2 = Foo<<expr>>
             ```
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -5427,11 +5269,7 @@ enum E {
 
             ---
 
-            size = 1, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 1, align = 1, no Drop
 
             ---
 
@@ -5460,11 +5298,7 @@ enum E {
 
             ---
 
-            size = 1, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 1, align = 1, no Drop
 
             ---
 
@@ -5494,11 +5328,7 @@ enum E {
 
             ---
 
-            size = 1, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 1, align = 1, no Drop
 
             ---
 
@@ -5528,11 +5358,7 @@ enum E {
 
             ---
 
-            size = 1, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 1, align = 1, no Drop
 
             ---
 
@@ -6197,7 +6023,7 @@ const FOO$0: &[i32; 5] = &[12; 5];
             ```
 
             ```rust
-            const FOO: &[i32; 5] = &[12, 12, 12, 12, 12]
+            const FOO: &[i32; {const}] = &[12, 12, 12, 12, 12]
             ```
         "#]],
     );
@@ -6463,11 +6289,7 @@ fn main() {
 
             ---
 
-            size = 32 (0x20), align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 32 (0x20), align = 4, no Drop
         "#]],
     );
 }
@@ -7671,11 +7493,7 @@ enum Enum {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 4, no Drop
         "#]],
     );
 }
@@ -7701,11 +7519,7 @@ enum Enum {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 4, no Drop
         "#]],
     );
 }
@@ -8375,11 +8189,7 @@ fn test() {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -9024,15 +8834,11 @@ fn main(notable$0: u32) {}
 
             ---
 
-            Implements notable traits: Notable\<Assoc = &str, Assoc2 = char>
+            Implements notable traits: `Notable<Assoc = &str, Assoc2 = char>`
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 4, no Drop
         "#]],
     );
 }
@@ -9124,11 +8930,7 @@ extern "C" {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -9157,7 +8959,7 @@ fn main() {
             S
             ```
             ___
-            Implements notable traits: Notable, Future<Output = u32>, Iterator<Item = S>"#]],
+            Implements notable traits: `Future<Output = u32>`, `Iterator<Item = S>`, `Notable`"#]],
     );
 }
 
@@ -9274,11 +9076,7 @@ struct Pedro$0<'a> {
 
             ---
 
-            size = 16 (0x10), align = 8, niches = 1
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 16 (0x10), align = 8, niches = 1, no Drop
         "#]],
     )
 }
@@ -9299,7 +9097,7 @@ fn main(a$0: impl T) {}
 
             ---
 
-            may contain types with destructors (drop glue) depending on type parameters
+            type param may need Drop
         "#]],
     );
 }
@@ -9320,11 +9118,7 @@ fn main(a$0: T) {}
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -9377,11 +9171,7 @@ fn main() {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -9715,11 +9505,7 @@ type A$0 = B;
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
 
             ---
 
@@ -9752,11 +9538,7 @@ type A$0 = B;
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
 
             ---
 
@@ -9790,11 +9572,7 @@ type A$0 = B;
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
 
             ---
 
@@ -9826,11 +9604,7 @@ type A$0 = B;
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 
@@ -9954,11 +9728,7 @@ fn main() {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 
@@ -9986,11 +9756,7 @@ fn main() {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 
@@ -10025,11 +9791,7 @@ fn main() {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
 }
@@ -10348,11 +10110,7 @@ fn bar() {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 4, align = 4, no Drop
 
             ---
 
@@ -10366,7 +10124,7 @@ fn bar() {
 
             ---
 
-            may contain types with destructors (drop glue) depending on type parameters
+            type param may need Drop
 
             ---
 
@@ -10599,11 +10357,7 @@ struct NoDrop$0;
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            size = 0, align = 1, no Drop
         "#]],
     );
     check(
@@ -10627,11 +10381,7 @@ impl Drop for NeedsDrop {
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue); has a destructor
+            size = 0, align = 1, impl Drop
         "#]],
     );
     check(
@@ -10656,11 +10406,7 @@ type NoDrop$0 = core::mem::ManuallyDrop<NeedsDrop>;
 
             ---
 
-            size = 0, align = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 0, align = 1, no Drop
         "#]],
     );
     check(
@@ -10691,11 +10437,7 @@ struct DropField$0 {
 
             ---
 
-            size = 4, align = 4
-
-            ---
-
-            contain types with destructors (drop glue); doesn't have a destructor
+            size = 4, align = 4, needs Drop
         "#]],
     );
     check(
@@ -10716,7 +10458,7 @@ type Foo$0 = impl Sized;
 
             ---
 
-            contain types with destructors (drop glue)
+            needs Drop
         "#]],
     );
     check(
@@ -10744,11 +10486,7 @@ enum Enum {
 
             ---
 
-            size = 16 (0x10), align = 8, niches = 1
-
-            ---
-
-            does not contain types with destructors (drop glue)
+            size = 16 (0x10), align = 8, niches = 1, no Drop
         "#]],
     );
     check(
@@ -10768,7 +10506,7 @@ struct Foo$0<T>(T);
 
             ---
 
-            may contain types with destructors (drop glue) depending on type parameters; doesn't have a destructor
+            type param may need Drop
         "#]],
     );
     check(
@@ -10791,7 +10529,7 @@ struct Foo$0<T: Copy>(T);
 
             ---
 
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            no Drop
         "#]],
     );
     check(
@@ -10817,7 +10555,7 @@ struct Foo$0<T: Trait>(T::Assoc);
 
             ---
 
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            no Drop
         "#]],
     );
     check(
@@ -10848,7 +10586,7 @@ pub struct ManuallyDrop$0<T: ?Sized> {
 
             ---
 
-            does not contain types with destructors (drop glue); doesn't have a destructor
+            no Drop
         "#]],
     );
 }
@@ -10891,3 +10629,73 @@ impl PublicFlags for NoteDialects {
         "#]],
     );
 }
+
+#[test]
+fn bounds_from_container_do_not_panic() {
+    check(
+        r#"
+//- minicore: copy
+struct Foo<T>(T);
+
+impl<T: Copy> Foo<T> {
+    fn foo<U: Copy>(&self, _u: U) {}
+}
+
+fn bar(v: &Foo<i32>) {
+    v.$0foo(1u32);
+}
+    "#,
+        expect![[r#"
+            *foo*
+
+            ```rust
+            ra_test_fixture::Foo
+            ```
+
+            ```rust
+            impl<T> Foo<T>
+            fn foo<U>(&self, _u: U)
+            where
+                U: Copy,
+                // Bounds from impl:
+                T: Copy,
+            ```
+
+            ---
+
+            `T` = `i32`, `U` = `u32`
+        "#]],
+    );
+}
+
+#[test]
+fn extra_lifetime_param_on_trait_method_subst() {
+    check(
+        r#"
+struct AudioFormat;
+
+trait ValueEnum {
+    fn to_possible_value(&self);
+}
+
+impl ValueEnum for AudioFormat {
+    fn to_possible_value<'a>(&'a self) {}
+}
+
+fn main() {
+    ValueEnum::to_possible_value$0(&AudioFormat);
+}
+    "#,
+        expect![[r#"
+            *to_possible_value*
+
+            ```rust
+            ra_test_fixture::AudioFormat
+            ```
+
+            ```rust
+            fn to_possible_value<'a>(&'a self)
+            ```
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 6babdff52a2..82704af647d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -5,21 +5,21 @@ use std::{
 
 use either::Either;
 use hir::{
-    sym, ClosureStyle, DisplayTarget, HasVisibility, HirDisplay, HirDisplayError, HirWrite,
-    ModuleDef, ModuleDefId, Semantics,
+    ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
+    HirWrite, ModuleDef, ModuleDefId, Semantics, sym,
 };
-use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase};
-use ide_db::{text_edit::TextEdit, FxHashSet};
+use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder};
+use ide_db::{FxHashSet, text_edit::TextEdit};
 use itertools::Itertools;
-use smallvec::{smallvec, SmallVec};
-use span::EditionedFileId;
+use smallvec::{SmallVec, smallvec};
 use stdx::never;
 use syntax::{
+    SmolStr, SyntaxNode, TextRange, TextSize, WalkEvent,
     ast::{self, AstNode, HasGenericParams},
-    format_smolstr, match_ast, SmolStr, SyntaxNode, TextRange, TextSize, WalkEvent,
+    format_smolstr, match_ast,
 };
 
-use crate::{navigation_target::TryToNav, FileId};
+use crate::{FileId, navigation_target::TryToNav};
 
 mod adjustment;
 mod bind_pat;
@@ -85,7 +85,7 @@ pub(crate) fn inlay_hints(
     let sema = Semantics::new(db);
     let file_id = sema
         .attach_first_edition(file_id)
-        .unwrap_or_else(|| EditionedFileId::current_edition(file_id));
+        .unwrap_or_else(|| EditionedFileId::current_edition(db, file_id));
     let file = sema.parse(file_id);
     let file = file.syntax();
 
@@ -136,7 +136,7 @@ pub(crate) fn inlay_hints_resolve(
     let sema = Semantics::new(db);
     let file_id = sema
         .attach_first_edition(file_id)
-        .unwrap_or_else(|| EditionedFileId::current_edition(file_id));
+        .unwrap_or_else(|| EditionedFileId::current_edition(db, file_id));
     let file = sema.parse(file_id);
     let file = file.syntax();
 
@@ -207,7 +207,11 @@ fn hints(
     file_id: EditionedFileId,
     node: SyntaxNode,
 ) {
-    let display_target = sema.first_crate_or_default(file_id.file_id()).to_display_target(sema.db);
+    let file_id = file_id.editioned_file_id(sema.db);
+    let Some(krate) = sema.first_crate(file_id.file_id()) else {
+        return;
+    };
+    let display_target = krate.to_display_target(sema.db);
     closing_brace::hints(hints, sema, config, file_id, display_target, node.clone());
     if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
         generic_param::hints(hints, famous_defs, config, any_has_generic_args);
@@ -219,12 +223,12 @@ fn hints(
                 chaining::hints(hints, famous_defs, config, display_target, &expr);
                 adjustment::hints(hints, famous_defs, config, display_target, &expr);
                 match expr {
-                    ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)),
+                    ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, ast::Expr::from(it)),
                     ast::Expr::MethodCallExpr(it) => {
-                        param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it))
+                        param_name::hints(hints, famous_defs, config, ast::Expr::from(it))
                     }
                     ast::Expr::ClosureExpr(it) => {
-                        closure_captures::hints(hints, famous_defs, config, file_id, it.clone());
+                        closure_captures::hints(hints, famous_defs, config, it.clone());
                         closure_ret::hints(hints, famous_defs, config, display_target, it)
                     },
                     ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, file_id,  it),
@@ -793,7 +797,7 @@ fn hint_iterator(
 
     if ty.impls_trait(db, iter_trait, &[]) {
         let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
-            hir::AssocItem::TypeAlias(alias) if alias.name(db) == sym::Item.clone() => Some(alias),
+            hir::AssocItem::TypeAlias(alias) if alias.name(db) == sym::Item => Some(alias),
             _ => None,
         })?;
         if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) {
@@ -809,7 +813,8 @@ fn ty_to_text_edit(
     config: &InlayHintsConfig,
     node_for_hint: &SyntaxNode,
     ty: &hir::Type,
-    offset_to_insert: TextSize,
+    offset_to_insert_ty: TextSize,
+    additional_edits: &dyn Fn(&mut TextEditBuilder),
     prefix: impl Into<String>,
 ) -> Option<LazyProperty<TextEdit>> {
     // FIXME: Limit the length and bail out on excess somehow?
@@ -818,8 +823,11 @@ fn ty_to_text_edit(
         .and_then(|scope| ty.display_source_code(scope.db, scope.module().into(), false).ok())?;
     Some(config.lazy_text_edit(|| {
         let mut builder = TextEdit::builder();
-        builder.insert(offset_to_insert, prefix.into());
-        builder.insert(offset_to_insert, rendered);
+        builder.insert(offset_to_insert_ty, prefix.into());
+        builder.insert(offset_to_insert_ty, rendered);
+
+        additional_edits(&mut builder);
+
         builder.finish()
     }))
 }
@@ -836,9 +844,9 @@ mod tests {
     use itertools::Itertools;
     use test_utils::extract_annotations;
 
-    use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode};
     use crate::DiscriminantHints;
-    use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
+    use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode};
+    use crate::{LifetimeElisionHints, fixture, inlay_hints::InlayHintsConfig};
 
     use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve};
 
@@ -996,4 +1004,51 @@ fn foo() {
 "#,
         );
     }
+
+    #[test]
+    fn closure_dependency_cycle_no_panic() {
+        check(
+            r#"
+fn foo() {
+    let closure;
+     // ^^^^^^^ impl Fn()
+    closure = || {
+        closure();
+    };
+}
+
+fn bar() {
+    let closure1;
+     // ^^^^^^^^ impl Fn()
+    let closure2;
+     // ^^^^^^^^ impl Fn()
+    closure1 = || {
+        closure2();
+    };
+    closure2 = || {
+        closure1();
+    };
+}
+        "#,
+        );
+    }
+
+    #[test]
+    fn regression_19610() {
+        check(
+            r#"
+trait Trait {
+    type Assoc;
+}
+struct Foo<A>(A);
+impl<A: Trait<Assoc = impl Trait>> Foo<A> {
+    fn foo<'a, 'b>(_: &'a [i32], _: &'b [i32]) {}
+}
+
+fn bar() {
+    Foo::foo(&[1], &[2]);
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index 91b81872952..f2844a2eaa6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
@@ -13,7 +13,7 @@ use hir::{
 use ide_db::famous_defs::FamousDefs;
 
 use ide_db::text_edit::TextEditBuilder;
-use syntax::ast::{self, prec::ExprPrecedence, AstNode};
+use syntax::ast::{self, AstNode, prec::ExprPrecedence};
 
 use crate::{
     AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintLabelPart,
@@ -224,7 +224,7 @@ fn mode_and_needs_parens_for_adjustment_hints(
     expr: &ast::Expr,
     mode: AdjustmentHintsMode,
 ) -> (bool, bool, bool) {
-    use {std::cmp::Ordering::*, AdjustmentHintsMode::*};
+    use {AdjustmentHintsMode::*, std::cmp::Ordering::*};
 
     match mode {
         Prefix | Postfix => {
@@ -284,8 +284,8 @@ fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool,
 #[cfg(test)]
 mod tests {
     use crate::{
-        inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
         AdjustmentHints, AdjustmentHintsMode, InlayHintsConfig,
+        inlay_hints::tests::{DISABLED_CONFIG, check_with_config},
     };
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index 4379153acaa..52ea2e5ec58 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -4,7 +4,7 @@
 //! let _x /* i32 */= f(4, 4);
 //! ```
 use hir::{DisplayTarget, Semantics};
-use ide_db::{famous_defs::FamousDefs, RootDatabase};
+use ide_db::{RootDatabase, famous_defs::FamousDefs};
 
 use itertools::Itertools;
 use syntax::{
@@ -13,8 +13,8 @@ use syntax::{
 };
 
 use crate::{
-    inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit},
     InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind,
+    inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit},
 };
 
 pub(super) fn hints(
@@ -87,6 +87,7 @@ pub(super) fn hints(
                 .as_ref()
                 .map_or_else(|| pat.syntax().text_range(), |t| t.text_range())
                 .end(),
+            &|_| (),
             if colon_token.is_some() { "" } else { ": " },
         )
     } else {
@@ -181,10 +182,10 @@ mod tests {
     use syntax::{TextRange, TextSize};
     use test_utils::extract_annotations;
 
-    use crate::{fixture, inlay_hints::InlayHintsConfig, ClosureReturnTypeHints};
+    use crate::{ClosureReturnTypeHints, fixture, inlay_hints::InlayHintsConfig};
 
     use crate::inlay_hints::tests::{
-        check, check_edit, check_no_edit, check_with_config, DISABLED_CONFIG, TEST_CONFIG,
+        DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_no_edit, check_with_config,
     };
 
     #[track_caller]
@@ -861,28 +862,6 @@ fn main() {
         check_with_config(
             InlayHintsConfig {
                 type_hints: true,
-                closure_style: ClosureStyle::ClosureWithId,
-                ..DISABLED_CONFIG
-            },
-            r#"
-//- minicore: fn
-fn main() {
-    let x = || 2;
-      //^ {closure#0}
-    let y = |t: i32| x() + t;
-      //^ {closure#1}
-    let mut t = 5;
-          //^ i32
-    let z = |k: i32| { t += k; };
-      //^ {closure#2}
-    let p = (y, z);
-      //^ ({closure#1}, {closure#2})
-}
-            "#,
-        );
-        check_with_config(
-            InlayHintsConfig {
-                type_hints: true,
                 closure_style: ClosureStyle::Hide,
                 ..DISABLED_CONFIG
             },
@@ -1140,12 +1119,11 @@ fn test() {
 
     #[test]
     fn no_edit_for_closure_return_without_body_block() {
-        // We can lift this limitation; see FIXME in closure_ret module.
         let config = InlayHintsConfig {
             closure_return_type_hints: ClosureReturnTypeHints::Always,
             ..TEST_CONFIG
         };
-        check_no_edit(
+        check_edit(
             config,
             r#"
 struct S<T>(T);
@@ -1154,6 +1132,13 @@ fn test() {
     let f = |a: S<usize>| S(a);
 }
 "#,
+            expect![[r#"
+            struct S<T>(T);
+            fn test() {
+                let f = || -> i32 { 3 };
+                let f = |a: S<usize>| -> S<S<usize>> { S(a) };
+            }
+            "#]],
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
index 5bbb4fe4e66..d2917320688 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
@@ -128,8 +128,8 @@ mod tests {
     use expect_test::expect;
 
     use crate::{
-        inlay_hints::tests::{check_edit, check_with_config, DISABLED_CONFIG},
         InlayHintsConfig,
+        inlay_hints::tests::{DISABLED_CONFIG, check_edit, check_with_config},
     };
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
index e9b728bcaa7..8ddbfaeffe8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
@@ -1,7 +1,7 @@
 //! Implementation of trait bound hints.
 //!
 //! Currently this renders the implied `Sized` bound.
-use ide_db::{famous_defs::FamousDefs, FileRange};
+use ide_db::{FileRange, famous_defs::FamousDefs};
 
 use span::EditionedFileId;
 use syntax::ast::{self, AstNode, HasTypeBounds};
@@ -86,7 +86,7 @@ mod tests {
 
     use crate::inlay_hints::InlayHintsConfig;
 
-    use crate::inlay_hints::tests::{check_expect, check_with_config, DISABLED_CONFIG};
+    use crate::inlay_hints::tests::{DISABLED_CONFIG, check_expect, check_with_config};
 
     #[track_caller]
     fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index 604719bc366..ff157fa171b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -2,8 +2,8 @@
 use hir::DisplayTarget;
 use ide_db::famous_defs::FamousDefs;
 use syntax::{
-    ast::{self, AstNode},
     Direction, NodeOrToken, SyntaxKind, T,
+    ast::{self, AstNode},
 };
 
 use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind};
@@ -76,16 +76,15 @@ pub(super) fn hints(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::{Expect, expect};
     use ide_db::text_edit::{TextRange, TextSize};
 
     use crate::{
-        fixture,
+        InlayHintsConfig, fixture,
         inlay_hints::{
-            tests::{check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG},
             LazyProperty,
+            tests::{DISABLED_CONFIG, TEST_CONFIG, check_expect, check_with_config},
         },
-        InlayHintsConfig,
     };
 
     #[track_caller]
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
index bec6d38ee9c..de9ca8c000f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
@@ -7,13 +7,14 @@ use hir::{DisplayTarget, HirDisplay, Semantics};
 use ide_db::{FileRange, RootDatabase};
 use span::EditionedFileId;
 use syntax::{
+    SyntaxKind, SyntaxNode, T,
     ast::{self, AstNode, HasLoopBody, HasName},
-    match_ast, SyntaxKind, SyntaxNode, T,
+    match_ast,
 };
 
 use crate::{
-    inlay_hints::LazyProperty, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig,
-    InlayKind,
+    InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind,
+    inlay_hints::LazyProperty,
 };
 
 pub(super) fn hints(
@@ -159,8 +160,8 @@ pub(super) fn hints(
 #[cfg(test)]
 mod tests {
     use crate::{
-        inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
         InlayHintsConfig,
+        inlay_hints::tests::{DISABLED_CONFIG, check_with_config},
     };
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
index 9b981c0a3ac..3186a566d2b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
@@ -3,8 +3,7 @@
 //! Tests live in [`bind_pat`][super::bind_pat] module.
 use ide_db::famous_defs::FamousDefs;
 use ide_db::text_edit::{TextRange, TextSize};
-use span::EditionedFileId;
-use stdx::{never, TupleExt};
+use stdx::{TupleExt, never};
 use syntax::ast::{self, AstNode};
 
 use crate::{
@@ -15,7 +14,6 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
     closure: ast::ClosureExpr,
 ) -> Option<()> {
     if !config.closure_capture_hints {
@@ -75,10 +73,12 @@ pub(super) fn hints(
                 // force cache the source file, otherwise sema lookup will potentially panic
                 _ = sema.parse_or_expand(source.file());
                 source.name().and_then(|name| {
-                    name.syntax()
-                        .original_file_range_opt(sema.db)
-                        .map(TupleExt::head)
-                        .map(Into::into)
+                    name.syntax().original_file_range_opt(sema.db).map(TupleExt::head).map(
+                        |frange| ide_db::FileRange {
+                            file_id: frange.file_id.file_id(sema.db),
+                            range: frange.range,
+                        },
+                    )
                 })
             }),
             tooltip: None,
@@ -96,8 +96,8 @@ pub(super) fn hints(
 #[cfg(test)]
 mod tests {
     use crate::{
-        inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
         InlayHintsConfig,
+        inlay_hints::tests::{DISABLED_CONFIG, check_with_config},
     };
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
index 61c9c25fe73..9e600b5455b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
@@ -2,12 +2,12 @@
 //!
 //! Tests live in [`bind_pat`][super::bind_pat] module.
 use hir::DisplayTarget;
-use ide_db::famous_defs::FamousDefs;
+use ide_db::{famous_defs::FamousDefs, text_edit::TextEditBuilder};
 use syntax::ast::{self, AstNode};
 
 use crate::{
-    inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit},
     ClosureReturnTypeHints, InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind,
+    inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit},
 };
 
 pub(super) fn hints(
@@ -35,8 +35,9 @@ pub(super) fn hints(
 
     let param_list = closure.param_list()?;
 
-    let closure = sema.descend_node_into_attributes(closure).pop()?;
-    let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure.clone()))?.adjusted();
+    let resolve_parent = Some(closure.syntax().text_range());
+    let descended_closure = sema.descend_node_into_attributes(closure.clone()).pop()?;
+    let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(descended_closure.clone()))?.adjusted();
     let callable = ty.as_callable(sema.db)?;
     let ty = callable.return_type();
     if arrow.is_none() && ty.is_unit() {
@@ -48,23 +49,30 @@ pub(super) fn hints(
     if arrow.is_none() {
         label.prepend_str(" -> ");
     }
-    // FIXME?: We could provide text edit to insert braces for closures with non-block body.
-    let text_edit = if has_block_body {
-        ty_to_text_edit(
-            sema,
-            config,
-            closure.syntax(),
-            &ty,
-            arrow
-                .as_ref()
-                .map_or_else(|| param_list.syntax().text_range(), |t| t.text_range())
-                .end(),
-            if arrow.is_none() { " -> " } else { "" },
-        )
-    } else {
-        None
+
+    let offset_to_insert_ty =
+        arrow.as_ref().map_or_else(|| param_list.syntax().text_range(), |t| t.text_range()).end();
+
+    // Insert braces if necessary
+    let insert_braces = |builder: &mut TextEditBuilder| {
+        if !has_block_body {
+            if let Some(range) = closure.body().map(|b| b.syntax().text_range()) {
+                builder.insert(range.start(), "{ ".to_owned());
+                builder.insert(range.end(), " }".to_owned());
+            }
+        }
     };
 
+    let text_edit = ty_to_text_edit(
+        sema,
+        config,
+        descended_closure.syntax(),
+        &ty,
+        offset_to_insert_ty,
+        &insert_braces,
+        if arrow.is_none() { " -> " } else { "" },
+    );
+
     acc.push(InlayHint {
         range: param_list.syntax().text_range(),
         kind: InlayKind::Type,
@@ -73,14 +81,14 @@ pub(super) fn hints(
         position: InlayHintPosition::After,
         pad_left: false,
         pad_right: false,
-        resolve_parent: Some(closure.syntax().text_range()),
+        resolve_parent,
     });
     Some(())
 }
 
 #[cfg(test)]
 mod tests {
-    use crate::inlay_hints::tests::{check_with_config, DISABLED_CONFIG};
+    use crate::inlay_hints::tests::{DISABLED_CONFIG, check_with_config};
 
     use super::*;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
index f1e1955d14c..827a0438dd0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
@@ -6,7 +6,7 @@
 //! ```
 use hir::Semantics;
 use ide_db::text_edit::TextEdit;
-use ide_db::{famous_defs::FamousDefs, RootDatabase};
+use ide_db::{RootDatabase, famous_defs::FamousDefs};
 use span::EditionedFileId;
 use syntax::ast::{self, AstNode, HasName};
 
@@ -107,8 +107,8 @@ mod tests {
     use expect_test::expect;
 
     use crate::inlay_hints::{
-        tests::{check_edit, check_with_config, DISABLED_CONFIG},
         DiscriminantHints, InlayHintsConfig,
+        tests::{DISABLED_CONFIG, check_edit, check_with_config},
     };
 
     #[track_caller]
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
index 652dff0bc56..20f54b2cd19 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
@@ -1,7 +1,7 @@
 //! Extern block hints
 use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit};
 use span::EditionedFileId;
-use syntax::{ast, AstNode, SyntaxToken};
+use syntax::{AstNode, SyntaxToken, ast};
 
 use crate::{InlayHint, InlayHintsConfig};
 
@@ -98,7 +98,7 @@ fn item_hint(
 
 #[cfg(test)]
 mod tests {
-    use crate::inlay_hints::tests::{check_with_config, DISABLED_CONFIG};
+    use crate::inlay_hints::tests::{DISABLED_CONFIG, check_with_config};
 
     #[test]
     fn unadorned() {
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
index 762a4c26551..6e1b3bdbdf0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
@@ -1,12 +1,14 @@
 //! Implementation of inlay hints for generic parameters.
+use either::Either;
 use ide_db::{active_parameter::generic_def_for_node, famous_defs::FamousDefs};
 use syntax::{
-    ast::{self, AnyHasGenericArgs, HasGenericArgs, HasName},
     AstNode,
+    ast::{self, AnyHasGenericArgs, HasGenericArgs, HasName},
 };
 
 use crate::{
-    inlay_hints::GenericParameterHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
+    InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
+    inlay_hints::{GenericParameterHints, param_name},
 };
 
 use super::param_name::is_argument_similar_to_param_name;
@@ -62,8 +64,17 @@ pub(crate) fn hints(
         let param_name = param.name(sema.db);
 
         let should_hide = {
-            let argument = get_string_representation(&arg)?;
-            is_argument_similar_to_param_name(&argument, param_name.as_str())
+            let param_name = param_name.as_str();
+            get_segment_representation(&arg).map_or(false, |seg| match seg {
+                Either::Left(Either::Left(argument)) => {
+                    is_argument_similar_to_param_name(&argument, param_name)
+                }
+                Either::Left(Either::Right(argument)) => argument
+                    .segment()
+                    .and_then(|it| it.name_ref())
+                    .is_some_and(|it| it.text().eq_ignore_ascii_case(param_name)),
+                Either::Right(lifetime) => lifetime.text().eq_ignore_ascii_case(param_name),
+            })
         };
 
         if should_hide {
@@ -91,7 +102,10 @@ pub(crate) fn hints(
                     }
                 };
                 let linked_location = source_syntax.and_then(|it| sema.original_range_opt(&it));
-                linked_location.map(Into::into)
+                linked_location.map(|frange| ide_db::FileRange {
+                    file_id: frange.file_id.file_id(sema.db),
+                    range: frange.range,
+                })
             }),
         );
 
@@ -111,32 +125,34 @@ pub(crate) fn hints(
     Some(())
 }
 
-fn get_string_representation(arg: &ast::GenericArg) -> Option<String> {
+fn get_segment_representation(
+    arg: &ast::GenericArg,
+) -> Option<Either<Either<Vec<ast::NameRef>, ast::Path>, ast::Lifetime>> {
     return match arg {
         ast::GenericArg::AssocTypeArg(_) => None,
-        ast::GenericArg::ConstArg(const_arg) => Some(const_arg.to_string()),
+        ast::GenericArg::ConstArg(const_arg) => {
+            param_name::get_segment_representation(&const_arg.expr()?).map(Either::Left)
+        }
         ast::GenericArg::LifetimeArg(lifetime_arg) => {
             let lifetime = lifetime_arg.lifetime()?;
-            Some(lifetime.to_string())
+            Some(Either::Right(lifetime))
         }
         ast::GenericArg::TypeArg(type_arg) => {
             let ty = type_arg.ty()?;
-            Some(
-                type_path_segment(&ty)
-                    .map_or_else(|| type_arg.to_string(), |segment| segment.to_string()),
-            )
+            type_path(&ty).map(Either::Right).map(Either::Left)
         }
     };
 
-    fn type_path_segment(ty: &ast::Type) -> Option<ast::PathSegment> {
+    fn type_path(ty: &ast::Type) -> Option<ast::Path> {
         match ty {
-            ast::Type::ArrayType(it) => type_path_segment(&it.ty()?),
-            ast::Type::ForType(it) => type_path_segment(&it.ty()?),
-            ast::Type::ParenType(it) => type_path_segment(&it.ty()?),
-            ast::Type::PathType(path_type) => path_type.path()?.segment(),
-            ast::Type::PtrType(it) => type_path_segment(&it.ty()?),
-            ast::Type::RefType(it) => type_path_segment(&it.ty()?),
-            ast::Type::SliceType(it) => type_path_segment(&it.ty()?),
+            ast::Type::ArrayType(it) => type_path(&it.ty()?),
+            ast::Type::ForType(it) => type_path(&it.ty()?),
+            ast::Type::ParenType(it) => type_path(&it.ty()?),
+            ast::Type::PathType(path_type) => path_type.path(),
+            ast::Type::PtrType(it) => type_path(&it.ty()?),
+            ast::Type::RefType(it) => type_path(&it.ty()?),
+            ast::Type::SliceType(it) => type_path(&it.ty()?),
+            ast::Type::MacroType(macro_type) => macro_type.macro_call()?.path(),
             _ => None,
         }
     }
@@ -145,11 +161,11 @@ fn get_string_representation(arg: &ast::GenericArg) -> Option<String> {
 #[cfg(test)]
 mod tests {
     use crate::{
+        InlayHintsConfig,
         inlay_hints::{
-            tests::{check_with_config, DISABLED_CONFIG},
             GenericParameterHints,
+            tests::{DISABLED_CONFIG, check_with_config},
         },
-        InlayHintsConfig,
     };
 
     #[track_caller]
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
index 390139d214e..f52e27946ff 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -6,16 +6,17 @@
 //! }
 //! ```
 use hir::{
+    ChalkTyInterner, DefWithBody,
     db::{DefDatabase as _, HirDatabase as _},
     mir::{MirSpan, TerminatorKind},
-    ChalkTyInterner, DefWithBody,
 };
-use ide_db::{famous_defs::FamousDefs, FileRange};
+use ide_db::{FileRange, famous_defs::FamousDefs};
 
 use span::EditionedFileId;
 use syntax::{
+    ToSmolStr,
     ast::{self, AstNode},
-    match_ast, ToSmolStr,
+    match_ast,
 };
 
 use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
@@ -107,7 +108,7 @@ pub(super) fn hints(
                         .and_then(|d| source_map.pat_syntax(*d).ok())
                         .and_then(|d| {
                             Some(FileRange {
-                                file_id: d.file_id.file_id()?.into(),
+                                file_id: d.file_id.file_id()?.file_id(sema.db),
                                 range: d.value.text_range(),
                             })
                         })
@@ -143,8 +144,8 @@ fn nearest_token_after_node(
 #[cfg(test)]
 mod tests {
     use crate::{
-        inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
         InlayHintsConfig,
+        inlay_hints::tests::{DISABLED_CONFIG, check_with_config},
     };
 
     const ONLY_DROP_CONFIG: InlayHintsConfig =
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
index ae5b519b43d..f3be09f30a1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
@@ -7,8 +7,8 @@ use ide_db::famous_defs::FamousDefs;
 use ide_db::text_edit::TextEdit;
 use span::EditionedFileId;
 use syntax::{
-    ast::{self, AstNode},
     SyntaxKind,
+    ast::{self, AstNode},
 };
 
 use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints};
@@ -56,8 +56,8 @@ pub(super) fn hints(
 #[cfg(test)]
 mod tests {
     use crate::{
-        inlay_hints::tests::{check_with_config, TEST_CONFIG},
         InlayHintsConfig, LifetimeElisionHints,
+        inlay_hints::tests::{TEST_CONFIG, check_with_config},
     };
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs
index 1fdd6989917..baba49a427d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs
@@ -4,18 +4,18 @@
 //! ```
 use std::iter;
 
-use ide_db::{famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap};
+use ide_db::{FxHashMap, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty};
 use itertools::Itertools;
 use span::EditionedFileId;
+use syntax::{SmolStr, format_smolstr};
 use syntax::{
-    ast::{self, AstNode, HasGenericParams, HasName},
     SyntaxKind, SyntaxToken,
+    ast::{self, AstNode, HasGenericParams, HasName},
 };
-use syntax::{format_smolstr, SmolStr};
 
 use crate::{
-    inlay_hints::InlayHintCtx, InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind,
-    LifetimeElisionHints,
+    InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints,
+    inlay_hints::InlayHintCtx,
 };
 
 pub(super) fn fn_hints(
@@ -268,13 +268,14 @@ fn hints_(
         ctx.lifetime_stacks.iter().flat_map(|it| it.iter()).cloned().zip(iter::repeat(0)).collect();
     // allocate names
     let mut gen_idx_name = {
-        let mut gen = (0u8..).map(|idx| match idx {
+        let mut generic = (0u8..).map(|idx| match idx {
             idx if idx < 10 => SmolStr::from_iter(['\'', (idx + 48) as char]),
             idx => format_smolstr!("'{idx}"),
         });
         let ctx = &*ctx;
         move || {
-            gen.by_ref()
+            generic
+                .by_ref()
                 .find(|s| ctx.lifetime_stacks.iter().flat_map(|it| it.iter()).all(|n| n != s))
                 .unwrap_or_default()
         }
@@ -406,8 +407,8 @@ fn hints_(
 #[cfg(test)]
 mod tests {
     use crate::{
-        inlay_hints::tests::{check, check_with_config, TEST_CONFIG},
         InlayHintsConfig, LifetimeElisionHints,
+        inlay_hints::tests::{TEST_CONFIG, check, check_with_config},
     };
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index 8f01b1bd38b..5ff9fee60ab 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -4,16 +4,14 @@
 //! _ = max(/*x*/4, /*y*/4);
 //! ```
 
+use std::iter::zip;
+
 use either::Either;
-use hir::{Callable, Semantics};
-use ide_db::{famous_defs::FamousDefs, RootDatabase};
+use hir::Semantics;
+use ide_db::{RootDatabase, famous_defs::FamousDefs};
 
-use span::EditionedFileId;
 use stdx::to_lower_snake_case;
-use syntax::{
-    ast::{self, AstNode, HasArgList, HasName, UnaryOp},
-    ToSmolStr,
-};
+use syntax::ast::{self, AstNode, HasArgList, HasName, UnaryOp};
 
 use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
 
@@ -21,7 +19,6 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, krate): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
     expr: ast::Expr,
 ) -> Option<()> {
     if !config.parameter_hints {
@@ -29,6 +26,12 @@ pub(super) fn hints(
     }
 
     let (callable, arg_list) = get_callable(sema, &expr)?;
+    let unary_function = callable.n_params() == 1;
+    let function_name = match callable.kind() {
+        hir::CallableKind::Function(function) => Some(function.name(sema.db)),
+        _ => None,
+    };
+    let function_name = function_name.as_ref().map(|it| it.as_str());
     let hints = callable
         .params()
         .into_iter()
@@ -40,7 +43,13 @@ pub(super) fn hints(
             Some((p, param_name, arg, range))
         })
         .filter(|(_, param_name, arg, _)| {
-            !should_hide_param_name_hint(sema, &callable, param_name.as_str(), arg)
+            !should_hide_param_name_hint(
+                sema,
+                unary_function,
+                function_name,
+                param_name.as_str(),
+                arg,
+            )
         })
         .map(|(param, param_name, _, hir::FileRange { range, .. })| {
             let colon = if config.render_colons { ":" } else { "" };
@@ -56,7 +65,10 @@ pub(super) fn hints(
                             _ => None,
                         },
                     }?;
-                    sema.original_range_opt(name_syntax.syntax()).map(Into::into)
+                    sema.original_range_opt(name_syntax.syntax()).map(|frange| ide_db::FileRange {
+                        file_id: frange.file_id.file_id(sema.db),
+                        range: frange.range,
+                    })
                 }),
             );
             InlayHint {
@@ -94,9 +106,13 @@ fn get_callable(
     }
 }
 
+const INSIGNIFICANT_METHOD_NAMES: &[&str] = &["clone", "as_ref", "into"];
+const INSIGNIFICANT_PARAMETER_NAMES: &[&str] = &["predicate", "value", "pat", "rhs", "other"];
+
 fn should_hide_param_name_hint(
     sema: &Semantics<'_, RootDatabase>,
-    callable: &hir::Callable,
+    unary_function: bool,
+    function_name: Option<&str>,
     param_name: &str,
     argument: &ast::Expr,
 ) -> bool {
@@ -114,95 +130,128 @@ fn should_hide_param_name_hint(
         return true;
     }
 
-    if matches!(argument, ast::Expr::PrefixExpr(prefix) if prefix.op_kind() == Some(UnaryOp::Not)) {
-        return false;
+    if param_name.starts_with("ra_fixture") {
+        return true;
     }
 
-    let fn_name = match callable.kind() {
-        hir::CallableKind::Function(it) => Some(it.name(sema.db).as_str().to_smolstr()),
-        _ => None,
-    };
-    let fn_name = fn_name.as_deref();
-    is_param_name_suffix_of_fn_name(param_name, callable, fn_name)
-        || is_argument_expr_similar_to_param_name(argument, param_name)
-        || param_name.starts_with("ra_fixture")
-        || (callable.n_params() == 1 && is_obvious_param(param_name))
-        || is_adt_constructor_similar_to_param_name(sema, argument, param_name)
+    if unary_function {
+        if let Some(function_name) = function_name {
+            if is_param_name_suffix_of_fn_name(param_name, function_name) {
+                return true;
+            }
+        }
+        if is_obvious_param(param_name) {
+            return true;
+        }
+    }
+
+    is_argument_expr_similar_to_param_name(sema, argument, param_name)
 }
 
 /// Hide the parameter name of a unary function if it is a `_` - prefixed suffix of the function's name, or equal.
 ///
 /// `fn strip_suffix(suffix)` will be hidden.
 /// `fn stripsuffix(suffix)` will not be hidden.
-fn is_param_name_suffix_of_fn_name(
+fn is_param_name_suffix_of_fn_name(param_name: &str, fn_name: &str) -> bool {
+    fn_name == param_name
+        || fn_name
+            .len()
+            .checked_sub(param_name.len())
+            .and_then(|at| fn_name.is_char_boundary(at).then(|| fn_name.split_at(at)))
+            .is_some_and(|(prefix, suffix)| {
+                suffix.eq_ignore_ascii_case(param_name) && prefix.ends_with('_')
+            })
+}
+
+fn is_argument_expr_similar_to_param_name(
+    sema: &Semantics<'_, RootDatabase>,
+    argument: &ast::Expr,
     param_name: &str,
-    callable: &Callable,
-    fn_name: Option<&str>,
 ) -> bool {
-    match (callable.n_params(), fn_name) {
-        (1, Some(function)) => {
-            function == param_name
-                || function
-                    .len()
-                    .checked_sub(param_name.len())
-                    .and_then(|at| function.is_char_boundary(at).then(|| function.split_at(at)))
-                    .is_some_and(|(prefix, suffix)| {
-                        suffix.eq_ignore_ascii_case(param_name) && prefix.ends_with('_')
-                    })
+    match get_segment_representation(argument) {
+        Some(Either::Left(argument)) => is_argument_similar_to_param_name(&argument, param_name),
+        Some(Either::Right(path)) => {
+            path.segment()
+                .and_then(|it| it.name_ref())
+                .is_some_and(|name_ref| name_ref.text().eq_ignore_ascii_case(param_name))
+                || is_adt_constructor_similar_to_param_name(sema, &path, param_name)
         }
-        _ => false,
+        None => false,
     }
 }
 
-fn is_argument_expr_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool {
-    let argument = match get_string_representation(argument) {
-        Some(argument) => argument,
-        None => return false,
-    };
-    is_argument_similar_to_param_name(&argument, param_name)
-}
-
 /// Check whether param_name and argument are the same or
 /// whether param_name is a prefix/suffix of argument(split at `_`).
-pub(super) fn is_argument_similar_to_param_name(argument: &str, param_name: &str) -> bool {
-    // std is honestly too panic happy...
-    let str_split_at = |str: &str, at| str.is_char_boundary(at).then(|| argument.split_at(at));
-
-    let param_name = param_name.trim_start_matches('_');
-    let argument = argument.trim_start_matches('_');
-
-    match str_split_at(argument, param_name.len()) {
-        Some((prefix, rest)) if prefix.eq_ignore_ascii_case(param_name) => {
-            return rest.is_empty() || rest.starts_with('_');
-        }
-        _ => (),
-    }
-    match argument.len().checked_sub(param_name.len()).and_then(|at| str_split_at(argument, at)) {
-        Some((rest, suffix)) if param_name.eq_ignore_ascii_case(suffix) => {
-            return rest.is_empty() || rest.ends_with('_');
-        }
-        _ => (),
-    }
-    false
+pub(super) fn is_argument_similar_to_param_name(
+    argument: &[ast::NameRef],
+    param_name: &str,
+) -> bool {
+    debug_assert!(!argument.is_empty());
+    debug_assert!(!param_name.is_empty());
+    let param_name = param_name.split('_');
+    let argument = argument.iter().flat_map(|it| it.text_non_mutable().split('_'));
+
+    let prefix_match = zip(argument.clone(), param_name.clone())
+        .all(|(arg, param)| arg.eq_ignore_ascii_case(param));
+    let postfix_match = || {
+        zip(argument.rev(), param_name.rev()).all(|(arg, param)| arg.eq_ignore_ascii_case(param))
+    };
+    prefix_match || postfix_match()
 }
 
-fn get_string_representation(expr: &ast::Expr) -> Option<String> {
+pub(super) fn get_segment_representation(
+    expr: &ast::Expr,
+) -> Option<Either<Vec<ast::NameRef>, ast::Path>> {
     match expr {
         ast::Expr::MethodCallExpr(method_call_expr) => {
+            let receiver =
+                method_call_expr.receiver().and_then(|expr| get_segment_representation(&expr));
             let name_ref = method_call_expr.name_ref()?;
-            match name_ref.text().as_str() {
-                "clone" | "as_ref" => method_call_expr.receiver().map(|rec| rec.to_string()),
-                name_ref => Some(name_ref.to_owned()),
+            if INSIGNIFICANT_METHOD_NAMES.contains(&name_ref.text().as_str()) {
+                return receiver;
             }
+            Some(Either::Left(match receiver {
+                Some(Either::Left(mut left)) => {
+                    left.push(name_ref);
+                    left
+                }
+                Some(Either::Right(_)) | None => vec![name_ref],
+            }))
+        }
+        ast::Expr::FieldExpr(field_expr) => {
+            let expr = field_expr.expr().and_then(|expr| get_segment_representation(&expr));
+            let name_ref = field_expr.name_ref()?;
+            let res = match expr {
+                Some(Either::Left(mut left)) => {
+                    left.push(name_ref);
+                    left
+                }
+                Some(Either::Right(_)) | None => vec![name_ref],
+            };
+            Some(Either::Left(res))
         }
-        ast::Expr::MacroExpr(macro_expr) => {
-            Some(macro_expr.macro_call()?.path()?.segment()?.to_string())
+        // paths
+        ast::Expr::MacroExpr(macro_expr) => macro_expr.macro_call()?.path().map(Either::Right),
+        ast::Expr::RecordExpr(record_expr) => record_expr.path().map(Either::Right),
+        ast::Expr::PathExpr(path_expr) => {
+            let path = path_expr.path()?;
+            // single segment paths are likely locals
+            Some(match path.as_single_name_ref() {
+                None => Either::Right(path),
+                Some(name_ref) => Either::Left(vec![name_ref]),
+            })
         }
-        ast::Expr::FieldExpr(field_expr) => Some(field_expr.name_ref()?.to_string()),
-        ast::Expr::PathExpr(path_expr) => Some(path_expr.path()?.segment()?.to_string()),
-        ast::Expr::PrefixExpr(prefix_expr) => get_string_representation(&prefix_expr.expr()?),
-        ast::Expr::RefExpr(ref_expr) => get_string_representation(&ref_expr.expr()?),
-        ast::Expr::CastExpr(cast_expr) => get_string_representation(&cast_expr.expr()?),
+        ast::Expr::PrefixExpr(prefix_expr) if prefix_expr.op_kind() == Some(UnaryOp::Not) => None,
+        // recurse
+        ast::Expr::PrefixExpr(prefix_expr) => get_segment_representation(&prefix_expr.expr()?),
+        ast::Expr::RefExpr(ref_expr) => get_segment_representation(&ref_expr.expr()?),
+        ast::Expr::CastExpr(cast_expr) => get_segment_representation(&cast_expr.expr()?),
+        ast::Expr::CallExpr(call_expr) => get_segment_representation(&call_expr.expr()?),
+        ast::Expr::AwaitExpr(await_expr) => get_segment_representation(&await_expr.expr()?),
+        ast::Expr::IndexExpr(index_expr) => get_segment_representation(&index_expr.base()?),
+        ast::Expr::ParenExpr(paren_expr) => get_segment_representation(&paren_expr.expr()?),
+        ast::Expr::TryExpr(try_expr) => get_segment_representation(&try_expr.expr()?),
+        // ast::Expr::ClosureExpr(closure_expr) => todo!(),
         _ => None,
     }
 }
@@ -210,30 +259,15 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> {
 fn is_obvious_param(param_name: &str) -> bool {
     // avoid displaying hints for common functions like map, filter, etc.
     // or other obvious words used in std
-    let is_obvious_param_name =
-        matches!(param_name, "predicate" | "value" | "pat" | "rhs" | "other");
-    param_name.len() == 1 || is_obvious_param_name
+    param_name.len() == 1 || INSIGNIFICANT_PARAMETER_NAMES.contains(&param_name)
 }
 
 fn is_adt_constructor_similar_to_param_name(
     sema: &Semantics<'_, RootDatabase>,
-    argument: &ast::Expr,
+    path: &ast::Path,
     param_name: &str,
 ) -> bool {
-    let path = match argument {
-        ast::Expr::CallExpr(c) => c.expr().and_then(|e| match e {
-            ast::Expr::PathExpr(p) => p.path(),
-            _ => None,
-        }),
-        ast::Expr::PathExpr(p) => p.path(),
-        ast::Expr::RecordExpr(r) => r.path(),
-        _ => return false,
-    };
-    let path = match path {
-        Some(it) => it,
-        None => return false,
-    };
-    (|| match sema.resolve_path(&path)? {
+    (|| match sema.resolve_path(path)? {
         hir::PathResolution::Def(hir::ModuleDef::Adt(_)) => {
             Some(to_lower_snake_case(&path.segment()?.name_ref()?.text()) == param_name)
         }
@@ -257,8 +291,8 @@ fn is_adt_constructor_similar_to_param_name(
 #[cfg(test)]
 mod tests {
     use crate::{
-        inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
         InlayHintsConfig,
+        inlay_hints::tests::{DISABLED_CONFIG, check_with_config},
     };
 
     #[track_caller]
@@ -501,6 +535,7 @@ fn enum_matches_param_name(completion_kind: CompletionKind) {}
 
 fn foo(param: u32) {}
 fn bar(param_eter: u32) {}
+fn baz(a_d_e: u32) {}
 
 enum CompletionKind {
     Keyword,
@@ -553,6 +588,14 @@ fn main() {
       //^^^^^^^^^^^ param_eter
 
     non_ident_pat((0, 0));
+
+    baz(a.d.e);
+    baz(a.dc.e);
+     // ^^^^^^ a_d_e
+    baz(ac.d.e);
+     // ^^^^^^ a_d_e
+    baz(a.d.ec);
+     // ^^^^^^ a_d_e
 }"#,
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
index de9b0e98a4b..d67d8458840 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
@@ -5,7 +5,7 @@
 //! ```
 use ide_db::famous_defs::FamousDefs;
 use span::EditionedFileId;
-use syntax::{ast, SyntaxToken, T};
+use syntax::{SyntaxToken, T, ast};
 
 use crate::{InlayHint, InlayHintsConfig};
 
@@ -41,8 +41,8 @@ fn inlay_hint(token: SyntaxToken) -> InlayHint {
 #[cfg(test)]
 mod tests {
     use crate::{
-        inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
         InlayHintsConfig,
+        inlay_hints::tests::{DISABLED_CONFIG, check_with_config},
     };
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/interpret.rs b/src/tools/rust-analyzer/crates/ide/src/interpret.rs
index 74dad488b4d..8f9d2d6bf11 100644
--- a/src/tools/rust-analyzer/crates/ide/src/interpret.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/interpret.rs
@@ -1,8 +1,8 @@
 use hir::{ConstEvalError, DefWithBody, DisplayTarget, Semantics};
-use ide_db::{base_db::SourceRootDatabase, FilePosition, LineIndexDatabase, RootDatabase};
+use ide_db::{FilePosition, LineIndexDatabase, RootDatabase, base_db::SourceDatabase};
 use std::time::{Duration, Instant};
 use stdx::format_to;
-use syntax::{algo::ancestors_at_offset, ast, AstNode, TextRange};
+use syntax::{AstNode, TextRange, algo::ancestors_at_offset, ast};
 
 // Feature: Interpret A Function, Static Or Const.
 //
@@ -35,10 +35,10 @@ fn find_and_interpret(db: &RootDatabase, position: FilePosition) -> Option<(Dura
         _ => return None,
     };
     let span_formatter = |file_id, text_range: TextRange| {
-        let path = &db
-            .source_root(db.file_source_root(file_id))
-            .path_for_file(&file_id)
-            .map(|x| x.to_string());
+        let source_root = db.file_source_root(file_id).source_root_id(db);
+        let source_root = db.source_root(source_root).source_root(db);
+
+        let path = source_root.path_for_file(&file_id).map(|x| x.to_string());
         let path = path.as_deref().unwrap_or("<unknown file>");
         match db.line_index(file_id).try_line_col(text_range.start()) {
             Some(line_col) => format!("file://{path}:{}:{}", line_col.line + 1, line_col.col),
@@ -64,10 +64,9 @@ pub(crate) fn render_const_eval_error(
     display_target: DisplayTarget,
 ) -> String {
     let span_formatter = |file_id, text_range: TextRange| {
-        let path = &db
-            .source_root(db.file_source_root(file_id))
-            .path_for_file(&file_id)
-            .map(|x| x.to_string());
+        let source_root = db.file_source_root(file_id).source_root_id(db);
+        let source_root = db.source_root(source_root).source_root(db);
+        let path = source_root.path_for_file(&file_id).map(|x| x.to_string());
         let path = path.as_deref().unwrap_or("<unknown file>");
         match db.line_index(file_id).try_line_col(text_range.start()) {
             Some(line_col) => format!("file://{path}:{}:{}", line_col.line + 1, line_col.col),
diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
index ea18a97070c..0188c105faa 100644
--- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
@@ -2,10 +2,10 @@ use ide_assists::utils::extract_trivial_expression;
 use ide_db::syntax_helpers::node_ext::expr_as_name_ref;
 use itertools::Itertools;
 use syntax::{
-    ast::{self, AstNode, AstToken, IsString},
     NodeOrToken, SourceFile, SyntaxElement,
     SyntaxKind::{self, USE_TREE, WHITESPACE},
-    SyntaxToken, TextRange, TextSize, T,
+    SyntaxToken, T, TextRange, TextSize,
+    ast::{self, AstNode, AstToken, IsString},
 };
 
 use ide_db::text_edit::{TextEdit, TextEditBuilder};
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 8ac1a96cc65..a13be6c4927 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -20,6 +20,7 @@ mod navigation_target;
 
 mod annotations;
 mod call_hierarchy;
+mod child_modules;
 mod doc_links;
 mod expand_macro;
 mod extend_selection;
@@ -57,23 +58,22 @@ mod view_memory_layout;
 mod view_mir;
 mod view_syntax_tree;
 
-use std::{iter, panic::UnwindSafe};
+use std::panic::{AssertUnwindSafe, UnwindSafe};
 
 use cfg::CfgOptions;
 use fetch_crates::CrateInfo;
-use hir::{sym, ChangeWithProcMacros};
+use hir::{ChangeWithProcMacros, EditionedFileId, sym};
 use ide_db::{
+    FxHashMap, FxIndexSet, LineIndexDatabase,
     base_db::{
-        ra_salsa::{self, ParallelDatabase},
-        CrateOrigin, CrateWorkspaceData, Env, FileLoader, FileSet, SourceDatabase,
-        SourceRootDatabase, VfsPath,
+        CrateOrigin, CrateWorkspaceData, Env, FileSet, RootQueryDb, SourceDatabase, VfsPath,
+        salsa::Cancelled,
     },
-    prime_caches, symbol_index, FxHashMap, FxIndexSet, LineIndexDatabase,
+    prime_caches, symbol_index,
 };
-use span::EditionedFileId;
 use syntax::SourceFile;
 use triomphe::Arc;
-use view_memory_layout::{view_memory_layout, RecursiveMemoryLayout};
+use view_memory_layout::{RecursiveMemoryLayout, view_memory_layout};
 
 use crate::navigation_target::ToNav;
 
@@ -110,8 +110,8 @@ pub use crate::{
         StaticIndex, StaticIndexedFile, TokenId, TokenStaticData, VendoredLibrariesConfig,
     },
     syntax_highlighting::{
-        tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag},
         HighlightConfig, HlRange,
+        tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag},
     },
     test_explorer::{TestItem, TestItemKind},
 };
@@ -125,7 +125,8 @@ pub use ide_completion::{
 };
 pub use ide_db::text_edit::{Indel, TextEdit};
 pub use ide_db::{
-    base_db::{Cancelled, CrateGraph, CrateId, FileChange, SourceRoot, SourceRootId},
+    FileId, FilePosition, FileRange, RootDatabase, Severity, SymbolKind,
+    base_db::{Crate, CrateGraphBuilder, FileChange, SourceRoot, SourceRootId},
     documentation::Documentation,
     label::Label,
     line_index::{LineCol, LineIndex},
@@ -133,7 +134,6 @@ pub use ide_db::{
     search::{ReferenceCategory, SearchScope},
     source_change::{FileSystemEdit, SnippetEdit, SourceChange},
     symbol_index::Query,
-    FileId, FilePosition, FileRange, RootDatabase, Severity, SymbolKind,
 };
 pub use ide_diagnostics::{Diagnostic, DiagnosticCode, DiagnosticsConfig, ExprFillDefaultMode};
 pub use ide_ssr::SsrError;
@@ -217,7 +217,7 @@ impl Default for AnalysisHost {
 /// `Analysis` are canceled (most method return `Err(Canceled)`).
 #[derive(Debug)]
 pub struct Analysis {
-    db: ra_salsa::Snapshot<RootDatabase>,
+    db: RootDatabase,
 }
 
 // As a general design guideline, `Analysis` API are intended to be independent
@@ -237,34 +237,37 @@ impl Analysis {
         file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_owned()));
         let source_root = SourceRoot::new_local(file_set);
 
-        let mut change = ChangeWithProcMacros::new();
+        let mut change = ChangeWithProcMacros::default();
         change.set_roots(vec![source_root]);
-        let mut crate_graph = CrateGraph::default();
+        let mut crate_graph = CrateGraphBuilder::default();
         // FIXME: cfg options
         // Default to enable test for single file.
         let mut cfg_options = CfgOptions::default();
-        cfg_options.insert_atom(sym::test.clone());
+
+        // FIXME: This is less than ideal
+        let proc_macro_cwd = Arc::new(
+            TryFrom::try_from(&*std::env::current_dir().unwrap().as_path().to_string_lossy())
+                .unwrap(),
+        );
+        cfg_options.insert_atom(sym::test);
         crate_graph.add_crate_root(
             file_id,
             Edition::CURRENT,
             None,
             None,
-            Arc::new(cfg_options),
+            cfg_options,
             None,
             Env::default(),
             CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
-        );
-        change.change_file(file_id, Some(text));
-        let ws_data = crate_graph
-            .iter()
-            .zip(iter::repeat(Arc::new(CrateWorkspaceData {
+            proc_macro_cwd,
+            Arc::new(CrateWorkspaceData {
                 data_layout: Err("fixture has no layout".into()),
                 toolchain: None,
-            })))
-            .collect();
-        change.set_crate_graph(crate_graph, ws_data);
+            }),
+        );
+        change.change_file(file_id, Some(text));
+        change.set_crate_graph(crate_graph);
 
         host.apply_change(change);
         (host.analysis(), file_id)
@@ -276,12 +279,12 @@ impl Analysis {
     }
 
     pub fn source_root_id(&self, file_id: FileId) -> Cancellable<SourceRootId> {
-        self.with_db(|db| db.file_source_root(file_id))
+        self.with_db(|db| db.file_source_root(file_id).source_root_id(db))
     }
 
     pub fn is_local_source_root(&self, source_root_id: SourceRootId) -> Cancellable<bool> {
         self.with_db(|db| {
-            let sr = db.source_root(source_root_id);
+            let sr = db.source_root(source_root_id).source_root(db);
             !sr.is_library
         })
     }
@@ -295,18 +298,25 @@ impl Analysis {
 
     /// Gets the text of the source file.
     pub fn file_text(&self, file_id: FileId) -> Cancellable<Arc<str>> {
-        self.with_db(|db| SourceDatabase::file_text(db, file_id))
+        self.with_db(|db| SourceDatabase::file_text(db, file_id).text(db))
     }
 
     /// Gets the syntax tree of the file.
     pub fn parse(&self, file_id: FileId) -> Cancellable<SourceFile> {
         // FIXME edition
-        self.with_db(|db| db.parse(EditionedFileId::current_edition(file_id)).tree())
+        self.with_db(|db| {
+            let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
+
+            db.parse(editioned_file_id_wrapper).tree()
+        })
     }
 
     /// Returns true if this file belongs to an immutable library.
     pub fn is_library_file(&self, file_id: FileId) -> Cancellable<bool> {
-        self.with_db(|db| db.source_root(db.file_source_root(file_id)).is_library)
+        self.with_db(|db| {
+            let source_root = db.file_source_root(file_id).source_root_id(db);
+            db.source_root(source_root).source_root(db).is_library
+        })
     }
 
     /// Gets the file's `LineIndex`: data structure to convert between absolute
@@ -324,7 +334,8 @@ impl Analysis {
     /// supported).
     pub fn matching_brace(&self, position: FilePosition) -> Cancellable<Option<TextSize>> {
         self.with_db(|db| {
-            let parse = db.parse(EditionedFileId::current_edition(position.file_id));
+            let file_id = EditionedFileId::current_edition(&self.db, position.file_id);
+            let parse = db.parse(file_id);
             let file = parse.tree();
             matching_brace::matching_brace(&file, position.offset)
         })
@@ -358,7 +369,7 @@ impl Analysis {
         self.with_db(|db| test_explorer::discover_tests_in_crate_by_test_id(db, crate_id))
     }
 
-    pub fn discover_tests_in_crate(&self, crate_id: CrateId) -> Cancellable<Vec<TestItem>> {
+    pub fn discover_tests_in_crate(&self, crate_id: Crate) -> Cancellable<Vec<TestItem>> {
         self.with_db(|db| test_explorer::discover_tests_in_crate(db, crate_id))
     }
 
@@ -383,7 +394,9 @@ impl Analysis {
     /// stuff like trailing commas.
     pub fn join_lines(&self, config: &JoinLinesConfig, frange: FileRange) -> Cancellable<TextEdit> {
         self.with_db(|db| {
-            let parse = db.parse(EditionedFileId::current_edition(frange.file_id));
+            let editioned_file_id_wrapper =
+                EditionedFileId::current_edition(&self.db, frange.file_id);
+            let parse = db.parse(editioned_file_id_wrapper);
             join_lines::join_lines(config, &parse.tree(), frange.range)
         })
     }
@@ -419,9 +432,9 @@ impl Analysis {
     pub fn file_structure(&self, file_id: FileId) -> Cancellable<Vec<StructureNode>> {
         // FIXME: Edition
         self.with_db(|db| {
-            file_structure::file_structure(
-                &db.parse(EditionedFileId::current_edition(file_id)).tree(),
-            )
+            let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
+
+            file_structure::file_structure(&db.parse(editioned_file_id_wrapper).tree())
         })
     }
 
@@ -450,9 +463,9 @@ impl Analysis {
     /// Returns the set of folding ranges.
     pub fn folding_ranges(&self, file_id: FileId) -> Cancellable<Vec<Fold>> {
         self.with_db(|db| {
-            folding_ranges::folding_ranges(
-                &db.parse(EditionedFileId::current_edition(file_id)).tree(),
-            )
+            let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
+
+            folding_ranges::folding_ranges(&db.parse(editioned_file_id_wrapper).tree())
         })
     }
 
@@ -506,7 +519,11 @@ impl Analysis {
         position: FilePosition,
         search_scope: Option<SearchScope>,
     ) -> Cancellable<Option<Vec<ReferenceSearchResult>>> {
-        self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope))
+        let search_scope = AssertUnwindSafe(search_scope);
+        self.with_db(|db| {
+            let _ = &search_scope;
+            references::find_all_refs(&Semantics::new(db), position, search_scope.0)
+        })
     }
 
     /// Returns a short text describing element at position.
@@ -577,34 +594,44 @@ impl Analysis {
         self.with_db(|db| parent_module::parent_module(db, position))
     }
 
+    /// Returns vec of `mod name;` declaration which are created by the current module.
+    pub fn child_modules(&self, position: FilePosition) -> Cancellable<Vec<NavigationTarget>> {
+        self.with_db(|db| child_modules::child_modules(db, position))
+    }
+
     /// Returns crates that this file belongs to.
-    pub fn crates_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
+    pub fn crates_for(&self, file_id: FileId) -> Cancellable<Vec<Crate>> {
         self.with_db(|db| parent_module::crates_for(db, file_id))
     }
 
     /// Returns crates that this file belongs to.
-    pub fn transitive_rev_deps(&self, crate_id: CrateId) -> Cancellable<Vec<CrateId>> {
-        self.with_db(|db| db.crate_graph().transitive_rev_deps(crate_id).collect())
+    pub fn transitive_rev_deps(&self, crate_id: Crate) -> Cancellable<Vec<Crate>> {
+        self.with_db(|db| Vec::from_iter(db.transitive_rev_deps(crate_id)))
     }
 
     /// Returns crates that this file *might* belong to.
-    pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> {
+    pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable<Vec<Crate>> {
         self.with_db(|db| db.relevant_crates(file_id).iter().copied().collect())
     }
 
     /// Returns the edition of the given crate.
-    pub fn crate_edition(&self, crate_id: CrateId) -> Cancellable<Edition> {
-        self.with_db(|db| db.crate_graph()[crate_id].edition)
+    pub fn crate_edition(&self, crate_id: Crate) -> Cancellable<Edition> {
+        self.with_db(|db| crate_id.data(db).edition)
+    }
+
+    /// Returns whether the given crate is a proc macro.
+    pub fn is_proc_macro_crate(&self, crate_id: Crate) -> Cancellable<bool> {
+        self.with_db(|db| crate_id.data(db).is_proc_macro)
     }
 
     /// Returns true if this crate has `no_std` or `no_core` specified.
-    pub fn is_crate_no_std(&self, crate_id: CrateId) -> Cancellable<bool> {
+    pub fn is_crate_no_std(&self, crate_id: Crate) -> Cancellable<bool> {
         self.with_db(|db| hir::db::DefDatabase::crate_def_map(db, crate_id).is_no_std())
     }
 
     /// Returns the root file of the given crate.
-    pub fn crate_root(&self, crate_id: CrateId) -> Cancellable<FileId> {
-        self.with_db(|db| db.crate_graph()[crate_id].root_file_id)
+    pub fn crate_root(&self, crate_id: Crate) -> Cancellable<FileId> {
+        self.with_db(|db| crate_id.data(db).root_file_id)
     }
 
     /// Returns the set of possible targets to run for the current file.
@@ -618,7 +645,11 @@ impl Analysis {
         position: FilePosition,
         search_scope: Option<SearchScope>,
     ) -> Cancellable<Vec<Runnable>> {
-        self.with_db(|db| runnables::related_tests(db, position, search_scope))
+        let search_scope = AssertUnwindSafe(search_scope);
+        self.with_db(|db| {
+            let _ = &search_scope;
+            runnables::related_tests(db, position, search_scope.0)
+        })
     }
 
     /// Computes syntax highlighting for the given file
@@ -717,7 +748,7 @@ impl Analysis {
         frange: FileRange,
     ) -> Cancellable<Vec<Assist>> {
         let include_fixes = match &assist_config.allowed {
-            Some(it) => it.iter().any(|&it| it == AssistKind::None || it == AssistKind::QuickFix),
+            Some(it) => it.contains(&AssistKind::QuickFix),
             None => true,
         };
 
@@ -811,6 +842,10 @@ impl Analysis {
         self.with_db(|db| view_memory_layout(db, position))
     }
 
+    pub fn editioned_file_id_to_vfs(&self, file_id: hir::EditionedFileId) -> FileId {
+        file_id.file_id(&self.db)
+    }
+
     /// Performs an operation on the database that may be canceled.
     ///
     /// rust-analyzer needs to be able to answer semantic questions about the
@@ -828,7 +863,8 @@ impl Analysis {
     where
         F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe,
     {
-        Cancelled::catch(|| f(&self.db))
+        let snap = self.db.snapshot();
+        Cancelled::catch(|| f(&snap))
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs b/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
index 67346ea9cf9..b2b91d6e3cf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
@@ -1,6 +1,6 @@
 use syntax::{
+    SourceFile, SyntaxKind, T, TextSize,
     ast::{self, AstNode},
-    SourceFile, SyntaxKind, TextSize, T,
 };
 
 // Feature: Matching Brace
diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
index 5754b4fa82f..4a06cd919fc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
@@ -5,15 +5,15 @@ use core::fmt;
 
 use hir::{Adt, AsAssocItem, Crate, HirDisplay, MacroKind, Semantics};
 use ide_db::{
+    FilePosition, RootDatabase,
     base_db::{CrateOrigin, LangCrateOrigin},
     defs::{Definition, IdentClass},
     helpers::pick_best_token,
-    FilePosition, RootDatabase,
 };
 use itertools::Itertools;
 use syntax::{AstNode, SyntaxKind::*, T};
 
-use crate::{doc_links::token_as_doc_comment, parent_module::crates_for, RangeInfo};
+use crate::{RangeInfo, doc_links::token_as_doc_comment, parent_module::crates_for};
 
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub enum MonikerDescriptorKind {
@@ -194,11 +194,7 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati
         Definition::Function(it) => {
             if it.as_assoc_item(db).is_some() {
                 if it.has_self_param(db) {
-                    if it.has_body(db) {
-                        Method
-                    } else {
-                        TraitMethod
-                    }
+                    if it.has_body(db) { Method } else { TraitMethod }
                 } else {
                     StaticMethod
                 }
@@ -405,7 +401,7 @@ fn display<T: HirDisplay>(db: &RootDatabase, module: hir::Module, it: T) -> Stri
 
 #[cfg(test)]
 mod tests {
-    use crate::{fixture, MonikerResult};
+    use crate::{MonikerResult, fixture};
 
     use super::MonikerKind;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
index 3fb3a788b91..f3bb3df1cd8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
@@ -3,9 +3,9 @@ use std::{iter::once, mem};
 use hir::Semantics;
 use ide_db::syntax_helpers::tree_diff::diff;
 use ide_db::text_edit::{TextEdit, TextEditBuilder};
-use ide_db::{helpers::pick_best_token, FileRange, RootDatabase};
+use ide_db::{FileRange, RootDatabase, helpers::pick_best_token};
 use itertools::Itertools;
-use syntax::{ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange};
+use syntax::{AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, ast, match_ast};
 
 #[derive(Copy, Clone, Debug)]
 pub enum Direction {
@@ -174,7 +174,7 @@ fn replace_nodes<'a>(
 #[cfg(test)]
 mod tests {
     use crate::fixture;
-    use expect_test::{expect, Expect};
+    use expect_test::{Expect, expect};
 
     use crate::Direction;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index d67aaac06fb..9334b73fc7b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -5,19 +5,20 @@ use std::fmt;
 use arrayvec::ArrayVec;
 use either::Either;
 use hir::{
-    db::ExpandDatabase, symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasCrate,
-    HasSource, HirDisplay, HirFileId, InFile, LocalSource, ModuleSource,
+    AssocItem, FieldSource, HasContainer, HasCrate, HasSource, HirDisplay, HirFileId, InFile,
+    LocalSource, ModuleSource, db::ExpandDatabase, symbols::FileSymbol,
 };
 use ide_db::{
+    FileId, FileRange, RootDatabase, SymbolKind,
     defs::Definition,
     documentation::{Documentation, HasDocs},
-    FileId, FileRange, RootDatabase, SymbolKind,
 };
 use span::Edition;
 use stdx::never;
 use syntax::{
+    AstNode, SmolStr, SyntaxNode, TextRange, ToSmolStr,
     ast::{self, HasName},
-    format_smolstr, AstNode, SmolStr, SyntaxNode, TextRange, ToSmolStr,
+    format_smolstr,
 };
 
 /// `NavigationTarget` represents an element in the editor's UI which you can
@@ -816,14 +817,10 @@ pub(crate) fn orig_range_with_focus_r(
 ) -> UpmappingResult<(FileRange, Option<TextRange>)> {
     let Some(name) = focus_range else { return orig_range_r(db, hir_file, value) };
 
-    let call_kind =
-        || db.lookup_intern_macro_call(hir_file.macro_file().unwrap().macro_call_id).kind;
+    let call_kind = || db.lookup_intern_macro_call(hir_file.macro_file().unwrap()).kind;
 
-    let def_range = || {
-        db.lookup_intern_macro_call(hir_file.macro_file().unwrap().macro_call_id)
-            .def
-            .definition_range(db)
-    };
+    let def_range =
+        || db.lookup_intern_macro_call(hir_file.macro_file().unwrap()).def.definition_range(db);
 
     // FIXME: Also make use of the syntax context to determine which site we are at?
     let value_range = InFile::new(hir_file, value).original_node_file_range_opt(db);
@@ -900,7 +897,7 @@ pub(crate) fn orig_range_with_focus_r(
 
     UpmappingResult {
         call_site: (
-            call_site_range.into(),
+            call_site_range.into_file_id(db),
             call_site_focus.and_then(|hir::FileRange { file_id, range }| {
                 if call_site_range.file_id == file_id && call_site_range.range.contains_range(range)
                 {
@@ -912,7 +909,7 @@ pub(crate) fn orig_range_with_focus_r(
         ),
         def_site: def_site.map(|(def_site_range, def_site_focus)| {
             (
-                def_site_range.into(),
+                def_site_range.into_file_id(db),
                 def_site_focus.and_then(|hir::FileRange { file_id, range }| {
                     if def_site_range.file_id == file_id
                         && def_site_range.range.contains_range(range)
@@ -933,7 +930,10 @@ fn orig_range(
     value: &SyntaxNode,
 ) -> UpmappingResult<(FileRange, Option<TextRange>)> {
     UpmappingResult {
-        call_site: (InFile::new(hir_file, value).original_file_range_rooted(db).into(), None),
+        call_site: (
+            InFile::new(hir_file, value).original_file_range_rooted(db).into_file_id(db),
+            None,
+        ),
         def_site: None,
     }
 }
@@ -944,7 +944,10 @@ fn orig_range_r(
     value: TextRange,
 ) -> UpmappingResult<(FileRange, Option<TextRange>)> {
     UpmappingResult {
-        call_site: (InFile::new(hir_file, value).original_node_file_range(db).0.into(), None),
+        call_site: (
+            InFile::new(hir_file, value).original_node_file_range(db).0.into_file_id(db),
+            None,
+        ),
         def_site: None,
     }
 }
@@ -953,7 +956,7 @@ fn orig_range_r(
 mod tests {
     use expect_test::expect;
 
-    use crate::{fixture, Query};
+    use crate::{Query, fixture};
 
     #[test]
     fn test_nav_for_symbol() {
diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
index 6d82f9b0634..6dc01c45063 100644
--- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
@@ -1,7 +1,7 @@
-use hir::{db::DefDatabase, Semantics};
+use hir::{Semantics, db::DefDatabase};
 use ide_db::{
-    base_db::{CrateId, FileLoader},
     FileId, FilePosition, RootDatabase,
+    base_db::{Crate, RootQueryDb},
 };
 use itertools::Itertools;
 use syntax::{
@@ -53,11 +53,13 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
 }
 
 /// This returns `Vec` because a module may be included from several places.
-pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
+pub(crate) fn crates_for(db: &RootDatabase, file_id: FileId) -> Vec<Crate> {
     db.relevant_crates(file_id)
         .iter()
         .copied()
-        .filter(|&crate_id| db.crate_def_map(crate_id).modules_for_file(file_id).next().is_some())
+        .filter(|&crate_id| {
+            db.crate_def_map(crate_id).modules_for_file(db, file_id).next().is_some()
+        })
         .sorted()
         .collect()
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index 069818d50e7..4fa116444b7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -11,21 +11,22 @@
 
 use hir::{PathResolution, Semantics};
 use ide_db::{
+    FileId, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
     search::{ReferenceCategory, SearchScope, UsageSearchResult},
-    FileId, RootDatabase,
 };
 use itertools::Itertools;
 use nohash_hasher::IntMap;
 use span::Edition;
 use syntax::{
-    ast::{self, HasName},
-    match_ast, AstNode,
+    AstNode,
     SyntaxKind::*,
-    SyntaxNode, TextRange, TextSize, T,
+    SyntaxNode, T, TextRange, TextSize,
+    ast::{self, HasName},
+    match_ast,
 };
 
-use crate::{highlight_related, FilePosition, HighlightedRange, NavigationTarget, TryToNav};
+use crate::{FilePosition, HighlightedRange, NavigationTarget, TryToNav, highlight_related};
 
 #[derive(Debug, Clone)]
 pub struct ReferenceSearchResult {
@@ -67,7 +68,7 @@ pub(crate) fn find_all_refs(
                 .into_iter()
                 .map(|(file_id, refs)| {
                     (
-                        file_id.into(),
+                        file_id.file_id(sema.db),
                         refs.into_iter()
                             .map(|file_ref| (file_ref.range, file_ref.category))
                             .unique()
@@ -123,11 +124,11 @@ pub(crate) fn find_all_refs(
     }
 }
 
-pub(crate) fn find_defs<'a>(
-    sema: &'a Semantics<'_, RootDatabase>,
+pub(crate) fn find_defs(
+    sema: &Semantics<'_, RootDatabase>,
     syntax: &SyntaxNode,
     offset: TextSize,
-) -> Option<impl IntoIterator<Item = Definition> + 'a> {
+) -> Option<Vec<Definition>> {
     let token = syntax.token_at_offset(offset).find(|t| {
         matches!(
             t.kind(),
@@ -306,8 +307,10 @@ fn handle_control_flow_keywords(
     FilePosition { file_id, offset }: FilePosition,
 ) -> Option<ReferenceSearchResult> {
     let file = sema.parse_guess_edition(file_id);
-    let edition =
-        sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
+    let edition = sema
+        .attach_first_edition(file_id)
+        .map(|it| it.edition(sema.db))
+        .unwrap_or(Edition::CURRENT);
     let token = file.syntax().token_at_offset(offset).find(|t| t.kind().is_keyword(edition))?;
 
     let references = match token.kind() {
@@ -327,7 +330,7 @@ fn handle_control_flow_keywords(
             .into_iter()
             .map(|HighlightedRange { range, category }| (range, category))
             .collect();
-        (file_id.into(), ranges)
+        (file_id.file_id(sema.db), ranges)
     })
     .collect();
 
@@ -336,12 +339,12 @@ fn handle_control_flow_keywords(
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
-    use ide_db::FileId;
-    use span::EditionedFileId;
+    use expect_test::{Expect, expect};
+    use hir::EditionedFileId;
+    use ide_db::{FileId, RootDatabase};
     use stdx::format_to;
 
-    use crate::{fixture, SearchScope};
+    use crate::{SearchScope, fixture};
 
     #[test]
     fn exclude_tests() {
@@ -1003,7 +1006,9 @@ pub(super) struct Foo$0 {
 
         check_with_scope(
             code,
-            Some(SearchScope::single_file(EditionedFileId::current_edition(FileId::from_raw(2)))),
+            Some(&mut |db| {
+                SearchScope::single_file(EditionedFileId::current_edition(db, FileId::from_raw(2)))
+            }),
             expect![[r#"
                 quux Function FileId(0) 19..35 26..30
 
@@ -1259,11 +1264,12 @@ impl Foo {
 
     fn check_with_scope(
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
-        search_scope: Option<SearchScope>,
+        search_scope: Option<&mut dyn FnMut(&RootDatabase) -> SearchScope>,
         expect: Expect,
     ) {
         let (analysis, pos) = fixture::position(ra_fixture);
-        let refs = analysis.find_all_refs(pos, search_scope).unwrap().unwrap();
+        let refs =
+            analysis.find_all_refs(pos, search_scope.map(|it| it(&analysis.db))).unwrap().unwrap();
 
         let mut actual = String::new();
         for mut refs in refs {
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index d0e1c2097a7..e6cda60cd95 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -4,16 +4,16 @@
 //! tests. This module also implements a couple of magic tricks, like renaming
 //! `self` and to `self` (to switch between associated function and method).
 
-use hir::{AsAssocItem, HirFileIdExt, InFile, Semantics};
+use hir::{AsAssocItem, InFile, Semantics};
 use ide_db::{
+    FileId, FileRange, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
-    rename::{bail, format_err, source_edit_from_references, IdentifierKind},
+    rename::{IdentifierKind, bail, format_err, source_edit_from_references},
     source_change::SourceChangeBuilder,
-    FileId, FileRange, RootDatabase,
 };
 use itertools::Itertools;
 use stdx::{always, never};
-use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize};
+use syntax::{AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize, ast};
 
 use ide_db::text_edit::TextEdit;
 
@@ -120,7 +120,7 @@ pub(crate) fn rename(
                 source_change.extend(usages.references.get_mut(&file_id).iter().map(|refs| {
                     (
                         position.file_id,
-                        source_edit_from_references(refs, def, new_name, file_id.edition()),
+                        source_edit_from_references(refs, def, new_name, file_id.edition(db)),
                     )
                 }));
 
@@ -297,7 +297,7 @@ fn find_definitions(
                 // remove duplicates, comparing `Definition`s
                 Ok(v.into_iter()
                     .unique_by(|&(.., def)| def)
-                    .map(|(a, b, c)| (a.into(), b, c))
+                    .map(|(a, b, c)| (a.into_file_id(sema.db), b, c))
                     .collect::<Vec<_>>()
                     .into_iter())
             }
@@ -368,10 +368,13 @@ fn rename_to_self(
     let usages = def.usages(sema).all();
     let mut source_change = SourceChange::default();
     source_change.extend(usages.iter().map(|(file_id, references)| {
-        (file_id.into(), source_edit_from_references(references, def, "self", file_id.edition()))
+        (
+            file_id.file_id(sema.db),
+            source_edit_from_references(references, def, "self", file_id.edition(sema.db)),
+        )
     }));
     source_change.insert_source_edit(
-        file_id.original_file(sema.db),
+        file_id.original_file(sema.db).file_id(sema.db),
         TextEdit::replace(param_source.syntax().text_range(), String::from(self_param)),
     );
     Ok(source_change)
@@ -402,9 +405,12 @@ fn rename_self_to_param(
         bail!("Cannot rename reference to `_` as it is being referenced multiple times");
     }
     let mut source_change = SourceChange::default();
-    source_change.insert_source_edit(file_id.original_file(sema.db), edit);
+    source_change.insert_source_edit(file_id.original_file(sema.db).file_id(sema.db), edit);
     source_change.extend(usages.iter().map(|(file_id, references)| {
-        (file_id.into(), source_edit_from_references(references, def, new_name, file_id.edition()))
+        (
+            file_id.file_id(sema.db),
+            source_edit_from_references(references, def, new_name, file_id.edition(sema.db)),
+        )
     }));
     Ok(source_change)
 }
@@ -443,7 +449,7 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::{Expect, expect};
     use ide_db::source_change::SourceChange;
     use ide_db::text_edit::TextEdit;
     use itertools::Itertools;
@@ -509,10 +515,9 @@ mod tests {
         let found_conflicts = source_change
             .source_file_edits
             .iter()
+            .filter(|(_, (edit, _))| edit.change_annotation().is_some())
             .flat_map(|(file_id, (edit, _))| {
-                edit.into_iter()
-                    .filter(|edit| edit.annotation.is_some())
-                    .map(move |edit| (*file_id, edit.delete))
+                edit.into_iter().map(move |edit| (*file_id, edit.delete))
             })
             .sorted_unstable_by_key(|(file_id, range)| (*file_id, range.start()))
             .collect_vec();
@@ -1081,7 +1086,6 @@ mod foo$0;
                             Indel {
                                 insert: "foo2",
                                 delete: 4..7,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1129,7 +1133,6 @@ use crate::foo$0::FooContent;
                             Indel {
                                 insert: "quux",
                                 delete: 8..11,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1141,7 +1144,6 @@ use crate::foo$0::FooContent;
                             Indel {
                                 insert: "quux",
                                 delete: 11..14,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1183,7 +1185,6 @@ mod fo$0o;
                             Indel {
                                 insert: "foo2",
                                 delete: 4..7,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1232,7 +1233,6 @@ mod outer { mod fo$0o; }
                             Indel {
                                 insert: "bar",
                                 delete: 16..19,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1304,7 +1304,6 @@ pub mod foo$0;
                             Indel {
                                 insert: "foo2",
                                 delete: 27..30,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1316,7 +1315,6 @@ pub mod foo$0;
                             Indel {
                                 insert: "foo2",
                                 delete: 8..11,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1372,7 +1370,6 @@ mod quux;
                             Indel {
                                 insert: "foo2",
                                 delete: 4..7,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1506,12 +1503,10 @@ pub fn baz() {}
                             Indel {
                                 insert: "r#fn",
                                 delete: 4..7,
-                                annotation: None,
                             },
                             Indel {
                                 insert: "r#fn",
                                 delete: 22..25,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1576,12 +1571,10 @@ pub fn baz() {}
                             Indel {
                                 insert: "foo",
                                 delete: 4..8,
-                                annotation: None,
                             },
                             Indel {
                                 insert: "foo",
                                 delete: 23..27,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1643,7 +1636,6 @@ fn bar() {
                             Indel {
                                 insert: "dyn",
                                 delete: 7..10,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1655,7 +1647,6 @@ fn bar() {
                             Indel {
                                 insert: "r#dyn",
                                 delete: 18..21,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1685,7 +1676,6 @@ fn bar() {
                             Indel {
                                 insert: "r#dyn",
                                 delete: 7..10,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1697,7 +1687,6 @@ fn bar() {
                             Indel {
                                 insert: "dyn",
                                 delete: 18..21,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1727,7 +1716,6 @@ fn bar() {
                             Indel {
                                 insert: "r#dyn",
                                 delete: 7..10,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1739,7 +1727,6 @@ fn bar() {
                             Indel {
                                 insert: "dyn",
                                 delete: 18..21,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1776,12 +1763,10 @@ fn bar() {
                             Indel {
                                 insert: "abc",
                                 delete: 7..10,
-                                annotation: None,
                             },
                             Indel {
                                 insert: "abc",
                                 delete: 32..35,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1793,7 +1778,6 @@ fn bar() {
                             Indel {
                                 insert: "abc",
                                 delete: 18..23,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1827,12 +1811,10 @@ fn bar() {
                             Indel {
                                 insert: "abc",
                                 delete: 7..12,
-                                annotation: None,
                             },
                             Indel {
                                 insert: "abc",
                                 delete: 34..39,
-                                annotation: None,
                             },
                         ],
                     ),
@@ -1844,7 +1826,6 @@ fn bar() {
                             Indel {
                                 insert: "abc",
                                 delete: 18..21,
-                                annotation: None,
                             },
                         ],
                     ),
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index b8deed01fb7..ab139602404 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -4,28 +4,29 @@ use arrayvec::ArrayVec;
 use ast::HasName;
 use cfg::{CfgAtom, CfgExpr};
 use hir::{
-    db::HirDatabase, sym, symbols::FxIndexSet, AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate,
-    HasSource, HirFileIdExt, ModPath, Name, PathKind, Semantics, Symbol,
+    AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate, HasSource, ModPath, Name, PathKind, Semantics,
+    Symbol, db::HirDatabase, sym, symbols::FxIndexSet,
 };
 use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
 use ide_db::{
-    base_db::SourceDatabase,
+    FilePosition, FxHashMap, FxIndexMap, RootDatabase, SymbolKind,
+    base_db::RootQueryDb,
     defs::Definition,
     documentation::docs_from_attrs,
     helpers::visit_file_defs,
     search::{FileReferenceNode, SearchScope},
-    FilePosition, FxHashMap, FxIndexMap, RootDatabase, SymbolKind,
 };
 use itertools::Itertools;
 use smallvec::SmallVec;
 use span::{Edition, TextSize};
 use stdx::format_to;
 use syntax::{
+    SmolStr, SyntaxNode, ToSmolStr,
     ast::{self, AstNode},
-    format_smolstr, SmolStr, SyntaxNode, ToSmolStr,
+    format_smolstr,
 };
 
-use crate::{references, FileId, NavigationTarget, ToNav, TryToNav};
+use crate::{FileId, NavigationTarget, ToNav, TryToNav, references};
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct Runnable {
@@ -284,8 +285,10 @@ fn find_related_tests_in_module(
 
     let file_id = mod_source.file_id.original_file(sema.db);
     let mod_scope = SearchScope::file_range(hir::FileRange { file_id, range: mod_source.value });
-    let fn_pos =
-        FilePosition { file_id: file_id.into(), offset: fn_name.syntax().text_range().start() };
+    let fn_pos = FilePosition {
+        file_id: file_id.file_id(sema.db),
+        offset: fn_name.syntax().text_range().start(),
+    };
     find_related_tests(sema, syntax, fn_pos, Some(mod_scope), tests)
 }
 
@@ -499,7 +502,7 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
     let krate = def.krate(db);
     let edition = krate.map(|it| it.edition(db)).unwrap_or(Edition::CURRENT);
     let display_target = krate
-        .unwrap_or_else(|| (*db.crate_graph().crates_in_topological_order().last().unwrap()).into())
+        .unwrap_or_else(|| (*db.all_crates().last().expect("no crate graph present")).into())
         .to_display_target(db);
     if !has_runnable_doc_test(&attrs) {
         return None;
@@ -752,7 +755,7 @@ impl UpdateTest {
 
 #[cfg(test)]
 mod tests {
-    use expect_test::{expect, Expect};
+    use expect_test::{Expect, expect};
 
     use crate::fixture;
 
@@ -1209,13 +1212,13 @@ impl Foo {
             r#"
 //- /lib.rs
 $0
-macro_rules! gen {
+macro_rules! generate {
     () => {
         #[test]
         fn foo_test() {}
     }
 }
-macro_rules! gen2 {
+macro_rules! generate2 {
     () => {
         mod tests2 {
             #[test]
@@ -1223,25 +1226,25 @@ macro_rules! gen2 {
         }
     }
 }
-macro_rules! gen_main {
+macro_rules! generate_main {
     () => {
         fn main() {}
     }
 }
 mod tests {
-    gen!();
+    generate!();
 }
-gen2!();
-gen_main!();
+generate2!();
+generate_main!();
 "#,
             expect![[r#"
                 [
-                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..315, name: \"\", kind: Module })",
-                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 267..292, focus_range: 271..276, name: \"tests\", kind: Module, description: \"mod tests\" })",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 283..290, name: \"foo_test\", kind: Function })",
-                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 293..301, name: \"tests2\", kind: Module, description: \"mod tests2\" }, true)",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 293..301, name: \"foo_test2\", kind: Function }, true)",
-                    "(Bin, NavigationTarget { file_id: FileId(0), full_range: 302..314, name: \"main\", kind: Function })",
+                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..345, name: \"\", kind: Module })",
+                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 282..312, focus_range: 286..291, name: \"tests\", kind: Module, description: \"mod tests\" })",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 298..310, name: \"foo_test\", kind: Function })",
+                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 313..326, name: \"tests2\", kind: Module, description: \"mod tests2\" }, true)",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 313..326, name: \"foo_test2\", kind: Function }, true)",
+                    "(Bin, NavigationTarget { file_id: FileId(0), full_range: 327..344, name: \"main\", kind: Function })",
                 ]
             "#]],
         );
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index b5468a5aee9..0e17b355907 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -5,20 +5,22 @@ use std::collections::BTreeSet;
 
 use either::Either;
 use hir::{
-    AssocItem, DisplayTarget, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics, Trait,
+    AssocItem, DisplayTarget, GenericDef, GenericParam, HirDisplay, ModuleDef, PathResolution,
+    Semantics, Trait,
 };
 use ide_db::{
-    active_parameter::{callable_for_node, generic_def_for_node},
-    documentation::{Documentation, HasDocs},
     FilePosition, FxIndexMap,
+    active_parameter::{callable_for_arg_list, generic_def_for_node},
+    documentation::{Documentation, HasDocs},
 };
+use itertools::Itertools;
 use span::Edition;
 use stdx::format_to;
 use syntax::{
-    algo,
-    ast::{self, AstChildren, HasArgList},
-    match_ast, AstNode, Direction, NodeOrToken, SyntaxElementChildren, SyntaxNode, SyntaxToken,
-    TextRange, TextSize, ToSmolStr, T,
+    AstNode, Direction, NodeOrToken, SyntaxElementChildren, SyntaxNode, SyntaxToken, T, TextRange,
+    TextSize, ToSmolStr, algo,
+    ast::{self, AstChildren},
+    match_ast,
 };
 
 use crate::RootDatabase;
@@ -83,8 +85,8 @@ pub(crate) fn signature_help(
         .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;
     let token = sema.descend_into_macros_single_exact(token);
     let edition =
-        sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
-    let display_target = sema.first_crate_or_default(file_id).to_display_target(db);
+        sema.attach_first_edition(file_id).map(|it| it.edition(db)).unwrap_or(Edition::CURRENT);
+    let display_target = sema.first_crate(file_id)?.to_display_target(db);
 
     for node in token.parent_ancestors() {
         match_ast! {
@@ -163,20 +165,8 @@ fn signature_help_for_call(
     edition: Edition,
     display_target: DisplayTarget,
 ) -> Option<SignatureHelp> {
-    // Find the calling expression and its NameRef
-    let mut nodes = arg_list.syntax().ancestors().skip(1);
-    let calling_node = loop {
-        if let Some(callable) = ast::CallableExpr::cast(nodes.next()?) {
-            let inside_callable = callable
-                .arg_list()
-                .is_some_and(|it| it.syntax().text_range().contains(token.text_range().start()));
-            if inside_callable {
-                break callable;
-            }
-        }
-    };
-
-    let (callable, active_parameter) = callable_for_node(sema, &calling_node, &token)?;
+    let (callable, active_parameter) =
+        callable_for_arg_list(sema, arg_list, token.text_range().start())?;
 
     let mut res =
         SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter };
@@ -187,6 +177,20 @@ fn signature_help_for_call(
         hir::CallableKind::Function(func) => {
             res.doc = func.docs(db);
             format_to!(res.signature, "fn {}", func.name(db).display(db, edition));
+
+            let generic_params = GenericDef::Function(func)
+                .params(db)
+                .iter()
+                .filter(|param| match param {
+                    GenericParam::TypeParam(type_param) => !type_param.is_implicit(db),
+                    GenericParam::ConstParam(_) | GenericParam::LifetimeParam(_) => true,
+                })
+                .map(|param| param.display(db, display_target))
+                .join(", ");
+            if !generic_params.is_empty() {
+                format_to!(res.signature, "<{}>", generic_params);
+            }
+
             fn_params = Some(match callable.receiver_param(db) {
                 Some(_self) => func.params_without_self(db),
                 None => func.assoc_fn_params(db),
@@ -195,15 +199,34 @@ fn signature_help_for_call(
         hir::CallableKind::TupleStruct(strukt) => {
             res.doc = strukt.docs(db);
             format_to!(res.signature, "struct {}", strukt.name(db).display(db, edition));
+
+            let generic_params = GenericDef::Adt(strukt.into())
+                .params(db)
+                .iter()
+                .map(|param| param.display(db, display_target))
+                .join(", ");
+            if !generic_params.is_empty() {
+                format_to!(res.signature, "<{}>", generic_params);
+            }
         }
         hir::CallableKind::TupleEnumVariant(variant) => {
             res.doc = variant.docs(db);
             format_to!(
                 res.signature,
-                "enum {}::{}",
+                "enum {}",
                 variant.parent_enum(db).name(db).display(db, edition),
-                variant.name(db).display(db, edition)
             );
+
+            let generic_params = GenericDef::Adt(variant.parent_enum(db).into())
+                .params(db)
+                .iter()
+                .map(|param| param.display(db, display_target))
+                .join(", ");
+            if !generic_params.is_empty() {
+                format_to!(res.signature, "<{}>", generic_params);
+            }
+
+            format_to!(res.signature, "::{}", variant.name(db).display(db, edition))
         }
         hir::CallableKind::Closure(closure) => {
             let fn_trait = closure.fn_trait(db);
@@ -327,7 +350,7 @@ fn signature_help_for_generics(
         }
         // These don't have generic args that can be specified
         hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) | hir::GenericDef::Static(_) => {
-            return None
+            return None;
         }
     }
 
@@ -351,6 +374,20 @@ fn signature_help_for_generics(
 
         buf.clear();
         format_to!(buf, "{}", param.display(db, display_target));
+        match param {
+            GenericParam::TypeParam(param) => {
+                if let Some(ty) = param.default(db) {
+                    format_to!(buf, " = {}", ty.display(db, display_target));
+                }
+            }
+            GenericParam::ConstParam(param) => {
+                if let Some(expr) = param.default(db, display_target).and_then(|konst| konst.expr())
+                {
+                    format_to!(buf, " = {}", expr);
+                }
+            }
+            _ => {}
+        }
         res.push_generic_param(&buf);
     }
     if let hir::GenericDef::Trait(tr) = generics_def {
@@ -695,9 +732,8 @@ fn signature_help_for_tuple_pat_ish(
 }
 #[cfg(test)]
 mod tests {
-    use std::iter;
 
-    use expect_test::{expect, Expect};
+    use expect_test::{Expect, expect};
     use ide_db::FilePosition;
     use stdx::format_to;
     use test_fixture::ChangeFixture;
@@ -708,13 +744,14 @@ mod tests {
     pub(crate) fn position(
         #[rust_analyzer::rust_fixture] ra_fixture: &str,
     ) -> (RootDatabase, FilePosition) {
-        let change_fixture = ChangeFixture::parse(ra_fixture);
         let mut database = RootDatabase::default();
+        let change_fixture = ChangeFixture::parse(&database, ra_fixture);
         database.apply_change(change_fixture.change);
         let (file_id, range_or_offset) =
             change_fixture.file_position.expect("expected a marker ($0)");
         let offset = range_or_offset.expect_offset();
-        (database, FilePosition { file_id: file_id.into(), offset })
+        let position = FilePosition { file_id: file_id.file_id(&database), offset };
+        (database, position)
     }
 
     #[track_caller]
@@ -742,11 +779,11 @@ mod tests {
                     let gap = start.checked_sub(offset).unwrap_or_else(|| {
                         panic!("parameter ranges out of order: {:?}", sig_help.parameter_ranges())
                     });
-                    rendered.extend(iter::repeat(' ').take(gap as usize));
+                    rendered.extend(std::iter::repeat_n(' ', gap as usize));
                     let param_text = &sig_help.signature[*range];
                     let width = param_text.chars().count(); // …
                     let marker = if is_active { '^' } else { '-' };
-                    rendered.extend(iter::repeat(marker).take(width));
+                    rendered.extend(std::iter::repeat_n(marker, width));
                     offset += gap + u32::from(range.len());
                 }
                 if !sig_help.parameter_ranges().is_empty() {
@@ -828,8 +865,8 @@ fn foo<T, U: Copy + Display>(x: T, y: U) -> u32
 fn bar() { foo($03, ); }
 "#,
             expect![[r#"
-                fn foo(x: i32, y: U) -> u32
-                       ^^^^^^  ----
+                fn foo<T, U>(x: i32, y: U) -> u32
+                             ^^^^^^  ----
             "#]],
         );
     }
@@ -842,7 +879,7 @@ fn foo<T>() -> T where T: Copy + Display {}
 fn bar() { foo($0); }
 "#,
             expect![[r#"
-                fn foo() -> T
+                fn foo<T>() -> T
             "#]],
         );
     }
@@ -1292,8 +1329,8 @@ fn main() {
 }
 "#,
             expect![[r#"
-                struct S({unknown})
-                         ^^^^^^^^^
+                struct S<T>({unknown})
+                            ^^^^^^^^^
             "#]],
         );
     }
@@ -1388,7 +1425,7 @@ id! {
 fn test() { S.foo($0); }
 "#,
             expect![[r#"
-                fn foo(&'a mut self)
+                fn foo<'a>(&'a mut self)
             "#]],
         );
     }
@@ -1737,8 +1774,8 @@ fn sup() {
 }
 "#,
             expect![[r#"
-                fn test(&mut self, val: V)
-                                   ^^^^^^
+                fn test<V>(&mut self, val: V)
+                                      ^^^^^^
             "#]],
         );
     }
@@ -1914,8 +1951,8 @@ fn f() {
 }
 "#,
             expect![[r#"
-                fn foo(x: Wrap<impl Trait<U>>)
-                       ^^^^^^^^^^^^^^^^^^^^^^
+                fn foo<U>(x: Wrap<impl Trait<U>>)
+                          ^^^^^^^^^^^^^^^^^^^^^^
             "#]],
         );
     }
@@ -2407,4 +2444,96 @@ fn main() {
             "#]],
         );
     }
+
+    #[test]
+    fn test_tuple_generic_param() {
+        check(
+            r#"
+struct S<T>(T);
+
+fn main() {
+    let s: S<$0
+}
+            "#,
+            expect![[r#"
+                struct S<T>
+                         ^
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_enum_generic_param() {
+        check(
+            r#"
+enum Option<T> {
+    Some(T),
+    None,
+}
+
+fn main() {
+    let opt: Option<$0
+}
+            "#,
+            expect![[r#"
+                enum Option<T>
+                            ^
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_enum_variant_generic_param() {
+        check(
+            r#"
+enum Option<T> {
+    Some(T),
+    None,
+}
+
+fn main() {
+    let opt = Option::Some($0);
+}
+            "#,
+            expect![[r#"
+                enum Option<T>::Some({unknown})
+                                     ^^^^^^^^^
+            "#]],
+        );
+    }
+
+    #[test]
+    fn test_generic_arg_with_default() {
+        check(
+            r#"
+struct S<T = u8> {
+    field: T,
+}
+
+fn main() {
+    let s: S<$0
+}
+            "#,
+            expect![[r#"
+                struct S<T = u8>
+                         ^^^^^^
+            "#]],
+        );
+
+        check(
+            r#"
+struct S<const C: u8 = 5> {
+    field: C,
+}
+
+fn main() {
+    let s: S<$0
+}
+            "#,
+            expect![[r#"
+                struct S<const C: u8 = 5>
+                         ^^^^^^^^^^^^^^^
+            "#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/ssr.rs b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
index 90e350949b8..7df4499a0c2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/ssr.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
@@ -2,8 +2,8 @@
 //! assist in ide_assists because that would require the ide_assists crate
 //! depend on the ide_ssr crate.
 
-use ide_assists::{Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel};
-use ide_db::{label::Label, source_change::SourceChange, FileRange, RootDatabase};
+use ide_assists::{Assist, AssistId, AssistResolveStrategy, GroupLabel};
+use ide_db::{FileRange, RootDatabase, label::Label, source_change::SourceChange};
 
 pub(crate) fn ssr_assists(
     db: &RootDatabase,
@@ -16,7 +16,7 @@ pub(crate) fn ssr_assists(
         Some(ssr_data) => ssr_data,
         None => return ssr_assists,
     };
-    let id = AssistId("ssr", AssistKind::RefactorRewrite);
+    let id = AssistId::refactor_rewrite("ssr");
 
     let (source_change_for_file, source_change_for_workspace) = if resolve.should_resolve(&id) {
         let edits = match_finder.edits();
@@ -59,8 +59,8 @@ mod tests {
     use expect_test::expect;
     use ide_assists::{Assist, AssistResolveStrategy};
     use ide_db::{
-        base_db::ra_salsa::Durability, symbol_index::SymbolsDatabase, FileRange, FxHashSet,
-        RootDatabase,
+        FileRange, FxHashSet, RootDatabase, base_db::salsa::Durability,
+        symbol_index::SymbolsDatabase,
     };
     use test_fixture::WithFixture;
     use triomphe::Arc;
@@ -78,7 +78,7 @@ mod tests {
         ssr_assists(
             &db,
             &resolve,
-            FileRange { file_id: file_id.into(), range: range_or_offset.into() },
+            FileRange { file_id: file_id.file_id(&db), range: range_or_offset.into() },
         )
     }
 
@@ -120,6 +120,7 @@ mod tests {
                 id: AssistId(
                     "ssr",
                     RefactorRewrite,
+                    None,
                 ),
                 label: "Apply SSR in file",
                 group: Some(
@@ -139,9 +140,9 @@ mod tests {
                                         Indel {
                                             insert: "3",
                                             delete: 33..34,
-                                            annotation: None,
                                         },
                                     ],
+                                    annotation: None,
                                 },
                                 None,
                             ),
@@ -163,6 +164,7 @@ mod tests {
                 id: AssistId(
                     "ssr",
                     RefactorRewrite,
+                    None,
                 ),
                 label: "Apply SSR in workspace",
                 group: Some(
@@ -182,9 +184,9 @@ mod tests {
                                         Indel {
                                             insert: "3",
                                             delete: 33..34,
-                                            annotation: None,
                                         },
                                     ],
+                                    annotation: None,
                                 },
                                 None,
                             ),
@@ -196,9 +198,9 @@ mod tests {
                                         Indel {
                                             insert: "3",
                                             delete: 11..12,
-                                            annotation: None,
                                         },
                                     ],
+                                    annotation: None,
                                 },
                                 None,
                             ),
@@ -240,6 +242,7 @@ mod tests {
                 id: AssistId(
                     "ssr",
                     RefactorRewrite,
+                    None,
                 ),
                 label: "Apply SSR in file",
                 group: Some(
@@ -260,6 +263,7 @@ mod tests {
                 id: AssistId(
                     "ssr",
                     RefactorRewrite,
+                    None,
                 ),
                 label: "Apply SSR in workspace",
                 group: Some(
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index 332aecf1e3c..efee39c13db 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -1,25 +1,25 @@
 //! This module provides `StaticIndex` which is used for powering
 //! read-only code browsers and emitting LSIF
 
-use hir::{db::HirDatabase, Crate, HirFileIdExt, Module, Semantics};
+use arrayvec::ArrayVec;
+use hir::{Crate, Module, Semantics, db::HirDatabase};
 use ide_db::{
-    base_db::{SourceDatabase, SourceRootDatabase, VfsPath},
-    defs::Definition,
+    FileId, FileRange, FxHashMap, FxHashSet, RootDatabase,
+    base_db::{RootQueryDb, SourceDatabase, VfsPath},
+    defs::{Definition, IdentClass},
     documentation::Documentation,
     famous_defs::FamousDefs,
-    helpers::get_definition,
-    FileId, FileRange, FxHashMap, FxHashSet, RootDatabase,
 };
 use span::Edition;
-use syntax::{AstNode, SyntaxKind::*, SyntaxNode, TextRange, T};
+use syntax::{AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, T, TextRange};
 
 use crate::navigation_target::UpmappingResult;
 use crate::{
-    hover::{hover_for_definition, SubstTyLen},
+    Analysis, Fold, HoverConfig, HoverResult, InlayHint, InlayHintsConfig, TryToNav,
+    hover::{SubstTyLen, hover_for_definition},
     inlay_hints::{AdjustmentHintsMode, InlayFieldsToResolve},
-    moniker::{def_to_kind, def_to_moniker, MonikerResult, SymbolInformationKind},
+    moniker::{MonikerResult, SymbolInformationKind, def_to_kind, def_to_moniker},
     parent_module::crates_for,
-    Analysis, Fold, HoverConfig, HoverResult, InlayHint, InlayHintsConfig, TryToNav,
 };
 
 /// A static representation of fully analyzed source code.
@@ -120,12 +120,28 @@ fn documentation_for_definition(
         famous_defs.as_ref(),
         def.krate(sema.db)
             .unwrap_or_else(|| {
-                (*sema.db.crate_graph().crates_in_topological_order().last().unwrap()).into()
+                (*sema.db.all_crates().last().expect("no crate graph present")).into()
             })
             .to_display_target(sema.db),
     )
 }
 
+// FIXME: This is a weird function
+fn get_definitions(
+    sema: &Semantics<'_, RootDatabase>,
+    token: SyntaxToken,
+) -> Option<ArrayVec<Definition, 2>> {
+    for token in sema.descend_into_macros_exact(token) {
+        let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
+        if let Some(defs) = def {
+            if !defs.is_empty() {
+                return Some(defs);
+            }
+        }
+    }
+    None
+}
+
 pub enum VendoredLibrariesConfig<'a> {
     Included { workspace_root: &'a VfsPath },
     Excluded,
@@ -175,9 +191,14 @@ impl StaticIndex<'_> {
         // hovers
         let sema = hir::Semantics::new(self.db);
         let root = sema.parse_guess_edition(file_id).syntax().clone();
-        let edition =
-            sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
-        let display_target = sema.first_crate_or_default(file_id).to_display_target(self.db);
+        let edition = sema
+            .attach_first_edition(file_id)
+            .map(|it| it.edition(self.db))
+            .unwrap_or(Edition::CURRENT);
+        let display_target = match sema.first_crate(file_id) {
+            Some(krate) => krate.to_display_target(sema.db),
+            None => return,
+        };
         let tokens = root.descendants_with_tokens().filter_map(|it| match it {
             syntax::NodeOrToken::Node(_) => None,
             syntax::NodeOrToken::Token(it) => Some(it),
@@ -254,11 +275,14 @@ impl StaticIndex<'_> {
         for token in tokens {
             let range = token.text_range();
             let node = token.parent().unwrap();
-            let def = match get_definition(&sema, token.clone()) {
-                Some(it) => it,
+            match get_definitions(&sema, token.clone()) {
+                Some(it) => {
+                    for i in it {
+                        add_token(i, range, &node);
+                    }
+                }
                 None => continue,
             };
-            add_token(def, range, &node);
         }
         self.files.push(result);
     }
@@ -267,14 +291,14 @@ impl StaticIndex<'_> {
         analysis: &'a Analysis,
         vendored_libs_config: VendoredLibrariesConfig<'_>,
     ) -> StaticIndex<'a> {
-        let db = &*analysis.db;
+        let db = &analysis.db;
         let work = all_modules(db).into_iter().filter(|module| {
             let file_id = module.definition_source_file_id(db).original_file(db);
-            let source_root = db.file_source_root(file_id.into());
-            let source_root = db.source_root(source_root);
+            let source_root = db.file_source_root(file_id.file_id(&analysis.db)).source_root_id(db);
+            let source_root = db.source_root(source_root).source_root(db);
             let is_vendored = match vendored_libs_config {
                 VendoredLibrariesConfig::Included { workspace_root } => source_root
-                    .path_for_file(&file_id.into())
+                    .path_for_file(&file_id.file_id(&analysis.db))
                     .is_some_and(|module_path| module_path.starts_with(workspace_root)),
                 VendoredLibrariesConfig::Excluded => false,
             };
@@ -294,7 +318,7 @@ impl StaticIndex<'_> {
             if visited_files.contains(&file_id) {
                 continue;
             }
-            this.add_file(file_id.into());
+            this.add_file(file_id.file_id(&analysis.db));
             // mark the file
             visited_files.insert(file_id);
         }
@@ -304,8 +328,8 @@ impl StaticIndex<'_> {
 
 #[cfg(test)]
 mod tests {
-    use crate::{fixture, StaticIndex};
-    use ide_db::{base_db::VfsPath, FileRange, FxHashSet};
+    use crate::{StaticIndex, fixture};
+    use ide_db::{FileRange, FxHashMap, FxHashSet, base_db::VfsPath};
     use syntax::TextSize;
 
     use super::VendoredLibrariesConfig;
@@ -360,6 +384,71 @@ mod tests {
         }
     }
 
+    #[track_caller]
+    fn check_references(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        vendored_libs_config: VendoredLibrariesConfig<'_>,
+    ) {
+        let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
+        let s = StaticIndex::compute(&analysis, vendored_libs_config);
+        let mut range_set: FxHashMap<_, i32> = ranges.iter().map(|it| (it.0, 0)).collect();
+
+        // Make sure that all references have at least one range. We use a HashMap instead of a
+        // a HashSet so that we can have more than one reference at the same range.
+        for (_, t) in s.tokens.iter() {
+            for r in &t.references {
+                if r.is_definition {
+                    continue;
+                }
+                if r.range.range.start() == TextSize::from(0) {
+                    // ignore whole file range corresponding to module definition
+                    continue;
+                }
+                match range_set.entry(r.range) {
+                    std::collections::hash_map::Entry::Occupied(mut entry) => {
+                        let count = entry.get_mut();
+                        *count += 1;
+                    }
+                    std::collections::hash_map::Entry::Vacant(_) => {
+                        panic!("additional reference {r:?}");
+                    }
+                }
+            }
+        }
+        for (range, count) in range_set.iter() {
+            if *count == 0 {
+                panic!("unfound reference {range:?}");
+            }
+        }
+    }
+
+    #[test]
+    fn field_initialization() {
+        check_references(
+            r#"
+struct Point {
+    x: f64,
+     //^^^
+    y: f64,
+     //^^^
+}
+    fn foo() {
+        let x = 5.;
+        let y = 10.;
+        let mut p = Point { x, y };
+                  //^^^^^   ^  ^
+        p.x = 9.;
+      //^ ^
+        p.y = 10.;
+      //^ ^
+    }
+"#,
+            VendoredLibrariesConfig::Included {
+                workspace_root: &VfsPath::new_virtual_path("/workspace".to_owned()),
+            },
+        );
+    }
+
     #[test]
     fn struct_and_enum() {
         check_all_ranges(
@@ -384,6 +473,17 @@ enum E { X(Foo) }
                 workspace_root: &VfsPath::new_virtual_path("/workspace".to_owned()),
             },
         );
+
+        check_references(
+            r#"
+struct Foo;
+enum E { X(Foo) }
+   //      ^^^
+"#,
+            VendoredLibrariesConfig::Included {
+                workspace_root: &VfsPath::new_virtual_path("/workspace".to_owned()),
+            },
+        );
     }
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs
index a44be67668c..55a0db2d820 100644
--- a/src/tools/rust-analyzer/crates/ide/src/status.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/status.rs
@@ -1,29 +1,8 @@
-use std::{fmt, marker::PhantomData};
-
-use hir::{
-    db::{AstIdMapQuery, AttrsQuery, BlockDefMapQuery, ParseMacroExpansionQuery},
-    Attr, Attrs, ExpandResult, MacroFileId, Module,
-};
-use ide_db::{
-    base_db::{
-        ra_salsa::{
-            debug::{DebugQueryTable, TableEntry},
-            Query, QueryTable,
-        },
-        CompressedFileTextQuery, CrateData, ParseQuery, SourceDatabase, SourceRootId,
-    },
-    symbol_index::ModuleSymbolsQuery,
-};
-use ide_db::{
-    symbol_index::{LibrarySymbolsQuery, SymbolIndex},
-    RootDatabase,
-};
+use ide_db::RootDatabase;
+use ide_db::base_db::{BuiltCrateData, ExtraCrateData};
 use itertools::Itertools;
-use profile::{memory_usage, Bytes};
-use span::{EditionedFileId, FileId};
+use span::FileId;
 use stdx::format_to;
-use syntax::{ast, Parse, SyntaxNode};
-use triomphe::Arc;
 
 // Feature: Status
 //
@@ -37,17 +16,17 @@ use triomphe::Arc;
 pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
     let mut buf = String::new();
 
-    format_to!(buf, "{}\n", collect_query(CompressedFileTextQuery.in_db(db)));
-    format_to!(buf, "{}\n", collect_query(ParseQuery.in_db(db)));
-    format_to!(buf, "{}\n", collect_query(ParseMacroExpansionQuery.in_db(db)));
-    format_to!(buf, "{}\n", collect_query(LibrarySymbolsQuery.in_db(db)));
-    format_to!(buf, "{}\n", collect_query(ModuleSymbolsQuery.in_db(db)));
-    format_to!(buf, "{} in total\n", memory_usage());
+    // format_to!(buf, "{}\n", collect_query(CompressedFileTextQuery.in_db(db)));
+    // format_to!(buf, "{}\n", collect_query(ParseQuery.in_db(db)));
+    // format_to!(buf, "{}\n", collect_query(ParseMacroExpansionQuery.in_db(db)));
+    // format_to!(buf, "{}\n", collect_query(LibrarySymbolsQuery.in_db(db)));
+    // format_to!(buf, "{}\n", collect_query(ModuleSymbolsQuery.in_db(db)));
+    // format_to!(buf, "{} in total\n", memory_usage());
 
-    format_to!(buf, "\nDebug info:\n");
-    format_to!(buf, "{}\n", collect_query(AttrsQuery.in_db(db)));
-    format_to!(buf, "{} ast id maps\n", collect_query_count(AstIdMapQuery.in_db(db)));
-    format_to!(buf, "{} block def maps\n", collect_query_count(BlockDefMapQuery.in_db(db)));
+    // format_to!(buf, "\nDebug info:\n");
+    // format_to!(buf, "{}\n", collect_query(AttrsQuery.in_db(db)));
+    // format_to!(buf, "{} ast id maps\n", collect_query_count(AstIdMapQuery.in_db(db)));
+    // format_to!(buf, "{} block def maps\n", collect_query_count(BlockDefMapQuery.in_db(db)));
 
     if let Some(file_id) = file_id {
         format_to!(buf, "\nCrates for file {}:\n", file_id.index());
@@ -55,27 +34,25 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
         if crates.is_empty() {
             format_to!(buf, "Does not belong to any crate");
         }
-        let crate_graph = db.crate_graph();
         for crate_id in crates {
-            let CrateData {
+            let BuiltCrateData {
                 root_file_id,
                 edition,
-                version,
-                display_name,
-                cfg_options,
-                potential_cfg_options,
-                env,
                 dependencies,
                 origin,
                 is_proc_macro,
                 proc_macro_cwd,
-            } = &crate_graph[crate_id];
+            } = crate_id.data(db);
+            let ExtraCrateData { version, display_name, potential_cfg_options } =
+                crate_id.extra_data(db);
+            let cfg_options = crate_id.cfg_options(db);
+            let env = crate_id.env(db);
             format_to!(
                 buf,
                 "Crate: {}\n",
                 match display_name {
-                    Some(it) => format!("{it}({})", crate_id.into_raw()),
-                    None => format!("{}", crate_id.into_raw()),
+                    Some(it) => format!("{it}({:?})", crate_id),
+                    None => format!("{:?}", crate_id),
                 }
             );
             format_to!(buf, "    Root module file id: {}\n", root_file_id.index());
@@ -89,7 +66,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
             format_to!(buf, "    Proc macro cwd: {:?}\n", proc_macro_cwd);
             let deps = dependencies
                 .iter()
-                .map(|dep| format!("{}={}", dep.name, dep.crate_id.into_raw()))
+                .map(|dep| format!("{}={:?}", dep.name, dep.crate_id))
                 .format(", ");
             format_to!(buf, "    Dependencies: {}\n", deps);
         }
@@ -97,190 +74,3 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
 
     buf.trim().to_owned()
 }
-
-fn collect_query<'q, Q>(table: QueryTable<'q, Q>) -> <Q as QueryCollect>::Collector
-where
-    QueryTable<'q, Q>: DebugQueryTable,
-    Q: QueryCollect,
-    <Q as Query>::Storage: 'q,
-    <Q as QueryCollect>::Collector: StatCollect<
-        <QueryTable<'q, Q> as DebugQueryTable>::Key,
-        <QueryTable<'q, Q> as DebugQueryTable>::Value,
-    >,
-{
-    struct StatCollectorWrapper<C>(C);
-    impl<C: StatCollect<K, V>, K, V> FromIterator<TableEntry<K, V>> for StatCollectorWrapper<C> {
-        fn from_iter<T>(iter: T) -> StatCollectorWrapper<C>
-        where
-            T: IntoIterator<Item = TableEntry<K, V>>,
-        {
-            let mut res = C::default();
-            for entry in iter {
-                res.collect_entry(entry.key, entry.value);
-            }
-            StatCollectorWrapper(res)
-        }
-    }
-    table.entries::<StatCollectorWrapper<<Q as QueryCollect>::Collector>>().0
-}
-
-fn collect_query_count<'q, Q>(table: QueryTable<'q, Q>) -> usize
-where
-    QueryTable<'q, Q>: DebugQueryTable,
-    Q: Query,
-    <Q as Query>::Storage: 'q,
-{
-    struct EntryCounter(usize);
-    impl<K, V> FromIterator<TableEntry<K, V>> for EntryCounter {
-        fn from_iter<T>(iter: T) -> EntryCounter
-        where
-            T: IntoIterator<Item = TableEntry<K, V>>,
-        {
-            EntryCounter(iter.into_iter().count())
-        }
-    }
-    table.entries::<EntryCounter>().0
-}
-
-trait QueryCollect: Query {
-    type Collector;
-}
-
-impl QueryCollect for LibrarySymbolsQuery {
-    type Collector = SymbolsStats<SourceRootId>;
-}
-
-impl QueryCollect for ParseQuery {
-    type Collector = SyntaxTreeStats<false>;
-}
-
-impl QueryCollect for ParseMacroExpansionQuery {
-    type Collector = SyntaxTreeStats<true>;
-}
-
-impl QueryCollect for CompressedFileTextQuery {
-    type Collector = FilesStats;
-}
-
-impl QueryCollect for ModuleSymbolsQuery {
-    type Collector = SymbolsStats<Module>;
-}
-
-impl QueryCollect for AttrsQuery {
-    type Collector = AttrsStats;
-}
-
-trait StatCollect<K, V>: Default {
-    fn collect_entry(&mut self, key: K, value: Option<V>);
-}
-
-#[derive(Default)]
-struct FilesStats {
-    total: usize,
-    size: Bytes,
-}
-
-impl fmt::Display for FilesStats {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "{} of files", self.size)
-    }
-}
-
-impl StatCollect<FileId, Arc<[u8]>> for FilesStats {
-    fn collect_entry(&mut self, _: FileId, value: Option<Arc<[u8]>>) {
-        self.total += 1;
-        self.size += value.unwrap().len();
-    }
-}
-
-#[derive(Default)]
-pub(crate) struct SyntaxTreeStats<const MACROS: bool> {
-    total: usize,
-    pub(crate) retained: usize,
-}
-
-impl<const MACROS: bool> fmt::Display for SyntaxTreeStats<MACROS> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            fmt,
-            "{} trees, {} preserved{}",
-            self.total,
-            self.retained,
-            if MACROS { " (macros)" } else { "" }
-        )
-    }
-}
-
-impl StatCollect<EditionedFileId, Parse<ast::SourceFile>> for SyntaxTreeStats<false> {
-    fn collect_entry(&mut self, _: EditionedFileId, value: Option<Parse<ast::SourceFile>>) {
-        self.total += 1;
-        self.retained += value.is_some() as usize;
-    }
-}
-
-impl<M> StatCollect<MacroFileId, ExpandResult<(Parse<SyntaxNode>, M)>> for SyntaxTreeStats<true> {
-    fn collect_entry(
-        &mut self,
-        _: MacroFileId,
-        value: Option<ExpandResult<(Parse<SyntaxNode>, M)>>,
-    ) {
-        self.total += 1;
-        self.retained += value.is_some() as usize;
-    }
-}
-
-struct SymbolsStats<Key> {
-    total: usize,
-    size: Bytes,
-    phantom: PhantomData<Key>,
-}
-
-impl<Key> Default for SymbolsStats<Key> {
-    fn default() -> Self {
-        Self { total: Default::default(), size: Default::default(), phantom: PhantomData }
-    }
-}
-
-impl fmt::Display for SymbolsStats<Module> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "{} of module index symbols ({})", self.size, self.total)
-    }
-}
-impl fmt::Display for SymbolsStats<SourceRootId> {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(fmt, "{} of library index symbols ({})", self.size, self.total)
-    }
-}
-impl<Key> StatCollect<Key, Arc<SymbolIndex>> for SymbolsStats<Key> {
-    fn collect_entry(&mut self, _: Key, value: Option<Arc<SymbolIndex>>) {
-        if let Some(symbols) = value {
-            self.total += symbols.len();
-            self.size += symbols.memory_size();
-        }
-    }
-}
-
-#[derive(Default)]
-struct AttrsStats {
-    entries: usize,
-    total: usize,
-}
-
-impl fmt::Display for AttrsStats {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let size = self.entries * size_of::<Attrs>() + self.total * size_of::<Attr>();
-        let size = Bytes::new(size as _);
-        write!(
-            fmt,
-            "{} attribute query entries, {} total attributes ({} for storing entries)",
-            self.entries, self.total, size
-        )
-    }
-}
-
-impl<Key> StatCollect<Key, Attrs> for AttrsStats {
-    fn collect_entry(&mut self, _: Key, value: Option<Attrs>) {
-        self.entries += 1;
-        self.total += value.map_or(0, |it| it.len());
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
index 83082496d5b..e1bc76318f8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
@@ -15,26 +15,23 @@ mod tests;
 use std::ops::ControlFlow;
 
 use either::Either;
-use hir::{
-    DefWithBody, HirFileIdExt, InFile, InRealFile, MacroFileIdExt, MacroKind, Name, Semantics,
-};
+use hir::{DefWithBody, EditionedFileId, InFile, InRealFile, MacroKind, Name, Semantics};
 use ide_db::{FxHashMap, FxHashSet, Ranker, RootDatabase, SymbolKind};
-use span::EditionedFileId;
 use syntax::{
-    ast::{self, IsString},
     AstNode, AstToken, NodeOrToken,
     SyntaxKind::*,
-    SyntaxNode, SyntaxToken, TextRange, WalkEvent, T,
+    SyntaxNode, SyntaxToken, T, TextRange, WalkEvent,
+    ast::{self, IsString},
 };
 
 use crate::{
+    FileId, HlMod, HlOperator, HlPunct, HlTag,
     syntax_highlighting::{
         escape::{highlight_escape_byte, highlight_escape_char, highlight_escape_string},
         format::highlight_format_string,
         highlights::Highlights,
         tags::Highlight,
     },
-    FileId, HlMod, HlOperator, HlPunct, HlTag,
 };
 
 pub(crate) use html::highlight_as_html;
@@ -199,7 +196,7 @@ pub(crate) fn highlight(
     let sema = Semantics::new(db);
     let file_id = sema
         .attach_first_edition(file_id)
-        .unwrap_or_else(|| EditionedFileId::current_edition(file_id));
+        .unwrap_or_else(|| EditionedFileId::current_edition(db, file_id));
 
     // Determine the root based on the given range.
     let (root, range_to_highlight) = {
@@ -218,10 +215,7 @@ pub(crate) fn highlight(
     };
 
     let mut hl = highlights::Highlights::new(root.text_range());
-    let krate = match sema.scope(&root) {
-        Some(it) => it.krate(),
-        None => return hl.to_vec(),
-    };
+    let krate = sema.scope(&root).map(|it| it.krate());
     traverse(&mut hl, &sema, config, InRealFile::new(file_id, &root), krate, range_to_highlight);
     hl.to_vec()
 }
@@ -231,10 +225,10 @@ fn traverse(
     sema: &Semantics<'_, RootDatabase>,
     config: HighlightConfig,
     InRealFile { file_id, value: root }: InRealFile<&SyntaxNode>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     range_to_highlight: TextRange,
 ) {
-    let is_unlinked = sema.file_to_module_def(file_id).is_none();
+    let is_unlinked = sema.file_to_module_def(file_id.file_id(sema.db)).is_none();
 
     enum AttrOrDerive {
         Attr(ast::Item),
@@ -494,7 +488,7 @@ fn string_injections(
     sema: &Semantics<'_, RootDatabase>,
     config: HighlightConfig,
     file_id: EditionedFileId,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     token: SyntaxToken,
     descended_token: &SyntaxToken,
 ) -> ControlFlow<()> {
@@ -508,7 +502,14 @@ fn string_injections(
             {
                 return ControlFlow::Break(());
             }
-            highlight_format_string(hl, sema, krate, &string, &descended_string, file_id.edition());
+            highlight_format_string(
+                hl,
+                sema,
+                krate,
+                &string,
+                &descended_string,
+                file_id.edition(sema.db),
+            );
 
             if !string.is_raw() {
                 highlight_escape_string(hl, &string);
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
index cc02aff2acf..3716dcfed00 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
@@ -1,21 +1,21 @@
 //! Syntax highlighting for format macro strings.
 use ide_db::{
-    defs::Definition,
-    syntax_helpers::format_string::{is_format_string, lex_format_specifiers, FormatSpecifier},
     SymbolKind,
+    defs::Definition,
+    syntax_helpers::format_string::{FormatSpecifier, is_format_string, lex_format_specifiers},
 };
 use span::Edition;
-use syntax::{ast, AstToken};
+use syntax::{AstToken, ast};
 
 use crate::{
-    syntax_highlighting::{highlight::highlight_def, highlights::Highlights},
     HlRange, HlTag,
+    syntax_highlighting::{highlight::highlight_def, highlights::Highlights},
 };
 
 pub(super) fn highlight_format_string(
     stack: &mut Highlights,
     sema: &hir::Semantics<'_, ide_db::RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     string: &ast::String,
     expanded_string: &ast::String,
     edition: Edition,
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
index 282fbb4433b..87db0cd7dc5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
@@ -3,23 +3,23 @@
 use std::ops::ControlFlow;
 
 use either::Either;
-use hir::{AsAssocItem, HasVisibility, MacroFileIdExt, Semantics};
+use hir::{AsAssocItem, HasVisibility, Semantics};
 use ide_db::{
+    FxHashMap, RootDatabase, SymbolKind,
     defs::{Definition, IdentClass, NameClass, NameRefClass},
     syntax_helpers::node_ext::walk_pat,
-    FxHashMap, RootDatabase, SymbolKind,
 };
 use span::Edition;
 use stdx::hash_once;
 use syntax::{
-    ast, match_ast, AstNode, AstPtr, AstToken, NodeOrToken,
+    AstNode, AstPtr, AstToken, NodeOrToken,
     SyntaxKind::{self, *},
-    SyntaxNode, SyntaxNodePtr, SyntaxToken, T,
+    SyntaxNode, SyntaxNodePtr, SyntaxToken, T, ast, match_ast,
 };
 
 use crate::{
-    syntax_highlighting::tags::{HlOperator, HlPunct},
     Highlight, HlMod, HlTag,
+    syntax_highlighting::tags::{HlOperator, HlPunct},
 };
 
 pub(super) fn token(
@@ -63,7 +63,7 @@ pub(super) fn token(
 
 pub(super) fn name_like(
     sema: &Semantics<'_, RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>,
     is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
     syntactic_name_ref_highlighting: bool,
@@ -113,7 +113,8 @@ fn punctuation(
 ) -> Highlight {
     let operator_parent = token.parent();
     let parent_kind = operator_parent.as_ref().map_or(EOF, SyntaxNode::kind);
-    let h = match (kind, parent_kind) {
+
+    match (kind, parent_kind) {
         (T![?], TRY_EXPR) => HlTag::Operator(HlOperator::Other) | HlMod::ControlFlow,
         (T![&], BIN_EXPR) => HlOperator::Bitwise.into(),
         (T![&], REF_EXPR | REF_PAT) => HlTag::Operator(HlOperator::Other).into(),
@@ -143,11 +144,7 @@ fn punctuation(
             let ptr = operator_parent
                 .as_ref()
                 .and_then(|it| AstPtr::try_from_raw(SyntaxNodePtr::new(it)));
-            if ptr.is_some_and(is_unsafe_node) {
-                h | HlMod::Unsafe
-            } else {
-                h
-            }
+            if ptr.is_some_and(is_unsafe_node) { h | HlMod::Unsafe } else { h }
         }
         (T![-], PREFIX_EXPR) => {
             let prefix_expr =
@@ -223,11 +220,7 @@ fn punctuation(
                 let is_unsafe = is_unsafe_macro
                     || operator_parent
                         .and_then(|it| {
-                            if ast::ArgList::can_cast(it.kind()) {
-                                it.parent()
-                            } else {
-                                Some(it)
-                            }
+                            if ast::ArgList::can_cast(it.kind()) { it.parent() } else { Some(it) }
                         })
                         .and_then(|it| AstPtr::try_from_raw(SyntaxNodePtr::new(&it)))
                         .is_some_and(is_unsafe_node);
@@ -248,8 +241,7 @@ fn punctuation(
             _ => HlPunct::Other,
         }
         .into(),
-    };
-    h
+    }
 }
 
 fn keyword(token: SyntaxToken, kind: SyntaxKind) -> Highlight {
@@ -280,7 +272,7 @@ fn keyword(token: SyntaxToken, kind: SyntaxKind) -> Highlight {
 
 fn highlight_name_ref(
     sema: &Semantics<'_, RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>,
     binding_hash: &mut Option<u64>,
     is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
@@ -296,7 +288,7 @@ fn highlight_name_ref(
     let name_class = match NameRefClass::classify(sema, &name_ref) {
         Some(name_kind) => name_kind,
         None if syntactic_name_ref_highlighting => {
-            return highlight_name_ref_by_syntax(name_ref, sema, krate, is_unsafe_node)
+            return highlight_name_ref_by_syntax(name_ref, sema, krate, is_unsafe_node);
         }
         // FIXME: This is required for helper attributes used by proc-macros, as those do not map down
         // to anything when used.
@@ -409,9 +401,10 @@ fn highlight_name_ref(
         NameRefClass::ExternCrateShorthand { decl, krate: resolved_krate } => {
             let mut h = HlTag::Symbol(SymbolKind::Module).into();
 
-            if resolved_krate != krate {
-                h |= HlMod::Library
+            if krate.as_ref().is_some_and(|krate| resolved_krate != *krate) {
+                h |= HlMod::Library;
             }
+
             let is_public = decl.visibility(db) == hir::Visibility::Public;
             if is_public {
                 h |= HlMod::Public
@@ -439,7 +432,7 @@ fn highlight_name(
     bindings_shadow_count: Option<&mut FxHashMap<hir::Name, u32>>,
     binding_hash: &mut Option<u64>,
     is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     name: ast::Name,
     edition: Edition,
 ) -> Highlight {
@@ -484,7 +477,7 @@ fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 {
 
 pub(super) fn highlight_def(
     sema: &Semantics<'_, RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     def: Definition,
     edition: Edition,
     is_ref: bool,
@@ -668,7 +661,7 @@ pub(super) fn highlight_def(
     };
 
     let def_crate = def.krate(db);
-    let is_from_other_crate = def_crate != Some(krate);
+    let is_from_other_crate = def_crate != krate;
     let is_from_builtin_crate = def_crate.is_some_and(|def_crate| def_crate.is_builtin(db));
     let is_builtin = matches!(
         def,
@@ -689,7 +682,7 @@ pub(super) fn highlight_def(
 
 fn highlight_method_call_by_name_ref(
     sema: &Semantics<'_, RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     name_ref: &ast::NameRef,
     is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
 ) -> Option<Highlight> {
@@ -699,7 +692,7 @@ fn highlight_method_call_by_name_ref(
 
 fn highlight_method_call(
     sema: &Semantics<'_, RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     method_call: &ast::MethodCallExpr,
     is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
 ) -> Option<Highlight> {
@@ -726,7 +719,7 @@ fn highlight_method_call(
     }
 
     let def_crate = func.module(sema.db).krate();
-    let is_from_other_crate = def_crate != krate;
+    let is_from_other_crate = krate.as_ref().map_or(false, |krate| def_crate != *krate);
     let is_from_builtin_crate = def_crate.is_builtin(sema.db);
     let is_public = func.visibility(sema.db) == hir::Visibility::Public;
 
@@ -799,7 +792,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
 fn highlight_name_ref_by_syntax(
     name: ast::NameRef,
     sema: &Semantics<'_, RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     is_unsafe_node: &impl Fn(AstPtr<Either<ast::Expr, ast::Pat>>) -> bool,
 ) -> Highlight {
     let default = HlTag::UnresolvedReference;
@@ -818,12 +811,9 @@ fn highlight_name_ref_by_syntax(
             let h = HlTag::Symbol(SymbolKind::Field);
             let is_unsafe = ast::Expr::cast(parent)
                 .is_some_and(|it| is_unsafe_node(AstPtr::new(&it).wrap_left()));
-            if is_unsafe {
-                h | HlMod::Unsafe
-            } else {
-                h.into()
-            }
+            if is_unsafe { h | HlMod::Unsafe } else { h.into() }
         }
+        RECORD_EXPR_FIELD | RECORD_PAT_FIELD => HlTag::Symbol(SymbolKind::Field).into(),
         PATH_SEGMENT => {
             let name_based_fallback = || {
                 if name.text().chars().next().unwrap_or_default().is_uppercase() {
@@ -862,6 +852,8 @@ fn highlight_name_ref_by_syntax(
                 .into(),
             }
         }
+        ASSOC_TYPE_ARG => SymbolKind::TypeAlias.into(),
+        USE_BOUND_GENERIC_ARGS => SymbolKind::TypeParam.into(),
         _ => default.into(),
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
index 07d40bafeba..9fd807f031f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/html.rs
@@ -1,21 +1,20 @@
 //! Renders a bit of code as HTML.
 
-use hir::Semantics;
+use hir::{EditionedFileId, Semantics};
 use oorandom::Rand32;
-use span::EditionedFileId;
 use stdx::format_to;
 use syntax::AstNode;
 
 use crate::{
-    syntax_highlighting::{highlight, HighlightConfig},
     FileId, RootDatabase,
+    syntax_highlighting::{HighlightConfig, highlight},
 };
 
 pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: bool) -> String {
     let sema = Semantics::new(db);
     let file_id = sema
         .attach_first_edition(file_id)
-        .unwrap_or_else(|| EditionedFileId::current_edition(file_id));
+        .unwrap_or_else(|| EditionedFileId::current_edition(db, file_id));
     let file = sema.parse(file_id);
     let file = file.syntax();
     fn rainbowify(seed: u64) -> String {
@@ -40,7 +39,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
             macro_bang: true,
             syntactic_name_ref_highlighting: false,
         },
-        file_id.into(),
+        file_id.file_id(db),
         None,
     );
     let text = file.to_string();
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
index 1be90ad6a1e..0998e14c87b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
@@ -3,21 +3,20 @@
 use std::mem;
 
 use either::Either;
-use hir::{sym, HirFileId, InFile, Semantics};
+use hir::{EditionedFileId, HirFileId, InFile, Semantics, sym};
 use ide_db::{
-    active_parameter::ActiveParameter, defs::Definition, documentation::docs_with_rangemap,
-    rust_doc::is_rust_fence, SymbolKind,
+    SymbolKind, active_parameter::ActiveParameter, defs::Definition,
+    documentation::docs_with_rangemap, rust_doc::is_rust_fence,
 };
-use span::EditionedFileId;
 use syntax::{
-    ast::{self, AstNode, IsString, QuoteOffsets},
     AstToken, NodeOrToken, SyntaxNode, TextRange, TextSize,
+    ast::{self, AstNode, IsString, QuoteOffsets},
 };
 
 use crate::{
-    doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def},
-    syntax_highlighting::{highlights::Highlights, injector::Injector, HighlightConfig},
     Analysis, HlMod, HlRange, HlTag, RootDatabase,
+    doc_links::{doc_attributes, extract_definitions_from_docs, resolve_doc_path_for_def},
+    syntax_highlighting::{HighlightConfig, highlights::Highlights, injector::Injector},
 };
 
 pub(super) fn ra_fixture(
@@ -161,7 +160,7 @@ pub(super) fn doc_comment(
     let mut new_comments = Vec::new();
     let mut string;
 
-    for attr in attributes.by_key(&sym::doc).attrs() {
+    for attr in attributes.by_key(sym::doc).attrs() {
         let InFile { file_id, value: src } = attrs_source_map.source_of(attr);
         if file_id != src_file_id {
             continue;
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs
index a902fd717f0..c30f7973249 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/injector.rs
@@ -53,11 +53,7 @@ impl<T> Delta<T> {
     where
         T: Ord + Sub<Output = T>,
     {
-        if to >= from {
-            Delta::Add(to - from)
-        } else {
-            Delta::Sub(from - to)
-        }
+        if to >= from { Delta::Add(to - from) } else { Delta::Sub(from - to) }
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index c8c8c5dba4c..d00f279c829 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -45,14 +45,13 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">test</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span>
 <span class="comment documentation">//! ```</span>
 
+<span class="comment documentation">//! Syntactic name ref highlighting testing</span>
 <span class="comment documentation">//! ```rust</span>
 <span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="self_keyword crate_root injected">self</span><span class="semicolon injected">;</span>
-<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">std</span><span class="semicolon injected">;</span>
+<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">other</span><span class="none injected"> </span><span class="keyword injected">as</span><span class="none injected"> </span><span class="module crate_root declaration injected">otter</span><span class="semicolon injected">;</span>
 <span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">core</span><span class="semicolon injected">;</span>
-<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">alloc</span><span class="semicolon injected">;</span>
-<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">proc_macro</span><span class="semicolon injected">;</span>
-<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">test</span><span class="semicolon injected">;</span>
-<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">extern</span><span class="none injected"> </span><span class="keyword injected">crate</span><span class="none injected"> </span><span class="module crate_root injected">Krate</span><span class="semicolon injected">;</span>
+<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">trait</span><span class="none injected"> </span><span class="trait declaration injected">T</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="keyword injected">type</span><span class="none injected"> </span><span class="type_alias associated declaration injected static trait">Assoc</span><span class="semicolon injected">;</span><span class="none injected"> </span><span class="brace injected">}</span>
+<span class="comment documentation">//!</span><span class="comment documentation"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">f</span><span class="angle injected">&lt;</span><span class="type_param declaration injected">Arg</span><span class="angle injected">&gt;</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">-&gt;</span><span class="none injected"> </span><span class="keyword injected">use</span><span class="angle injected">&lt;</span><span class="struct injected">Arg</span><span class="angle injected">&gt;</span><span class="none injected"> </span><span class="keyword injected">where</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="colon injected">:</span><span class="none injected"> </span><span class="trait injected">T</span><span class="comparison injected">&lt;</span><span class="struct injected">Assoc</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="comparison injected">&gt;</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span>
 <span class="comment documentation">//! ```</span>
 <span class="keyword">mod</span> <span class="module declaration">outline_module</span><span class="semicolon">;</span>
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_19357.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_19357.html
new file mode 100644
index 00000000000..36ed8c594f7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_19357.html
@@ -0,0 +1,46 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.proc_macro         { color: #94BFF3; text-decoration: underline; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+.const              { font-weight: bolder; }
+.unsafe             { color: #BC8383; }
+
+.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
+.unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
+    <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword">mut</span> <span class="numeric_literal">5</span><span class="semicolon">;</span>
+<span class="brace">}</span>
+</code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
index 7f6b4c2c880..e1a8d876c41 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
@@ -41,14 +41,14 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><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="keyword">let</span> <span class="variable declaration reference" data-binding-hash="16711699953829236520" style="color: hsl(345,54%,46%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span>
-    <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="10753541418856619067" style="color: hsl(51,52%,47%);">x</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="16711699953829236520" style="color: hsl(345,54%,46%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="9865812862466303869" style="color: hsl(329,86%,55%);">y</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="16711699953829236520" style="color: hsl(345,54%,46%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration reference" data-binding-hash="18084384843626695225" style="color: hsl(154,95%,53%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="5697120079570210533" style="color: hsl(268,86%,80%);">x</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="18084384843626695225" style="color: hsl(154,95%,53%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="4222724691718692706" style="color: hsl(156,71%,51%);">y</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="18084384843626695225" style="color: hsl(154,95%,53%);">hello</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 
-    <span class="keyword">let</span> <span class="variable declaration reference" data-binding-hash="4890670724659097491" style="color: hsl(330,46%,45%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="semicolon">;</span>
-    <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="4002942168268782293" style="color: hsl(114,87%,67%);">y</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="4890670724659097491" style="color: hsl(330,46%,45%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration reference" data-binding-hash="17855021198829413584" style="color: hsl(230,76%,79%);">x</span> <span class="operator">=</span> <span class="string_literal">"other color please!"</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration" data-binding-hash="16380625810977895757" style="color: hsl(262,75%,75%);">y</span> <span class="operator">=</span> <span class="variable reference" data-binding-hash="17855021198829413584" style="color: hsl(230,76%,79%);">x</span><span class="operator">.</span><span class="unresolved_reference">to_string</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span>
 
 <span class="keyword">fn</span> <span class="function declaration">bar</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
-    <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable reference" data-binding-hash="16711699953829236520" style="color: hsl(345,54%,46%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable reference" data-binding-hash="18084384843626695225" style="color: hsl(154,95%,53%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index 8f69bb82300..dd359326c61 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -1,11 +1,11 @@
 use std::time::Instant;
 
-use expect_test::{expect_file, ExpectFile};
+use expect_test::{ExpectFile, expect_file};
 use ide_db::SymbolKind;
 use span::Edition;
-use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear};
+use test_utils::{AssertLinear, bench, bench_fixture, skip_slow_tests};
 
-use crate::{fixture, FileRange, HighlightConfig, HlTag, TextRange};
+use crate::{FileRange, HighlightConfig, HlTag, TextRange, fixture};
 
 const HL_CONFIG: HighlightConfig = HighlightConfig {
     strings: true,
@@ -739,14 +739,13 @@ fn test_highlight_doc_comment() {
 //! fn test() {}
 //! ```
 
+//! Syntactic name ref highlighting testing
 //! ```rust
 //! extern crate self;
-//! extern crate std;
+//! extern crate other as otter;
 //! extern crate core;
-//! extern crate alloc;
-//! extern crate proc_macro;
-//! extern crate test;
-//! extern crate Krate;
+//! trait T { type Assoc; }
+//! fn f<Arg>() -> use<Arg> where (): T<Assoc = ()> {}
 //! ```
 mod outline_module;
 
@@ -1302,7 +1301,7 @@ fn benchmark_syntax_highlighting_parser() {
             })
             .count()
     };
-    assert_eq!(hash, 1167);
+    assert_eq!(hash, 1606);
 }
 
 #[test]
@@ -1421,3 +1420,18 @@ fn template() {}
         false,
     );
 }
+
+#[test]
+fn issue_19357() {
+    check_highlighting(
+        r#"
+//- /foo.rs
+fn main() {
+    let x = &raw mut 5;
+}
+//- /main.rs
+"#,
+        expect_file!["./test_data/highlight_issue_19357.html"],
+        false,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
index 30b1d4c39b3..06cbd50e946 100644
--- a/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/test_explorer.rs
@@ -1,17 +1,15 @@
 //! Discovers tests
 
 use hir::{Crate, Module, ModuleDef, Semantics};
-use ide_db::{
-    base_db::{CrateGraph, CrateId, SourceDatabase},
-    FileId, RootDatabase,
-};
+use ide_db::base_db;
+use ide_db::{FileId, RootDatabase, base_db::RootQueryDb};
 use syntax::TextRange;
 
-use crate::{runnables::runnable_fn, NavigationTarget, Runnable, TryToNav};
+use crate::{NavigationTarget, Runnable, TryToNav, runnables::runnable_fn};
 
 #[derive(Debug)]
 pub enum TestItemKind {
-    Crate(CrateId),
+    Crate(base_db::Crate),
     Module,
     Function,
 }
@@ -28,12 +26,12 @@ pub struct TestItem {
 }
 
 pub(crate) fn discover_test_roots(db: &RootDatabase) -> Vec<TestItem> {
-    let crate_graph = db.crate_graph();
-    crate_graph
+    db.all_crates()
         .iter()
-        .filter(|&id| crate_graph[id].origin.is_local())
+        .copied()
+        .filter(|&id| id.data(db).origin.is_local())
         .filter_map(|id| {
-            let test_id = crate_graph[id].display_name.as_ref()?.to_string();
+            let test_id = id.extra_data(db).display_name.as_ref()?.to_string();
             Some(TestItem {
                 kind: TestItemKind::Crate(id),
                 label: test_id.clone(),
@@ -47,12 +45,12 @@ pub(crate) fn discover_test_roots(db: &RootDatabase) -> Vec<TestItem> {
         .collect()
 }
 
-fn find_crate_by_id(crate_graph: &CrateGraph, crate_id: &str) -> Option<CrateId> {
+fn find_crate_by_id(db: &RootDatabase, crate_id: &str) -> Option<base_db::Crate> {
     // here, we use display_name as the crate id. This is not super ideal, but it works since we
     // only show tests for the local crates.
-    crate_graph.iter().find(|&id| {
-        crate_graph[id].origin.is_local()
-            && crate_graph[id].display_name.as_ref().is_some_and(|x| x.to_string() == crate_id)
+    db.all_crates().iter().copied().find(|&id| {
+        id.data(db).origin.is_local()
+            && id.extra_data(db).display_name.as_ref().is_some_and(|x| x.to_string() == crate_id)
     })
 }
 
@@ -115,8 +113,7 @@ pub(crate) fn discover_tests_in_crate_by_test_id(
     db: &RootDatabase,
     crate_test_id: &str,
 ) -> Vec<TestItem> {
-    let crate_graph = db.crate_graph();
-    let Some(crate_id) = find_crate_by_id(&crate_graph, crate_test_id) else {
+    let Some(crate_id) = find_crate_by_id(db, crate_test_id) else {
         return vec![];
     };
     discover_tests_in_crate(db, crate_id)
@@ -171,12 +168,14 @@ fn find_module_id_and_test_parents(
     Some((r, id))
 }
 
-pub(crate) fn discover_tests_in_crate(db: &RootDatabase, crate_id: CrateId) -> Vec<TestItem> {
-    let crate_graph = db.crate_graph();
-    if !crate_graph[crate_id].origin.is_local() {
+pub(crate) fn discover_tests_in_crate(
+    db: &RootDatabase,
+    crate_id: base_db::Crate,
+) -> Vec<TestItem> {
+    if !crate_id.data(db).origin.is_local() {
         return vec![];
     }
-    let Some(crate_test_id) = &crate_graph[crate_id].display_name else {
+    let Some(crate_test_id) = &crate_id.extra_data(db).display_name else {
         return vec![];
     };
     let kind = TestItemKind::Crate(crate_id);
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index 8c9dd051452..4df7e25223d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -15,14 +15,15 @@
 
 mod on_enter;
 
+use hir::EditionedFileId;
+use ide_db::{FilePosition, RootDatabase, base_db::RootQueryDb};
+use span::Edition;
 use std::iter;
 
-use ide_db::{base_db::SourceDatabase, FilePosition, RootDatabase};
-use span::{Edition, EditionedFileId};
 use syntax::{
-    algo::{ancestors_at_offset, find_node_at_offset},
-    ast::{self, edit::IndentLevel, AstToken},
     AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize,
+    algo::{ancestors_at_offset, find_node_at_offset},
+    ast::{self, AstToken, edit::IndentLevel},
 };
 
 use ide_db::text_edit::TextEdit;
@@ -73,7 +74,8 @@ pub(crate) fn on_char_typed(
     // FIXME: We are hitting the database here, if we are unlucky this call might block momentarily
     // causing the editor to feel sluggish!
     let edition = Edition::CURRENT_FIXME;
-    let file = &db.parse(EditionedFileId::new(position.file_id, edition));
+    let editioned_file_id_wrapper = EditionedFileId::new(db, position.file_id, edition);
+    let file = &db.parse(editioned_file_id_wrapper);
     let char_matches_position =
         file.tree().syntax().text().char_at(position.offset) == Some(char_typed);
     if !stdx::always!(char_matches_position) {
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
index c6d1c283f4e..fdc583a15cc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
@@ -1,15 +1,14 @@
 //! Handles the `Enter` key press. At the momently, this only continues
 //! comments, but should handle indent some time in the future as well.
 
-use ide_db::RootDatabase;
-use ide_db::{base_db::SourceDatabase, FilePosition};
-use span::EditionedFileId;
+use ide_db::base_db::RootQueryDb;
+use ide_db::{FilePosition, RootDatabase};
 use syntax::{
-    algo::find_node_at_offset,
-    ast::{self, edit::IndentLevel, AstToken},
     AstNode, SmolStr, SourceFile,
     SyntaxKind::*,
     SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset,
+    algo::find_node_at_offset,
+    ast::{self, AstToken, edit::IndentLevel},
 };
 
 use ide_db::text_edit::TextEdit;
@@ -51,7 +50,9 @@ use ide_db::text_edit::TextEdit;
 //
 // ![On Enter](https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif)
 pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> {
-    let parse = db.parse(EditionedFileId::current_edition(position.file_id));
+    let editioned_file_id_wrapper =
+        ide_db::base_db::EditionedFileId::current_edition(db, position.file_id);
+    let parse = db.parse(editioned_file_id_wrapper);
     let file = parse.tree();
     let token = file.syntax().token_at_offset(position.offset).left_biased()?;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
index eb6eb7da1e9..4696fef3209 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
@@ -1,9 +1,11 @@
 use dot::{Id, LabelText};
+use ide_db::base_db::salsa::plumbing::AsId;
 use ide_db::{
-    base_db::{CrateGraph, CrateId, Dependency, SourceDatabase, SourceRootDatabase},
-    FxHashSet, RootDatabase,
+    FxHashMap, RootDatabase,
+    base_db::{
+        BuiltCrateData, BuiltDependency, Crate, ExtraCrateData, RootQueryDb, SourceDatabase,
+    },
 };
-use triomphe::Arc;
 
 // Feature: View Crate Graph
 //
@@ -16,76 +18,81 @@ use triomphe::Arc;
 // |---------|-------------|
 // | VS Code | **rust-analyzer: View Crate Graph** |
 pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result<String, String> {
-    let crate_graph = db.crate_graph();
-    let crates_to_render = crate_graph
+    let all_crates = db.all_crates();
+    let crates_to_render = all_crates
         .iter()
-        .filter(|krate| {
+        .copied()
+        .map(|krate| (krate, (krate.data(db), krate.extra_data(db))))
+        .filter(|(_, (crate_data, _))| {
             if full {
                 true
             } else {
                 // Only render workspace crates
-                let root_id = db.file_source_root(crate_graph[*krate].root_file_id);
-                !db.source_root(root_id).is_library
+                let root_id = db.file_source_root(crate_data.root_file_id).source_root_id(db);
+                !db.source_root(root_id).source_root(db).is_library
             }
         })
         .collect();
-    let graph = DotCrateGraph { graph: crate_graph, crates_to_render };
+    let graph = DotCrateGraph { crates_to_render };
 
     let mut dot = Vec::new();
     dot::render(&graph, &mut dot).unwrap();
     Ok(String::from_utf8(dot).unwrap())
 }
 
-struct DotCrateGraph {
-    graph: Arc<CrateGraph>,
-    crates_to_render: FxHashSet<CrateId>,
+struct DotCrateGraph<'db> {
+    crates_to_render: FxHashMap<Crate, (&'db BuiltCrateData, &'db ExtraCrateData)>,
 }
 
-type Edge<'a> = (CrateId, &'a Dependency);
+type Edge<'a> = (Crate, &'a BuiltDependency);
 
-impl<'a> dot::GraphWalk<'a, CrateId, Edge<'a>> for DotCrateGraph {
-    fn nodes(&'a self) -> dot::Nodes<'a, CrateId> {
-        self.crates_to_render.iter().copied().collect()
+impl<'a> dot::GraphWalk<'a, Crate, Edge<'a>> for DotCrateGraph<'_> {
+    fn nodes(&'a self) -> dot::Nodes<'a, Crate> {
+        self.crates_to_render.keys().copied().collect()
     }
 
     fn edges(&'a self) -> dot::Edges<'a, Edge<'a>> {
         self.crates_to_render
             .iter()
-            .flat_map(|krate| {
-                self.graph[*krate]
+            .flat_map(|(krate, (crate_data, _))| {
+                crate_data
                     .dependencies
                     .iter()
-                    .filter(|dep| self.crates_to_render.contains(&dep.crate_id))
+                    .filter(|dep| self.crates_to_render.contains_key(&dep.crate_id))
                     .map(move |dep| (*krate, dep))
             })
             .collect()
     }
 
-    fn source(&'a self, edge: &Edge<'a>) -> CrateId {
+    fn source(&'a self, edge: &Edge<'a>) -> Crate {
         edge.0
     }
 
-    fn target(&'a self, edge: &Edge<'a>) -> CrateId {
+    fn target(&'a self, edge: &Edge<'a>) -> Crate {
         edge.1.crate_id
     }
 }
 
-impl<'a> dot::Labeller<'a, CrateId, Edge<'a>> for DotCrateGraph {
+impl<'a> dot::Labeller<'a, Crate, Edge<'a>> for DotCrateGraph<'_> {
     fn graph_id(&'a self) -> Id<'a> {
         Id::new("rust_analyzer_crate_graph").unwrap()
     }
 
-    fn node_id(&'a self, n: &CrateId) -> Id<'a> {
-        Id::new(format!("_{}", u32::from(n.into_raw()))).unwrap()
+    fn node_id(&'a self, n: &Crate) -> Id<'a> {
+        let id = n.as_id().as_u32();
+        Id::new(format!("_{:?}", id)).unwrap()
     }
 
-    fn node_shape(&'a self, _node: &CrateId) -> Option<LabelText<'a>> {
+    fn node_shape(&'a self, _node: &Crate) -> Option<LabelText<'a>> {
         Some(LabelText::LabelStr("box".into()))
     }
 
-    fn node_label(&'a self, n: &CrateId) -> LabelText<'a> {
-        let name =
-            self.graph[*n].display_name.as_ref().map_or("(unnamed crate)", |name| name.as_str());
+    fn node_label(&'a self, n: &Crate) -> LabelText<'a> {
+        let name = self.crates_to_render[n]
+            .1
+            .display_name
+            .as_ref()
+            .map_or("(unnamed crate)", |name| name.as_str());
         LabelText::LabelStr(name.into())
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
index bfdf9d0f337..ec5e993f5a6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
@@ -1,6 +1,6 @@
-use hir::{DefWithBody, Semantics};
+use hir::Semantics;
 use ide_db::{FilePosition, RootDatabase};
-use syntax::{algo::ancestors_at_offset, ast, AstNode};
+use syntax::AstNode;
 
 // Feature: View Hir
 //
@@ -10,21 +10,10 @@ use syntax::{algo::ancestors_at_offset, ast, AstNode};
 //
 // ![View Hir](https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif)
 pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
-    body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_owned())
-}
-
-fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> {
-    let sema = Semantics::new(db);
-    let source_file = sema.parse_guess_edition(position.file_id);
-
-    let item = ancestors_at_offset(source_file.syntax(), position.offset)
-        .filter(|it| !ast::MacroCall::can_cast(it.kind()))
-        .find_map(ast::Item::cast)?;
-    let def: DefWithBody = match item {
-        ast::Item::Fn(it) => sema.to_def(&it)?.into(),
-        ast::Item::Const(it) => sema.to_def(&it)?.into(),
-        ast::Item::Static(it) => sema.to_def(&it)?.into(),
-        _ => return None,
-    };
-    Some(def.debug_hir(db))
+    (|| {
+        let sema = Semantics::new(db);
+        let source_file = sema.parse_guess_edition(position.file_id);
+        sema.debug_hir_at(source_file.syntax().token_at_offset(position.offset).next()?)
+    })()
+    .unwrap_or_else(|| "Not inside a lowerable item".to_owned())
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs
index 67c241cbb91..2cd751463bd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs
@@ -1,6 +1,5 @@
-use hir::{db::DefDatabase, Semantics};
+use hir::{EditionedFileId, Semantics, db::DefDatabase};
 use ide_db::{FileId, RootDatabase};
-use span::EditionedFileId;
 
 // Feature: Debug ItemTree
 //
@@ -13,6 +12,6 @@ pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String {
     let sema = Semantics::new(db);
     let file_id = sema
         .attach_first_edition(file_id)
-        .unwrap_or_else(|| EditionedFileId::current_edition(file_id));
-    db.file_item_tree(file_id.into()).pretty_print(db, file_id.edition())
+        .unwrap_or_else(|| EditionedFileId::current_edition(db, file_id));
+    db.file_item_tree(file_id.into()).pretty_print(db, file_id.edition(db))
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
index 34bca7bce12..140ae4265be 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
@@ -2,9 +2,9 @@ use std::fmt;
 
 use hir::{DisplayTarget, Field, HirDisplay, Layout, Semantics, Type};
 use ide_db::{
+    RootDatabase,
     defs::Definition,
     helpers::{get_definition, pick_best_token},
-    RootDatabase,
 };
 use syntax::{AstNode, SyntaxKind};
 
@@ -83,7 +83,7 @@ pub(crate) fn view_memory_layout(
 ) -> Option<RecursiveMemoryLayout> {
     let sema = Semantics::new(db);
     let file = sema.parse_guess_edition(position.file_id);
-    let display_target = sema.first_crate_or_default(position.file_id).to_display_target(db);
+    let display_target = sema.first_crate(position.file_id)?.to_display_target(db);
     let token =
         pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind {
             SyntaxKind::IDENT => 3,
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_mir.rs b/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
index aa4ff64a819..6ca231c7a81 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
@@ -1,6 +1,6 @@
 use hir::{DefWithBody, Semantics};
 use ide_db::{FilePosition, RootDatabase};
-use syntax::{algo::ancestors_at_offset, ast, AstNode};
+use syntax::{AstNode, algo::ancestors_at_offset, ast};
 
 // Feature: View Mir
 //
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs
index 407720864bf..ecd93e8b281 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs
@@ -1,13 +1,13 @@
 use hir::Semantics;
 use ide_db::{
-    line_index::{LineCol, LineIndex},
     FileId, LineIndexDatabase, RootDatabase,
+    line_index::{LineCol, LineIndex},
 };
 use span::{TextRange, TextSize};
 use stdx::format_to;
 use syntax::{
-    ast::{self, IsString},
     AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, WalkEvent,
+    ast::{self, IsString},
 };
 use triomphe::Arc;