diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 236487d8e52..7857edb521a 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1327,14 +1327,14 @@ impl<'a> SemanticsScope<'a> { resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()), - resolver::ScopeDef::Local(pat_id) => { - let parent = self.resolver.body_owner().unwrap(); - ScopeDef::Local(Local { parent, pat_id }) - } - resolver::ScopeDef::Label(label_id) => { - let parent = self.resolver.body_owner().unwrap(); - ScopeDef::Label(Label { parent, label_id }) - } + resolver::ScopeDef::Local(pat_id) => match self.resolver.body_owner() { + Some(parent) => ScopeDef::Local(Local { parent, pat_id }), + None => continue, + }, + resolver::ScopeDef::Label(label_id) => match self.resolver.body_owner() { + Some(parent) => ScopeDef::Label(Label { parent, label_id }), + None => continue, + }, }; f(name.clone(), def) } diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index 72856a1bfe7..b8c88282d67 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs @@ -1,5 +1,5 @@ //! Name resolution façade. -use std::sync::Arc; +use std::{hash::BuildHasherDefault, sync::Arc}; use base_db::CrateId; use hir_expand::name::{name, Name}; @@ -343,7 +343,7 @@ impl Resolver { /// Returns a set of names available in the current scope. /// /// Note that this is a somewhat fuzzy concept -- internally, the compiler - /// doesn't necessary follow a strict scoping discipline. Rathe, it just + /// doesn't necessary follow a strict scoping discipline. Rather, it just /// tells for each ident what it resolves to. /// /// A good example is something like `str::from_utf8`. From scopes point of @@ -378,10 +378,13 @@ impl Resolver { /// The result is ordered *roughly* from the innermost scope to the /// outermost: when the name is introduced in two namespaces in two scopes, /// we use the position of the first scope. - pub fn names_in_scope(&self, db: &dyn DefDatabase) -> IndexMap> { + pub fn names_in_scope( + &self, + db: &dyn DefDatabase, + ) -> FxIndexMap> { let mut res = ScopeNames::default(); for scope in self.scopes() { - scope.process_names(db, &mut res); + scope.process_names(&mut res, db); } res.map } @@ -466,7 +469,7 @@ impl Resolver { } } -#[derive(Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ScopeDef { ModuleDef(ModuleDefId), Unknown, @@ -478,7 +481,7 @@ pub enum ScopeDef { } impl Scope { - fn process_names(&self, db: &dyn DefDatabase, acc: &mut ScopeNames) { + fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) { match self { Scope::ModuleScope(m) => { // FIXME: should we provide `self` here? @@ -691,9 +694,10 @@ fn to_type_ns(per_ns: PerNs) -> Option { Some(res) } +type FxIndexMap = IndexMap>; #[derive(Default)] struct ScopeNames { - map: IndexMap>, + map: FxIndexMap>, } impl ScopeNames { diff --git a/crates/ide_completion/src/completions/lifetime.rs b/crates/ide_completion/src/completions/lifetime.rs index b8a50442bc6..4fffd1aa0c4 100644 --- a/crates/ide_completion/src/completions/lifetime.rs +++ b/crates/ide_completion/src/completions/lifetime.rs @@ -30,7 +30,7 @@ pub(crate) fn complete_lifetime(acc: &mut Completions, ctx: &CompletionContext) let param_lifetime = param_lifetime.as_ref().map(ast::Lifetime::text); let param_lifetime = param_lifetime.as_ref().map(TokenText::as_str); - ctx.scope.process_all_names(&mut |name, res| { + ctx.process_all_names_raw(&mut |name, res| { if matches!( res, ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) @@ -49,7 +49,7 @@ pub(crate) fn complete_label(acc: &mut Completions, ctx: &CompletionContext) { if !matches!(ctx.lifetime_ctx, Some(LifetimeContext::LabelRef)) { return; } - ctx.scope.process_all_names(&mut |name, res| { + ctx.process_all_names_raw(&mut |name, res| { if let ScopeDef::Label(_) = res { acc.add_label(ctx, name); } diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index a203ebd45a0..ba664a29dae 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs @@ -12,7 +12,7 @@ use ide_db::{ famous_defs::FamousDefs, RootDatabase, }; -use rustc_hash::FxHashSet; +use rustc_hash::{FxHashMap, FxHashSet}; use syntax::{ algo::{find_node_at_offset, non_trivia_sibling}, ast::{self, AttrKind, HasName, NameOrNameRef}, @@ -146,7 +146,7 @@ pub(crate) struct CompletionContext<'a> { pub(super) existing_derives: FxHashSet, - pub(super) locals: Vec<(Name, Local)>, + pub(super) locals: FxHashMap, } impl<'a> CompletionContext<'a> { @@ -293,6 +293,10 @@ impl<'a> CompletionContext<'a> { self.path_context.as_ref().and_then(|it| it.kind) } + pub(crate) fn is_immediately_after_macro_bang(&self) -> bool { + self.token.kind() == BANG && self.token.parent().map_or(false, |it| it.kind() == MACRO_CALL) + } + /// Checks if an item is visible and not `doc(hidden)` at the completion site. pub(crate) fn is_visible(&self, item: &I) -> Visible where @@ -318,11 +322,6 @@ impl<'a> CompletionContext<'a> { _ => false, } } - - pub(crate) fn is_immediately_after_macro_bang(&self) -> bool { - self.token.kind() == BANG && self.token.parent().map_or(false, |it| it.kind() == MACRO_CALL) - } - /// Whether the given trait is an operator trait or not. pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool { match trait_.attrs(self.db).lang() { @@ -340,7 +339,12 @@ impl<'a> CompletionContext<'a> { } f(name, def); - }) + }); + } + + pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) { + let _p = profile::span("CompletionContext::process_all_names_raw"); + self.scope.process_all_names(&mut |name, def| f(name, def)); } fn is_visible_impl( @@ -372,16 +376,11 @@ impl<'a> CompletionContext<'a> { } fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool { - let krate = match self.krate { - Some(it) => it, - None => return true, - }; - if krate != defining_crate && attrs.has_doc_hidden() { + match self.krate { // `doc(hidden)` items are only completed within the defining crate. - return true; + Some(krate) => krate != defining_crate && attrs.has_doc_hidden(), + None => true, } - - false } } @@ -413,10 +412,10 @@ impl<'a> CompletionContext<'a> { let scope = sema.scope_at_offset(&token.parent()?, offset); let krate = scope.krate(); let module = scope.module(); - let mut locals = vec![]; + let mut locals = FxHashMap::default(); scope.process_all_names(&mut |name, scope| { if let ScopeDef::Local(local) = scope { - locals.push((name, local)); + locals.insert(name, local); } });