Repository: rust-analyzer/rust-analyzer
Pull request #11276 (2022-01-13 18:14:10)

internal: Slightly cleanup HasFormatSpecifier::lex_format_specifier
bors r+


Patch:
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 4b4eb38336..95696936b8 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -28,7 +28,6 @@ mod has_source;
 
 pub mod diagnostics;
 pub mod db;
-pub mod symbols;
 
 mod display;
 
@@ -41,18 +40,14 @@ use hir_def::{
     adt::{ReprKind, VariantData},
     body::{BodyDiagnostic, SyntheticSyntax},
     expr::{BindingAnnotation, LabelId, Pat, PatId},
-    item_tree::ItemTreeNode,
     lang_item::LangItemTarget,
     nameres::{self, diagnostics::DefDiagnostic},
     per_ns::PerNs,
     resolver::{HasResolver, Resolver},
-    src::HasSource as _,
-    AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
-    FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, 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::{eval_const, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt},
@@ -111,14 +106,28 @@ pub use {
         builtin_attr::AttributeTemplate,
         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,
+        AssocItemId,
+        AssocItemLoc,
+        DefWithBodyId,
+        ImplId,
+        ItemContainerId,
+        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,
 };
@@ -182,11 +191,6 @@ impl Crate {
         Module { id: def_map.module_id(def_map.root()) }
     }
 
-    pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
-        let def_map = db.crate_def_map(self.id);
-        def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect()
-    }
-
     pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
         db.crate_graph()[self.id].root_file_id
     }
diff --git a/crates/hir/src/symbols.rs b/crates/hir/src/symbols.rs
deleted file mode 100644
index f1669d5288..0000000000
--- a/crates/hir/src/symbols.rs
+++ /dev/null
@@ -1,359 +0,0 @@
-//! File symbol extraction.
-
-use base_db::FileRange;
-use either::Either;
-use hir_def::{
-    item_tree::ItemTreeNode, src::HasSource, AdtId, AssocItemId, AssocItemLoc, DefWithBodyId,
-    ImplId, ItemContainerId, ItemLoc, Lookup, ModuleDefId, ModuleId, TraitId,
-};
-use hir_expand::{HirFileId, InFile};
-use hir_ty::db::HirDatabase;
-use syntax::{ast::HasName, AstNode, SmolStr, SyntaxNode, SyntaxNodePtr};
-
-use crate::{HasSource as _, MacroDef, Module, Semantics};
-
-/// The actual data that is stored in the index. It should be as compact as
-/// possible.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct FileSymbol {
-    pub name: SmolStr,
-    pub loc: DeclarationLocation,
-    pub kind: FileSymbolKind,
-    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<DB: HirDatabase>(&self, sema: &Semantics<DB>) -> Option<SyntaxNode> {
-        let root = sema.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,
-    Enum,
-    Function,
-    Macro,
-    Module,
-    Static,
-    Struct,
-    Trait,
-    TypeAlias,
-    Union,
-}
-
-impl FileSymbolKind {
-    pub fn is_type(self: FileSymbolKind) -> bool {
-        matches!(
-            self,
-            FileSymbolKind::Struct
-                | FileSymbolKind::Enum
-                | FileSymbolKind::Trait
-                | FileSymbolKind::TypeAlias
-                | FileSymbolKind::Union
-        )
-    }
-}
-
-/// Represents an outstanding module that the symbol collector must collect symbols from.
-struct SymbolCollectorWork {
-    module_id: ModuleId,
-    parent: Option<DefWithBodyId>,
-}
-
-pub struct SymbolCollector<'a> {
-    db: &'a dyn HirDatabase,
-    symbols: Vec<FileSymbol>,
-    work: Vec<SymbolCollectorWork>,
-    current_container_name: Option<SmolStr>,
-}
-
-/// Given a [`ModuleId`] and a [`HirDatabase`], use the DefMap for the module's crate to collect
-/// all symbols that should be indexed for the given module.
-impl<'a> SymbolCollector<'a> {
-    pub fn collect(db: &dyn HirDatabase, module: Module) -> 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: module.into(), 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));
-    }
-
-    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;
-
-        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_assoc(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);
-        }
-
-        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: ItemContainerId) -> Option<SmolStr> {
-            match container {
-                ItemContainerId::ModuleId(module_id) => {
-                    let module = Module::from(module_id);
-                    module.name(db).and_then(|name| name.as_text())
-                }
-                ItemContainerId::TraitId(trait_id) => {
-                    let trait_data = db.trait_data(trait_id);
-                    trait_data.name.as_text()
-                }
-                ItemContainerId::ImplId(_) | ItemContainerId::ExternBlockId(_) => 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, 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()),
-                },
-            })
-        })
-    }
-
-    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 push_decl_macro(&mut self, macro_def: MacroDef) {
-        self.push_file_symbol(|s| {
-            let name = macro_def.name(s.db)?.as_text()?;
-            let source = macro_def.source(s.db)?;
-
-            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 },
-            })
-        })
-    }
-
-    fn push_file_symbol(&mut self, f: impl FnOnce(&Self) -> Option<FileSymbol>) {
-        if let Some(file_symbol) = f(self) {
-            self.symbols.push(file_symbol);
-        }
-    }
-}
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index db7b80f71b..b8482d0222 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -66,7 +66,8 @@ use ide_db::{
         salsa::{self, ParallelDatabase},
         Env, FileLoader, FileSet, SourceDatabase, VfsPath,
     },
