Unnamed repository; edit this file 'description' to name the repository.
Fix crate root search in world symbols duplicating root entries
| -rw-r--r-- | crates/hir/src/symbols.rs | 15 | ||||
| -rw-r--r-- | crates/ide-db/src/items_locator.rs | 4 | ||||
| -rw-r--r-- | crates/ide-db/src/symbol_index.rs | 102 | ||||
| -rw-r--r-- | crates/ide-db/src/test_data/test_doc_alias.txt | 28 | ||||
| -rw-r--r-- | crates/ide-db/src/test_data/test_symbol_index_collection.txt | 28 | ||||
| -rw-r--r-- | crates/ide/src/syntax_highlighting/highlight.rs | 9 | ||||
| -rw-r--r-- | crates/rust-analyzer/tests/slow-tests/main.rs | 4 |
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": { |