summary refs log tree commit diff
path: root/src/tools/rust-analyzer/crates/ide-db
diff options
context:
space:
mode:
authorLaurențiu Nicola <lnicola@dend.ro>2023-06-05 12:04:23 +0300
committerLaurențiu Nicola <lnicola@dend.ro>2023-06-05 12:04:23 +0300
commitb8a7d439db0cfd765ed4bfedd2bbaeeee58b05a5 (patch)
tree5adcbc6cf50af3bebc2cd4f42d5252a4d728690e /src/tools/rust-analyzer/crates/ide-db
parent51f714c8c5021fe25442e46798b1cbef2f2249ed (diff)
parentaa9bc8612514d216f84eec218dfd19ab83f3598a (diff)
downloadrust-b8a7d439db0cfd765ed4bfedd2bbaeeee58b05a5.tar.gz
rust-b8a7d439db0cfd765ed4bfedd2bbaeeee58b05a5.zip
Merge commit 'aa9bc8612514d216f84eec218dfd19ab83f3598a' into sync-from-ra
Diffstat (limited to 'src/tools/rust-analyzer/crates/ide-db')
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/assists.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs23
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/helpers.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/lib.rs225
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/line_index.rs314
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/source_change.rs125
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs103
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt202
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt238
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/tests/line_index.rs49
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/traits.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs4
24 files changed, 924 insertions, 516 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
index 57daaf623df..4e75dc4dba5 100644
--- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
@@ -23,6 +23,8 @@ itertools = "0.10.5"
 arrayvec = "0.7.2"
 indexmap = "1.9.1"
 memchr = "2.5.0"
+triomphe.workspace = true
+nohash-hasher.workspace = true
 
 # local deps
 base-db.workspace = true
@@ -36,6 +38,8 @@ text-edit.workspace = true
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
 hir.workspace = true
 
+line-index.workspace = true
+
 [dev-dependencies]
 expect-test = "1.4.0"
 oorandom = "11.1.3"
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
index ea1d9cc4919..8edda432ce3 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
@@ -1,13 +1,12 @@
 //! Applies changes to the IDE state transactionally.
 
-use std::sync::Arc;
-
 use base_db::{
     salsa::{Database, Durability},
     Change, SourceRootId,
 };
 use profile::{memory_usage, Bytes};
 use rustc_hash::FxHashSet;
+use triomphe::Arc;
 
 use crate::{symbol_index::SymbolsDatabase, RootDatabase};
 
