about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-11-30 14:07:39 +0000
committerGitHub <noreply@github.com>2021-11-30 14:07:39 +0000
commit2d0db312b543343f1c208b6be21a7a001cec7dd6 (patch)
tree2cf8e7b9adf14afae77e2722f672c5f7d6049281
parente217632b9819876cd59f4f6f963d04b0637bd8d2 (diff)
parentf4bf750016c4c51b0ec1f1b0e6e2fe25578796f3 (diff)
downloadrust-2d0db312b543343f1c208b6be21a7a001cec7dd6.tar.gz
rust-2d0db312b543343f1c208b6be21a7a001cec7dd6.zip
Merge #10872
10872: ide_db: build symbol index from crate def map r=Veykril a=jhgg

fixes #4842, #10764

Is this looking correct? :eyes: 

- [x] build the symbol index based upon the CrateDefMap for the given crate in `crate_symbols`
   - [x] make it multi threaded again, and figure out how to cache each moduleid's symbol index in salsa.
   - [x] NavigationTarget for names in macros is wrong, need to figure out how to compute a text range in the original file id?
   - [x] cleanup some duped code
   - [x] collect macros from `ItemScope.declared_macros()` into symbol index.
        - [x] store declared macros in `ItemScope` so we can figure out where macros were defined for the index.  
   - [x] do something about `SymbolIndex::for_files` - ideally it should use the new module symbol index stuff. 
       - [x] delete `source_file_to_file_symbols` & co...
           - [x] figure out what to do about `library_symbols` 
           - [x] maybe... speed up the new `library_symbols` - the new impl is probably much slower, and definitely much less parallel. **deciding to do nothing here, we can optimize later if necerssary.** 
   - [x] fix failing test: `navigation_target::tests::test_nav_for_symbol` - notably the crate def map doesn't seem to find declarations inside function. 
       - [x] now a bunch of other tests are failing around auto_import & qualify_path handlers. :(
           - [x] need to assoc items in traits and impls
 

Co-authored-by: Jake Heinz <jh@discordapp.com>
-rw-r--r--crates/base_db/src/fixture.rs4
-rw-r--r--crates/base_db/src/lib.rs2
-rw-r--r--crates/hir/src/lib.rs28
-rw-r--r--crates/hir/src/semantics.rs10
-rw-r--r--crates/hir_def/src/item_scope.rs16
-rw-r--r--crates/hir_def/src/nameres.rs2
-rw-r--r--crates/hir_def/src/nameres/collector.rs3
-rw-r--r--crates/ide/src/lib.rs4
-rw-r--r--crates/ide/src/navigation_target.rs20
-rw-r--r--crates/ide/src/status.rs15
-rw-r--r--crates/ide_db/src/apply_change.rs2
-rw-r--r--crates/ide_db/src/items_locator.rs3
-rw-r--r--crates/ide_db/src/symbol_index.rs587
-rw-r--r--crates/ide_db/src/test_data/test_symbol_index_collection.txt527
14 files changed, 1045 insertions, 178 deletions
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 9baae921445..5326a5a4404 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -19,8 +19,8 @@ use crate::{
 pub const WORKSPACE: SourceRootId = SourceRootId(0);
 
 pub trait WithFixture: Default + SourceDatabaseExt + 'static {
-    fn with_single_file(text: &str) -> (Self, FileId) {
-        let fixture = ChangeFixture::parse(text);
+    fn with_single_file(ra_fixture: &str) -> (Self, FileId) {
+        let fixture = ChangeFixture::parse(ra_fixture);
         let mut db = Self::default();
         fixture.change.apply(&mut db);
         assert_eq!(fixture.files.len(), 1);
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index d4070457cdd..d80660f7c9a 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -102,7 +102,7 @@ fn source_root_crates(db: &dyn SourceDatabaseExt, id: SourceRootId) -> Arc<FxHas
             let root_file = graph[krate].root_file_id;
             db.file_source_root(root_file) == id
         })
-        .collect::<FxHashSet<_>>();
+        .collect();
     Arc::new(res)
 }
 
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index badd9ac5891..e0dc921c9f0 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -40,18 +40,14 @@ use hir_def::{
     adt::{ReprKind, VariantData},
     body::{BodyDiagnostic, SyntheticSyntax},
     expr::{BindingAnnotation, LabelId, Pat, PatId},
-    item_tree::ItemTreeNode,
     lang_item::LangItemTarget,
     nameres,
     per_ns::PerNs,
     resolver::{HasResolver, Resolver},
-    src::HasSource as _,
-    AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId,
-    DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId,
-    LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
-    TypeParamId, UnionId,
+    AttrDefId, ConstId, ConstParamId, EnumId, FunctionId, GenericDefId, HasModule, LifetimeParamId,
+    LocalEnumVariantId, LocalFieldId, StaticId, StructId, TypeAliasId, TypeParamId, UnionId,
 };
-use hir_expand::{name::name, MacroCallKind, MacroDefId, MacroDefKind};
+use hir_expand::{name::name, MacroCallKind, MacroDefKind};
 use hir_ty::{
     autoderef,
     consteval::ConstExt,
@@ -109,14 +105,28 @@ pub use {
         attr::{Attr, Attrs, AttrsWithOwner, Documentation},
         find_path::PrefixKind,
         import_map,
-        nameres::ModuleSource,
+        item_scope::ItemScope,
+        item_tree::ItemTreeNode,
+        nameres::{DefMap, ModuleData, ModuleOrigin, ModuleSource},
         path::{ModPath, PathKind},
+        src::HasSource as DefHasSource, // xx: I don't like this shadowing of HasSource... :(
         type_ref::{Mutability, TypeRef},
         visibility::Visibility,
+        AdtId,
+        AssocContainerId,
+        AssocItemId,
+        AssocItemLoc,
+        DefWithBodyId,
+        ImplId,
+        ItemLoc,
+        Lookup,
+        ModuleDefId,
+        ModuleId,
+        TraitId,
     },
     hir_expand::{
         name::{known, Name},
-        ExpandResult, HirFileId, InFile, MacroFile, Origin,
+        ExpandResult, HirFileId, InFile, MacroDefId, MacroFile, Origin,
     },
     hir_ty::display::HirDisplay,
 };
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 281e6c65dc4..27ba42ce1af 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -143,6 +143,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.parse(file_id)
     }
 