-    symbol_index, LineIndexDatabase,
+    symbol_index::{self, FileSymbol},
+    LineIndexDatabase,
 };
 use syntax::SourceFile;
 
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index 1c3ff06247..52e099513a 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -4,8 +4,8 @@ use std::fmt;
 
 use either::Either;
 use hir::{
-    symbols::FileSymbol, AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirDisplay,
-    InFile, ModuleSource, Semantics,
+    AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirDisplay, InFile, ModuleSource,
+    Semantics,
 };
 use ide_db::{
     base_db::{FileId, FileRange},
@@ -17,6 +17,8 @@ use syntax::{
     match_ast, AstNode, SmolStr, TextRange,
 };
 
+use crate::FileSymbol;
+
 /// `NavigationTarget` represents an element in the editor's UI which you can
 /// click on to navigate to a particular piece of code.
 ///
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 2603ad2003..f67d7d56d8 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -56,7 +56,6 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
             _ => (),
         },
         (_, Some(_)) => (),
-        (_, None) if attribute.expr().is_some() => (),
         (_, None) => complete_new_attribute(acc, ctx, attribute),
     }
     Some(())
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index a55bab67e1..bb4ce0a24d 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -83,15 +83,9 @@ fn remove_duplicated(
         let whole_param = param.syntax().text().to_string();
         file_params.remove(&whole_param);
 
-        match param.pat() {
-            // remove suggestions for patterns that already exist
-            // if the type is missing we are checking the current param to be completed
-            // in which case this would find itself removing the suggestions due to itself
-            Some(pattern) if param.ty().is_some() => {
-                let binding = pattern.syntax().text().to_string();
-                file_params.retain(|_, v| v != &binding);
-            }
-            _ => (),
+        if let Some(pattern) = param.pat() {
+            let binding = pattern.syntax().text().to_string();
+            file_params.retain(|_, v| v != &binding);
         }
     })
 }
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index 0dfb8abb8b..a212a98461 100644
--- a/crates/ide_completion/src/completions/postfix.rs
+++ b/crates/ide_completion/src/completions/postfix.rs
@@ -225,10 +225,6 @@ fn build_postfix_snippet_builder<'ctx>(
 ) -> Option<impl Fn(&str, &str, &str) -> Builder + 'ctx> {
     let receiver_syntax = receiver.syntax();
     let receiver_range = ctx.sema.original_range_opt(receiver_syntax)?.range;
-    if ctx.source_range().end() < receiver_range.start() {
-        // This shouldn't happen, yet it does. I assume this might be due to an incorrect token mapping.
-        return None;
-    }
     let delete_range = TextRange::new(receiver_range.start(), ctx.source_range().end());
 
     // Wrapping impl Fn in an option ruins lifetime inference for the parameters in a way that
diff --git a/crates/ide_db/src/items_locator.rs b/crates/ide_db/src/items_locator.rs
index db38a48783..ca8266b6d2 100644
--- a/crates/ide_db/src/items_locator.rs
+++ b/crates/ide_db/src/items_locator.rs
@@ -5,7 +5,6 @@
 use either::Either;
 use hir::{
     import_map::{self, ImportKind},
-    symbols::FileSymbol,
     AsAssocItem, Crate, ItemInNs, Semantics,
 };
 use limit::Limit;