@@ -64,6 +63,7 @@ impl RootDatabase {
             // SourceDatabase
             base_db::ParseQuery
             base_db::CrateGraphQuery
+            base_db::ProcMacrosQuery
 
             // SourceDatabaseExt
             base_db::FileTextQuery
@@ -79,7 +79,6 @@ impl RootDatabase {
             hir::db::MacroDefQuery
             hir::db::MacroExpandQuery
             hir::db::ExpandProcMacroQuery
-            hir::db::MacroExpandErrorQuery
             hir::db::HygieneFrameQuery
 
             // DefDatabase
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs
index 8c6c1c44aa7..7a7328f312d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs
@@ -98,7 +98,7 @@ impl FromStr for AssistKind {
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub struct AssistId(pub &'static str, pub AssistKind);
 
-/// A way to control how many asssist to resolve during the assist resolution.
+/// A way to control how many assist to resolve during the assist resolution.
 /// When an assist is resolved, its edits are calculated that might be costly to always do by default.
 #[derive(Debug)]
 pub enum AssistResolveStrategy {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index 4071c490b7f..760834bfafc 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -8,8 +8,8 @@
 use arrayvec::ArrayVec;
 use hir::{
     Adt, AsAssocItem, AssocItem, BuiltinAttr, BuiltinType, Const, Crate, DeriveHelper, Field,
-    Function, GenericParam, HasVisibility, Impl, ItemInNs, Label, Local, Macro, Module, ModuleDef,
-    Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TypeAlias, Variant,
+    Function, GenericParam, HasVisibility, Impl, Label, Local, Macro, Module, ModuleDef, Name,
+    PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TypeAlias, Variant,
     Visibility,
 };
 use stdx::impl_from;
@@ -622,22 +622,3 @@ impl From<ModuleDef> for Definition {
         }
     }
 }
-
-impl From<Definition> for Option<ItemInNs> {
-    fn from(def: Definition) -> Self {
-        let item = match def {
-            Definition::Module(it) => ModuleDef::Module(it),
-            Definition::Function(it) => ModuleDef::Function(it),
-            Definition::Adt(it) => ModuleDef::Adt(it),
-            Definition::Variant(it) => ModuleDef::Variant(it),
-            Definition::Const(it) => ModuleDef::Const(it),
-            Definition::Static(it) => ModuleDef::Static(it),
-            Definition::Trait(it) => ModuleDef::Trait(it),
-            Definition::TraitAlias(it) => ModuleDef::TraitAlias(it),
-            Definition::TypeAlias(it) => ModuleDef::TypeAlias(it),
-            Definition::BuiltinType(it) => ModuleDef::BuiltinType(it),
-            _ => return None,
-        };
-        Some(ItemInNs::from(item))
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
index f0c3690962a..e488300b41c 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
@@ -4230,7 +4230,7 @@ pub union GenericUnion<T: Copy> { // Unions with non-`Copy` fields are unstable.
 pub const THIS_IS_OKAY: GenericUnion<()> = GenericUnion { field: () };
 ```
 
-Like transarent `struct`s, a transparent `union` of type `U` has the same
+Like transparent `struct`s, a transparent `union` of type `U` has the same
 layout, size, and ABI as its single non-ZST field. If it is generic over a type
 `T`, and all its fields are ZSTs except for exactly one field of type `T`, then
 it has the same layout and ABI as `T` (even if `T` is a ZST when monomorphized).
@@ -6548,7 +6548,7 @@ subtracting elements in an Add impl."##,
     },
     Lint {
         label: "clippy::suspicious_assignment_formatting",
-        description: r##"Checks for use of the non-existent `=*`, `=!` and `=-`
+        description: r##"Checks for use of the nonexistent `=*`, `=!` and `=-`
 operators."##,
     },
     Lint {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs
index 8e3b1eef15b..eba9d8afc40 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs
@@ -77,7 +77,7 @@ pub fn visit_file_defs(
     }
     module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
 
-    let is_root = module.is_crate_root(db);
+    let is_root = module.is_crate_root();
     module
         .legacy_macros(db)
         .into_iter()
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index b26b0a9087e..901d592c691 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -362,12 +362,12 @@ fn import_for_item(
 
     let original_item_candidate = item_for_path_search(db, original_item)?;
     let import_path_candidate = mod_path(original_item_candidate)?;
-    let import_path_string = import_path_candidate.to_string();
+    let import_path_string = import_path_candidate.display(db).to_string();
 
     let expected_import_end = if item_as_assoc(db, original_item).is_some() {
         unresolved_qualifier.to_string()
     } else {
-        format!("{unresolved_qualifier}::{}", item_name(db, original_item)?)
+        format!("{unresolved_qualifier}::{}", item_name(db, original_item)?.display(db))
     };
     if !import_path_string.contains(unresolved_first_segment)
         || !import_path_string.ends_with(&expected_import_end)
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
index 07a57c883b2..46f1353e2e1 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
@@ -5,17 +5,11 @@
 use either::Either;
 use hir::{
     import_map::{self, ImportKind},
-    symbols::FileSymbol,
     AsAssocItem, Crate, ItemInNs, Semantics,
 };
 use limit::Limit;
-use syntax::{ast, AstNode, SyntaxKind::NAME};
 
-use crate::{
-    defs::{Definition, NameClass},
-    imports::import_assets::NameToImport,
-    symbol_index, RootDatabase,
-};
+use crate::{imports::import_assets::NameToImport, symbol_index, RootDatabase};
 
 /// A value to use, when uncertain which limit to pick.
 pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(40);
@@ -115,12 +109,12 @@ fn find_items<'a>(
         });
 
     // Query the local crate using the symbol index.
-    let local_results = symbol_index::crate_symbols(db, krate, local_query)
+    let local_results = local_query
+        .search(&symbol_index::crate_symbols(db, krate))
         .into_iter()
-        .filter_map(move |local_candidate| get_name_definition(sema, &local_candidate))
-        .filter_map(|name_definition_to_import| match name_definition_to_import {
-            Definition::Macro(macro_def) => Some(ItemInNs::from(macro_def)),
-            def => <Option<_>>::from(def),
+        .filter_map(|local_candidate| match local_candidate.def {
+            hir::ModuleDef::Macro(macro_def) => Some(ItemInNs::Macros(macro_def)),
+            def => Some(ItemInNs::from(def)),
         });
 
     external_importables.chain(local_results).filter(move |&item| match assoc_item_search {
@@ -130,22 +124,6 @@ fn find_items<'a>(
     })
 }
 
-fn get_name_definition(
-    sema: &Semantics<'_, RootDatabase>,
-    import_candidate: &FileSymbol,
-) -> Option<Definition> {
-    let _p = profile::span("get_name_definition");
-
-    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 {
-        candidate_node
-    };
-    let name = ast::Name::cast(candidate_name_node)?;
-    NameClass::classify(sema, &name)?.defined()
-}
-
 fn is_assoc_item(item: ItemInNs, db: &RootDatabase) -> bool {
     item.as_module_def().and_then(|module_def| module_def.as_assoc_item(db)).is_some()
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index b1df11bf911..ff1a20f03f4 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -13,7 +13,6 @@ pub mod famous_defs;
 pub mod helpers;
 pub mod items_locator;
 pub mod label;
-pub mod line_index;
 pub mod path_transform;
 pub mod rename;
 pub mod rust_doc;
@@ -43,21 +42,20 @@ pub mod syntax_helpers {
     pub use parser::LexedStr;
 }
 
-use std::{fmt, mem::ManuallyDrop, sync::Arc};
+use std::{fmt, mem::ManuallyDrop};
 
 use base_db::{
     salsa::{self, Durability},
     AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast,
 };
-use hir::{
-    db::{DefDatabase, ExpandDatabase, HirDatabase},
-    symbols::FileSymbolKind,
-};
-use stdx::hash::NoHashHashSet;
+use hir::db::{DefDatabase, ExpandDatabase, HirDatabase};
+use triomphe::Arc;
 
 use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase};
 pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
 
+pub use ::line_index;
+
 /// `base_db` is normally also needed in places where `ide_db` is used, so this re-export is for convenience.
 pub use base_db;
 
@@ -114,13 +112,13 @@ impl Upcast<dyn HirDatabase> for RootDatabase {
 }
 
 impl FileLoader for RootDatabase {
-    fn file_text(&self, file_id: FileId) -> Arc<String> {
+    fn file_text(&self, file_id: FileId) -> Arc<str> {
         FileLoaderDelegate(self).file_text(file_id)
     }
     fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId> {
         FileLoaderDelegate(self).resolve_path(path)
     }
-    fn relevant_crates(&self, file_id: FileId) -> Arc<NoHashHashSet<CrateId>> {
+    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
         FileLoaderDelegate(self).relevant_crates(file_id)
     }
 }
@@ -137,18 +135,186 @@ impl RootDatabase {
     pub fn new(lru_capacity: Option<usize>) -> RootDatabase {
         let mut db = RootDatabase { storage: ManuallyDrop::new(salsa::Storage::default()) };
         db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
+        db.set_proc_macros_with_durability(Default::default(), Durability::HIGH);
         db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
         db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
-        db.set_enable_proc_attr_macros(false);
-        db.update_lru_capacity(lru_capacity);
+        db.set_expand_proc_attr_macros_with_durability(false, Durability::HIGH);
+        db.update_parse_query_lru_capacity(lru_capacity);
         db
     }
 
-    pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
-        let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_LRU_CAP);
+    pub fn enable_proc_attr_macros(&mut self) {
+        self.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
+    }
+
+    pub fn update_parse_query_lru_capacity(&mut self, lru_capacity: Option<usize>) {
+        let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_PARSE_LRU_CAP);
         base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
-        hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
-        hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(lru_capacity);
+        // macro expansions are usually rather small, so we can afford to keep more of them alive
+        hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(4 * lru_capacity);
+        hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(4 * lru_capacity);
+    }
+
+    pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap<Box<str>, usize>) {
+        use hir::db as hir_db;
+
+        base_db::ParseQuery.in_db_mut(self).set_lru_capacity(
+            lru_capacities
+                .get(stringify!(ParseQuery))
+                .copied()
+                .unwrap_or(base_db::DEFAULT_PARSE_LRU_CAP),
+        );
+        hir_db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(
+            lru_capacities
+                .get(stringify!(ParseMacroExpansionQuery))
+                .copied()
+                .unwrap_or(4 * base_db::DEFAULT_PARSE_LRU_CAP),
+        );
+        hir_db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(
+            lru_capacities
+                .get(stringify!(MacroExpandQuery))
+                .copied()
+                .unwrap_or(4 * base_db::DEFAULT_PARSE_LRU_CAP),
+        );
+
+        macro_rules! update_lru_capacity_per_query {
+            ($( $module:ident :: $query:ident )*) => {$(
+                if let Some(&cap) = lru_capacities.get(stringify!($query)) {
+                    $module::$query.in_db_mut(self).set_lru_capacity(cap);
+                }
+            )*}
+        }
+        update_lru_capacity_per_query![
+            // SourceDatabase
+            // base_db::ParseQuery
+            // base_db::CrateGraphQuery
+            // base_db::ProcMacrosQuery
+
+            // SourceDatabaseExt
+            // base_db::FileTextQuery
+            // base_db::FileSourceRootQuery
+            // base_db::SourceRootQuery
+            base_db::SourceRootCratesQuery
+
+            // ExpandDatabase
+            hir_db::AstIdMapQuery
+            // hir_db::ParseMacroExpansionQuery
+            // hir_db::InternMacroCallQuery
+            hir_db::MacroArgTextQuery
+            hir_db::MacroDefQuery
+            // hir_db::MacroExpandQuery
+            hir_db::ExpandProcMacroQuery
+            hir_db::HygieneFrameQuery
+            hir_db::ParseMacroExpansionErrorQuery
+
+            // DefDatabase
+            hir_db::FileItemTreeQuery
+            hir_db::CrateDefMapQueryQuery
+            hir_db::BlockDefMapQuery
+            hir_db::StructDataQuery
+            hir_db::StructDataWithDiagnosticsQuery
+            hir_db::UnionDataQuery
+            hir_db::UnionDataWithDiagnosticsQuery
+            hir_db::EnumDataQuery
+            hir_db::EnumDataWithDiagnosticsQuery
+            hir_db::ImplDataQuery
+            hir_db::ImplDataWithDiagnosticsQuery
+            hir_db::TraitDataQuery
+            hir_db::TraitDataWithDiagnosticsQuery
+            hir_db::TraitAliasDataQuery
+            hir_db::TypeAliasDataQuery
+            hir_db::FunctionDataQuery
+            hir_db::ConstDataQuery
+            hir_db::StaticDataQuery
+            hir_db::Macro2DataQuery
+            hir_db::MacroRulesDataQuery
+            hir_db::ProcMacroDataQuery
+            hir_db::BodyWithSourceMapQuery
+            hir_db::BodyQuery
+            hir_db::ExprScopesQuery
+            hir_db::GenericParamsQuery
+            hir_db::VariantsAttrsQuery
+            hir_db::FieldsAttrsQuery
+            hir_db::VariantsAttrsSourceMapQuery
+            hir_db::FieldsAttrsSourceMapQuery
+            hir_db::AttrsQuery
+            hir_db::CrateLangItemsQuery
+            hir_db::LangItemQuery
+            hir_db::ImportMapQuery
+            hir_db::FieldVisibilitiesQuery
+            hir_db::FunctionVisibilityQuery
+            hir_db::ConstVisibilityQuery
+            hir_db::CrateSupportsNoStdQuery
+
+            // HirDatabase
+            hir_db::InferQueryQuery
+            hir_db::MirBodyQuery
+            hir_db::BorrowckQuery
+            hir_db::TyQuery
+            hir_db::ValueTyQuery
+            hir_db::ImplSelfTyQuery
+            hir_db::ConstParamTyQuery
+            hir_db::ConstEvalQuery
+            hir_db::ConstEvalDiscriminantQuery
+            hir_db::ImplTraitQuery
+            hir_db::FieldTypesQuery
+            hir_db::LayoutOfAdtQuery
+            hir_db::TargetDataLayoutQuery
+            hir_db::CallableItemSignatureQuery
+            hir_db::ReturnTypeImplTraitsQuery
+            hir_db::GenericPredicatesForParamQuery
+            hir_db::GenericPredicatesQuery
+            hir_db::TraitEnvironmentQuery
+            hir_db::GenericDefaultsQuery
+            hir_db::InherentImplsInCrateQuery
+            hir_db::InherentImplsInBlockQuery
+            hir_db::IncoherentInherentImplCratesQuery
+            hir_db::TraitImplsInCrateQuery
+            hir_db::TraitImplsInBlockQuery
+            hir_db::TraitImplsInDepsQuery
+            // hir_db::InternCallableDefQuery
+            // hir_db::InternLifetimeParamIdQuery
+            // hir_db::InternImplTraitIdQuery
+            // hir_db::InternTypeOrConstParamIdQuery
+            // hir_db::InternClosureQuery
+            // hir_db::InternGeneratorQuery
+            hir_db::AssociatedTyDataQuery
+            hir_db::TraitDatumQuery
+            hir_db::StructDatumQuery
+            hir_db::ImplDatumQuery
+            hir_db::FnDefDatumQuery
+            hir_db::FnDefVarianceQuery
+            hir_db::AdtVarianceQuery
+            hir_db::AssociatedTyValueQuery
+            hir_db::TraitSolveQueryQuery
+            hir_db::ProgramClausesForChalkEnvQuery
+
+            // SymbolsDatabase
+            symbol_index::ModuleSymbolsQuery
+            symbol_index::LibrarySymbolsQuery
+            // symbol_index::LocalRootsQuery
+            // symbol_index::LibraryRootsQuery
+
+            // LineIndexDatabase
+            crate::LineIndexQuery
+
+            // InternDatabase
+            // hir_db::InternFunctionQuery
+            // hir_db::InternStructQuery
+            // hir_db::InternUnionQuery
+            // hir_db::InternEnumQuery
+            // hir_db::InternConstQuery
+            // hir_db::InternStaticQuery
+            // hir_db::InternTraitQuery
+            // hir_db::InternTraitAliasQuery
+            // hir_db::InternTypeAliasQuery
+            // hir_db::InternImplQuery
+            // hir_db::InternExternBlockQuery
+            // hir_db::InternBlockQuery
+            // hir_db::InternMacro2Query
+            // hir_db::InternProcMacroQuery
+            // hir_db::InternMacroRulesQuery
+        ];
     }
 }
 
@@ -211,20 +377,22 @@ impl From<hir::MacroKind> for SymbolKind {
     }
 }
 
-impl From<FileSymbolKind> for SymbolKind {
-    fn from(it: FileSymbolKind) -> Self {
+impl From<hir::ModuleDefId> for SymbolKind {
+    fn from(it: hir::ModuleDefId) -> 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::TraitAlias => SymbolKind::TraitAlias,
-            FileSymbolKind::TypeAlias => SymbolKind::TypeAlias,
-            FileSymbolKind::Union => SymbolKind::Union,
+            hir::ModuleDefId::ConstId(..) => SymbolKind::Const,
+            hir::ModuleDefId::EnumVariantId(..) => SymbolKind::Variant,
+            hir::ModuleDefId::FunctionId(..) => SymbolKind::Function,
+            hir::ModuleDefId::MacroId(..) => SymbolKind::Macro,
+            hir::ModuleDefId::ModuleId(..) => SymbolKind::Module,
+            hir::ModuleDefId::StaticId(..) => SymbolKind::Static,
+            hir::ModuleDefId::AdtId(hir::AdtId::StructId(..)) => SymbolKind::Struct,
+            hir::ModuleDefId::AdtId(hir::AdtId::EnumId(..)) => SymbolKind::Enum,
+            hir::ModuleDefId::AdtId(hir::AdtId::UnionId(..)) => SymbolKind::Union,
+            hir::ModuleDefId::TraitId(..) => SymbolKind::Trait,
+            hir::ModuleDefId::TraitAliasId(..) => SymbolKind::TraitAlias,
+            hir::ModuleDefId::TypeAliasId(..) => SymbolKind::TypeAlias,
+            hir::ModuleDefId::BuiltinType(..) => SymbolKind::TypeAlias,
         }
     }
 }
@@ -247,4 +415,5 @@ impl SnippetCap {
 #[cfg(test)]
 mod tests {
     mod sourcegen_lints;
+    mod line_index;
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs
deleted file mode 100644
index 16814a1e636..00000000000
--- a/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs
+++ /dev/null
@@ -1,314 +0,0 @@
-//! `LineIndex` maps flat `TextSize` offsets into `(Line, Column)`
-//! representation.
-use std::{iter, mem};
-
-use stdx::hash::NoHashHashMap;
-use syntax::{TextRange, TextSize};
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct LineIndex {
-    /// Offset the beginning of each line, zero-based.
-    pub(crate) newlines: Vec<TextSize>,
-    /// List of non-ASCII characters on each line.
-    pub(crate) line_wide_chars: NoHashHashMap<u32, Vec<WideChar>>,
-}
-
-/// Line/Column information in native, utf8 format.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct LineCol {
-    /// Zero-based
-    pub line: u32,
-    /// Zero-based utf8 offset
-    pub col: u32,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum WideEncoding {
-    Utf16,
-    Utf32,
-}
-
-/// Line/Column information in legacy encodings.
-///
-/// Deliberately not a generic type and different from `LineCol`.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct WideLineCol {
-    /// Zero-based
-    pub line: u32,
-    /// Zero-based
-    pub col: u32,
-}
-
-#[derive(Clone, Debug, Hash, PartialEq, Eq)]
-pub(crate) struct WideChar {
-    /// Start offset of a character inside a line, zero-based
-    pub(crate) start: TextSize,
-    /// End offset of a character inside a line, zero-based
-    pub(crate) end: TextSize,
-}
-
-impl WideChar {
-    /// Returns the length in 8-bit UTF-8 code units.
-    fn len(&self) -> TextSize {
-        self.end - self.start
-    }
-
-    /// Returns the length in UTF-16 or UTF-32 code units.
-    fn wide_len(&self, enc: WideEncoding) -> usize {
-        match enc {
-            WideEncoding::Utf16 => {
-                if self.len() == TextSize::from(4) {
-                    2
-                } else {
-                    1
-                }
-            }
-
-            WideEncoding::Utf32 => 1,
-        }
-    }
-}
-
-impl LineIndex {
-    pub fn new(text: &str) -> LineIndex {
-        let mut line_wide_chars = NoHashHashMap::default();
-        let mut wide_chars = Vec::new();
-
-        let mut newlines = Vec::with_capacity(16);
-        newlines.push(TextSize::from(0));
-
-        let mut curr_row = 0.into();
-        let mut curr_col = 0.into();
-        let mut line = 0;
-        for c in text.chars() {
-            let c_len = TextSize::of(c);
-            curr_row += c_len;
-            if c == '\n' {
-                newlines.push(curr_row);
-
-                // Save any utf-16 characters seen in the previous line
-                if !wide_chars.is_empty() {
-                    line_wide_chars.insert(line, mem::take(&mut wide_chars));
-                }
-
-                // Prepare for processing the next line
-                curr_col = 0.into();
-                line += 1;
-                continue;
-            }
-
-            if !c.is_ascii() {
-                wide_chars.push(WideChar { start: curr_col, end: curr_col + c_len });
-            }
-
-            curr_col += c_len;
-        }
-
-        // Save any utf-16 characters seen in the last line
-        if !wide_chars.is_empty() {
-            line_wide_chars.insert(line, wide_chars);
-        }
-
-        LineIndex { newlines, line_wide_chars }
-    }
-
-    pub fn line_col(&self, offset: TextSize) -> LineCol {
-        let line = self.newlines.partition_point(|&it| it <= offset) - 1;
-        let line_start_offset = self.newlines[line];
-        let col = offset - line_start_offset;
-        LineCol { line: line as u32, col: col.into() }
-    }
-
-    pub fn offset(&self, line_col: LineCol) -> Option<TextSize> {
-        self.newlines
-            .get(line_col.line as usize)
-            .map(|offset| offset + TextSize::from(line_col.col))
-    }
-
-    pub fn to_wide(&self, enc: WideEncoding, line_col: LineCol) -> WideLineCol {
-        let col = self.utf8_to_wide_col(enc, line_col.line, line_col.col.into());
-        WideLineCol { line: line_col.line, col: col as u32 }
-    }
-
-    pub fn to_utf8(&self, enc: WideEncoding, line_col: WideLineCol) -> LineCol {
-        let col = self.wide_to_utf8_col(enc, line_col.line, line_col.col);
-        LineCol { line: line_col.line, col: col.into() }
-    }
-
-    pub fn lines(&self, range: TextRange) -> impl Iterator<Item = TextRange> + '_ {
-        let lo = self.newlines.partition_point(|&it| it < range.start());
-        let hi = self.newlines.partition_point(|&it| it <= range.end());
-        let all = iter::once(range.start())
-            .chain(self.newlines[lo..hi].iter().copied())
-            .chain(iter::once(range.end()));
-
-        all.clone()
-            .zip(all.skip(1))
-            .map(|(lo, hi)| TextRange::new(lo, hi))
-            .filter(|it| !it.is_empty())
-    }
-
-    fn utf8_to_wide_col(&self, enc: WideEncoding, line: u32, col: TextSize) -> usize {
-        let mut res: usize = col.into();
-        if let Some(wide_chars) = self.line_wide_chars.get(&line) {
-            for c in wide_chars {
-                if c.end <= col {
-                    res -= usize::from(c.len()) - c.wide_len(enc);
-                } else {
-                    // From here on, all utf16 characters come *after* the character we are mapping,
-                    // so we don't need to take them into account
-                    break;
-                }
-            }
-        }
-        res
-    }
-
-    fn wide_to_utf8_col(&self, enc: WideEncoding, line: u32, mut col: u32) -> TextSize {
-        if let Some(wide_chars) = self.line_wide_chars.get(&line) {
-            for c in wide_chars {
-                if col > u32::from(c.start) {
-                    col += u32::from(c.len()) - c.wide_len(enc) as u32;
-                } else {
-                    // From here on, all utf16 characters come *after* the character we are mapping,
-                    // so we don't need to take them into account
-                    break;
-                }
-            }
-        }
-
-        col.into()
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use test_utils::skip_slow_tests;
-
-    use super::WideEncoding::{Utf16, Utf32};
-    use super::*;
-
-    #[test]
-    fn test_line_index() {
-        let text = "hello\nworld";
-        let table = [
-            (00, 0, 0),
-            (01, 0, 1),
-            (05, 0, 5),
-            (06, 1, 0),
-            (07, 1, 1),
-            (08, 1, 2),
-            (10, 1, 4),
-            (11, 1, 5),
-            (12, 1, 6),
-        ];
-
-        let index = LineIndex::new(text);
-        for (offset, line, col) in table {
-            assert_eq!(index.line_col(offset.into()), LineCol { line, col });
-        }
-
-        let text = "\nhello\nworld";
-        let table = [(0, 0, 0), (1, 1, 0), (2, 1, 1), (6, 1, 5), (7, 2, 0)];
-        let index = LineIndex::new(text);
-        for (offset, line, col) in table {
-            assert_eq!(index.line_col(offset.into()), LineCol { line, col });
-        }
-    }
-
-    #[test]
-    fn test_char_len() {
-        assert_eq!('メ'.len_utf8(), 3);
-        assert_eq!('メ'.len_utf16(), 1);
-    }
-
-    #[test]
-    fn test_empty_index() {
-        let col_index = LineIndex::new(
-            "
-const C: char = 'x';
-",
-        );
-        assert_eq!(col_index.line_wide_chars.len(), 0);
-    }
-
-    #[test]
-    fn test_every_chars() {
-        if skip_slow_tests() {
-            return;
-        }
-
-        let text: String = {
-            let mut chars: Vec<char> = ((0 as char)..char::MAX).collect(); // Neat!
-            chars.extend("\n".repeat(chars.len() / 16).chars());
-            let mut rng = oorandom::Rand32::new(stdx::rand::seed());
-            stdx::rand::shuffle(&mut chars, |i| rng.rand_range(0..i as u32) as usize);
-            chars.into_iter().collect()
-        };
-        assert!(text.contains('💩')); // Sanity check.
-
-        let line_index = LineIndex::new(&text);
-
-        let mut lin_col = LineCol { line: 0, col: 0 };
-        let mut col_utf16 = 0;
-        let mut col_utf32 = 0;
-        for (offset, c) in text.char_indices() {
-            let got_offset = line_index.offset(lin_col).unwrap();
-            assert_eq!(usize::from(got_offset), offset);
-
-            let got_lin_col = line_index.line_col(got_offset);
-            assert_eq!(got_lin_col, lin_col);
-
-            for enc in [Utf16, Utf32] {
-                let wide_lin_col = line_index.to_wide(enc, lin_col);
-                let got_lin_col = line_index.to_utf8(enc, wide_lin_col);
-                assert_eq!(got_lin_col, lin_col);
-
-                let want_col = match enc {
-                    Utf16 => col_utf16,
-                    Utf32 => col_utf32,
-                };
-                assert_eq!(wide_lin_col.col, want_col)
-            }
-
-            if c == '\n' {
-                lin_col.line += 1;
-                lin_col.col = 0;
-                col_utf16 = 0;
-                col_utf32 = 0;
-            } else {
-                lin_col.col += c.len_utf8() as u32;
-                col_utf16 += c.len_utf16() as u32;
-                col_utf32 += 1;
-            }
-        }
-    }
-
-    #[test]
-    fn test_splitlines() {
-        fn r(lo: u32, hi: u32) -> TextRange {
-            TextRange::new(lo.into(), hi.into())
-        }
-
-        let text = "a\nbb\nccc\n";
-        let line_index = LineIndex::new(text);
-
-        let actual = line_index.lines(r(0, 9)).collect::<Vec<_>>();
-        let expected = vec![r(0, 2), r(2, 5), r(5, 9)];
-        assert_eq!(actual, expected);
-
-        let text = "";
-        let line_index = LineIndex::new(text);
-
-        let actual = line_index.lines(r(0, 0)).collect::<Vec<_>>();
-        let expected = vec![];
-        assert_eq!(actual, expected);
-
-        let text = "\n";
-        let line_index = LineIndex::new(text);
-
-        let actual = line_index.lines(r(0, 1)).collect::<Vec<_>>();
-        let expected = vec![r(0, 1)];
-        assert_eq!(actual, expected)
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index 6402a84a68b..0ee627a44c6 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -116,7 +116,9 @@ impl<'a> PathTransform<'a> {
                         Some((
                             k,
                             ast::make::ty(
-                                &default.display_source_code(db, source_module.into()).ok()?,
+                                &default
+                                    .display_source_code(db, source_module.into(), false)
+                                    .ok()?,
                             ),
                         ))
                     }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index f710211c8cb..52a23b4b8f3 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -178,7 +178,7 @@ fn rename_mod(
 
     let mut source_change = SourceChange::default();
 
-    if module.is_crate_root(sema.db) {
+    if module.is_crate_root() {
         return Ok(source_change);
     }
 
@@ -202,12 +202,13 @@ fn rename_mod(
         //  - Module has submodules defined in separate files
         let dir_paths = match (is_mod_rs, has_detached_child, module.name(sema.db)) {
             // Go up one level since the anchor is inside the dir we're trying to rename
-            (true, _, Some(mod_name)) => {
-                Some((format!("../{}", mod_name.unescaped()), format!("../{new_name}")))
-            }
+            (true, _, Some(mod_name)) => Some((
+                format!("../{}", mod_name.unescaped().display(sema.db)),
+                format!("../{new_name}"),
+            )),
             // The anchor is on the same level as target dir
             (false, true, Some(mod_name)) => {
-                Some((mod_name.unescaped().to_string(), new_name.to_string()))
+                Some((mod_name.unescaped().display(sema.db).to_string(), new_name.to_owned()))
             }
             _ => None,
         };
@@ -232,7 +233,7 @@ fn rename_mod(
                 {
                     source_change.insert_source_edit(
                         file_id,
-                        TextEdit::replace(file_range.range, new_name.to_string()),
+                        TextEdit::replace(file_range.range, new_name.to_owned()),
                     )
                 };
             }
@@ -442,7 +443,7 @@ fn source_edit_from_name_ref(
                         let s = field_name.syntax().text_range().start();
                         let e = pat.syntax().text_range().start();
                         edit.delete(TextRange::new(s, e));
-                        edit.replace(name.syntax().text_range(), new_name.to_string());
+                        edit.replace(name.syntax().text_range(), new_name.to_owned());
                         return true;
                     }
                 }
@@ -462,7 +463,19 @@ fn source_edit_from_def(
     if let Definition::Local(local) = def {
         let mut file_id = None;
         for source in local.sources(sema.db) {
-            let source = source.source;
+            let source = match source.source.clone().original_ast_node(sema.db) {
+                Some(source) => source,
+                None => match source.source.syntax().original_file_range_opt(sema.db) {
+                    Some(FileRange { file_id: file_id2, range }) => {
+                        file_id = Some(file_id2);
+                        edit.replace(range, new_name.to_owned());
+                        continue;
+                    }
+                    None => {
+                        bail!("Can't rename local that is defined in a macro declaration")
+                    }
+                },
+            };
             file_id = source.file_id.file_id();
             if let Either::Left(pat) = source.value {
                 let name_range = pat.name().unwrap().syntax().text_range();
@@ -485,7 +498,7 @@ fn source_edit_from_def(
                             // Foo { field: ref mut local @ local 2} -> Foo { field: ref mut new_name @ local2 }
                             // Foo { field: ref mut local } -> Foo { field: ref mut new_name }
                             //                      ^^^^^ replace this with `new_name`
-                            edit.replace(name_range, new_name.to_string());
+                            edit.replace(name_range, new_name.to_owned());
                         }
                     } else {
                         // Foo { ref mut field } -> Foo { field: ref mut new_name }
@@ -495,10 +508,10 @@ fn source_edit_from_def(
                             pat.syntax().text_range().start(),
                             format!("{}: ", pat_field.field_name().unwrap()),
                         );
-                        edit.replace(name_range, new_name.to_string());
+                        edit.replace(name_range, new_name.to_owned());
                     }
                 } else {
-                    edit.replace(name_range, new_name.to_string());
+                    edit.replace(name_range, new_name.to_owned());
                 }
             }
         }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index 12f5e4e2a23..73cd5dcaf23 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -4,17 +4,18 @@
 //! get a super-set of matches. Then, we we confirm each match using precise
 //! name resolution.
 
-use std::{mem, sync::Arc};
+use std::mem;
 
 use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
 use hir::{
     AsAssocItem, DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility,
 };
 use memchr::memmem::Finder;
+use nohash_hasher::IntMap;
 use once_cell::unsync::Lazy;
 use parser::SyntaxKind;
-use stdx::hash::NoHashHashMap;
 use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
+use triomphe::Arc;
 
 use crate::{
     defs::{Definition, NameClass, NameRefClass},
@@ -24,7 +25,7 @@ use crate::{
 
 #[derive(Debug, Default, Clone)]
 pub struct UsageSearchResult {
-    pub references: NoHashHashMap<FileId, Vec<FileReference>>,
+    pub references: IntMap<FileId, Vec<FileReference>>,
 }
 
 impl UsageSearchResult {
@@ -49,7 +50,7 @@ impl UsageSearchResult {
 
 impl IntoIterator for UsageSearchResult {
     type Item = (FileId, Vec<FileReference>);
-    type IntoIter = <NoHashHashMap<FileId, Vec<FileReference>> as IntoIterator>::IntoIter;
+    type IntoIter = <IntMap<FileId, Vec<FileReference>> as IntoIterator>::IntoIter;
 
     fn into_iter(self) -> Self::IntoIter {
         self.references.into_iter()
@@ -83,17 +84,17 @@ pub enum ReferenceCategory {
 /// e.g. for things like local variables.
 #[derive(Clone, Debug)]
 pub struct SearchScope {
-    entries: NoHashHashMap<FileId, Option<TextRange>>,
+    entries: IntMap<FileId, Option<TextRange>>,
 }
 
 impl SearchScope {
-    fn new(entries: NoHashHashMap<FileId, Option<TextRange>>) -> SearchScope {
+    fn new(entries: IntMap<FileId, Option<TextRange>>) -> SearchScope {
         SearchScope { entries }
     }
 
     /// Build a search scope spanning the entire crate graph of files.
     fn crate_graph(db: &RootDatabase) -> SearchScope {
-        let mut entries = NoHashHashMap::default();
+        let mut entries = IntMap::default();
 
         let graph = db.crate_graph();
         for krate in graph.iter() {
@@ -107,7 +108,7 @@ impl SearchScope {
 
     /// Build a search scope spanning all the reverse dependencies of the given crate.
     fn reverse_dependencies(db: &RootDatabase, of: hir::Crate) -> SearchScope {
-        let mut entries = NoHashHashMap::default();
+        let mut entries = IntMap::default();
         for rev_dep in of.transitive_reverse_dependencies(db) {
             let root_file = rev_dep.root_file(db);
             let source_root_id = db.file_source_root(root_file);
@@ -127,7 +128,7 @@ impl SearchScope {
 
     /// Build a search scope spanning the given module and all its submodules.
     fn module_and_children(db: &RootDatabase, module: hir::Module) -> SearchScope {
-        let mut entries = NoHashHashMap::default();
+        let mut entries = IntMap::default();
 
         let (file_id, range) = {
             let InFile { file_id, value } = module.definition_source(db);
@@ -160,7 +161,7 @@ impl SearchScope {
 
     /// Build an empty search scope.
     pub fn empty() -> SearchScope {
-        SearchScope::new(NoHashHashMap::default())
+        SearchScope::new(IntMap::default())
     }
 
     /// Build a empty search scope spanning the given file.
@@ -224,7 +225,7 @@ impl Definition {
         // def is crate root
         // FIXME: We don't do searches for crates currently, as a crate does not actually have a single name
         if let &Definition::Module(module) = self {
-            if module.is_crate_root(db) {
+            if module.is_crate_root() {
                 return SearchScope::reverse_dependencies(db, module.krate());
             }
         }
@@ -391,7 +392,7 @@ impl<'a> FindUsages<'a> {
 
         let name = match self.def {
             // special case crate modules as these do not have a proper name
-            Definition::Module(module) if module.is_crate_root(self.sema.db) => {
+            Definition::Module(module) if module.is_crate_root() => {
                 // FIXME: This assumes the crate name is always equal to its display name when it really isn't
                 module
                     .krate()
@@ -438,11 +439,11 @@ impl<'a> FindUsages<'a> {
         fn scope_files<'a>(
             sema: &'a Semantics<'_, RootDatabase>,
             scope: &'a SearchScope,
-        ) -> impl Iterator<Item = (Arc<String>, FileId, TextRange)> + 'a {
+        ) -> impl Iterator<Item = (Arc<str>, FileId, TextRange)> + 'a {
             scope.entries.iter().map(|(&file_id, &search_range)| {
                 let text = sema.db.file_text(file_id);
                 let search_range =
-                    search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
+                    search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&*text)));
 
                 (text, file_id, search_range)
             })
@@ -499,7 +500,7 @@ impl<'a> FindUsages<'a> {
             let scope =
                 search_scope.intersection(&SearchScope::module_and_children(self.sema.db, module));
 
-            let is_crate_root = module.is_crate_root(self.sema.db).then(|| Finder::new("crate"));
+            let is_crate_root = module.is_crate_root().then(|| Finder::new("crate"));
             let finder = &Finder::new("super");
 
             for (text, file_id, search_range) in scope_files(sema, &scope) {
@@ -553,7 +554,7 @@ impl<'a> FindUsages<'a> {
 
                 let text = sema.db.file_text(file_id);
                 let search_range =
-                    search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(text.as_str())));
+                    search_range.unwrap_or_else(|| TextRange::up_to(TextSize::of(&*text)));
 
                 let tree = Lazy::new(|| sema.parse(file_id).syntax().clone());
                 let finder = &Finder::new("self");
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
index 936354f2961..061fb0f05cf 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
@@ -5,16 +5,16 @@
 
 use std::{collections::hash_map::Entry, iter, mem};
 
+use crate::SnippetCap;
 use base_db::{AnchoredPathBuf, FileId};
-use stdx::{hash::NoHashHashMap, never};
-use syntax::{algo, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize};
+use nohash_hasher::IntMap;
+use stdx::never;
+use syntax::{algo, ast, ted, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize};
 use text_edit::{TextEdit, TextEditBuilder};
 
-use crate::SnippetCap;
-
 #[derive(Default, Debug, Clone)]
 pub struct SourceChange {
-    pub source_file_edits: NoHashHashMap<FileId, TextEdit>,
+    pub source_file_edits: IntMap<FileId, TextEdit>,
     pub file_system_edits: Vec<FileSystemEdit>,
     pub is_snippet: bool,
 }
@@ -23,7 +23,7 @@ impl SourceChange {
     /// Creates a new SourceChange with the given label
     /// from the edits.
     pub fn from_edits(
-        source_file_edits: NoHashHashMap<FileId, TextEdit>,
+        source_file_edits: IntMap<FileId, TextEdit>,
         file_system_edits: Vec<FileSystemEdit>,
     ) -> Self {
         SourceChange { source_file_edits, file_system_edits, is_snippet: false }
@@ -77,8 +77,8 @@ impl Extend<FileSystemEdit> for SourceChange {
     }
 }
 
-impl From<NoHashHashMap<FileId, TextEdit>> for SourceChange {
-    fn from(source_file_edits: NoHashHashMap<FileId, TextEdit>) -> SourceChange {
+impl From<IntMap<FileId, TextEdit>> for SourceChange {
+    fn from(source_file_edits: IntMap<FileId, TextEdit>) -> SourceChange {
         SourceChange { source_file_edits, file_system_edits: Vec::new(), is_snippet: false }
     }
 }
@@ -99,6 +99,8 @@ pub struct SourceChangeBuilder {
 
     /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin.
     pub mutated_tree: Option<TreeMutator>,
+    /// Keeps track of where to place snippets
+    pub snippet_builder: Option<SnippetBuilder>,
 }
 
 pub struct TreeMutator {
@@ -106,6 +108,12 @@ pub struct TreeMutator {
     mutable_clone: SyntaxNode,
 }
 
+#[derive(Default)]
+pub struct SnippetBuilder {
+    /// Where to place snippets at
+    places: Vec<PlaceSnippet>,
+}
+
 impl TreeMutator {
     pub fn new(immutable: &SyntaxNode) -> TreeMutator {
         let immutable = immutable.ancestors().last().unwrap();
@@ -131,6 +139,7 @@ impl SourceChangeBuilder {
             source_change: SourceChange::default(),
             trigger_signature_help: false,
             mutated_tree: None,
+            snippet_builder: None,
         }
     }
 
@@ -140,6 +149,17 @@ impl SourceChangeBuilder {
     }
 
     fn commit(&mut self) {
+        // Render snippets first so that they get bundled into the tree diff
+        if let Some(mut snippets) = self.snippet_builder.take() {
+            // Last snippet always has stop index 0
+            let last_stop = snippets.places.pop().unwrap();
+            last_stop.place(0);
+
+            for (index, stop) in snippets.places.into_iter().enumerate() {
+                stop.place(index + 1)
+            }
+        }
+
         if let Some(tm) = self.mutated_tree.take() {
             algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit)
         }
@@ -161,7 +181,7 @@ impl SourceChangeBuilder {
     /// mutability, and different nodes in the same tree see the same mutations.
     ///
     /// The typical pattern for an assist is to find specific nodes in the read
-    /// phase, and then get their mutable couterparts using `make_mut` in the
+    /// phase, and then get their mutable counterparts using `make_mut` in the
     /// mutable state.
     pub fn make_syntax_mut(&mut self, node: SyntaxNode) -> SyntaxNode {
         self.mutated_tree.get_or_insert_with(|| TreeMutator::new(&node)).make_syntax_mut(&node)
@@ -214,6 +234,30 @@ impl SourceChangeBuilder {
         self.trigger_signature_help = true;
     }
 
+    /// Adds a tabstop snippet to place the cursor before `node`
+    pub fn add_tabstop_before(&mut self, _cap: SnippetCap, node: impl AstNode) {
+        assert!(node.syntax().parent().is_some());
+        self.add_snippet(PlaceSnippet::Before(node.syntax().clone()));
+    }
+
+    /// Adds a tabstop snippet to place the cursor after `node`
+    pub fn add_tabstop_after(&mut self, _cap: SnippetCap, node: impl AstNode) {
+        assert!(node.syntax().parent().is_some());
+        self.add_snippet(PlaceSnippet::After(node.syntax().clone()));
+    }
+
+    /// Adds a snippet to move the cursor selected over `node`
+    pub fn add_placeholder_snippet(&mut self, _cap: SnippetCap, node: impl AstNode) {
+        assert!(node.syntax().parent().is_some());
+        self.add_snippet(PlaceSnippet::Over(node.syntax().clone()))
+    }
+
+    fn add_snippet(&mut self, snippet: PlaceSnippet) {
+        let snippet_builder = self.snippet_builder.get_or_insert(SnippetBuilder { places: vec![] });
+        snippet_builder.places.push(snippet);
+        self.source_change.is_snippet = true;
+    }
+
     pub fn finish(mut self) -> SourceChange {
         self.commit();
         mem::take(&mut self.source_change)
@@ -236,3 +280,66 @@ impl From<FileSystemEdit> for SourceChange {
         }
     }
 }
+
+enum PlaceSnippet {
+    /// Place a tabstop before a node
+    Before(SyntaxNode),
+    /// Place a tabstop before a node
+    After(SyntaxNode),
+    /// Place a placeholder snippet in place of the node
+    Over(SyntaxNode),
+}
+
+impl PlaceSnippet {
+    /// Places the snippet before or over a node with the given tab stop index
+    fn place(self, order: usize) {
+        // ensure the target node is still attached
+        match &self {
+            PlaceSnippet::Before(node) | PlaceSnippet::After(node) | PlaceSnippet::Over(node) => {
+                // node should still be in the tree, but if it isn't
+                // then it's okay to just ignore this place
+                if stdx::never!(node.parent().is_none()) {
+                    return;
+                }
+            }
+        }
+
+        match self {
+            PlaceSnippet::Before(node) => {
+                ted::insert_raw(ted::Position::before(&node), Self::make_tab_stop(order));
+            }
+            PlaceSnippet::After(node) => {
+                ted::insert_raw(ted::Position::after(&node), Self::make_tab_stop(order));
+            }
+            PlaceSnippet::Over(node) => {
+                let position = ted::Position::before(&node);
+                node.detach();
+
+                let snippet = ast::SourceFile::parse(&format!("${{{order}:_}}"))
+                    .syntax_node()
+                    .clone_for_update();
+
+                let placeholder =
+                    snippet.descendants().find_map(ast::UnderscoreExpr::cast).unwrap();
+                ted::replace(placeholder.syntax(), node);
+
+                ted::insert_raw(position, snippet);
+            }
+        }
+    }
+
+    fn make_tab_stop(order: usize) -> SyntaxNode {
+        let stop = ast::SourceFile::parse(&format!("stop!(${order})"))
+            .syntax_node()
+            .descendants()
+            .find_map(ast::TokenTree::cast)
+            .unwrap()
+            .syntax()
+            .clone_for_update();
+
+        stop.first_token().unwrap().detach();
+        stop.last_token().unwrap().detach();
+
+        stop
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index a91ffd1ec4f..b54c43b296b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -25,7 +25,6 @@ use std::{
     fmt,
     hash::{Hash, Hasher},
     mem,
-    sync::Arc,
 };
 
 use base_db::{
@@ -40,6 +39,7 @@ use hir::{
 };
 use rayon::prelude::*;
 use rustc_hash::FxHashSet;
+use triomphe::Arc;
 
 use crate::RootDatabase;
 
@@ -98,6 +98,10 @@ pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast<dyn HirDatab
     /// The symbol index for a given source root within library_roots.
     fn library_symbols(&self, source_root_id: SourceRootId) -> Arc<SymbolIndex>;
 
+    #[salsa::transparent]
+    /// The symbol indices of modules that make up a given crate.
+    fn crate_symbols(&self, krate: Crate) -> Box<[Arc<SymbolIndex>]>;
+
     /// The set of "local" (that is, from the current workspace) roots.
     /// Files in local roots are assumed to change frequently.
     #[salsa::input]
@@ -112,26 +116,33 @@ pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast<dyn HirDatab
 fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Arc<SymbolIndex> {
     let _p = profile::span("library_symbols");
 
-    // todo: this could be parallelized, once I figure out how to do that...
-    let symbols = db
-        .source_root_crates(source_root_id)
+    let mut symbol_collector = SymbolCollector::new(db.upcast());
+
+    db.source_root_crates(source_root_id)
         .iter()
         .flat_map(|&krate| Crate::from(krate).modules(db.upcast()))
-        // we specifically avoid calling SymbolsDatabase::module_symbols here, even they do the same thing,
+        // we specifically avoid calling other SymbolsDatabase queries here, even though 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.
-        .flat_map(|module| SymbolCollector::collect(db.upcast(), module))
-        .collect();
+        // the module or crate indices for those in salsa unless we need to.
+        .for_each(|module| symbol_collector.collect(module));
 
+    let mut symbols = symbol_collector.finish();
+    symbols.shrink_to_fit();
     Arc::new(SymbolIndex::new(symbols))
 }
 
 fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc<SymbolIndex> {
     let _p = profile::span("module_symbols");
-    let symbols = SymbolCollector::collect(db.upcast(), module);
+
+    let symbols = SymbolCollector::collect_module(db.upcast(), module);
     Arc::new(SymbolIndex::new(symbols))
 }
 
+pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc<SymbolIndex>]> {
+    let _p = profile::span("crate_symbols");
+    krate.modules(db.upcast()).into_iter().map(|module| db.module_symbols(module)).collect()
+}
+
 /// Need to wrap Snapshot to provide `Clone` impl for `map_with`
 struct Snap<DB>(DB);
 impl<DB: ParallelDatabase> Snap<salsa::Snapshot<DB>> {
@@ -187,36 +198,21 @@ 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 crates = 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));
-            }
+            crates.extend(db.source_root_crates(root).iter().copied())
         }
-
-        modules
-            .par_iter()
-            .map_with(Snap::new(db), |snap, &module| snap.module_symbols(module))
-            .collect()
+        let indices: Vec<_> = crates
+            .into_par_iter()
+            .map_with(Snap::new(db), |snap, krate| snap.crate_symbols(krate.into()))
+            .collect();
+        indices.iter().flat_map(|indices| indices.iter().cloned()).collect()
     };
 
     query.search(&indices)
 }
 
-pub fn crate_symbols(db: &RootDatabase, krate: Crate, query: Query) -> Vec<FileSymbol> {
-    let _p = profile::span("crate_symbols").detail(|| format!("{query:?}"));
-
-    let modules = krate.modules(db);
-    let indices: Vec<_> = modules
-        .par_iter()
-        .map_with(Snap::new(db), |snap, &module| snap.module_symbols(module))
-        .collect();
-
-    query.search(&indices)
-}
-
 #[derive(Default)]
 pub struct SymbolIndex {
     symbols: Vec<FileSymbol>,
@@ -274,7 +270,12 @@ impl SymbolIndex {
             builder.insert(key, value).unwrap();
         }
 
-        let map = fst::Map::new(builder.into_inner().unwrap()).unwrap();
+        let map = fst::Map::new({
+            let mut buf = builder.into_inner().unwrap();
+            buf.shrink_to_fit();
+            buf
+        })
+        .unwrap();
         SymbolIndex { symbols, map }
     }
 
@@ -316,7 +317,14 @@ impl Query {
                 let (start, end) = SymbolIndex::map_value_to_range(indexed_value.value);
 
                 for symbol in &symbol_index.symbols[start..end] {
-                    if self.only_types && !symbol.kind.is_type() {
+                    if self.only_types
+                        && !matches!(
+                            symbol.def,
+                            hir::ModuleDef::Adt(..)
+                                | hir::ModuleDef::TypeAlias(..)
+                                | hir::ModuleDef::BuiltinType(..)
+                        )
+                    {
                         continue;
                     }
                     if self.exact {
@@ -418,7 +426,7 @@ struct StructInModB;
             .modules(&db)
             .into_iter()
             .map(|module_id| {
-                let mut symbols = SymbolCollector::collect(&db, module_id);
+                let mut symbols = SymbolCollector::collect_module(&db, module_id);
                 symbols.sort_by_key(|it| it.name.clone());
                 (module_id, symbols)
             })
@@ -426,4 +434,31 @@ struct StructInModB;
 
         expect_file!["./test_data/test_symbol_index_collection.txt"].assert_debug_eq(&symbols);
     }
+
+    #[test]
+    fn test_doc_alias() {
+        let (db, _) = RootDatabase::with_single_file(
+            r#"
+#[doc(alias="s1")]
+#[doc(alias="s2")]
+#[doc(alias("mul1","mul2"))]
+struct Struct;
+
+#[doc(alias="s1")]
+struct Duplicate;
+        "#,
+        );
+
+        let symbols: Vec<_> = Crate::from(db.test_crate())
+            .modules(&db)
+            .into_iter()
+            .map(|module_id| {
+                let mut symbols = SymbolCollector::collect_module(&db, module_id);
+                symbols.sort_by_key(|it| it.name.clone());
+                (module_id, symbols)
+            })
+            .collect();
+
+        expect_file!["./test_data/test_doc_alias.txt"].assert_debug_eq(&symbols);
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs
index 2d6927cee99..acf0a67de4a 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs
@@ -92,7 +92,7 @@ pub fn lex_format_specifiers(
                 let (_, second) = cloned.next().unwrap_or_default();
                 match second {
                     '<' | '^' | '>' => {
-                        // alignment specifier, first char specifies fillment
+                        // alignment specifier, first char specifies fill
                         skip_char_and_emit(&mut chars, FormatSpecifier::Fill, &mut callback);
                         skip_char_and_emit(&mut chars, FormatSpecifier::Align, &mut callback);
                     }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
index fcef71fb74e..fc230818193 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
@@ -1,7 +1,7 @@
 //! Tools to work with expressions present in format string literals for the `format_args!` family of macros.
 //! Primarily meant for assists and completions.
 
-/// Enum for represenging extraced format string args.
+/// Enum for representing extracted format string args.
 /// Can either be extracted expressions (which includes identifiers),
 /// or placeholders `{}`.
 #[derive(Debug, PartialEq, Eq)]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
index 8bc093a85a2..0b0fc669352 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs
@@ -60,7 +60,9 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode {
             |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };
 
         match tok.kind() {
-            k if is_text(k) && is_next(|it| !it.is_punct() || it == UNDERSCORE, false) => {
+            k if is_text(k)
+                && is_next(|it| !it.is_punct() || matches!(it, T![_] | T![#]), false) =>
+            {
                 mods.push(do_ws(after, tok));
             }
             L_CURLY if is_next(|it| it != R_CURLY, true) => {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
index a34dc1b6950..22ced69d81e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -52,7 +52,9 @@ pub fn preorder_expr(start: &ast::Expr, cb: &mut dyn FnMut(WalkEvent<ast::Expr>)
             }
         };
         if let Some(let_stmt) = node.parent().and_then(ast::LetStmt::cast) {
-            if Some(node.clone()) != let_stmt.initializer().map(|it| it.syntax().clone()) {
+            if let_stmt.initializer().map(|it| it.syntax() != &node).unwrap_or(true)
+                && let_stmt.let_else().map(|it| it.syntax() != &node).unwrap_or(true)
+            {
                 // skipping potential const pat expressions in  let statements
                 preorder.skip_subtree();
                 continue;
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
new file mode 100644
index 00000000000..77714efa350
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
@@ -0,0 +1,202 @@
+[
+    (
+        Module {
+            id: ModuleId {
+                krate: Idx::<CrateData>(0),
+                block: None,
+                local_id: Idx::<ModuleData>(0),
+            },
+        },
+        [
+            FileSymbol {
+                name: "Duplicate",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                1,
+                            ),
+                        },
+                    ),
+                ),
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        0,
+                    ),
+                    ptr: SyntaxNodePtr {
+                        kind: STRUCT,
+                        range: 83..119,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        kind: NAME,
+                        range: 109..118,
+                    },
+                },
+                container_name: None,
+                is_alias: false,
+            },
+            FileSymbol {
+                name: "Struct",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                0,
+                            ),
+                        },
+                    ),
+                ),
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        0,
+                    ),
+                    ptr: SyntaxNodePtr {
+                        kind: STRUCT,
+                        range: 0..81,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        kind: NAME,
+                        range: 74..80,
+                    },
+                },
+                container_name: None,
+                is_alias: false,
+            },
+            FileSymbol {
+                name: "mul1",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                0,
+                            ),
+                        },
+                    ),
+                ),
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        0,
+                    ),
+                    ptr: SyntaxNodePtr {
+                        kind: STRUCT,
+                        range: 0..81,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        kind: NAME,
+                        range: 74..80,
+                    },
+                },
+                container_name: None,
+                is_alias: true,
+            },
+            FileSymbol {
+                name: "mul2",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                0,
+                            ),
+                        },
+                    ),
+                ),
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        0,
+                    ),
+                    ptr: SyntaxNodePtr {
+                        kind: STRUCT,
+                        range: 0..81,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        kind: NAME,
+                        range: 74..80,
+                    },
+                },
+                container_name: None,
+                is_alias: true,
+            },
+            FileSymbol {
+                name: "s1",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                0,
+                            ),
+                        },
+                    ),
+                ),
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        0,
+                    ),
+                    ptr: SyntaxNodePtr {
+                        kind: STRUCT,
+                        range: 0..81,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        kind: NAME,
+                        range: 74..80,
+                    },
+                },
+                container_name: None,
+                is_alias: true,
+            },
+            FileSymbol {
+                name: "s1",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                1,
+                            ),
+                        },
+                    ),
+                ),
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        0,
+                    ),
+                    ptr: SyntaxNodePtr {
+                        kind: STRUCT,
+                        range: 83..119,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        kind: NAME,
+                        range: 109..118,
+                    },
+                },
+                container_name: None,
+                is_alias: true,
+            },
+            FileSymbol {
+                name: "s2",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                0,
+                            ),
+                        },
+                    ),
+                ),
+                loc: DeclarationLocation {
+                    hir_file_id: HirFileId(
+                        0,
+                    ),
+                    ptr: SyntaxNodePtr {
+                        kind: STRUCT,
+                        range: 0..81,
+                    },
+                    name_ptr: SyntaxNodePtr {
+                        kind: NAME,
+                        range: 74..80,
+                    },
+                },
+                container_name: None,
+                is_alias: true,
+            },
+        ],
+    ),
+]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index 8c11408dec5..b5adfc13d96 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -2,9 +2,7 @@
     (
         Module {
             id: ModuleId {
-                krate: CrateId(
-                    0,
-                ),
+                krate: Idx::<CrateData>(0),
                 block: None,
                 local_id: Idx::<ModuleData>(0),
             },
@@ -12,6 +10,13 @@
         [
             FileSymbol {
                 name: "Alias",
+                def: TypeAlias(
+                    TypeAlias {
+                        id: TypeAliasId(
+                            0,
+                        ),
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -25,11 +30,18 @@
                         range: 402..407,
                     },
                 },
-                kind: TypeAlias,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "CONST",
+                def: Const(
+                    Const {
+                        id: ConstId(
+                            0,
+                        ),
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -43,11 +55,18 @@
                         range: 346..351,
                     },
                 },
-                kind: Const,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "CONST_WITH_INNER",
+                def: Const(
+                    Const {
+                        id: ConstId(
+                            2,
+                        ),
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -61,11 +80,20 @@
                         range: 526..542,
                     },
                 },
-                kind: Const,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "Enum",
+                def: Adt(
+                    Enum(
+                        Enum {
+                            id: EnumId(
+                                0,
+                            ),
+                        },
+                    ),
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -79,11 +107,20 @@
                         range: 190..194,
                     },
                 },
-                kind: Enum,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "Macro",
+                def: Macro(
+                    Macro {
+                        id: Macro2Id(
+                            Macro2Id(
+                                0,
+                            ),
+                        ),
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -97,11 +134,18 @@
                         range: 159..164,
                     },
                 },
-                kind: Macro,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "STATIC",
+                def: Static(
+                    Static {
+                        id: StaticId(
+                            0,
+                        ),
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -115,11 +159,20 @@
                         range: 369..375,
                     },
                 },
-                kind: Static,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "Struct",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                1,
+                            ),
+                        },
+                    ),
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -133,11 +186,20 @@
                         range: 177..183,
                     },
                 },
-                kind: Struct,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "StructFromMacro",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                0,
+                            ),
+                        },
+                    ),
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         2147483648,
@@ -151,11 +213,20 @@
                         range: 6..21,
                     },
                 },
-                kind: Struct,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "StructInFn",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                4,
+                            ),
+                        },
+                    ),
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -169,13 +240,22 @@
                         range: 325..335,
                     },
                 },
-                kind: Struct,
                 container_name: Some(
                     "main",
                 ),
+                is_alias: false,
             },
             FileSymbol {
                 name: "StructInNamedConst",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                5,
+                            ),
+                        },
+                    ),
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -189,13 +269,22 @@
                         range: 562..580,
                     },
                 },
-                kind: Struct,
                 container_name: Some(
                     "CONST_WITH_INNER",
                 ),
+                is_alias: false,
             },
             FileSymbol {
                 name: "StructInUnnamedConst",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                6,
+                            ),
+                        },
+                    ),
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -209,11 +298,18 @@
                         range: 486..506,
                     },
                 },
-                kind: Struct,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "Trait",
+                def: Trait(
+                    Trait {
+                        id: TraitId(
+                            0,
+                        ),
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -227,11 +323,20 @@
                         range: 267..272,
                     },
                 },
-                kind: Trait,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "Union",
+                def: Adt(
+                    Union(
+                        Union {
+                            id: UnionId(
+                                0,
+                            ),
+                        },
+                    ),
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -245,11 +350,20 @@
                         range: 214..219,
                     },
                 },
-                kind: Union,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "a_mod",
+                def: Module(
+                    Module {
+                        id: ModuleId {
+                            krate: Idx::<CrateData>(0),
+                            block: None,
+                            local_id: Idx::<ModuleData>(1),
+                        },
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -263,11 +377,20 @@
                         range: 423..428,
                     },
                 },
-                kind: Module,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "b_mod",
+                def: Module(
+                    Module {
+                        id: ModuleId {
+                            krate: Idx::<CrateData>(0),
+                            block: None,
+                            local_id: Idx::<ModuleData>(2),
+                        },
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -281,11 +404,20 @@
                         range: 598..603,
                     },
                 },
-                kind: Module,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "define_struct",
+                def: Macro(
+                    Macro {
+                        id: MacroRulesId(
+                            MacroRulesId(
+                                1,
+                            ),
+                        ),
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -299,11 +431,18 @@
                         range: 64..77,
                     },
                 },
-                kind: Macro,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "impl_fn",
+                def: Function(
+                    Function {
+                        id: FunctionId(
+                            2,
+                        ),
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -317,11 +456,20 @@
                         range: 245..252,
                     },
                 },
-                kind: Function,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "macro_rules_macro",
+                def: Macro(
+                    Macro {
+                        id: MacroRulesId(
+                            MacroRulesId(
+                                0,
+                            ),
+                        ),
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -335,11 +483,18 @@
                         range: 14..31,
                     },
                 },
-                kind: Macro,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "main",
+                def: Function(
+                    Function {
+                        id: FunctionId(
+                            0,
+                        ),
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -353,11 +508,18 @@
                         range: 305..309,
                     },
                 },
-                kind: Function,
                 container_name: None,
+                is_alias: false,
             },
             FileSymbol {
                 name: "trait_fn",
+                def: Function(
+                    Function {
+                        id: FunctionId(
+                            1,
+                        ),
+                    },
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -371,19 +533,17 @@
                         range: 282..290,
                     },
                 },
-                kind: Function,
                 container_name: Some(
                     "Trait",
                 ),
+                is_alias: false,
             },
         ],
     ),
     (
         Module {
             id: ModuleId {
-                krate: CrateId(
-                    0,
-                ),
+                krate: Idx::<CrateData>(0),
                 block: None,
                 local_id: Idx::<ModuleData>(1),
             },
@@ -391,6 +551,15 @@
         [
             FileSymbol {
                 name: "StructInModA",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                2,
+                            ),
+                        },
+                    ),
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         0,
@@ -404,17 +573,15 @@
                         range: 442..454,
                     },
                 },
-                kind: Struct,
                 container_name: None,
+                is_alias: false,
             },
         ],
     ),
     (
         Module {
             id: ModuleId {
-                krate: CrateId(
-                    0,
-                ),
+                krate: Idx::<CrateData>(0),
                 block: None,
                 local_id: Idx::<ModuleData>(2),
             },
@@ -422,6 +589,15 @@
         [
             FileSymbol {
                 name: "StructInModB",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                3,
+                            ),
+                        },
+                    ),
+                ),
                 loc: DeclarationLocation {
                     hir_file_id: HirFileId(
                         1,
@@ -435,8 +611,8 @@
                         range: 7..19,
                     },
                 },
-                kind: Struct,
                 container_name: None,
+                is_alias: false,
             },
         ],
     ),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/tests/line_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/tests/line_index.rs
new file mode 100644
index 00000000000..6b49bb2631c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-db/src/tests/line_index.rs
@@ -0,0 +1,49 @@
+use line_index::{LineCol, LineIndex, WideEncoding};
+use test_utils::skip_slow_tests;
+
+#[test]
+fn test_every_chars() {
+    if skip_slow_tests() {
+        return;
+    }
+
+    let text: String = {
+        let mut chars: Vec<char> = ((0 as char)..char::MAX).collect(); // Neat!
+        chars.extend("\n".repeat(chars.len() / 16).chars());
+        let mut rng = oorandom::Rand32::new(stdx::rand::seed());
+        stdx::rand::shuffle(&mut chars, |i| rng.rand_range(0..i as u32) as usize);
+        chars.into_iter().collect()
+    };
+    assert!(text.contains('💩')); // Sanity check.
+
+    let line_index = LineIndex::new(&text);
+
+    let mut lin_col = LineCol { line: 0, col: 0 };
+    let mut col_utf16 = 0;
+    let mut col_utf32 = 0;
+    for (offset, c) in text.char_indices() {
+        let got_offset = line_index.offset(lin_col).unwrap();
+        assert_eq!(usize::from(got_offset), offset);
+
+        let got_lin_col = line_index.line_col(got_offset);
+        assert_eq!(got_lin_col, lin_col);
+
+        for (enc, col) in [(WideEncoding::Utf16, col_utf16), (WideEncoding::Utf32, col_utf32)] {
+            let wide_lin_col = line_index.to_wide(enc, lin_col).unwrap();
+            let got_lin_col = line_index.to_utf8(enc, wide_lin_col).unwrap();
+            assert_eq!(got_lin_col, lin_col);
+            assert_eq!(wide_lin_col.col, col)
+        }
+
+        if c == '\n' {
+            lin_col.line += 1;
+            lin_col.col = 0;
+            col_utf16 = 0;
+            col_utf32 = 0;
+        } else {
+            lin_col.col += c.len_utf8() as u32;
+            col_utf16 += c.len_utf16() as u32;
+            col_utf32 += 1;
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
index 6a7ea7c19f2..9abbc344142 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
@@ -38,15 +38,15 @@ pub fn get_missing_assoc_items(
     for item in imp.items(sema.db) {
         match item {
             hir::AssocItem::Function(it) => {
-                impl_fns_consts.insert(it.name(sema.db).to_string());
+                impl_fns_consts.insert(it.name(sema.db).display(sema.db).to_string());
             }
             hir::AssocItem::Const(it) => {
                 if let Some(name) = it.name(sema.db) {
-                    impl_fns_consts.insert(name.to_string());
+                    impl_fns_consts.insert(name.display(sema.db).to_string());
                 }
             }
             hir::AssocItem::TypeAlias(it) => {
-                impl_type.insert(it.name(sema.db).to_string());
+                impl_type.insert(it.name(sema.db).display(sema.db).to_string());
             }
         }
     }
@@ -57,12 +57,14 @@ pub fn get_missing_assoc_items(
             .into_iter()
             .filter(|i| match i {
                 hir::AssocItem::Function(f) => {
-                    !impl_fns_consts.contains(&f.name(sema.db).to_string())
+                    !impl_fns_consts.contains(&f.name(sema.db).display(sema.db).to_string())
+                }
+                hir::AssocItem::TypeAlias(t) => {
+                    !impl_type.contains(&t.name(sema.db).display(sema.db).to_string())
                 }
-                hir::AssocItem::TypeAlias(t) => !impl_type.contains(&t.name(sema.db).to_string()),
                 hir::AssocItem::Const(c) => c
                     .name(sema.db)
-                    .map(|n| !impl_fns_consts.contains(&n.to_string()))
+                    .map(|n| !impl_fns_consts.contains(&n.display(sema.db).to_string()))
                     .unwrap_or_default(),
             })
             .collect()
@@ -137,7 +139,7 @@ mod tests {
             sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap();
         let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block);
         let actual = match trait_ {
-            Some(trait_) => trait_.name(&db).to_string(),
+            Some(trait_) => trait_.name(&db).display(&db).to_string(),
             None => String::new(),
         };
         expect.assert_eq(&actual);
@@ -152,7 +154,7 @@ mod tests {
         let items = crate::traits::get_missing_assoc_items(&sema, &impl_block);
         let actual = items
             .into_iter()
-            .map(|item| item.name(&db).unwrap().to_string())
+            .map(|item| item.name(&db).unwrap().display(&db).to_string())
             .collect::<Vec<_>>()
             .join("\n");
         expect.assert_eq(&actual);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
index 39431bed382..f96ea29ae2f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs
@@ -1,9 +1,9 @@
-//! Functionality for generating trivial contructors
+//! Functionality for generating trivial constructors
 
 use hir::StructKind;
 use syntax::ast;
 
-/// given a type return the trivial contructor (if one exists)
+/// given a type return the trivial constructor (if one exists)
 pub fn use_trivial_constructor(
     db: &crate::RootDatabase,
     path: ast::Path,