+    pub fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode> {
+        self.imp.parse_or_expand(file_id)
+    }
+
     pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
         self.imp.expand(macro_call)
     }
@@ -416,6 +420,12 @@ impl<'db> SemanticsImpl<'db> {
         tree
     }
 
+    fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode> {
+        let node = self.db.parse_or_expand(file_id)?;
+        self.cache(node.clone(), file_id);
+        Some(node)
+    }
+
     fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
         let sa = self.analyze(macro_call.syntax());
         let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?;
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index 0a2a6719edc..37599371f61 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -44,6 +44,8 @@ pub struct ItemScope {
     /// The defs declared in this scope. Each def has a single scope where it is
     /// declared.
     declarations: Vec<ModuleDefId>,
+    macro_declarations: Vec<MacroDefId>,
+
     impls: Vec<ImplId>,
     unnamed_consts: Vec<ConstId>,
     /// Traits imported via `use Trait as _;`.
@@ -101,6 +103,10 @@ impl ItemScope {
         self.declarations.iter().copied()
     }
 
+    pub fn macro_declarations(&self) -> impl Iterator<Item = MacroDefId> + '_ {
+        self.macro_declarations.iter().copied()
+    }
+
     pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
         self.impls.iter().copied()
     }
@@ -163,6 +169,10 @@ impl ItemScope {
         self.declarations.push(def)
     }
 
+    pub(crate) fn declare_macro(&mut self, def: MacroDefId) {
+        self.macro_declarations.push(def);
+    }
+
     pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
         self.legacy_macros.get(name).copied()
     }