@@ -14,7 +13,8 @@ use syntax::{ast, AstNode, SyntaxKind::NAME};
 use crate::{
     defs::{Definition, NameClass},
     helpers::import_assets::NameToImport,
-    symbol_index, RootDatabase,
+    symbol_index::{self, FileSymbol},
+    RootDatabase,
 };
 
 /// A value to use, when uncertain which limit to pick.
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs
index 602eaf0de5..bcbb09e31b 100644
--- a/crates/ide_db/src/lib.rs
+++ b/crates/ide_db/src/lib.rs
@@ -26,10 +26,7 @@ use base_db::{
     salsa::{self, Durability},
     AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast,
 };
-use hir::{
-    db::{AstDatabase, DefDatabase, HirDatabase},
-    symbols::FileSymbolKind,
-};
+use hir::db::{AstDatabase, DefDatabase, HirDatabase};
 use rustc_hash::FxHashSet;
 
 use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
@@ -186,23 +183,6 @@ impl From<hir::MacroKind> for SymbolKind {
     }
 }
 
-impl From<FileSymbolKind> for SymbolKind {
-    fn from(it: FileSymbolKind) -> Self {
-        match it {
-            FileSymbolKind::Const => SymbolKind::Const,
-            FileSymbolKind::Enum => SymbolKind::Enum,
-            FileSymbolKind::Function => SymbolKind::Function,
-            FileSymbolKind::Macro => SymbolKind::Macro,
-            FileSymbolKind::Module => SymbolKind::Module,
-            FileSymbolKind::Static => SymbolKind::Static,
-            FileSymbolKind::Struct => SymbolKind::Struct,
-            FileSymbolKind::Trait => SymbolKind::Trait,
-            FileSymbolKind::TypeAlias => SymbolKind::TypeAlias,
-            FileSymbolKind::Union => SymbolKind::Union,
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     mod sourcegen_lints;
diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs
index 9697ba24b8..62f4a81910 100644
--- a/crates/ide_db/src/symbol_index.rs
+++ b/crates/ide_db/src/symbol_index.rs
@@ -30,18 +30,21 @@ use std::{
 
 use base_db::{
     salsa::{self, ParallelDatabase},
-    SourceDatabaseExt, SourceRootId, Upcast,
+    CrateId, FileRange, SourceDatabaseExt, SourceRootId, Upcast,
 };
+use either::Either;
 use fst::{self, Streamer};
 use hir::{
-    db::HirDatabase,
-    symbols::{FileSymbol, SymbolCollector},
-    Crate, Module,
+    db::{DefDatabase, HirDatabase},
+    AdtId, AssocItemId, AssocItemLoc, DefHasSource, DefWithBodyId, HasSource, HirFileId, ImplId,
+    InFile, ItemContainerId, 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;
+use crate::{RootDatabase, SymbolKind};
 
 #[derive(Debug)]
 pub struct Query {
@@ -93,7 +96,7 @@ impl Query {
 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: Module) -> Arc<SymbolIndex>;
+    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>;
@@ -116,20 +119,20 @@ fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Ar
     let symbols = db
         .source_root_crates(source_root_id)
         .iter()
-        .flat_map(|&krate| Crate::from(krate).modules(db.upcast()))
+        .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| SymbolCollector::collect(db.upcast(), module))
+        .map(|module_id| SymbolCollector::collect(db, module_id))
         .flatten()
         .collect();
 
     Arc::new(SymbolIndex::new(symbols))
 }
 
-fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc<SymbolIndex> {
+fn module_symbols(db: &dyn SymbolsDatabase, module_id: ModuleId) -> Arc<SymbolIndex> {
     let _p = profile::span("module_symbols");
-    let symbols = SymbolCollector::collect(db.upcast(), module);
+    let symbols = SymbolCollector::collect(db, module_id);
     Arc::new(SymbolIndex::new(symbols))
 }
 
@@ -188,36 +191,41 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> {
             .map_with(Snap::new(db), |snap, &root| snap.library_symbols(root))
             .collect()
     } else {
-        let mut modules = Vec::new();
+        let mut module_ids = Vec::new();
 
         for &root in db.local_roots().iter() {
             let crates = db.source_root_crates(root);
             for &krate in crates.iter() {
-                modules.extend(Crate::from(krate).modules(db));
+                module_ids.extend(module_ids_for_crate(db, krate));
             }
         }
 
-        modules
+        module_ids
             .par_iter()
-            .map_with(Snap::new(db), |snap, &module| snap.module_symbols(module))
+            .map_with(Snap::new(db), |snap, &module_id| snap.module_symbols(module_id))
             .collect()
     };
 
     query.search(&indices)
 }
 
-pub fn crate_symbols(db: &RootDatabase, krate: Crate, query: Query) -> Vec<FileSymbol> {
+pub fn crate_symbols(db: &RootDatabase, krate: CrateId, query: Query) -> Vec<FileSymbol> {
     let _p = profile::span("crate_symbols").detail(|| format!("{:?}", query));
 
-    let modules = krate.modules(db);
-    let indices: Vec<_> = modules
+    let module_ids = module_ids_for_crate(db, krate);
+    let indices: Vec<_> = module_ids
         .par_iter()
-        .map_with(Snap::new(db), |snap, &module| snap.module_symbols(module))
+        .map_with(Snap::new(db), |snap, &module_id| snap.module_symbols(module_id))
         .collect();
 
     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> {
     let mut query = Query::new(name.to_string());
     query.exact();
@@ -348,12 +356,374 @@ impl Query {
     }
 }
 
+/// The actual data that is stored in the index. It should be as compact as
+/// possible.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FileSymbol {
+    pub name: SmolStr,
+    pub loc: DeclarationLocation,
+    pub kind: FileSymbolKind,
+    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,
+    Enum,
+    Function,
+    Macro,
+    Module,
+    Static,
+    Struct,
+    Trait,
+    TypeAlias,
+    Union,
+}
+
+impl FileSymbolKind {
+    fn is_type(self: FileSymbolKind) -> bool {
+        matches!(
+            self,
+            FileSymbolKind::Struct
+                | FileSymbolKind::Enum
+                | FileSymbolKind::Trait
+                | FileSymbolKind::TypeAlias
+                | FileSymbolKind::Union
+        )
+    }
+}
+
+impl From<FileSymbolKind> for SymbolKind {
+    fn from(it: FileSymbolKind) -> Self {
+        match it {
+            FileSymbolKind::Const => SymbolKind::Const,
+            FileSymbolKind::Enum => SymbolKind::Enum,
+            FileSymbolKind::Function => SymbolKind::Function,
+            FileSymbolKind::Macro => SymbolKind::Macro,
+            FileSymbolKind::Module => SymbolKind::Module,
+            FileSymbolKind::Static => SymbolKind::Static,
+            FileSymbolKind::Struct => SymbolKind::Struct,
+            FileSymbolKind::Trait => SymbolKind::Trait,
+            FileSymbolKind::TypeAlias => SymbolKind::TypeAlias,
+            FileSymbolKind::Union => SymbolKind::Union,
+        }
+    }
+}
+
+/// 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));
+    }
+
+    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;
+
+        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_assoc(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);
+        }
+
+        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: ItemContainerId) -> Option<SmolStr> {
+            match container {
+                ItemContainerId::ModuleId(module_id) => {
+                    let module = Module::from(module_id);
+                    module.name(db).and_then(|name| name.as_text())
+                }
+                ItemContainerId::TraitId(trait_id) => {
+                    let trait_data = db.trait_data(trait_id);
+                    trait_data.name.as_text()
+                }
+                ItemContainerId::ImplId(_) | ItemContainerId::ExternBlockId(_) => 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()),
+                },
+            })
+        })
+    }
+
+    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 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())?;
+
+            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 },
+            })
+        })
+    }
+
+    fn push_file_symbol(&mut self, f: impl FnOnce(&Self) -> Option<FileSymbol>) {
+        if let Some(file_symbol) = f(self) {
+            self.symbols.push(file_symbol);
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
 
     use base_db::fixture::WithFixture;
     use expect_test::expect_file;
-    use hir::symbols::SymbolCollector;
 
     use super::*;
 
@@ -422,10 +792,11 @@ struct StructInModB;
         "#,
         );
 
-        let symbols: Vec<_> = Crate::from(db.test_crate())
-            .modules(&db)
+        let symbols: Vec<_> = module_ids_for_crate(db.upcast(), db.test_crate())
             .into_iter()
-            .map(|module_id| (module_id, SymbolCollector::collect(&db, module_id)))
+            .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/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs
index cc7e5150b3..3b0a1c5ddc 100644
--- a/crates/syntax/src/ast/token_ext.rs
+++ b/crates/syntax/src/ast/token_ext.rs
@@ -288,124 +288,142 @@ pub trait HasFormatSpecifier: AstToken {
             Some(char_ranges) => char_ranges,
             None => return,
         };
-        let mut chars = char_ranges.iter().peekable();
+        let mut chars = char_ranges
+            .iter()
+            .filter_map(|(range, res)| Some((*range, *res.as_ref().ok()?)))
+            .peekable();
 
         while let Some((range, first_char)) = chars.next() {
-            match first_char {
-                Ok('{') => {
-                    // Format specifier, see syntax at https://doc.rust-lang.org/std/fmt/index.html#syntax
-                    if let Some((_, Ok('{'))) = chars.peek() {
-                        // Escaped format specifier, `{{`
-                        chars.next();
-                        continue;
-                    }
+            if let '{' = first_char {
+                // Format specifier, see syntax at https://doc.rust-lang.org/std/fmt/index.html#syntax
+                if let Some((_, '{')) = chars.peek() {
+                    // Escaped format specifier, `{{`
+                    chars.next();
+                    continue;
+                }
 
-                    callback(*range, FormatSpecifier::Open);
+                callback(range, FormatSpecifier::Open);
 
-                    // check for integer/identifier
-                    match chars
-                        .peek()
-                        .and_then(|next| next.1.as_ref().ok())
-                        .copied()
-                        .unwrap_or_default()
-                    {
-                        '0'..='9' => {
-                            // integer
-                            read_integer(&mut chars, &mut callback);
+                // check for integer/identifier
+                let (_, int_char) = chars.peek().copied().unwrap_or_default();
+                match int_char {
+                    // integer
+                    '0'..='9' => read_integer(&mut chars, &mut callback),
+                    // identifier
+                    c if c == '_' || c.is_alphabetic() => {
+                        read_identifier(&mut chars, &mut callback)
+                    }
+                    _ => {}
+                }
+
+                if let Some((_, ':')) = chars.peek() {
+                    skip_char_and_emit(&mut chars, FormatSpecifier::Colon, &mut callback);
+
+                    // check for fill/align
+                    let mut cloned = chars.clone().take(2);
+                    let (_, first) = cloned.next().unwrap_or_default();
+                    let (_, second) = cloned.next().unwrap_or_default();
+                    match second {
+                        '<' | '^' | '>' => {
+                            // alignment specifier, first char specifies fillment
+                            skip_char_and_emit(&mut chars, FormatSpecifier::Fill, &mut callback);
+                            skip_char_and_emit(&mut chars, FormatSpecifier::Align, &mut callback);
                         }
-                        c if c == '_' || c.is_alphabetic() => {
-                            // identifier
-                            read_identifier(&mut chars, &mut callback);
+                        _ => {
+                            if let '<' | '^' | '>' = first {
+                                skip_char_and_emit(
+                                    &mut chars,
+                                    FormatSpecifier::Align,
+                                    &mut callback,
+                                );
+                            }
+                        }
+                    }
+
+                    // check for sign
+                    match chars.peek().copied().unwrap_or_default().1 {
+                        '+' | '-' => {
+                            skip_char_and_emit(&mut chars, FormatSpecifier::Sign, &mut callback);
                         }
                         _ => {}
                     }
 
-                    if let Some((_, Ok(':'))) = chars.peek() {
-                        skip_char_and_emit(&mut chars, FormatSpecifier::Colon, &mut callback);
-
-                        // check for fill/align
-                        let mut cloned = chars.clone().take(2);
-                        let first = cloned
-                            .next()
-                            .and_then(|next| next.1.as_ref().ok())
-                            .copied()
-                            .unwrap_or_default();
-                        let second = cloned
-                            .next()
-                            .and_then(|next| next.1.as_ref().ok())
-                            .copied()
-                            .unwrap_or_default();
-                        match second {
-                            '<' | '^' | '>' => {
-                                // alignment specifier, first char specifies fillment
+                    // check for `#`
+                    if let Some((_, '#')) = chars.peek() {
+                        skip_char_and_emit(&mut chars, FormatSpecifier::NumberSign, &mut callback);
+                    }
+
+                    // check for `0`
+                    let mut cloned = chars.clone().take(2);
+                    let first = cloned.next().map(|next| next.1);
+                    let second = cloned.next().map(|next| next.1);
+
+                    if first == Some('0') && second != Some('$') {
+                        skip_char_and_emit(&mut chars, FormatSpecifier::Zero, &mut callback);
+                    }
+
+                    // width
+                    match chars.peek().copied().unwrap_or_default().1 {
+                        '0'..='9' => {
+                            read_integer(&mut chars, &mut callback);
+                            if let Some((_, '$')) = chars.peek() {
                                 skip_char_and_emit(
                                     &mut chars,
-                                    FormatSpecifier::Fill,
+                                    FormatSpecifier::DollarSign,
                                     &mut callback,
                                 );
+                            }
+                        }
+                        c if c == '_' || c.is_alphabetic() => {
+                            read_identifier(&mut chars, &mut callback);
+
+                            if chars.peek().map(|&(_, c)| c) == Some('?') {
                                 skip_char_and_emit(
                                     &mut chars,
-                                    FormatSpecifier::Align,
+                                    FormatSpecifier::QuestionMark,
                                     &mut callback,
                                 );
                             }
-                            _ => match first {
-                                '<' | '^' | '>' => {
+
+                            // can be either width (indicated by dollar sign, or type in which case
+                            // the next sign has to be `}`)
+                            let next = chars.peek().map(|&(_, c)| c);
+
+                            match next {
+                                Some('$') => skip_char_and_emit(
+                                    &mut chars,
+                                    FormatSpecifier::DollarSign,
+                                    &mut callback,
+                                ),
+                                Some('}') => {
                                     skip_char_and_emit(
                                         &mut chars,
-                                        FormatSpecifier::Align,
+                                        FormatSpecifier::Close,
                                         &mut callback,
                                     );
+                                    continue;
                                 }
-                                _ => {}
-                            },
+                                _ => continue,
+                            };
                         }
+                        _ => {}
+                    }
 
-                        // check for sign
-                        match chars
-                            .peek()
-                            .and_then(|next| next.1.as_ref().ok())
-                            .copied()
-                            .unwrap_or_default()
-                        {
-                            '+' | '-' => {
+                    // precision
+                    if let Some((_, '.')) = chars.peek() {
+                        skip_char_and_emit(&mut chars, FormatSpecifier::Dot, &mut callback);
+
+                        match chars.peek().copied().unwrap_or_default().1 {
+                            '*' => {
                                 skip_char_and_emit(
                                     &mut chars,
-                                    FormatSpecifier::Sign,
+                                    FormatSpecifier::Asterisk,
                                     &mut callback,
                                 );
                             }
-                            _ => {}
-                        }
-
-                        // check for `#`
-                        if let Some((_, Ok('#'))) = chars.peek() {
-                            skip_char_and_emit(
-                                &mut chars,
-                                FormatSpecifier::NumberSign,
-                                &mut callback,
-                            );
-                        }
-
-                        // check for `0`
-                        let mut cloned = chars.clone().take(2);
-                        let first = cloned.next().and_then(|next| next.1.as_ref().ok()).copied();
-                        let second = cloned.next().and_then(|next| next.1.as_ref().ok()).copied();
-
-                        if first == Some('0') && second != Some('$') {
-                            skip_char_and_emit(&mut chars, FormatSpecifier::Zero, &mut callback);
-                        }
-
-                        // width
-                        match chars
-                            .peek()
-                            .and_then(|next| next.1.as_ref().ok())
-                            .copied()
-                            .unwrap_or_default()
-                        {
                             '0'..='9' => {
                                 read_integer(&mut chars, &mut callback);
-                                if let Some((_, Ok('$'))) = chars.peek() {
+                                if let Some((_, '$')) = chars.peek() {
                                     skip_char_and_emit(
                                         &mut chars,
                                         FormatSpecifier::DollarSign,
@@ -415,160 +433,75 @@ pub trait HasFormatSpecifier: AstToken {
                             }
                             c if c == '_' || c.is_alphabetic() => {
                                 read_identifier(&mut chars, &mut callback);
-
-                                if chars.peek().and_then(|next| next.1.as_ref().ok()).copied()
-                                    == Some('?')
-                                {
-                                    skip_char_and_emit(
-                                        &mut chars,
-                                        FormatSpecifier::QuestionMark,
-                                        &mut callback,
-                                    );
+                                if chars.peek().map(|&(_, c)| c) != Some('$') {
+                                    continue;
                                 }
-
-                                // can be either width (indicated by dollar sign, or type in which case
-                                // the next sign has to be `}`)
-                                let next =
-                                    chars.peek().and_then(|next| next.1.as_ref().ok()).copied();
-
-                                match next {
-                                    Some('$') => skip_char_and_emit(
-                                        &mut chars,
-                                        FormatSpecifier::DollarSign,
-                                        &mut callback,
-                                    ),
-                                    Some('}') => {
-                                        skip_char_and_emit(
-                                            &mut chars,
-                                            FormatSpecifier::Close,
-                                            &mut callback,
-                                        );
-                                        continue;
-                                    }
-                                    _ => continue,
-                                };
+                                skip_char_and_emit(
+                                    &mut chars,
+                                    FormatSpecifier::DollarSign,
+                                    &mut callback,
+                                );
+                            }
+                            _ => {
+                                continue;
                             }
-                            _ => {}
                         }
+                    }
 
-                        // precision
-                        if let Some((_, Ok('.'))) = chars.peek() {
-                            skip_char_and_emit(&mut chars, FormatSpecifier::Dot, &mut callback);
-
-                            match chars
-                                .peek()
-                                .and_then(|next| next.1.as_ref().ok())
-                                .copied()
-                                .unwrap_or_default()
-                            {
-                                '*' => {
-                                    skip_char_and_emit(
-                                        &mut chars,
-                                        FormatSpecifier::Asterisk,
-                                        &mut callback,
-                                    );
-                                }
-                                '0'..='9' => {
-                                    read_integer(&mut chars, &mut callback);
-                                    if let Some((_, Ok('$'))) = chars.peek() {
-                                        skip_char_and_emit(
-                                            &mut chars,
-                                            FormatSpecifier::DollarSign,
-                                            &mut callback,
-                                        );
-                                    }
-                                }
-                                c if c == '_' || c.is_alphabetic() => {
-                                    read_identifier(&mut chars, &mut callback);
-                                    if chars.peek().and_then(|next| next.1.as_ref().ok()).copied()
-                                        != Some('$')
-                                    {
-                                        continue;
-                                    }
-                                    skip_char_and_emit(
-                                        &mut chars,
-                                        FormatSpecifier::DollarSign,
-                                        &mut callback,
-                                    );
-                                }
-                                _ => {
-                                    continue;
-                                }
-                            }
+                    // type
+                    match chars.peek().copied().unwrap_or_default().1 {
+                        '?' => {
+                            skip_char_and_emit(
+                                &mut chars,
+                                FormatSpecifier::QuestionMark,
+                                &mut callback,
+                            );
                         }
+                        c if c == '_' || c.is_alphabetic() => {
+                            read_identifier(&mut chars, &mut callback);
 
-                        // type
-                        match chars
-                            .peek()
-                            .and_then(|next| next.1.as_ref().ok())
-                            .copied()
-                            .unwrap_or_default()
-                        {
-                            '?' => {
+                            if chars.peek().map(|&(_, c)| c) == Some('?') {
                                 skip_char_and_emit(
                                     &mut chars,
                                     FormatSpecifier::QuestionMark,
                                     &mut callback,
                                 );
                             }
-                            c if c == '_' || c.is_alphabetic() => {
-                                read_identifier(&mut chars, &mut callback);
-
-                                if chars.peek().and_then(|next| next.1.as_ref().ok()).copied()
-                                    == Some('?')
-                                {
-                                    skip_char_and_emit(
-                                        &mut chars,
-                                        FormatSpecifier::QuestionMark,
-                                        &mut callback,
-                                    );
-                                }
-                            }
-                            _ => {}
                         }
-                    }
-
-                    match chars.peek() {
-                        Some((_, Ok('}'))) => {
-                            skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
-                        }
-                        Some((_, _)) | None => continue,
+                        _ => {}
                     }
                 }
-                _ => {
-                    while let Some((_, Ok(next_char))) = chars.peek() {
-                        if next_char == &'{' {
-                            break;
-                        }
-                        chars.next();
-                    }
+
+                if let Some((_, '}')) = chars.peek() {
+                    skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
                 }
-            };
+                continue;
+            }
         }
 
-        fn skip_char_and_emit<'a, I, F>(
+        fn skip_char_and_emit<I, F>(
             chars: &mut std::iter::Peekable<I>,
             emit: FormatSpecifier,
             callback: &mut F,
         ) where
-            I: Iterator<Item = &'a (TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>,
+            I: Iterator<Item = (TextRange, char)>,
             F: FnMut(TextRange, FormatSpecifier),
         {
             let (range, _) = chars.next().unwrap();
-            callback(*range, emit);
+            callback(range, emit);
         }
 
-        fn read_integer<'a, I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
+        fn read_integer<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
         where
-            I: Iterator<Item = &'a (TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>,
+            I: Iterator<Item = (TextRange, char)>,
             F: FnMut(TextRange, FormatSpecifier),
         {
             let (mut range, c) = chars.next().unwrap();
-            assert!(c.as_ref().unwrap().is_ascii_digit());
-            while let Some((r, Ok(next_char))) = chars.peek() {
+            assert!(c.is_ascii_digit());
+            while let Some(&(r, next_char)) = chars.peek() {
                 if next_char.is_ascii_digit() {
                     chars.next();
-                    range = range.cover(*r);
+                    range = range.cover(r);
                 } else {
                     break;
                 }
@@ -576,17 +509,17 @@ pub trait HasFormatSpecifier: AstToken {
             callback(range, FormatSpecifier::Integer);
         }
 
-        fn read_identifier<'a, I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
+        fn read_identifier<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
         where
-            I: Iterator<Item = &'a (TextRange, Result<char, rustc_lexer::unescape::EscapeError>)>,
+            I: Iterator<Item = (TextRange, char)>,
             F: FnMut(TextRange, FormatSpecifier),
         {
             let (mut range, c) = chars.next().unwrap();
-            assert!(c.as_ref().unwrap().is_alphabetic() || *c.as_ref().unwrap() == '_');
-            while let Some((r, Ok(next_char))) = chars.peek() {
-                if *next_char == '_' || next_char.is_ascii_digit() || next_char.is_alphabetic() {
+            assert!(c.is_alphabetic() || c == '_');
+            while let Some(&(r, next_char)) = chars.peek() {
+                if next_char == '_' || next_char.is_ascii_digit() || next_char.is_alphabetic() {
                     chars.next();
-                    range = range.cover(*r);
+                    range = range.cover(r);
                 } else {
                     break;
                 }


Test patch:
diff --git a/crates/ide_completion/src/tests/attribute.rs b/crates/ide_completion/src/tests/attribute.rs
index 2d2a1b867a..c2bd26e2d8 100644
--- a/crates/ide_completion/src/tests/attribute.rs
+++ b/crates/ide_completion/src/tests/attribute.rs
@@ -40,19 +40,6 @@ struct Foo;
     )
 }
 
-#[test]
-fn proc_macros_on_comment() {
-    check(
-        r#"
-//- proc_macros: identity
-/// $0
-#[proc_macros::identity]
-struct Foo;
-"#,
-        expect![[r#""#]],
-    )
-}
-
 #[test]
 fn proc_macros_qualified() {
     check(
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs
index 7f437e1a07..c9a31eea84 100644
--- a/crates/ide_completion/src/tests/pattern.rs
+++ b/crates/ide_completion/src/tests/pattern.rs
@@ -368,17 +368,3 @@ fn foo() {
         "#]],
     )
 }
-
-#[test]
-fn completes_fully_equal() {
-    check_empty(
-        r#"
-fn foo(bar: u32) {}
-fn bar(bar$0) {}
-"#,
-        expect![[r#"
-            bn bar: u32
-            kw mut
-        "#]],
-    )
-}
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 cc51d85da7..176d7e1579 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
@@ -1,13 +1,11 @@
 [
     (
-        Module {
-            id: ModuleId {
-                krate: CrateId(
-                    0,
-                ),
-                block: None,
-                local_id: Idx::<ModuleData>(0),
-            },
+        ModuleId {
+            krate: CrateId(
+                0,
+            ),
+            block: None,
+            local_id: Idx::<ModuleData>(0),
         },
         [
             FileSymbol {
@@ -461,14 +459,12 @@
         ],
     ),
     (
-        Module {
-            id: ModuleId {
-                krate: CrateId(
-                    0,
-                ),
-                block: None,
-                local_id: Idx::<ModuleData>(1),
-            },
+        ModuleId {
+            krate: CrateId(
+                0,
+            ),
+            block: None,
+            local_id: Idx::<ModuleData>(1),
         },
         [
             FileSymbol {
@@ -496,14 +492,12 @@
         ],
     ),
     (
-        Module {
-            id: ModuleId {
-                krate: CrateId(
-                    0,
-                ),
-                block: None,
-                local_id: Idx::<ModuleData>(2),
-            },
+        ModuleId {
+            krate: CrateId(
+                0,
+            ),
+            block: None,
+            local_id: Idx::<ModuleData>(2),
         },
         [
             FileSymbol {