summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/ide-db
diff options
context:
space:
mode:
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.rs39
-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.rs167
-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.rs35
-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.txt216
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt372
-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, 1183 insertions, 604 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
index 57daaf623..4e75dc4db 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 ea1d9cc49..0dd544d0a 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,15 @@
//! Applies changes to the IDE state transactionally.
-use std::sync::Arc;
-
use base_db::{
- salsa::{Database, Durability},
+ salsa::{
+ debug::{DebugQueryTable, TableEntry},
+ Database, Durability, Query, QueryTable,
+ },
Change, SourceRootId,
};
use profile::{memory_usage, Bytes};
use rustc_hash::FxHashSet;
+use triomphe::Arc;
use crate::{symbol_index::SymbolsDatabase, RootDatabase};
@@ -48,22 +50,44 @@ impl RootDatabase {
// | VS Code | **rust-analyzer: Memory Usage (Clears Database)**
// |===
// image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[]
- pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> {
- let mut acc: Vec<(String, Bytes)> = vec![];
+ pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes, usize)> {
+ let mut acc: Vec<(String, Bytes, usize)> = vec![];
+
+ fn collect_query_count<'q, Q>(table: &QueryTable<'q, Q>) -> usize
+ where
+ QueryTable<'q, Q>: DebugQueryTable,
+ Q: Query,
+ <Q as Query>::Storage: 'q,
+ {
+ struct EntryCounter(usize);
+ impl<K, V> FromIterator<TableEntry<K, V>> for EntryCounter {
+ fn from_iter<T>(iter: T) -> EntryCounter
+ where
+ T: IntoIterator<Item = TableEntry<K, V>>,
+ {
+ EntryCounter(iter.into_iter().count())
+ }
+ }
+ table.entries::<EntryCounter>().0
+ }
+
macro_rules! purge_each_query {
($($q:path)*) => {$(
let before = memory_usage().allocated;
- $q.in_db(self).purge();
+ let table = $q.in_db(self);
+ let count = collect_query_count(&table);
+ table.purge();
let after = memory_usage().allocated;
let q: $q = Default::default();
let name = format!("{:?}", q);
- acc.push((name, before - after));
+ acc.push((name, before - after, count));
)*}
}
purge_each_query![
// SourceDatabase
base_db::ParseQuery
base_db::CrateGraphQuery
+ base_db::ProcMacrosQuery
// SourceDatabaseExt
base_db::FileTextQuery
@@ -79,7 +103,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 8c6c1c44a..7a7328f31 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 4071c490b..760834bfa 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 f0c369096..e488300b4 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 8e3b1eef1..eba9d8afc 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 b26b0a908..901d592c6 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 07a57c883..46f1353e2 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 b1df11bf9..ff1a20f03 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 16814a1e6..000000000
--- 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 6402a84a6..73e6a920e 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
@@ -9,6 +9,19 @@ use syntax::{
ted, SyntaxNode,
};
+#[derive(Default)]
+struct AstSubsts {
+ types_and_consts: Vec<TypeOrConst>,
+ lifetimes: Vec<ast::LifetimeArg>,
+}
+
+enum TypeOrConst {
+ Either(ast::TypeArg), // indistinguishable type or const param
+ Const(ast::ConstArg),
+}
+
+type LifetimeName = String;
+
/// `PathTransform` substitutes path in SyntaxNodes in bulk.
///
/// This is mostly useful for IDE code generation. If you paste some existing
@@ -34,7 +47,7 @@ use syntax::{
/// ```
pub struct PathTransform<'a> {
generic_def: Option<hir::GenericDef>,
- substs: Vec<ast::Type>,
+ substs: AstSubsts,
target_scope: &'a SemanticsScope<'a>,
source_scope: &'a SemanticsScope<'a>,
}
@@ -72,7 +85,12 @@ impl<'a> PathTransform<'a> {
target_scope: &'a SemanticsScope<'a>,
source_scope: &'a SemanticsScope<'a>,
) -> PathTransform<'a> {
- PathTransform { source_scope, target_scope, generic_def: None, substs: Vec::new() }
+ PathTransform {
+ source_scope,
+ target_scope,
+ generic_def: None,
+ substs: AstSubsts::default(),
+ }
}
pub fn apply(&self, syntax: &SyntaxNode) {
@@ -91,12 +109,14 @@ impl<'a> PathTransform<'a> {
let target_module = self.target_scope.module();
let source_module = self.source_scope.module();
let skip = match self.generic_def {
- // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
+ // this is a trait impl, so we need to skip the first type parameter (i.e. Self) -- this is a bit hacky
Some(hir::GenericDef::Trait(_)) => 1,
_ => 0,
};
- let substs_by_param: FxHashMap<_, _> = self
- .generic_def
+ let mut type_substs: FxHashMap<hir::TypeParam, ast::Type> = Default::default();
+ let mut const_substs: FxHashMap<hir::ConstParam, SyntaxNode> = Default::default();
+ let mut default_types: Vec<hir::TypeParam> = Default::default();
+ self.generic_def
.into_iter()
.flat_map(|it| it.type_params(db))
.skip(skip)
@@ -106,51 +126,105 @@ impl<'a> PathTransform<'a> {
// can still hit those trailing values and check if they actually have
// a default type. If they do, go for that type from `hir` to `ast` so
// the resulting change can be applied correctly.
- .zip(self.substs.iter().map(Some).chain(std::iter::repeat(None)))
- .filter_map(|(k, v)| match k.split(db) {
- Either::Left(_) => None,
- Either::Right(t) => match v {
- Some(v) => Some((k, v.clone())),
- None => {
- let default = t.default(db)?;
- Some((
- k,
- ast::make::ty(
- &default.display_source_code(db, source_module.into()).ok()?,
- ),
- ))
+ .zip(self.substs.types_and_consts.iter().map(Some).chain(std::iter::repeat(None)))
+ .for_each(|(k, v)| match (k.split(db), v) {
+ (Either::Right(k), Some(TypeOrConst::Either(v))) => {
+ if let Some(ty) = v.ty() {
+ type_substs.insert(k, ty.clone());
+ }
+ }
+ (Either::Right(k), None) => {
+ if let Some(default) = k.default(db) {
+ if let Some(default) =
+ &default.display_source_code(db, source_module.into(), false).ok()
+ {
+ type_substs.insert(k, ast::make::ty(default).clone_for_update());
+ default_types.push(k);
+ }
+ }
+ }
+ (Either::Left(k), Some(TypeOrConst::Either(v))) => {
+ if let Some(ty) = v.ty() {
+ const_substs.insert(k, ty.syntax().clone());
}
- },
- })
+ }
+ (Either::Left(k), Some(TypeOrConst::Const(v))) => {
+ if let Some(expr) = v.expr() {
+ // FIXME: expressions in curly brackets can cause ambiguity after insertion
+ // (e.g. `N * 2` -> `{1 + 1} * 2`; it's unclear whether `{1 + 1}`
+ // is a standalone statement or a part of another expresson)
+ // and sometimes require slight modifications; see
+ // https://doc.rust-lang.org/reference/statements.html#expression-statements
+ const_substs.insert(k, expr.syntax().clone());
+ }
+ }
+ (Either::Left(_), None) => (), // FIXME: get default const value
+ _ => (), // ignore mismatching params
+ });
+ let lifetime_substs: FxHashMap<_, _> = self
+ .generic_def
+ .into_iter()
+ .flat_map(|it| it.lifetime_params(db))
+ .zip(self.substs.lifetimes.clone())
+ .filter_map(|(k, v)| Some((k.name(db).display(db.upcast()).to_string(), v.lifetime()?)))
.collect();
- Ctx { substs: substs_by_param, target_module, source_scope: self.source_scope }
+ let ctx = Ctx {
+ type_substs,
+ const_substs,
+ lifetime_substs,
+ target_module,
+ source_scope: self.source_scope,
+ };
+ ctx.transform_default_type_substs(default_types);
+ ctx
}
}
struct Ctx<'a> {
- substs: FxHashMap<hir::TypeOrConstParam, ast::Type>,
+ type_substs: FxHashMap<hir::TypeParam, ast::Type>,
+ const_substs: FxHashMap<hir::ConstParam, SyntaxNode>,
+ lifetime_substs: FxHashMap<LifetimeName, ast::Lifetime>,
target_module: hir::Module,
source_scope: &'a SemanticsScope<'a>,
}
+fn postorder(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
+ item.preorder().filter_map(|event| match event {
+ syntax::WalkEvent::Enter(_) => None,
+ syntax::WalkEvent::Leave(node) => Some(node),
+ })
+}
+
impl<'a> Ctx<'a> {
fn apply(&self, item: &SyntaxNode) {
// `transform_path` may update a node's parent and that would break the
// tree traversal. Thus all paths in the tree are collected into a vec
// so that such operation is safe.
- let paths = item
- .preorder()
- .filter_map(|event| match event {
- syntax::WalkEvent::Enter(_) => None,
- syntax::WalkEvent::Leave(node) => Some(node),
- })
- .filter_map(ast::Path::cast)
- .collect::<Vec<_>>();
-
+ let paths = postorder(item).filter_map(ast::Path::cast).collect::<Vec<_>>();
for path in paths {
self.transform_path(path);
}
+
+ postorder(item).filter_map(ast::Lifetime::cast).for_each(|lifetime| {
+ if let Some(subst) = self.lifetime_substs.get(&lifetime.syntax().text().to_string()) {
+ ted::replace(lifetime.syntax(), subst.clone_subtree().clone_for_update().syntax());
+ }
+ });
}
+
+ fn transform_default_type_substs(&self, default_types: Vec<hir::TypeParam>) {
+ for k in default_types {
+ let v = self.type_substs.get(&k).unwrap();
+ // `transform_path` may update a node's parent and that would break the
+ // tree traversal. Thus all paths in the tree are collected into a vec
+ // so that such operation is safe.
+ let paths = postorder(&v.syntax()).filter_map(ast::Path::cast).collect::<Vec<_>>();
+ for path in paths {
+ self.transform_path(path);
+ }
+ }
+ }
+
fn transform_path(&self, path: ast::Path) -> Option<()> {
if path.qualifier().is_some() {
return None;
@@ -167,7 +241,7 @@ impl<'a> Ctx<'a> {
match resolution {
hir::PathResolution::TypeParam(tp) => {
- if let Some(subst) = self.substs.get(&tp.merge()) {
+ if let Some(subst) = self.type_substs.get(&tp) {
let parent = path.syntax().parent()?;
if let Some(parent) = ast::Path::cast(parent.clone()) {
// Path inside path means that there is an associated
@@ -234,8 +308,12 @@ impl<'a> Ctx<'a> {
}
ted::replace(path.syntax(), res.syntax())
}
+ hir::PathResolution::ConstParam(cp) => {
+ if let Some(subst) = self.const_substs.get(&cp) {
+ ted::replace(path.syntax(), subst.clone_subtree().clone_for_update());
+ }
+ }
hir::PathResolution::Local(_)
- | hir::PathResolution::ConstParam(_)
| hir::PathResolution::SelfType(_)
| hir::PathResolution::Def(_)
| hir::PathResolution::BuiltinAttr(_)
@@ -248,7 +326,7 @@ impl<'a> Ctx<'a> {
// FIXME: It would probably be nicer if we could get this via HIR (i.e. get the
// trait ref, and then go from the types in the substs back to the syntax).
-fn get_syntactic_substs(impl_def: ast::Impl) -> Option<Vec<ast::Type>> {
+fn get_syntactic_substs(impl_def: ast::Impl) -> Option<AstSubsts> {
let target_trait = impl_def.trait_()?;
let path_type = match target_trait {
ast::Type::PathType(path) => path,
@@ -259,13 +337,22 @@ fn get_syntactic_substs(impl_def: ast::Impl) -> Option<Vec<ast::Type>> {
get_type_args_from_arg_list(generic_arg_list)
}
-fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option<Vec<ast::Type>> {
- let mut result = Vec::new();
- for generic_arg in generic_arg_list.generic_args() {
- if let ast::GenericArg::TypeArg(type_arg) = generic_arg {
- result.push(type_arg.ty()?)
+fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option<AstSubsts> {
+ let mut result = AstSubsts::default();
+ generic_arg_list.generic_args().for_each(|generic_arg| match generic_arg {
+ // Const params are marked as consts on definition only,
+ // being passed to the trait they are indistguishable from type params;
+ // anyway, we don't really need to distinguish them here.
+ ast::GenericArg::TypeArg(type_arg) => {
+ result.types_and_consts.push(TypeOrConst::Either(type_arg))
}
- }
+ // Some const values are recognized correctly.
+ ast::GenericArg::ConstArg(const_arg) => {
+ result.types_and_consts.push(TypeOrConst::Const(const_arg));
+ }
+ ast::GenericArg::LifetimeArg(l_arg) => result.lifetimes.push(l_arg),
+ _ => (),
+ });
Some(result)
}
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 f710211c8..52a23b4b8 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 12f5e4e2a..e8ff107bd 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());
}
}
@@ -242,6 +243,8 @@ impl Definition {
DefWithBody::Const(c) => c.source(db).map(|src| src.syntax().cloned()),
DefWithBody::Static(s) => s.source(db).map(|src| src.syntax().cloned()),
DefWithBody::Variant(v) => v.source(db).map(|src| src.syntax().cloned()),
+ // FIXME: implement
+ DefWithBody::InTypeConst(_) => return SearchScope::empty(),
};
return match def {
Some(def) => SearchScope::file_range(def.as_ref().original_file_range_full(db)),
@@ -391,7 +394,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 +441,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 +502,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 +556,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 936354f29..061fb0f05 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 a91ffd1ec..b54c43b29 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 2d6927cee..acf0a67de 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 fcef71fb7..fc2308181 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 8bc093a85..0b0fc6693 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 a34dc1b69..22ced69d8 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 000000000..7834c6603
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
@@ -0,0 +1,216 @@
+[
+ (
+ 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: FileId(
+ FileId(
+ 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: FileId(
+ FileId(
+ 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: FileId(
+ FileId(
+ 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: FileId(
+ FileId(
+ 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: FileId(
+ FileId(
+ 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: FileId(
+ FileId(
+ 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: FileId(
+ FileId(
+ 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 8c11408de..1a00e2938 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,9 +10,18 @@
[
FileSymbol {
name: "Alias",
+ def: TypeAlias(
+ TypeAlias {
+ id: TypeAliasId(
+ 0,
+ ),
+ },
+ ),
loc: DeclarationLocation {
- hir_file_id: HirFileId(
- 0,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: TYPE_ALIAS,
@@ -25,14 +32,23 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: CONST,
@@ -43,14 +59,23 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: CONST,
@@ -61,14 +86,25 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: ENUM,
@@ -79,14 +115,25 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: MACRO_DEF,
@@ -97,14 +144,23 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: STATIC,
@@ -115,14 +171,25 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: STRUCT,
@@ -133,14 +200,27 @@
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,
+ hir_file_id: MacroFile(
+ MacroFile {
+ macro_call_id: MacroCallId(
+ 0,
+ ),
+ },
),
ptr: SyntaxNodePtr {
kind: STRUCT,
@@ -151,14 +231,25 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: STRUCT,
@@ -169,16 +260,27 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: STRUCT,
@@ -189,16 +291,27 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: STRUCT,
@@ -209,14 +322,23 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: TRAIT,
@@ -227,14 +349,25 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: UNION,
@@ -245,14 +378,25 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: MODULE,
@@ -263,14 +407,25 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: MODULE,
@@ -281,14 +436,25 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: MACRO_RULES,
@@ -299,14 +465,23 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: FN,
@@ -317,14 +492,25 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: MACRO_RULES,
@@ -335,14 +521,23 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: FN,
@@ -353,14 +548,23 @@
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,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: FN,
@@ -371,19 +575,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,9 +593,20 @@
[
FileSymbol {
name: "StructInModA",
+ def: Adt(
+ Struct(
+ Struct {
+ id: StructId(
+ 2,
+ ),
+ },
+ ),
+ ),
loc: DeclarationLocation {
- hir_file_id: HirFileId(
- 0,
+ hir_file_id: FileId(
+ FileId(
+ 0,
+ ),
),
ptr: SyntaxNodePtr {
kind: STRUCT,
@@ -404,17 +617,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,9 +633,20 @@
[
FileSymbol {
name: "StructInModB",
+ def: Adt(
+ Struct(
+ Struct {
+ id: StructId(
+ 3,
+ ),
+ },
+ ),
+ ),
loc: DeclarationLocation {
- hir_file_id: HirFileId(
- 1,
+ hir_file_id: FileId(
+ FileId(
+ 1,
+ ),
),
ptr: SyntaxNodePtr {
kind: STRUCT,
@@ -435,8 +657,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 000000000..6b49bb263
--- /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 6a7ea7c19..9abbc3441 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 39431bed3..f96ea29ae 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,