From 19aae35b08d64c2ac4bcd5b888b6812fc803ab3f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 12 Jan 2026 08:36:32 +0100 Subject: [PATCH 1/2] Create a new `SymbolKind::CrateRoot` --- .../src/completions/extern_crate.rs | 6 +++--- .../crates/ide-completion/src/item.rs | 1 + .../rust-analyzer/crates/ide-db/src/lib.rs | 8 ++++--- .../crates/ide/src/navigation_target.rs | 13 ++++-------- .../crates/ide/src/references.rs | 2 +- .../rust-analyzer/crates/ide/src/runnables.rs | 8 +++---- .../ide/src/syntax_highlighting/highlight.rs | 21 +++++++++---------- .../ide/src/syntax_highlighting/inject.rs | 12 +++++------ .../ide/src/syntax_highlighting/tags.rs | 1 + .../test_data/highlight_asm.html | 8 +++---- .../test_data/highlight_attributes.html | 2 +- .../test_data/highlight_crate_root.html | 16 +++++++------- .../test_data/highlight_default_library.html | 2 +- .../test_data/highlight_deprecated.html | 4 ++-- .../test_data/highlight_doctest.html | 6 +++--- .../test_data/highlight_extern_crate.html | 14 ++++++------- .../test_data/highlight_general.html | 12 +++++------ .../test_data/highlight_injection_2.html | 2 +- .../test_data/highlight_issue_18089.html | 2 +- .../test_data/highlight_keywords_2015.html | 8 +++---- .../test_data/highlight_keywords_2018.html | 8 +++---- .../test_data/highlight_keywords_2021.html | 8 +++---- .../test_data/highlight_keywords_2024.html | 8 +++---- .../test_data/highlight_keywords_macros.html | 4 ++-- .../test_data/highlight_macros.html | 2 +- .../test_data/highlight_strings.html | 2 +- .../test_data/highlight_unsafe.html | 4 ++-- .../crates/rust-analyzer/src/lsp/to_proto.rs | 8 ++++++- 28 files changed, 98 insertions(+), 94 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs index 71a3e4eb4ed6..91202e8b32fc 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs @@ -17,7 +17,7 @@ pub(crate) fn complete_extern_crate(acc: &mut Completions, ctx: &CompletionConte } let mut item = CompletionItem::new( - CompletionItemKind::SymbolKind(SymbolKind::Module), + CompletionItemKind::SymbolKind(SymbolKind::CrateRoot), ctx.source_range(), name.display_no_db(ctx.edition).to_smolstr(), ctx.edition, @@ -48,7 +48,7 @@ mod other_mod {} let completion_list = completion_list_no_kw(case); - assert_eq!("md other_crate_a\n".to_owned(), completion_list); + assert_eq!("cr other_crate_a\n".to_owned(), completion_list); } #[test] @@ -68,6 +68,6 @@ mod other_mod {} let completion_list = completion_list_no_kw(case); - assert_eq!("md other_crate_a\n".to_owned(), completion_list); + assert_eq!("cr other_crate_a\n".to_owned(), completion_list); } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index 71d32da74710..1a9139d8553b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -381,6 +381,7 @@ impl CompletionItemKind { SymbolKind::BuiltinAttr => "ba", SymbolKind::Const => "ct", SymbolKind::ConstParam => "cp", + SymbolKind::CrateRoot => "cr", SymbolKind::Derive => "de", SymbolKind::DeriveHelper => "dh", SymbolKind::Enum => "en", diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index 413b58bf7980..023b32b36195 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -65,7 +65,7 @@ use base_db::{ }; use hir::{ FilePositionWrapper, FileRangeWrapper, - db::{DefDatabase, ExpandDatabase}, + db::{DefDatabase, ExpandDatabase, HirDatabase}, }; use triomphe::Arc; @@ -269,6 +269,7 @@ pub enum SymbolKind { BuiltinAttr, Const, ConstParam, + CrateRoot, Derive, DeriveHelper, Enum, @@ -307,14 +308,15 @@ impl From for SymbolKind { } } -impl From for SymbolKind { - fn from(it: hir::ModuleDef) -> Self { +impl SymbolKind { + pub fn from_module_def(db: &dyn HirDatabase, it: hir::ModuleDef) -> Self { match it { hir::ModuleDef::Const(..) => SymbolKind::Const, hir::ModuleDef::Variant(..) => SymbolKind::Variant, hir::ModuleDef::Function(..) => SymbolKind::Function, hir::ModuleDef::Macro(mac) if mac.is_proc_macro() => SymbolKind::ProcMacro, hir::ModuleDef::Macro(..) => SymbolKind::Macro, + hir::ModuleDef::Module(m) if m.is_crate_root(db) => SymbolKind::CrateRoot, hir::ModuleDef::Module(..) => SymbolKind::Module, hir::ModuleDef::Static(..) => SymbolKind::Static, hir::ModuleDef::Adt(hir::Adt::Struct(..)) => SymbolKind::Struct, 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 047df309eca6..185df92e2d39 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -264,7 +264,7 @@ impl<'db> TryToNav for FileSymbol<'db> { .flatten() .map_or_else(|| self.name.clone(), |it| it.symbol().clone()), alias: self.is_alias.then(|| self.name.clone()), - kind: Some(self.def.into()), + kind: Some(SymbolKind::from_module_def(db, self.def)), full_range, focus_range, container_name: self.container_name.clone(), @@ -480,16 +480,11 @@ impl ToNav for hir::Module { ModuleSource::Module(node) => (node.syntax(), node.name()), ModuleSource::BlockExpr(node) => (node.syntax(), None), }; + let kind = if self.is_crate_root(db) { SymbolKind::CrateRoot } else { SymbolKind::Module }; orig_range_with_focus(db, file_id, syntax, focus).map( |(FileRange { file_id, range: full_range }, focus_range)| { - NavigationTarget::from_syntax( - file_id, - name.clone(), - focus_range, - full_range, - SymbolKind::Module, - ) + NavigationTarget::from_syntax(file_id, name.clone(), focus_range, full_range, kind) }, ) } @@ -549,7 +544,7 @@ impl TryToNav for hir::ExternCrateDecl { self.alias_or_name(db).unwrap_or_else(|| self.name(db)).symbol().clone(), focus_range, full_range, - SymbolKind::Module, + SymbolKind::CrateRoot, ); res.docs = self.docs(db).map(Documentation::into_owned); diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 4918fe4ff9a4..5443021988d4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -1079,7 +1079,7 @@ use self$0; use self$0; "#, expect![[r#" - _ Module FileId(0) 0..10 + _ CrateRoot FileId(0) 0..10 FileId(0) 4..8 import "#]], diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 6cec91250351..42efa7142b50 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -815,7 +815,7 @@ mod not_a_root { "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..331, name: \"_\", kind: Module })", + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..331, name: \"_\", kind: CrateRoot })", "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })", "(Bin, NavigationTarget { file_id: FileId(0), full_range: 15..76, focus_range: 42..71, name: \"__cortex_m_rt_main_trampoline\", kind: Function })", "(Bin, NavigationTarget { file_id: FileId(0), full_range: 78..154, focus_range: 113..149, name: \"__cortex_m_rt_main_trampoline_unsafe\", kind: Function })", @@ -1136,7 +1136,7 @@ fn test_foo1() {} "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..51, name: \"_\", kind: Module })", + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..51, name: \"_\", kind: CrateRoot })", "(Test, NavigationTarget { file_id: FileId(0), full_range: 1..50, focus_range: 36..45, name: \"test_foo1\", kind: Function }, Atom(KeyValue { key: \"feature\", value: \"foo\" }))", ] "#]], @@ -1155,7 +1155,7 @@ fn test_foo1() {} "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..73, name: \"_\", kind: Module })", + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..73, name: \"_\", kind: CrateRoot })", "(Test, NavigationTarget { file_id: FileId(0), full_range: 1..72, focus_range: 58..67, name: \"test_foo1\", kind: Function }, All([Atom(KeyValue { key: \"feature\", value: \"foo\" }), Atom(KeyValue { key: \"feature\", value: \"bar\" })]))", ] "#]], @@ -1234,7 +1234,7 @@ generate_main!(); "#, expect![[r#" [ - "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..345, name: \"_\", kind: Module })", + "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..345, name: \"_\", kind: CrateRoot })", "(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..307, name: \"foo_test\", kind: Function })", "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 313..323, name: \"tests2\", kind: Module, description: \"mod tests2\" }, true)", 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 044fd3f5ac9a..3795d3d4146d 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 @@ -399,7 +399,7 @@ fn highlight_name_ref( highlight_def(sema, krate, field_ref.into(), edition, true) } NameRefClass::ExternCrateShorthand { decl, krate: resolved_krate } => { - let mut h = HlTag::Symbol(SymbolKind::Module).into(); + let mut h = HlTag::Symbol(SymbolKind::CrateRoot).into(); if krate.as_ref().is_some_and(|krate| resolved_krate != *krate) { h |= HlMod::Library; @@ -417,7 +417,6 @@ fn highlight_name_ref( if is_deprecated { h |= HlMod::Deprecated; } - h |= HlMod::CrateRoot; h } }; @@ -496,15 +495,15 @@ pub(super) fn highlight_def( } Definition::TupleField(_) => (Highlight::new(HlTag::Symbol(SymbolKind::Field)), None), Definition::Crate(krate) => ( - Highlight::new(HlTag::Symbol(SymbolKind::Module)) | HlMod::CrateRoot, + Highlight::new(HlTag::Symbol(SymbolKind::CrateRoot)).into(), Some(krate.attrs(sema.db)), ), Definition::Module(module) => { - let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module)); - if module.is_crate_root(db) { - h |= HlMod::CrateRoot; - } - + let h = Highlight::new(HlTag::Symbol(if module.is_crate_root(db) { + SymbolKind::CrateRoot + } else { + SymbolKind::Module + })); (h, Some(module.attrs(sema.db))) } Definition::Function(func) => { @@ -662,8 +661,7 @@ pub(super) fn highlight_def( (h, None) } Definition::ExternCrateDecl(extern_crate) => { - let mut highlight = - Highlight::new(HlTag::Symbol(SymbolKind::Module)) | HlMod::CrateRoot; + let mut highlight = Highlight::new(HlTag::Symbol(SymbolKind::CrateRoot)).into(); if extern_crate.alias(db).is_none() { highlight |= HlMod::Library; } @@ -805,6 +803,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight { TYPE_PARAM => SymbolKind::TypeParam, RECORD_FIELD => SymbolKind::Field, MODULE => SymbolKind::Module, + EXTERN_CRATE => SymbolKind::CrateRoot, FN => SymbolKind::Function, CONST => SymbolKind::Const, STATIC => SymbolKind::Static, @@ -835,7 +834,7 @@ fn highlight_name_ref_by_syntax( }; match parent.kind() { - EXTERN_CRATE => HlTag::Symbol(SymbolKind::Module) | HlMod::CrateRoot, + EXTERN_CRATE => HlTag::Symbol(SymbolKind::CrateRoot).into(), METHOD_CALL_EXPR => ast::MethodCallExpr::cast(parent) .and_then(|it| highlight_method_call(sema, krate, &it, is_unsafe_node)) .unwrap_or_else(|| SymbolKind::Method.into()), 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 26d2bb5e0288..291333f09cf8 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 @@ -1,6 +1,6 @@ //! "Recursive" Syntax highlighting for code in doctests and fixtures. -use hir::{EditionedFileId, HirFileId, InFile, Semantics}; +use hir::{EditionedFileId, HirFileId, InFile, Semantics, db::HirDatabase}; use ide_db::{ SymbolKind, defs::Definition, documentation::Documentation, range_mapper::RangeMapper, rust_doc::is_rust_fence, @@ -109,7 +109,7 @@ pub(super) fn doc_comment( .for_each(|(range, def)| { hl.add(HlRange { range, - highlight: module_def_to_hl_tag(def) + highlight: module_def_to_hl_tag(sema.db, def) | HlMod::Documentation | HlMod::Injected | HlMod::IntraDocLink, @@ -200,11 +200,11 @@ pub(super) fn doc_comment( } } -fn module_def_to_hl_tag(def: Definition) -> HlTag { +fn module_def_to_hl_tag(db: &dyn HirDatabase, def: Definition) -> HlTag { let symbol = match def { - Definition::Module(_) | Definition::Crate(_) | Definition::ExternCrateDecl(_) => { - SymbolKind::Module - } + Definition::Crate(_) | Definition::ExternCrateDecl(_) => SymbolKind::CrateRoot, + Definition::Module(m) if m.is_crate_root(db) => SymbolKind::CrateRoot, + Definition::Module(_) => SymbolKind::Module, Definition::Function(_) => SymbolKind::Function, Definition::Adt(hir::Adt::Struct(_)) => SymbolKind::Struct, Definition::Adt(hir::Adt::Enum(_)) => SymbolKind::Enum, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs index ca3c3e3aaace..0c64d3de1012 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tags.rs @@ -144,6 +144,7 @@ impl HlTag { SymbolKind::BuiltinAttr => "builtin_attr", SymbolKind::Const => "constant", SymbolKind::ConstParam => "const_param", + SymbolKind::CrateRoot => "crate_root", SymbolKind::Derive => "derive", SymbolKind::DeriveHelper => "derive_helper", SymbolKind::Enum => "enum", diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html index 100fdd2155a4..1228849c5bfd 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_asm.html @@ -45,7 +45,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd unsafe { let foo = 1; let mut o = 0; - core::arch::asm!( + core::arch::asm!( "%input = OpLoad _ {0}", concat!("%result = ", "bar", " _ %input"), "OpStore {1} %result", @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd ); let thread_id: usize; - core::arch::asm!(" + core::arch::asm!(" mov {0}, gs:[0x30] mov {0}, [{0}+0x48] ", out(reg) thread_id, options(pure, readonly, nostack)); @@ -64,7 +64,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd static VirtualFree: usize; const OffPtr: usize; const OffFn: usize; - core::arch::asm!(" + core::arch::asm!(" push {free_type} push {free_size} push {base} @@ -97,7 +97,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd // Ensure thumb mode is set. let rv = (rv as u32) | 1; let msp = msp as u32; - core::arch::asm!( + core::arch::asm!( "mrs {tmp}, CONTROL", "bics {tmp}, {spsel}", "msr CONTROL, {tmp}", diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html index b151ff42fc39..fa7f7b1cbafb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html @@ -43,7 +43,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
#[allow(dead_code)]
 #[rustfmt::skip]
