Unnamed repository; edit this file 'description' to name the repository.
Fix crate root search in world symbols duplicating root entries
Lukas Wirth 3 months ago
parent d90e7b6 · commit cfcbeea
-rw-r--r--crates/hir/src/symbols.rs15
-rw-r--r--crates/ide-db/src/items_locator.rs4
-rw-r--r--crates/ide-db/src/symbol_index.rs102
-rw-r--r--crates/ide-db/src/test_data/test_doc_alias.txt28
-rw-r--r--crates/ide-db/src/test_data/test_symbol_index_collection.txt28
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs9
-rw-r--r--crates/rust-analyzer/tests/slow-tests/main.rs4
7 files changed, 67 insertions, 123 deletions
diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs
index f9002f31fd..4461659f5c 100644
--- a/crates/hir/src/symbols.rs
+++ b/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/crates/ide-db/src/items_locator.rs b/crates/ide-db/src/items_locator.rs
index 0d305530d9..af0c69c685 100644
--- a/crates/ide-db/src/items_locator.rs
+++ b/crates/ide-db/src/items_locator.rs
@@ -110,7 +110,7 @@ pub fn items_with_name_in_module<T>(
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/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs
index 05c3f360fa..c95b541748 100644
--- a/crates/ide-db/src/symbol_index.rs
+++ b/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 | <kbd>Ctrl+T</kbd>
-pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol<'_>> {
+pub fn world_symbols(db: &RootDatabase, mut query: Query) -> Vec<FileSymbol<'_>> {
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<FileSymbol<'_>> {
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<FileSymbol<'_>> {
res
}
-/// Search for crates by name (handles "::" and "::foo" queries)
-fn search_crates<'db>(db: &'db RootDatabase, query: &Query) -> Vec<FileSymbol<'db>> {
- 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<T>,
) -> Option<T> {
@@ -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<T>,
@@ -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/crates/ide-db/src/test_data/test_doc_alias.txt b/crates/ide-db/src/test_data/test_doc_alias.txt
index 71680699b7..0c28c312f8 100644
--- a/crates/ide-db/src/test_data/test_doc_alias.txt
+++ b/crates/ide-db/src/test_data/test_doc_alias.txt
@@ -155,34 +155,6 @@
_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(
Struct(
diff --git a/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index 2d62a56fe2..4b588572d3 100644
--- a/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -920,34 +920,6 @@
_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(
Macro {
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 3795d3d414..dcc9a8c0d5 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/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/crates/rust-analyzer/tests/slow-tests/main.rs b/crates/rust-analyzer/tests/slow-tests/main.rs
index 9f3c6742d6..b4a7b44d16 100644
--- a/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/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": {