@@ -336,7 +346,8 @@ impl ItemScope {
             values,
             macros,
             unresolved,
-            declarations: defs,
+            declarations,
+            macro_declarations,
             impls,
             unnamed_consts,
             unnamed_trait_imports,
@@ -348,7 +359,8 @@ impl ItemScope {
         values.shrink_to_fit();
         macros.shrink_to_fit();
         unresolved.shrink_to_fit();
-        defs.shrink_to_fit();
+        declarations.shrink_to_fit();
+        macro_declarations.shrink_to_fit();
         impls.shrink_to_fit();
         unnamed_consts.shrink_to_fit();
         unnamed_trait_imports.shrink_to_fit();
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 882d54c996a..cf670e5cc17 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -148,7 +148,7 @@ pub enum ModuleOrigin {
 }
 
 impl ModuleOrigin {
-    fn declaration(&self) -> Option<AstId<ast::Module>> {
+    pub fn declaration(&self) -> Option<AstId<ast::Module>> {
         match self {
             ModuleOrigin::File { declaration: module, .. }
             | ModuleOrigin::Inline { definition: module, .. } => Some(*module),
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index a0210bc5032..d7a35caf29e 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -594,6 +594,7 @@ impl DefCollector<'_> {
     ) {
         // Textual scoping
         self.define_legacy_macro(module_id, name.clone(), macro_);
+        self.def_map.modules[module_id].scope.declare_macro(macro_);
 
         // Module scoping
         // In Rust, `#[macro_export]` macros are unconditionally visible at the
@@ -632,6 +633,7 @@ impl DefCollector<'_> {
     ) {
         let vis =
             self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public);
+        self.def_map.modules[module_id].scope.declare_macro(macro_);
         self.update(module_id, &[(Some(name), PerNs::macros(macro_, vis))], vis, ImportType::Named);
     }
 
@@ -640,6 +642,7 @@ impl DefCollector<'_> {
     /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped.
     /// And unconditionally exported.
     fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) {
+        self.def_map.modules[self.def_map.root].scope.declare_macro(macro_);
         self.update(
             self.def_map.root,
             &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 121baa86f1e..e7feb042b22 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -367,8 +367,8 @@ impl Analysis {
     pub fn symbol_search(&self, query: Query) -> Cancellable<Vec<NavigationTarget>> {
         self.with_db(|db| {
             symbol_index::world_symbols(db, query)
-                .into_iter()
-                .map(|s| s.to_nav(db))
+                .into_iter() // xx: should we make this a par iter?
+                .filter_map(|s| s.try_to_nav(db))
                 .collect::<Vec<_>>()
         })
     }
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index 3121cdd4a23..7deb6cae38b 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -167,10 +167,13 @@ impl NavigationTarget {
     }
 }
 
-impl ToNav for FileSymbol {
-    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
-        NavigationTarget {
-            file_id: self.file_id,
+impl TryToNav for FileSymbol {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+        let full_range = self.loc.original_range(db)?;
+        let name_range = self.loc.original_name_range(db)?;
+
+        Some(NavigationTarget {
+            file_id: full_range.file_id,
             name: self.name.clone(),
             kind: Some(match self.kind {
                 FileSymbolKind::Function => SymbolKind::Function,
@@ -184,12 +187,12 @@ impl ToNav for FileSymbol {
                 FileSymbolKind::Macro => SymbolKind::Macro,
                 FileSymbolKind::Union => SymbolKind::Union,
             }),
-            full_range: self.range,
-            focus_range: self.name_range,
+            full_range: full_range.range,
+            focus_range: Some(name_range.range),
             container_name: self.container_name.clone(),
             description: description_from_symbol(db, self),
             docs: None,
-        }
+        })
     }
 }
 
@@ -517,8 +520,7 @@ impl TryToNav for hir::ConstParam {
 /// e.g. `struct Name`, `enum Name`, `fn Name`
 pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
     let sema = Semantics::new(db);
-    let parse = sema.parse(symbol.file_id);
-    let node = symbol.ptr.to_node(parse.syntax());
+    let node = symbol.loc.syntax(&sema)?;
 
     match_ast! {
         match node {
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs
index d11c2c35e4d..9f589c1ea1a 100644
--- a/crates/ide/src/status.rs
+++ b/crates/ide/src/status.rs
@@ -11,7 +11,6 @@ use ide_db::{
 };
 use itertools::Itertools;
 use profile::{memory_usage, Bytes};
-use rustc_hash::FxHashMap;
 use std::env;
 use stdx::format_to;
 use syntax::{ast, Parse, SyntaxNode};
@@ -149,20 +148,16 @@ impl fmt::Display for LibrarySymbolsStats {
     }
 }
 
-impl FromIterator<TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>
-    for LibrarySymbolsStats
-{
+impl FromIterator<TableEntry<SourceRootId, Arc<SymbolIndex>>> for LibrarySymbolsStats {
     fn from_iter<T>(iter: T) -> LibrarySymbolsStats
     where
-        T: IntoIterator<Item = TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>,
+        T: IntoIterator<Item = TableEntry<SourceRootId, Arc<SymbolIndex>>>,
     {
         let mut res = LibrarySymbolsStats::default();
         for entry in iter {
-            let value = entry.value.unwrap();
-            for symbols in value.values() {
-                res.total += symbols.len();
-                res.size += symbols.memory_size();
-            }
+            let symbols = entry.value.unwrap();
+            res.total += symbols.len();
+            res.size += symbols.memory_size();
         }
         res
     }
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs
index bba270421cf..6c085ffc979 100644
--- a/crates/ide_db/src/apply_change.rs
+++ b/crates/ide_db/src/apply_change.rs
@@ -137,7 +137,7 @@ impl RootDatabase {
             hir::db::InternTypeParamIdQuery
 
             // SymbolsDatabase
-            crate::symbol_index::FileSymbolsQuery
+            crate::symbol_index::ModuleSymbolsQuery
             crate::symbol_index::LibrarySymbolsQuery
             crate::symbol_index::LocalRootsQuery
             crate::symbol_index::LibraryRootsQuery
diff --git a/crates/ide_db/src/items_locator.rs b/crates/ide_db/src/items_locator.rs
index a3ea3edc977..e0dbe6caf0a 100644
--- a/crates/ide_db/src/items_locator.rs
+++ b/crates/ide_db/src/items_locator.rs
@@ -133,9 +133,8 @@ fn get_name_definition(
     import_candidate: &FileSymbol,
 ) -> Option<Definition> {
     let _p = profile::span("get_name_definition");
-    let file_id = import_candidate.file_id;
 
-    let candidate_node = import_candidate.ptr.to_node(sema.parse(file_id).syntax());
+    let candidate_node = import_candidate.loc.syntax(sema)?;
     let candidate_name_node = if candidate_node.kind() != NAME {
         candidate_node.children().find(|it| it.kind() == NAME)?
     } else {
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index 54ceafa67f6..cc2b2bbb7b8 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -30,18 +30,19 @@ use std::{
 
 use base_db::{
     salsa::{self, ParallelDatabase},
-    CrateId, FileId, SourceDatabaseExt, SourceRootId,
+    CrateId, FileRange, SourceDatabaseExt, SourceRootId, Upcast,
 };
+use either::Either;
 use fst::{self, Streamer};
-use hir::db::DefDatabase;
-use rayon::prelude::*;
-use rustc_hash::{FxHashMap, FxHashSet};
-use syntax::{
-    ast::{self, HasName},
-    match_ast, AstNode, Parse, SmolStr, SourceFile,
-    SyntaxKind::*,
-    SyntaxNode, SyntaxNodePtr, TextRange, WalkEvent,
+use hir::{
+    db::{DefDatabase, HirDatabase},
+    AdtId, AssocContainerId, AssocItemId, AssocItemLoc, DefHasSource, DefWithBodyId, HasSource,
+    HirFileId, ImplId, InFile, ItemLoc, ItemTreeNode, Lookup, MacroDef, Module, ModuleDefId,
+    ModuleId, Semantics, TraitId,
 };
+use rayon::prelude::*;
+use rustc_hash::FxHashSet;
+use syntax::{ast::HasName, AstNode, SmolStr, SyntaxNode, SyntaxNodePtr};
 
 use crate::RootDatabase;
 
@@ -92,58 +93,68 @@ impl Query {
 }
 
 #[salsa::query_group(SymbolsDatabaseStorage)]
-pub trait SymbolsDatabase: hir::db::HirDatabase + SourceDatabaseExt {
-    fn file_symbols(&self, file_id: FileId) -> Arc<SymbolIndex>;
-    fn library_symbols(&self) -> Arc<FxHashMap<SourceRootId, SymbolIndex>>;
+pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast<dyn HirDatabase> {
+    /// The symbol index for a given module. These modules should only be in source roots that
+    /// are inside local_roots.
+    fn module_symbols(&self, module_id: ModuleId) -> Arc<SymbolIndex>;
+
+    /// The symbol index for a given source root within library_roots.
+    fn library_symbols(&self, source_root_id: SourceRootId) -> Arc<SymbolIndex>;
+
     /// The set of "local" (that is, from the current workspace) roots.
     /// Files in local roots are assumed to change frequently.
     #[salsa::input]
     fn local_roots(&self) -> Arc<FxHashSet<SourceRootId>>;
+
     /// The set of roots for crates.io libraries.
     /// Files in libraries are assumed to never change.
     #[salsa::input]
     fn library_roots(&self) -> Arc<FxHashSet<SourceRootId>>;
 }
 
-fn library_symbols(db: &dyn SymbolsDatabase) -> Arc<FxHashMap<SourceRootId, SymbolIndex>> {
+fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Arc<SymbolIndex> {
     let _p = profile::span("library_symbols");
 
-    let roots = db.library_roots();
-    let res = roots
+    // todo: this could be parallelized, once I figure out how to do that...
+    let symbols = db
+        .source_root_crates(source_root_id)
         .iter()
-        .map(|&root_id| {
-            let root = db.source_root(root_id);
-            let files = root
-                .iter()
-                .map(|it| (it, SourceDatabaseExt::file_text(db, it)))
-                .collect::<Vec<_>>();
-            let symbol_index = SymbolIndex::for_files(
-                files.into_par_iter().map(|(file, text)| (file, SourceFile::parse(&text))),
-            );
-            (root_id, symbol_index)
-        })
+        .flat_map(|&krate| module_ids_for_crate(db.upcast(), krate))
+        // we specifically avoid calling SymbolsDatabase::module_symbols here, even they do the same thing,
+        // as the index for a library is not going to really ever change, and we do not want to store each
+        // module's index in salsa.
+        .map(|module_id| SymbolCollector::collect(db, module_id))
+        .flatten()
         .collect();
-    Arc::new(res)
-}
-
-fn file_symbols(db: &dyn SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
-    db.unwind_if_cancelled();
-    let parse = db.parse(file_id);
-
-    let symbols = source_file_to_file_symbols(&parse.tree(), file_id);
 
-    // FIXME: add macros here
+    Arc::new(SymbolIndex::new(symbols))
+}
 
+fn module_symbols(db: &dyn SymbolsDatabase, module_id: ModuleId) -> Arc<SymbolIndex> {
+    let _p = profile::span("module_symbols");
+    let symbols = SymbolCollector::collect(db, module_id);
     Arc::new(SymbolIndex::new(symbols))
 }
 
 /// Need to wrap Snapshot to provide `Clone` impl for `map_with`
 struct Snap<DB>(DB);
+impl<DB: ParallelDatabase> Snap<salsa::Snapshot<DB>> {
+    fn new(db: &DB) -> Self {
+        Self(db.snapshot())
+    }
+}
 impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
     fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
         Snap(self.0.snapshot())
     }
 }
+impl<DB> std::ops::Deref for Snap<DB> {
+    type Target = DB;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
 
 // Feature: Workspace Symbol
 //
@@ -174,51 +185,45 @@ impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
 pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
     let _p = profile::span("world_symbols").detail(|| query.query.clone());
 
-    let tmp1;
-    let tmp2;
-    let buf: Vec<&SymbolIndex> = if query.libs {
-        tmp1 = db.library_symbols();
-        tmp1.values().collect()
+    let indices: Vec<_> = if query.libs {
+        db.library_roots()
+            .par_iter()
+            .map_with(Snap::new(db), |snap, &root| snap.library_symbols(root))
+            .collect()
     } else {
-        let mut files = Vec::new();
+        let mut module_ids = Vec::new();
+
         for &root in db.local_roots().iter() {
-            let sr = db.source_root(root);
-            files.extend(sr.iter())
+            let crates = db.source_root_crates(root);
+            for &krate in crates.iter() {
+                module_ids.extend(module_ids_for_crate(db, krate));
+            }
         }
 
-        let snap = Snap(db.snapshot());
-        tmp2 = files
+        module_ids
             .par_iter()
-            .map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
-            .collect::<Vec<_>>();
-        tmp2.iter().map(|it| &**it).collect()
+            .map_with(Snap::new(db), |snap, &module_id| snap.module_symbols(module_id))
+            .collect()
     };
-    query.search(&buf)
+
+    query.search(&indices)
 }
 
 pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<FileSymbol> {
     let _p = profile::span("crate_symbols").detail(|| format!("{:?}", query));
-    // FIXME(#4842): This now depends on DefMap, why not build the entire symbol index from
-    // that instead?
 
-    let def_map = db.crate_def_map(krate);
-    let mut files = Vec::new();
-    let mut modules = vec![def_map.root()];
-    while let Some(module) = modules.pop() {
-        let data = &def_map[module];
-        files.extend(data.origin.file_id());
-        modules.extend(data.children.values());
-    }
-
-    let snap = Snap(db.snapshot());
-
-    let buf = files
+    let module_ids = module_ids_for_crate(db, krate);
+    let indices: Vec<_> = module_ids
         .par_iter()
-        .map_with(snap, |db, &file_id| db.0.file_symbols(file_id))
-        .collect::<Vec<_>>();
-    let buf = buf.iter().map(|it| &**it).collect::<Vec<_>>();
+        .map_with(Snap::new(db), |snap, &module_id| snap.module_symbols(module_id))
+        .collect();
 
-    query.search(&buf)
+    query.search(&indices)
+}
+
+fn module_ids_for_crate(db: &dyn DefDatabase, krate: CrateId) -> Vec<ModuleId> {
+    let def_map = db.crate_def_map(krate);
+    def_map.modules().map(|(id, _)| def_map.module_id(id)).collect()
 }
 
 pub fn index_resolve(db: &RootDatabase, name: &str) -> Vec<FileSymbol> {
@@ -297,15 +302,6 @@ impl SymbolIndex {
         self.map.as_fst().size() + self.symbols.len() * mem::size_of::<FileSymbol>()
     }
 
-    pub(crate) fn for_files(
-        files: impl ParallelIterator<Item = (FileId, Parse<ast::SourceFile>)>,
-    ) -> SymbolIndex {
-        let symbols = files
-            .flat_map(|(file_id, file)| source_file_to_file_symbols(&file.tree(), file_id))
-            .collect::<Vec<_>>();
-        SymbolIndex::new(symbols)
-    }
-
     fn range_to_map_value(start: usize, end: usize) -> u64 {
         debug_assert![start <= (std::u32::MAX as usize)];
         debug_assert![end <= (std::u32::MAX as usize)];
@@ -321,7 +317,7 @@ impl SymbolIndex {
 }
 
 impl Query {
-    pub(crate) fn search(self, indices: &[&SymbolIndex]) -> Vec<FileSymbol> {
+    pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<FileSymbol> {
         let _p = profile::span("symbol_index::Query::search");
         let mut op = fst::map::OpBuilder::new();
         for file_symbols in indices.iter() {
@@ -364,15 +360,49 @@ impl Query {
 /// possible.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct FileSymbol {
-    pub file_id: FileId,
     pub name: SmolStr,
+    pub loc: DeclarationLocation,
     pub kind: FileSymbolKind,
-    pub range: TextRange,
-    pub ptr: SyntaxNodePtr,
-    pub name_range: Option<TextRange>,
     pub container_name: Option<SmolStr>,
 }
 
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DeclarationLocation {
+    /// The file id for both the `ptr` and `name_ptr`.
+    pub hir_file_id: HirFileId,
+    /// This points to the whole syntax node of the declaration.
+    pub ptr: SyntaxNodePtr,
+    /// This points to the [`syntax::ast::Name`] identifier of the declaration.
+    pub name_ptr: SyntaxNodePtr,
+}
+
+impl DeclarationLocation {
+    pub fn syntax(&self, semantics: &Semantics<'_, RootDatabase>) -> Option<SyntaxNode> {
+        let root = semantics.parse_or_expand(self.hir_file_id)?;
+        Some(self.ptr.to_node(&root))
+    }
+
+    pub fn original_range(&self, db: &dyn HirDatabase) -> Option<FileRange> {
+        find_original_file_range(db, self.hir_file_id, &self.ptr)
+    }
+
+    pub fn original_name_range(&self, db: &dyn HirDatabase) -> Option<FileRange> {
+        find_original_file_range(db, self.hir_file_id, &self.name_ptr)
+    }
+}
+
+fn find_original_file_range(
+    db: &dyn HirDatabase,
+    file_id: HirFileId,
+    ptr: &SyntaxNodePtr,
+) -> Option<FileRange> {
+    let root = db.parse_or_expand(file_id)?;
+    let node = ptr.to_node(&root);
+    let node = InFile::new(file_id, &node);
+
+    Some(node.original_file_range(db.upcast()))
+}
+
 #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
 pub enum FileSymbolKind {
     Const,
@@ -400,79 +430,358 @@ impl FileSymbolKind {
     }
 }
 
-fn source_file_to_file_symbols(source_file: &SourceFile, file_id: FileId) -> Vec<FileSymbol> {
-    let mut symbols = Vec::new();
-    let mut stack = Vec::new();
+/// Represents an outstanding module that the symbol collector must collect symbols from.
+struct SymbolCollectorWork {
+    module_id: ModuleId,
+    parent: Option<DefWithBodyId>,
+}
+
+struct SymbolCollector<'a> {
+    db: &'a dyn SymbolsDatabase,
+    symbols: Vec<FileSymbol>,
+    work: Vec<SymbolCollectorWork>,
+    current_container_name: Option<SmolStr>,
+}
+
+/// Given a [`ModuleId`] and a [`SymbolsDatabase`], use the DefMap for the module's crate to collect all symbols that should be
+/// indexed for the given module.
+impl<'a> SymbolCollector<'a> {
+    fn collect(db: &dyn SymbolsDatabase, module_id: ModuleId) -> Vec<FileSymbol> {
+        let mut symbol_collector = SymbolCollector {
+            db,
+            symbols: Default::default(),
+            current_container_name: None,
+            // The initial work is the root module we're collecting, additional work will
+            // be populated as we traverse the module's definitions.
+            work: vec![SymbolCollectorWork { module_id, parent: None }],
+        };
+
+        while let Some(work) = symbol_collector.work.pop() {
+            symbol_collector.do_work(work);
+        }
+
+        symbol_collector.symbols
+    }
+
+    fn do_work(&mut self, work: SymbolCollectorWork) {
+        self.db.unwind_if_cancelled();
+
+        let parent_name = work.parent.and_then(|id| self.def_with_body_id_name(id));
+        self.with_container_name(parent_name, |s| s.collect_from_module(work.module_id));
+    }
 
-    for event in source_file.syntax().preorder() {
-        match event {
-            WalkEvent::Enter(node) => {
-                if let Some(mut symbol) = to_file_symbol(&node, file_id) {
-                    symbol.container_name = stack.last().cloned();
+    fn collect_from_module(&mut self, module_id: ModuleId) {
+        let def_map = module_id.def_map(self.db.upcast());
+        let scope = &def_map[module_id.local_id].scope;
 
-                    stack.push(symbol.name.clone());
-                    symbols.push(symbol);
+        for module_def_id in scope.declarations() {
+            match module_def_id {
+                ModuleDefId::ModuleId(id) => self.push_module(id),
+                ModuleDefId::FunctionId(id) => {
+                    self.push_decl_assoc(id, FileSymbolKind::Function);
+                    self.collect_from_body(id);
+                }
+                ModuleDefId::AdtId(AdtId::StructId(id)) => {
+                    self.push_decl(id, FileSymbolKind::Struct)
+                }
+                ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id, FileSymbolKind::Enum),
+                ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id, FileSymbolKind::Union),
+                ModuleDefId::ConstId(id) => {
+                    self.push_decl_assoc(id, FileSymbolKind::Const);
+                    self.collect_from_body(id);
+                }
+                ModuleDefId::StaticId(id) => {
+                    self.push_decl(id, FileSymbolKind::Static);
+                    self.collect_from_body(id);
+                }
+                ModuleDefId::TraitId(id) => {
+                    self.push_decl(id, FileSymbolKind::Trait);
+                    self.collect_from_trait(id);
                 }
+                ModuleDefId::TypeAliasId(id) => {
+                    self.push_decl_assoc(id, FileSymbolKind::TypeAlias);
+                }
+                // Don't index these.
+                ModuleDefId::BuiltinType(_) => {}
+                ModuleDefId::EnumVariantId(_) => {}
             }
+        }
+
+        for impl_id in scope.impls() {
+            self.collect_from_impl(impl_id);
+        }
 
-            WalkEvent::Leave(node) => {
-                if to_symbol(&node).is_some() {
-                    stack.pop();
+        for const_id in scope.unnamed_consts() {
+            self.collect_from_body(const_id);
+        }
+
+        for macro_def_id in scope.macro_declarations() {
+            self.push_decl_macro(macro_def_id.into());
+        }
+    }
+
+    fn collect_from_body(&mut self, body_id: impl Into<DefWithBodyId>) {
+        let body_id = body_id.into();
+        let body = self.db.body(body_id);
+
+        // Descend into the blocks and enqueue collection of all modules within.
+        for (_, def_map) in body.blocks(self.db.upcast()) {
+            for (id, _) in def_map.modules() {
+                self.work.push(SymbolCollectorWork {
+                    module_id: def_map.module_id(id),
+                    parent: Some(body_id),
+                });
+            }
+        }
+    }
+
+    fn collect_from_impl(&mut self, impl_id: ImplId) {
+        let impl_data = self.db.impl_data(impl_id);
+        for &assoc_item_id in &impl_data.items {
+            self.push_assoc_item(assoc_item_id)
+        }
+    }
+
+    fn collect_from_trait(&mut self, trait_id: TraitId) {
+        let trait_data = self.db.trait_data(trait_id);
+        self.with_container_name(trait_data.name.as_text(), |s| {
+            for &(_, assoc_item_id) in &trait_data.items {
+                s.push_assoc_item(assoc_item_id);
+            }
+        });
+    }
+
+    fn with_container_name(&mut self, container_name: Option<SmolStr>, f: impl FnOnce(&mut Self)) {
+        if let Some(container_name) = container_name {
+            let prev = self.current_container_name.replace(container_name);
+            f(self);
+            self.current_container_name = prev;
+        } else {
+            f(self);
+        }
+    }
+
+    fn current_container_name(&self) -> Option<SmolStr> {
+        self.current_container_name.clone()
+    }
+
+    fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option<SmolStr> {
+        match body_id {
+            DefWithBodyId::FunctionId(id) => Some(
+                id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(),
+            ),
+            DefWithBodyId::StaticId(id) => Some(
+                id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(),
+            ),
+            DefWithBodyId::ConstId(id) => Some(
+                id.lookup(self.db.upcast()).source(self.db.upcast()).value.name()?.text().into(),
+            ),
+        }
+    }
+
+    fn push_assoc_item(&mut self, assoc_item_id: AssocItemId) {
+        match assoc_item_id {
+            AssocItemId::FunctionId(id) => self.push_decl_assoc(id, FileSymbolKind::Function),
+            AssocItemId::ConstId(id) => self.push_decl_assoc(id, FileSymbolKind::Const),
+            AssocItemId::TypeAliasId(id) => self.push_decl_assoc(id, FileSymbolKind::TypeAlias),
+        }
+    }
+
+    fn push_decl_assoc<L, T>(&mut self, id: L, kind: FileSymbolKind)
+    where
+        L: Lookup<Data = AssocItemLoc<T>>,
+        T: ItemTreeNode,
+        <T as ItemTreeNode>::Source: HasName,
+    {
+        fn container_name(db: &dyn HirDatabase, container: AssocContainerId) -> Option<SmolStr> {
+            match container {
+                AssocContainerId::ModuleId(module_id) => {
+                    let module = Module::from(module_id);
+                    module.name(db).and_then(|name| name.as_text())
                 }
+                AssocContainerId::TraitId(trait_id) => {
+                    let trait_data = db.trait_data(trait_id);
+                    trait_data.name.as_text()
+                }
+                AssocContainerId::ImplId(_) => None,
             }
         }
+
+        self.push_file_symbol(|s| {
+            let loc = id.lookup(s.db.upcast());
+            let source = loc.source(s.db.upcast());
+            let name_node = source.value.name()?;
+            let container_name =
+                container_name(s.db.upcast(), loc.container).or_else(|| s.current_container_name());
+
+            Some(FileSymbol {
+                name: name_node.text().into(),
+                kind,
+                container_name,
+                loc: DeclarationLocation {
+                    hir_file_id: source.file_id,
+                    ptr: SyntaxNodePtr::new(source.value.syntax()),
+                    name_ptr: SyntaxNodePtr::new(name_node.syntax()),
+                },
+            })
+        })
     }
 
-    symbols
-}
+    fn push_decl<L, T>(&mut self, id: L, kind: FileSymbolKind)
+    where
+        L: Lookup<Data = ItemLoc<T>>,
+        T: ItemTreeNode,
+        <T as ItemTreeNode>::Source: HasName,
+    {
+        self.push_file_symbol(|s| {
+            let loc = id.lookup(s.db.upcast());
+            let source = loc.source(s.db.upcast());
+            let name_node = source.value.name()?;
+
+            Some(FileSymbol {
+                name: name_node.text().into(),
+                kind,
+                container_name: s.current_container_name(),
+                loc: DeclarationLocation {
+                    hir_file_id: source.file_id,
+                    ptr: SyntaxNodePtr::new(source.value.syntax()),
+                    name_ptr: SyntaxNodePtr::new(name_node.syntax()),
+                },
+            })
+        })
+    }
+
+    fn push_module(&mut self, module_id: ModuleId) {
+        self.push_file_symbol(|s| {
+            let def_map = module_id.def_map(s.db.upcast());
+            let module_data = &def_map[module_id.local_id];
+            let declaration = module_data.origin.declaration()?;
+            let module = declaration.to_node(s.db.upcast());
+            let name_node = module.name()?;
+
+            Some(FileSymbol {
+                name: name_node.text().into(),
+                kind: FileSymbolKind::Module,
+                container_name: s.current_container_name(),
+                loc: DeclarationLocation {
+                    hir_file_id: declaration.file_id,
+                    ptr: SyntaxNodePtr::new(module.syntax()),
+                    name_ptr: SyntaxNodePtr::new(name_node.syntax()),
+                },
+            })
+        })
+    }
 
-fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
-    fn decl<N: HasName>(node: N) -> Option<(SmolStr, SyntaxNodePtr, TextRange)> {
-        let name = node.name()?;
-        let name_range = name.syntax().text_range();
-        let name = name.text().into();
-        let ptr = SyntaxNodePtr::new(node.syntax());
+    fn push_decl_macro(&mut self, macro_def: MacroDef) {
+        self.push_file_symbol(|s| {
+            let name = macro_def.name(s.db.upcast())?.as_text()?;
+            let source = macro_def.source(s.db.upcast())?;
 
-        Some((name, ptr, name_range))
+            let (ptr, name_ptr) = match source.value {
+                Either::Left(m) => {
+                    (SyntaxNodePtr::new(m.syntax()), SyntaxNodePtr::new(m.name()?.syntax()))
+                }
+                Either::Right(f) => {
+                    (SyntaxNodePtr::new(f.syntax()), SyntaxNodePtr::new(f.name()?.syntax()))
+                }
+            };
+
+            Some(FileSymbol {
+                name,
+                kind: FileSymbolKind::Macro,
+                container_name: s.current_container_name(),
+                loc: DeclarationLocation { hir_file_id: source.file_id, name_ptr, ptr },
+            })
+        })
     }
-    match_ast! {
-        match node {
-            ast::Fn(it) => decl(it),
-            ast::Struct(it) => decl(it),
-            ast::Enum(it) => decl(it),
-            ast::Trait(it) => decl(it),
-            ast::Module(it) => decl(it),
-            ast::TypeAlias(it) => decl(it),
-            ast::Const(it) => decl(it),
-            ast::Static(it) => decl(it),
-            ast::Macro(it) => decl(it),
-            ast::Union(it) => decl(it),
-            _ => None,
+
+    fn push_file_symbol(&mut self, f: impl FnOnce(&Self) -> Option<FileSymbol>) {
+        if let Some(file_symbol) = f(self) {
+            self.symbols.push(file_symbol);
         }
     }
 }
 
-fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
-    to_symbol(node).map(move |(name, ptr, name_range)| FileSymbol {
-        name,
-        kind: match node.kind() {
-            FN => FileSymbolKind::Function,
-            STRUCT => FileSymbolKind::Struct,
-            ENUM => FileSymbolKind::Enum,
-            TRAIT => FileSymbolKind::Trait,
-            MODULE => FileSymbolKind::Module,
-            TYPE_ALIAS => FileSymbolKind::TypeAlias,
-            CONST => FileSymbolKind::Const,
-            STATIC => FileSymbolKind::Static,
-            MACRO_RULES => FileSymbolKind::Macro,
-            MACRO_DEF => FileSymbolKind::Macro,
-            UNION => FileSymbolKind::Union,
-            kind => unreachable!("{:?}", kind),
-        },
-        range: node.text_range(),
-        ptr,
-        file_id,
-        name_range: Some(name_range),
-        container_name: None,
-    })
+#[cfg(test)]
+mod tests {
+
+    use base_db::fixture::WithFixture;
+    use expect_test::expect_file;
+
+    use super::*;
+
+    #[test]
+    fn test_symbol_index_collection() {
+        let (db, _) = RootDatabase::with_many_files(
+            r#"
+//- /main.rs
+
+macro_rules! macro_rules_macro {
+    () => {}
+};
+
+macro_rules! define_struct {
+    () => {
+        struct StructFromMacro;
+    }
+};
+
+define_struct!();
+
+macro Macro { }
+
+struct Struct;
+enum Enum {
+    A, B
+}
+union Union {}
+
+impl Struct {
+    fn impl_fn() {}
+}
+
+trait Trait {
+    fn trait_fn(&self);
+}
+
+fn main() {
+    struct StructInFn;
+}
+
+const CONST: u32 = 1;
+static STATIC: &'static str = "2";
+type Alias = Struct;
+
+mod a_mod {
+    struct StructInModA;
+}
+
+const _: () = {
+    struct StructInUnnamedConst;
+
+    ()
+};
+
+const CONST_WITH_INNER: () = {
+    struct StructInNamedConst;
+
+    ()
+};
+
+mod b_mod;
+
+//- /b_mod.rs
+struct StructInModB;
+        "#,
+        );
+
+        let symbols: Vec<_> = module_ids_for_crate(db.upcast(), db.test_crate())
+            .into_iter()
+            .map(|module_id| {
+                (module_id, SymbolCollector::collect(&db as &dyn SymbolsDatabase, module_id))
+            })
+            .collect();
+
+        expect_file!["./test_data/test_symbol_index_collection.txt"].assert_debug_eq(&symbols);
+    }
 }
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
new file mode 100644
index 00000000000..fe6eebc4f01
--- /dev/null
+++ b/crates/ide_db/src/test_data/test_symbol_index_collection.txt
@@ -0,0 +1,527 @@
+[
+    (
+        ModuleId {
+            krate: CrateId(
+                0,
+            ),
+            block: None,
+            local_id: Idx::<ModuleData>(0),
+        },
+        [
+            FileSymbol {
+                name: "StructFromMacro",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        MacroFile(
+                            MacroFile {
+                                macro_call_id: MacroCallId(
+                                    0,
+                                ),
+                            },
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 0..22,
+                        kind: STRUCT,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 6..21,
+                        kind: NAME,
+                    },
+                },
+                kind: Struct,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "Struct",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 170..184,
+                        kind: STRUCT,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 177..183,
+                        kind: NAME,
+                    },
+                },
+                kind: Struct,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "Enum",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 185..207,
+                        kind: ENUM,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 190..194,
+                        kind: NAME,
+                    },
+                },
+                kind: Enum,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "Union",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 208..222,
+                        kind: UNION,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 214..219,
+                        kind: NAME,
+                    },
+                },
+                kind: Union,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "Trait",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 261..300,
+                        kind: TRAIT,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 267..272,
+                        kind: NAME,
+                    },
+                },
+                kind: Trait,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "trait_fn",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 279..298,
+                        kind: FN,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 282..290,
+                        kind: NAME,
+                    },
+                },
+                kind: Function,
+                container_name: Some(
+                    "Trait",
+                ),
+            },
+            FileSymbol {
+                name: "main",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 302..338,
+                        kind: FN,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 305..309,
+                        kind: NAME,
+                    },
+                },
+                kind: Function,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "CONST",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 340..361,
+                        kind: CONST,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 346..351,
+                        kind: NAME,
+                    },
+                },
+                kind: Const,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "STATIC",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 362..396,
+                        kind: STATIC,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 369..375,
+                        kind: NAME,
+                    },
+                },
+                kind: Static,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "Alias",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 397..417,
+                        kind: TYPE_ALIAS,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 402..407,
+                        kind: NAME,
+                    },
+                },
+                kind: TypeAlias,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "a_mod",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 419..457,
+                        kind: MODULE,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 423..428,
+                        kind: NAME,
+                    },
+                },
+                kind: Module,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "CONST_WITH_INNER",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 520..592,
+                        kind: CONST,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 526..542,
+                        kind: NAME,
+                    },
+                },
+                kind: Const,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "b_mod",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 594..604,
+                        kind: MODULE,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 598..603,
+                        kind: NAME,
+                    },
+                },
+                kind: Module,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "impl_fn",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 242..257,
+                        kind: FN,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 245..252,
+                        kind: NAME,
+                    },
+                },
+                kind: Function,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "macro_rules_macro",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 1..48,
+                        kind: MACRO_RULES,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 14..31,
+                        kind: NAME,
+                    },
+                },
+                kind: Macro,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "define_struct",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 51..131,
+                        kind: MACRO_RULES,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 64..77,
+                        kind: NAME,
+                    },
+                },
+                kind: Macro,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "Macro",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 153..168,
+                        kind: MACRO_DEF,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 159..164,
+                        kind: NAME,
+                    },
+                },
+                kind: Macro,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "StructInUnnamedConst",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 479..507,
+                        kind: STRUCT,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 486..506,
+                        kind: NAME,
+                    },
+                },
+                kind: Struct,
+                container_name: None,
+            },
+            FileSymbol {
+                name: "StructInNamedConst",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 555..581,
+                        kind: STRUCT,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 562..580,
+                        kind: NAME,
+                    },
+                },
+                kind: Struct,
+                container_name: Some(
+                    "CONST_WITH_INNER",
+                ),
+            },
+            FileSymbol {
+                name: "StructInFn",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 318..336,
+                        kind: STRUCT,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 325..335,
+                        kind: NAME,
+                    },
+                },
+                kind: Struct,
+                container_name: Some(
+                    "main",
+                ),
+            },
+        ],
+    ),
+    (
+        ModuleId {
+            krate: CrateId(
+                0,
+            ),
+            block: None,
+            local_id: Idx::<ModuleData>(1),
+        },
+        [
+            FileSymbol {
+                name: "StructInModA",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                0,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 435..455,
+                        kind: STRUCT,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 442..454,
+                        kind: NAME,
+                    },
+                },
+                kind: Struct,
+                container_name: None,
+            },
+        ],
+    ),
+    (
+        ModuleId {
+            krate: CrateId(
+                0,
+            ),
+            block: None,
+            local_id: Idx::<ModuleData>(2),
+        },
+        [
+            FileSymbol {
+                name: "StructInModB",
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        FileId(
+                            FileId(
+                                1,
+                            ),
+                        ),
+                    ),
+                    ptr: SyntaxNodePtr {
+                        range: 0..20,
+                        kind: STRUCT,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        range: 7..19,
+                        kind: NAME,
+                    },
+                },
+                kind: Struct,
+                container_name: None,
+            },
+        ],
+    ),
+]