-#[proc_macros::identity]
+#[proc_macros::identity]
 #[derive(Default)]
 /// This is a doc comment
 // This is a normal comment
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
index a6e6b16bead5..0b32cedca5d8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
@@ -41,25 +41,25 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
-
extern crate foo;
-use core::iter;
+
extern crate foo;
+use core::iter;
 
 pub const NINETY_TWO: u8 = 92;
 
-use foo as foooo;
+use foo as foooo;
 
-pub(crate) fn main() {
+pub(crate) fn main() {
     let baz = iter::repeat(92);
 }
 
 mod bar {
-    pub(in super) const FORTY_TWO: u8 = 42;
+    pub(in super) const FORTY_TWO: u8 = 42;
 
     mod baz {
-        use super::super::NINETY_TWO;
-        use crate::foooo::Point;
+        use super::super::NINETY_TWO;
+        use crate::foooo::Point;
 
-        pub(in super::super) const TWENTY_NINE: u8 = 29;
+        pub(in super::super) const TWENTY_NINE: u8 = 29;
     }
 }
 
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html index 2f4a2004f1de..29f78959a54f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html @@ -41,7 +41,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } -
use core::iter;
+
use core::iter;
 
 fn main() {
     let foo = Some(92);
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_deprecated.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_deprecated.html
index 41d3dff8ed9e..5287affbfc5c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_deprecated.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_deprecated.html
@@ -42,8 +42,8 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
 
#![deprecated]
-use crate as _;
-extern crate bar;
+use crate as _;
+extern crate bar;
 #[deprecated]
 macro_rules! macro_ {
     () => {};
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 b5c3df6ee447..ce9ec7431a97 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
@@ -48,9 +48,9 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 //! Syntactic name ref highlighting testing
 //! ```rust
-//! extern crate self;
-//! extern crate other as otter;
-//! extern crate core;
+//! extern crate self;
+//! extern crate other as otter;
+//! extern crate core;
 //! trait T { type Assoc; }
 //! fn f<Arg>() -> use<Arg> where (): T<Assoc = ()> {}
 //! ```
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index 3a4518236883..8f7cbddd7ffb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -41,12 +41,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
-
extern crate self as this;
-extern crate std;
-extern crate alloc as abc;
-extern crate unresolved as definitely_unresolved;
+
extern crate self as this;
+extern crate std;
+extern crate alloc as abc;
+extern crate unresolved as definitely_unresolved;
 extern crate unresolved as _;
-extern crate test as opt_in_crate;
-extern crate test as _;
-extern crate proc_macro;
+extern crate test as opt_in_crate;
+extern crate test as _;
+extern crate proc_macro;
 
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html index fd652f444ffd..c6dbc435c0e8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html @@ -72,7 +72,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } } -use self::FooCopy::{self as BarCopy}; +use self::FooCopy::{self as BarCopy}; #[derive(Copy)] struct FooCopy { @@ -110,7 +110,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd FOO } -use core::ops::Fn; +use core::ops::Fn; fn baz<F: Fn() -> ()>(f: F) { f() } @@ -184,15 +184,15 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd } fn use_foo_items() { - let bob = foo::Person { + let bob = foo::Person { name: "Bob", - age: foo::consts::NUMBER, + age: foo::consts::NUMBER, }; - let control_flow = foo::identity(foo::ControlFlow::Continue); + let control_flow = foo::identity(foo::ControlFlow::Continue); if control_flow.should_die() { - foo::die!(); + foo::die!(); } } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html index 5a5d9bd1f909..391a46f706c8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection_2.html @@ -47,7 +47,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd fixture(r#" @@- /main.rs crate:main deps:other_crate fn test() { - let x = other_crate::foo::S::thing(); + let x = other_crate::foo::S::thing(); x; } //^ i128 diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html index b28818e679ff..fccf34083d7f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html @@ -45,5 +45,5 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd template!(template); } -#[proc_macros::issue_18089] +#[proc_macros::issue_18089] fn template() {}
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html index d2a53b2ff9e1..6366cba1bd03 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html @@ -41,12 +41,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } -
extern crate self;
+
extern crate self;
 
-use crate;
-use self;
+use crate;
+use self;
 mod __ {
-    use super::*;
+    use super::*;
 }
 
 macro_rules! void {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html
index d309b4723238..a89e8190832e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html
@@ -41,12 +41,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
-
extern crate self;
+
extern crate self;
 
-use crate;
-use self;
+use crate;
+use self;
 mod __ {
-    use super::*;
+    use super::*;
 }
 
 macro_rules! void {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html
index d309b4723238..a89e8190832e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html
@@ -41,12 +41,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
-
extern crate self;
+
extern crate self;
 
-use crate;
-use self;
+use crate;
+use self;
 mod __ {
-    use super::*;
+    use super::*;
 }
 
 macro_rules! void {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html
index 575c9a6b0aca..aa1500b8f85b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html
@@ -41,12 +41,12 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
-
extern crate self;
+
extern crate self;
 
-use crate;
-use self;
+use crate;
+use self;
 mod __ {
-    use super::*;
+    use super::*;
 }
 
 macro_rules! void {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html
index caf66ace7a68..484afd81ead2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_macros.html
@@ -41,6 +41,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 
-
lib2015::void_2015!(try async await gen);
-lib2024::void_2024!(try async await gen);
+
lib2015::void_2015!(try async await gen);
+lib2024::void_2024!(try async await gen);
 
\ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html index b63d5cedc825..59612634fda3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html @@ -41,7 +41,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } -
use proc_macros::{mirror, identity, DeriveIdentity};
+
use proc_macros::{mirror, identity, DeriveIdentity};
 
 mirror! {
     {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index e178782c79c4..4e3822c3d31f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -165,7 +165,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     toho!("{}fmt", 0);
     let i: u64 = 3;
     let o: u64;
-    core::arch::asm!(
+    core::arch::asm!(
         "mov {0}, {1}",
         "add {0}, 5",
         out(reg) o,
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 93513f5b575d..008987d409ad 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -91,7 +91,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
         // unsafe fn and method calls
         unsafe_fn();
-        self::unsafe_fn();
+        self::unsafe_fn();
         (unsafe_fn as unsafe fn())();
         Struct { field: 0 }.unsafe_method();
 
@@ -120,7 +120,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
         &EXTERN_STATIC;
         &raw const EXTERN_STATIC;
 
-        core::arch::asm!(
+        core::arch::asm!(
             "push {base}",
             base = const 0
         );
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index 6f0f57725fc7..e5b983dcbf85 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -70,6 +70,7 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind {
         | SymbolKind::Attribute
         | SymbolKind::Derive
         | SymbolKind::DeriveHelper => lsp_types::SymbolKind::FUNCTION,
+        SymbolKind::CrateRoot => lsp_types::SymbolKind::PACKAGE,
         SymbolKind::Module | SymbolKind::ToolModule => lsp_types::SymbolKind::MODULE,
         SymbolKind::TypeAlias | SymbolKind::TypeParam | SymbolKind::SelfType => {
             lsp_types::SymbolKind::TYPE_PARAMETER
@@ -141,6 +142,7 @@ pub(crate) fn completion_item_kind(
             SymbolKind::Method => lsp_types::CompletionItemKind::METHOD,
             SymbolKind::Const => lsp_types::CompletionItemKind::CONSTANT,
             SymbolKind::ConstParam => lsp_types::CompletionItemKind::TYPE_PARAMETER,
+            SymbolKind::CrateRoot => lsp_types::CompletionItemKind::MODULE,
             SymbolKind::Derive => lsp_types::CompletionItemKind::FUNCTION,
             SymbolKind::DeriveHelper => lsp_types::CompletionItemKind::FUNCTION,
             SymbolKind::Enum => lsp_types::CompletionItemKind::ENUM,
@@ -803,11 +805,16 @@ fn semantic_token_type_and_modifiers(
 ) -> (lsp_types::SemanticTokenType, semantic_tokens::ModifierSet) {
     use semantic_tokens::{modifiers as mods, types};
 
+    let mut mods = semantic_tokens::ModifierSet::default();
     let ty = match highlight.tag {
         HlTag::Symbol(symbol) => match symbol {
             SymbolKind::Attribute => types::DECORATOR,
             SymbolKind::Derive => types::DERIVE,
             SymbolKind::DeriveHelper => types::DERIVE_HELPER,
+            SymbolKind::CrateRoot => {
+                mods |= mods::CRATE_ROOT;
+                types::NAMESPACE
+            }
             SymbolKind::Module => types::NAMESPACE,
             SymbolKind::Impl => types::TYPE_ALIAS,
             SymbolKind::Field => types::PROPERTY,
@@ -870,7 +877,6 @@ fn semantic_token_type_and_modifiers(
         },
     };
 
-    let mut mods = semantic_tokens::ModifierSet::default();
     for modifier in highlight.mods.iter() {
         let modifier = match modifier {
             HlMod::Associated => mods::ASSOCIATED,

From 5f6d3852ee494e167eaa8128b1d5f81a0f03234d Mon Sep 17 00:00:00 2001
From: Lukas Wirth 
Date: Mon, 12 Jan 2026 08:46:20 +0100
Subject: [PATCH 2/2] Fix crate root search in world symbols duplicating root
 entries

---
 .../rust-analyzer/crates/hir/src/symbols.rs   |  15 +--
 .../crates/ide-db/src/items_locator.rs        |   4 +-
 .../crates/ide-db/src/symbol_index.rs         | 102 +++++++++---------
 .../ide-db/src/test_data/test_doc_alias.txt   |  28 -----
 .../test_symbol_index_collection.txt          |  28 -----
 .../ide/src/syntax_highlighting/highlight.rs  |   9 +-
 .../rust-analyzer/tests/slow-tests/main.rs    |   4 +-
 7 files changed, 67 insertions(+), 123 deletions(-)

diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index f9002f31fd15..4461659f5c4e 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -23,7 +23,7 @@ use intern::Symbol;
 use rustc_hash::FxHashMap;
 use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, ToSmolStr, ast::HasName};
 
-use crate::{HasCrate, Module, ModuleDef, Semantics};
+use crate::{Crate, HasCrate, Module, ModuleDef, Semantics};
 
 /// The actual data that is stored in the index. It should be as compact as
 /// possible.
@@ -100,11 +100,6 @@ impl<'a> SymbolCollector<'a> {
         let _p = tracing::info_span!("SymbolCollector::collect", ?module).entered();
         tracing::info!(?module, "SymbolCollector::collect");
 
-        // If this is a crate root module, add a symbol for the crate itself
-        if module.is_crate_root(self.db) {
-            self.push_crate_root(module);
-        }
-
         // The initial work is the root module we're collecting, additional work will
         // be populated as we traverse the module's definitions.
         self.work.push(SymbolCollectorWork { module_id: module.into(), parent: None });
@@ -116,8 +111,7 @@ impl<'a> SymbolCollector<'a> {
 
     /// Push a symbol for a crate's root module.
     /// This allows crate roots to appear in the symbol index for queries like `::` or `::foo`.
-    fn push_crate_root(&mut self, module: Module) {
-        let krate = module.krate(self.db);
+    pub fn push_crate_root(&mut self, krate: Crate) {
         let Some(display_name) = krate.display_name(self.db) else { return };
         let crate_name = display_name.crate_name();
         let canonical_name = display_name.canonical_name();
@@ -131,10 +125,11 @@ impl<'a> SymbolCollector<'a> {
         let ptr = SyntaxNodePtr::new(&syntax_node);
 
         let loc = DeclarationLocation { hir_file_id, ptr, name_ptr: None };
+        let root_module = krate.root_module(self.db);
 
         self.symbols.insert(FileSymbol {
             name: crate_name.symbol().clone(),
-            def: ModuleDef::Module(module),
+            def: ModuleDef::Module(root_module),
             loc,
             container_name: None,
             is_alias: false,
@@ -147,7 +142,7 @@ impl<'a> SymbolCollector<'a> {
         if canonical_name != crate_name.symbol() {
             self.symbols.insert(FileSymbol {
                 name: canonical_name.clone(),
-                def: ModuleDef::Module(module),
+                def: ModuleDef::Module(root_module),
                 loc,
                 container_name: None,
                 is_alias: false,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
index 0d305530d925..af0c69c6856d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
@@ -110,7 +110,7 @@ pub fn items_with_name_in_module(
             local_query
         }
     };
-    local_query.search(&[SymbolIndex::module_symbols(db, module)], |local_candidate| {
+    local_query.search(db, &[SymbolIndex::module_symbols(db, module)], |local_candidate| {
         cb(match local_candidate.def {
             hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def),
             def => ItemInNs::from(def),
@@ -140,7 +140,7 @@ fn find_items(
 
     // Query the local crate using the symbol index.
     let mut local_results = Vec::new();
-    local_query.search(&symbol_index::crate_symbols(db, krate), |local_candidate| {
+    local_query.search(db, &symbol_index::crate_symbols(db, krate), |local_candidate| {
         let def = match local_candidate.def {
             hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def),
             def => ItemInNs::from(def),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index 05c3f360fa87..c95b541748ec 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -218,15 +218,18 @@ pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex<'_
 // | Editor  | Shortcut |
 // |---------|-----------|
 // | VS Code | Ctrl+T
-pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec> {
+pub fn world_symbols(db: &RootDatabase, mut query: Query) -> Vec> {
     let _p = tracing::info_span!("world_symbols", query = ?query.query).entered();
 
-    if query.is_crate_search() {
-        return search_crates(db, &query);
-    }
-
-    // If we have a path filter, resolve it to target modules
-    let indices: Vec<_> = if !query.path_filter.is_empty() {
+    // Search for crates by name (handles "::" and "::foo" queries)
+    let indices: Vec<_> = if query.is_crate_search() {
+        query.only_types = false;
+        query.libs = true;
+        vec![SymbolIndex::extern_prelude_symbols(db)]
+        // If we have a path filter, resolve it to target modules
+    } else if !query.path_filter.is_empty() {
+        query.only_types = false;
+        query.libs = true;
         let target_modules = resolve_path_to_modules(
             db,
             &query.path_filter,
@@ -258,13 +261,17 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec> {
         crates
             .par_iter()
             .for_each_with(db.clone(), |snap, &krate| _ = crate_symbols(snap, krate.into()));
-        crates.into_iter().flat_map(|krate| Vec::from(crate_symbols(db, krate.into()))).collect()
+        crates
+            .into_iter()
+            .flat_map(|krate| Vec::from(crate_symbols(db, krate.into())))
+            .chain(std::iter::once(SymbolIndex::extern_prelude_symbols(db)))
+            .collect()
     };
 
     let mut res = vec![];
 
     // Normal search: use FST to match item name
-    query.search::<()>(&indices, |f| {
+    query.search::<()>(db, &indices, |f| {
         res.push(f.clone());
         ControlFlow::Continue(())
     });
@@ -272,39 +279,6 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec> {
     res
 }
 
-/// Search for crates by name (handles "::" and "::foo" queries)
-fn search_crates<'db>(db: &'db RootDatabase, query: &Query) -> Vec> {
-    let mut res = vec![];
-
-    for krate in Crate::all(db) {
-        let Some(display_name) = krate.display_name(db) else { continue };
-        let crate_name = display_name.crate_name().as_str();
-
-        // If query is empty (sole "::"), return all crates
-        // Otherwise, fuzzy match the crate name
-        let matches = if query.query.is_empty() {
-            true
-        } else {
-            query.mode.check(&query.query, query.case_sensitive, crate_name)
-        };
-
-        if matches {
-            // Get the crate root module's symbol index and find the root module symbol
-            let root_module = krate.root_module(db);
-            let index = SymbolIndex::module_symbols(db, root_module);
-            // Find the module symbol itself (representing the crate)
-            for symbol in index.symbols.iter() {
-                if matches!(symbol.def, hir::ModuleDef::Module(m) if m == root_module) {
-                    res.push(symbol.clone());
-                    break;
-                }
-            }
-        }
-    }
-
-    res
-}
-
 /// Resolve a path filter to the target module(s) it points to.
 /// Returns the modules whose symbol indices should be searched.
 ///
@@ -452,6 +426,33 @@ impl<'db> SymbolIndex<'db> {
 
         module_symbols(db, InternedModuleId::new(db, hir::ModuleId::from(module)))
     }
+
+    /// The symbol index for all extern prelude crates.
+    pub fn extern_prelude_symbols(db: &dyn HirDatabase) -> &SymbolIndex<'_> {
+        #[salsa::tracked(returns(ref))]
+        fn extern_prelude_symbols<'db>(db: &'db dyn HirDatabase) -> SymbolIndex<'db> {
+            let _p = tracing::info_span!("extern_prelude_symbols").entered();
+
+            // We call this without attaching because this runs in parallel, so we need to attach here.
+            hir::attach_db(db, || {
+                let mut collector = SymbolCollector::new(db, false);
+
+                for krate in Crate::all(db) {
+                    if krate
+                        .display_name(db)
+                        .is_none_or(|name| name.canonical_name().as_str() == "build-script-build")
+                    {
+                        continue;
+                    }
+                    collector.push_crate_root(krate);
+                }
+
+                SymbolIndex::new(collector.finish())
+            })
+        }
+
+        extern_prelude_symbols(db)
+    }
 }
 
 impl fmt::Debug for SymbolIndex<'_> {
@@ -555,6 +556,7 @@ impl Query {
     /// Search symbols in the given indices.
     pub(crate) fn search<'db, T>(
         &self,
+        db: &'db RootDatabase,
         indices: &[&'db SymbolIndex<'db>],
         cb: impl FnMut(&'db FileSymbol<'db>) -> ControlFlow,
     ) -> Option {
@@ -568,7 +570,7 @@ impl Query {
                 for index in indices.iter() {
                     op = op.add(index.map.search(&automaton));
                 }
-                self.search_maps(indices, op.union(), cb)
+                self.search_maps(db, indices, op.union(), cb)
             }
             SearchMode::Fuzzy => {
                 let automaton = fst::automaton::Subsequence::new(&self.lowercased);
@@ -576,7 +578,7 @@ impl Query {
                 for index in indices.iter() {
                     op = op.add(index.map.search(&automaton));
                 }
-                self.search_maps(indices, op.union(), cb)
+                self.search_maps(db, indices, op.union(), cb)
             }
             SearchMode::Prefix => {
                 let automaton = fst::automaton::Str::new(&self.lowercased).starts_with();
@@ -584,13 +586,14 @@ impl Query {
                 for index in indices.iter() {
                     op = op.add(index.map.search(&automaton));
                 }
-                self.search_maps(indices, op.union(), cb)
+                self.search_maps(db, indices, op.union(), cb)
             }
         }
     }
 
     fn search_maps<'db, T>(
         &self,
+        db: &'db RootDatabase,
         indices: &[&'db SymbolIndex<'db>],
         mut stream: fst::map::Union<'_>,
         mut cb: impl FnMut(&'db FileSymbol<'db>) -> ControlFlow,
@@ -598,18 +601,21 @@ impl Query {
         let ignore_underscore_prefixed = !self.query.starts_with("__");
         while let Some((_, indexed_values)) = stream.next() {
             for &IndexedValue { index, value } in indexed_values {
-                let symbol_index = &indices[index];
+                let symbol_index = indices[index];
                 let (start, end) = SymbolIndex::map_value_to_range(value);
 
                 for symbol in &symbol_index.symbols[start..end] {
                     let non_type_for_type_only_query = self.only_types
-                        && !matches!(
+                        && !(matches!(
                             symbol.def,
                             hir::ModuleDef::Adt(..)
                                 | hir::ModuleDef::TypeAlias(..)
                                 | hir::ModuleDef::BuiltinType(..)
                                 | hir::ModuleDef::Trait(..)
-                        );
+                        ) || matches!(
+                            symbol.def,
+                            hir::ModuleDef::Module(module) if module.is_crate_root(db)
+                        ));
                     if non_type_for_type_only_query || !self.matches_assoc_mode(symbol.is_assoc) {
                         continue;
                     }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
index 71680699b739..0c28c312f83b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
@@ -154,34 +154,6 @@
                 do_not_complete: Yes,
                 _marker: PhantomData<&()>,
             },
-            FileSymbol {
-                name: "ra_test_fixture",
-                def: Module(
-                    Module {
-                        id: ModuleIdLt {
-                            [salsa id]: Id(3800),
-                        },
-                    },
-                ),
-                loc: DeclarationLocation {
-                    hir_file_id: FileId(
-                        EditionedFileId(
-                            Id(3000),
-                        ),
-                    ),
-                    ptr: SyntaxNodePtr {
-                        kind: SOURCE_FILE,
-                        range: 0..128,
-                    },
-                    name_ptr: None,
-                },
-                container_name: None,
-                is_alias: false,
-                is_assoc: false,
-                is_import: false,
-                do_not_complete: Yes,
-                _marker: PhantomData<&()>,
-            },
             FileSymbol {
                 name: "s1",
                 def: Adt(
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index 2d62a56fe22d..4b588572d328 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -919,34 +919,6 @@
                 do_not_complete: Yes,
                 _marker: PhantomData<&()>,
             },
-            FileSymbol {
-                name: "ra_test_fixture",
-                def: Module(
-                    Module {
-                        id: ModuleIdLt {
-                            [salsa id]: Id(3800),
-                        },
-                    },
-                ),
-                loc: DeclarationLocation {
-                    hir_file_id: FileId(
-                        EditionedFileId(
-                            Id(3000),
-                        ),
-                    ),
-                    ptr: SyntaxNodePtr {
-                        kind: SOURCE_FILE,
-                        range: 0..793,
-                    },
-                    name_ptr: None,
-                },
-                container_name: None,
-                is_alias: false,
-                is_assoc: false,
-                is_import: false,
-                do_not_complete: Yes,
-                _marker: PhantomData<&()>,
-            },
             FileSymbol {
                 name: "really_define_struct",
                 def: Macro(
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 3795d3d4146d..dcc9a8c0d5f7 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
@@ -494,10 +494,9 @@ pub(super) fn highlight_def(
             (Highlight::new(HlTag::Symbol(SymbolKind::Field)), Some(field.attrs(sema.db)))
         }
         Definition::TupleField(_) => (Highlight::new(HlTag::Symbol(SymbolKind::Field)), None),
-        Definition::Crate(krate) => (
-            Highlight::new(HlTag::Symbol(SymbolKind::CrateRoot)).into(),
-            Some(krate.attrs(sema.db)),
-        ),
+        Definition::Crate(krate) => {
+            (Highlight::new(HlTag::Symbol(SymbolKind::CrateRoot)), Some(krate.attrs(sema.db)))
+        }
         Definition::Module(module) => {
             let h = Highlight::new(HlTag::Symbol(if module.is_crate_root(db) {
                 SymbolKind::CrateRoot
@@ -661,7 +660,7 @@ pub(super) fn highlight_def(
             (h, None)
         }
         Definition::ExternCrateDecl(extern_crate) => {
-            let mut highlight = Highlight::new(HlTag::Symbol(SymbolKind::CrateRoot)).into();
+            let mut highlight = Highlight::new(HlTag::Symbol(SymbolKind::CrateRoot));
             if extern_crate.alias(db).is_none() {
                 highlight |= HlMod::Library;
             }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index 9f3c6742d651..b4a7b44d165a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -1452,7 +1452,7 @@ foo = { path = "../foo" }
         json!([
         {
           "name": "bar",
-          "kind": 2,
+          "kind": 4,
           "location": {
             "uri": "file:///[..]bar/src/lib.rs",
             "range": {
@@ -1511,7 +1511,7 @@ version = "0.0.0"
         json!([
         {
           "name": "baz",
-          "kind": 2,
+          "kind": 4,
           "location": {
             "uri": "file:///[..]baz/src/lib.rs",
             "range": {