Unnamed repository; edit this file 'description' to name the repository.
internal: Simplify some completions
Lukas Wirth 2022-06-21
parent 8b07898 · commit 7a0774d
-rw-r--r--crates/hir/src/semantics.rs10
-rw-r--r--crates/ide-completion/src/completions.rs40
-rw-r--r--crates/ide-completion/src/completions/dot.rs2
-rw-r--r--crates/ide-completion/src/completions/expr.rs111
-rw-r--r--crates/ide-completion/src/completions/pattern.rs66
-rw-r--r--crates/ide-completion/src/completions/record.rs48
-rw-r--r--crates/ide-completion/src/completions/snippet.rs12
-rw-r--r--crates/ide-completion/src/completions/type.rs39
-rw-r--r--crates/ide-completion/src/context.rs28
-rw-r--r--crates/ide-completion/src/lib.rs6
-rw-r--r--crates/ide-completion/src/tests/pattern.rs5
11 files changed, 146 insertions, 221 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 592e7d3b97..aa10b0f878 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -2,7 +2,7 @@
mod source_to_def;
-use std::{cell::RefCell, fmt, iter};
+use std::{cell::RefCell, fmt, iter, ops};
use base_db::{FileId, FileRange};
use hir_def::{
@@ -1449,3 +1449,11 @@ impl<'a> SemanticsScope<'a> {
}
pub struct VisibleTraits(pub FxHashSet<TraitId>);
+
+impl ops::Deref for VisibleTraits {
+ type Target = FxHashSet<TraitId>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 147563ef10..81bb59681b 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -36,7 +36,7 @@ use crate::{
const_::render_const,
function::{render_fn, render_method},
literal::{render_struct_literal, render_variant_lit},
- macro_::{render_macro, render_macro_pat},
+ macro_::render_macro,
pattern::{render_struct_pat, render_variant_pat},
render_field, render_path_resolution, render_pattern_resolution, render_tuple_field,
type_alias::{render_type_alias, render_type_alias_with_eq},
@@ -101,15 +101,15 @@ impl Completions {
pub(crate) fn add_keyword_snippet_expr(
&mut self,
ctx: &CompletionContext,
+ incomplete_let: bool,
kw: &str,
snippet: &str,
- incomplete_let: bool,
) {
let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw);
match ctx.config.snippet_cap {
Some(cap) => {
- if snippet.ends_with('}') && incomplete_let {
+ if incomplete_let && snippet.ends_with('}') {
// complete block expression snippets with a trailing semicolon, if inside an incomplete let
cov_mark::hit!(let_semi);
item.insert_snippet(cap, format!("{};", snippet));
@@ -181,6 +181,17 @@ impl Completions {
);
}
+ pub(crate) fn add_enum_variants(
+ &mut self,
+ ctx: &CompletionContext,
+ path_ctx: &PathCompletionCtx,
+ e: hir::Enum,
+ ) {
+ e.variants(ctx.db)
+ .into_iter()
+ .for_each(|variant| self.add_enum_variant(ctx, path_ctx, variant, None));
+ }
+
pub(crate) fn add_module(
&mut self,
ctx: &CompletionContext,
@@ -219,29 +230,6 @@ impl Completions {
);
}
- pub(crate) fn add_macro_pat(
- &mut self,
- ctx: &CompletionContext,
- pattern_ctx: &PatternContext,
- mac: hir::Macro,
- local_name: hir::Name,
- ) {
- let is_private_editable = match ctx.is_visible(&mac) {
- Visible::Yes => false,
- Visible::Editable => true,
- Visible::No => return,
- };
- self.add(
- render_macro_pat(
- RenderContext::new(ctx).private_editable(is_private_editable),
- pattern_ctx,
- local_name,
- mac,
- )
- .build(),
- );
- }
-
pub(crate) fn add_function(
&mut self,
ctx: &CompletionContext,
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index bf0bce2198..911ef60930 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -121,7 +121,7 @@ fn complete_methods(
receiver.iterate_method_candidates(
ctx.db,
&ctx.scope,
- &ctx.traits_in_scope().0,
+ &ctx.traits_in_scope(),
Some(ctx.module),
None,
|func| {
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index 6b36801205..058d0ab7bb 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -1,7 +1,6 @@
//! Completion of names from the current scope in expression position.
use hir::ScopeDef;
-use ide_db::FxHashSet;
use crate::{
context::{ExprCtx, PathCompletionCtx, Qualified},
@@ -33,24 +32,24 @@ pub(crate) fn complete_expr_path(
let wants_mut_token =
ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
- let scope_def_applicable = |def| {
- match def {
- ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => {
- false
- }
- // Don't suggest attribute macros and derives.
- ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
- _ => true,
- }
+ let scope_def_applicable = |def| match def {
+ ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false,
+ ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
+ _ => true,
+ };
+
+ let add_assoc_item = |acc: &mut Completions, item| match item {
+ hir::AssocItem::Function(func) => acc.add_function(ctx, path_ctx, func, None),
+ hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
+ hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
};
match qualified {
Qualified::Infer => ctx
.traits_in_scope()
- .0
- .into_iter()
- .flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
- .for_each(|item| add_assoc_item(acc, ctx, path_ctx, item)),
+ .iter()
+ .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
+ .for_each(|item| add_assoc_item(acc, item)),
Qualified::With { resolution: None, .. } => {}
Qualified::With { resolution: Some(resolution), .. } => {
// Add associated types on type parameters and `Self`.
@@ -67,46 +66,32 @@ pub(crate) fn complete_expr_path(
}
}
}
-
hir::PathResolution::Def(
def @ (hir::ModuleDef::Adt(_)
| hir::ModuleDef::TypeAlias(_)
| hir::ModuleDef::BuiltinType(_)),
) => {
- if let &hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
- add_enum_variants(acc, ctx, path_ctx, e);
- }
let ty = match def {
hir::ModuleDef::Adt(adt) => adt.ty(ctx.db),
- hir::ModuleDef::TypeAlias(a) => {
- let ty = a.ty(ctx.db);
- if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
- cov_mark::hit!(completes_variant_through_alias);
- add_enum_variants(acc, ctx, path_ctx, e);
- }
- ty
- }
+ hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db),
hir::ModuleDef::BuiltinType(builtin) => {
cov_mark::hit!(completes_primitive_assoc_const);
builtin.ty(ctx.db)
}
- _ => unreachable!(),
+ _ => return,
};
+ if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+ cov_mark::hit!(completes_variant_through_alias);
+ acc.add_enum_variants(ctx, path_ctx, e);
+ }
+
// XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
// (where AssocType is defined on a trait, not an inherent impl)
- ty.iterate_path_candidates(
- ctx.db,
- &ctx.scope,
- &ctx.traits_in_scope().0,
- Some(ctx.module),
- None,
- |item| {
- add_assoc_item(acc, ctx, path_ctx, item);
- None::<()>
- },
- );
+ ctx.iterate_path_candidates(&ty, |item| {
+ add_assoc_item(acc, item);
+ });
// Iterate assoc types separately
ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
@@ -119,7 +104,7 @@ pub(crate) fn complete_expr_path(
hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
// Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
for item in t.items(ctx.db) {
- add_assoc_item(acc, ctx, path_ctx, item);
+ add_assoc_item(acc, item);
}
}
hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
@@ -130,24 +115,12 @@ pub(crate) fn complete_expr_path(
};
if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
- add_enum_variants(acc, ctx, path_ctx, e);
+ acc.add_enum_variants(ctx, path_ctx, e);
}
- let mut seen = FxHashSet::default();
- ty.iterate_path_candidates(
- ctx.db,
- &ctx.scope,
- &ctx.traits_in_scope().0,
- Some(ctx.module),
- None,
- |item| {
- // We might iterate candidates of a trait multiple times here, so deduplicate
- // them.
- if seen.insert(item) {
- add_assoc_item(acc, ctx, path_ctx, item);
- }
- None::<()>
- },
- );
+
+ ctx.iterate_path_candidates(&ty, |item| {
+ add_assoc_item(acc, item);
+ });
}
_ => (),
}
@@ -212,7 +185,7 @@ pub(crate) fn complete_expr_path(
if is_func_update.is_none() {
let mut add_keyword =
- |kw, snippet| acc.add_keyword_snippet_expr(ctx, kw, snippet, incomplete_let);
+ |kw, snippet| acc.add_keyword_snippet_expr(ctx, incomplete_let, kw, snippet);
if !in_block_expr {
add_keyword("unsafe", "unsafe {\n $0\n}");
@@ -265,27 +238,3 @@ pub(crate) fn complete_expr_path(
}
}
}
-
-fn add_assoc_item(
- acc: &mut Completions,
- ctx: &CompletionContext,
- path_ctx: &PathCompletionCtx,
- item: hir::AssocItem,
-) {
- match item {
- hir::AssocItem::Function(func) => acc.add_function(ctx, path_ctx, func, None),
- hir::AssocItem::Const(ct) => acc.add_const(ctx, ct),
- hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty),
- }
-}
-
-fn add_enum_variants(
- acc: &mut Completions,
- ctx: &CompletionContext,
- path_ctx: &PathCompletionCtx,
- e: hir::Enum,
-) {
- e.variants(ctx.db)
- .into_iter()
- .for_each(|variant| acc.add_enum_variant(ctx, path_ctx, variant, None));
-}
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index 4ea80a5077..7a344c2c7b 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -1,7 +1,6 @@
//! Completes constants and paths in unqualified patterns.
use hir::{db::DefDatabase, AssocItem, ScopeDef};
-use ide_db::FxHashSet;
use syntax::ast::Pat;
use crate::{
@@ -81,9 +80,7 @@ pub(crate) fn complete_pattern(
hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
hir::ModuleDef::Const(..) => refutable,
hir::ModuleDef::Module(..) => true,
- hir::ModuleDef::Macro(mac) if mac.is_fn_like(ctx.db) => {
- return acc.add_macro_pat(ctx, pattern_ctx, mac, name);
- }
+ hir::ModuleDef::Macro(mac) => mac.is_fn_like(ctx.db),
_ => false,
},
hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() {
@@ -136,12 +133,7 @@ pub(crate) fn complete_pattern_path(
}
}
}
- res @ (hir::PathResolution::TypeParam(_)
- | hir::PathResolution::SelfType(_)
- | hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Struct(_)))
- | hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(_)))
- | hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(_)))
- | hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_))) => {
+ res => {
let ty = match res {
hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
@@ -149,10 +141,6 @@ pub(crate) fn complete_pattern_path(
s.ty(ctx.db)
}
hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
- cov_mark::hit!(enum_plain_qualified_use_tree);
- e.variants(ctx.db).into_iter().for_each(|variant| {
- acc.add_enum_variant(ctx, path_ctx, variant, None)
- });
e.ty(ctx.db)
}
hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(u))) => {
@@ -162,41 +150,33 @@ pub(crate) fn complete_pattern_path(
_ => return,
};
- let mut seen = FxHashSet::default();
- ty.iterate_path_candidates(
- ctx.db,
- &ctx.scope,
- &ctx.scope.visible_traits().0,
- Some(ctx.module),
- None,
- |item| {
- match item {
- AssocItem::TypeAlias(ta) => {
- // We might iterate candidates of a trait multiple times here, so deduplicate them.
- if seen.insert(item) {
- acc.add_type_alias(ctx, ta);
- }
- }
- AssocItem::Const(c) => {
- if seen.insert(item) {
- acc.add_const(ctx, c);
- }
- }
- _ => {}
- }
- None::<()>
- },
- );
+ if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+ cov_mark::hit!(enum_plain_qualified_use_tree);
+ acc.add_enum_variants(ctx, path_ctx, e);
+ }
+
+ ctx.iterate_path_candidates(&ty, |item| match item {
+ AssocItem::TypeAlias(ta) => acc.add_type_alias(ctx, ta),
+ AssocItem::Const(c) => acc.add_const(ctx, c),
+ _ => {}
+ });
}
- _ => {}
}
}
- // qualifier can only be none here if we are in a TuplePat or RecordPat in which case special characters have to follow the path
Qualified::Absolute => acc.add_crate_roots(ctx, path_ctx),
Qualified::No => {
+ // this will only be hit if there are brackets or braces, otherwise this will be parsed as an ident pattern
ctx.process_all_names(&mut |name, res| {
- // FIXME: properly filter here
- if let ScopeDef::ModuleDef(_) = res {
+ // FIXME: we should check what kind of pattern we are in and filter accordingly
+ let add_completion = match res {
+ ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => mac.is_fn_like(ctx.db),
+ ScopeDef::ModuleDef(hir::ModuleDef::Adt(_)) => true,
+ ScopeDef::ModuleDef(hir::ModuleDef::Variant(_)) => true,
+ ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
+ ScopeDef::ImplSelfType(_) => true,
+ _ => false,
+ };
+ if add_completion {
acc.add_path_resolution(ctx, path_ctx, name, res);
}
});
diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs
index 8cef3a7018..9f5922c5b0 100644
--- a/crates/ide-completion/src/completions/record.rs
+++ b/crates/ide-completion/src/completions/record.rs
@@ -17,6 +17,7 @@ pub(crate) fn complete_record_pattern_fields(
complete_fields(acc, ctx, ctx.sema.record_pattern_missing_fields(record_pat));
}
}
+
pub(crate) fn complete_record_expr_fields(
acc: &mut Completions,
ctx: &CompletionContext,
@@ -41,7 +42,6 @@ pub(crate) fn complete_record_expr_fields(
}
_ => {
let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
-
add_default_update(acc, ctx, ty, &missing_fields);
if dot_prefix {
let mut item =
@@ -56,6 +56,29 @@ pub(crate) fn complete_record_expr_fields(
complete_fields(acc, ctx, missing_fields);
}
+// FIXME: This should probably be part of complete_path_expr
+pub(crate) fn complete_record_expr_func_update(
+ acc: &mut Completions,
+ ctx: &CompletionContext,
+ path_ctx: &PathCompletionCtx,
+ expr_ctx: &ExprCtx,
+) {
+ if !matches!(path_ctx.qualified, Qualified::No) {
+ return;
+ }
+ if let ExprCtx { is_func_update: Some(record_expr), .. } = expr_ctx {
+ let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
+
+ match ty.as_ref().and_then(|t| t.original.as_adt()) {
+ Some(hir::Adt::Union(_)) => (),
+ _ => {
+ let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
+ add_default_update(acc, ctx, ty, &missing_fields);
+ }
+ };
+ }
+}
+
fn add_default_update(
acc: &mut Completions,
ctx: &CompletionContext,
@@ -67,6 +90,7 @@ fn add_default_update(
.zip(ty.as_ref())
.map_or(false, |(default_trait, ty)| ty.original.impls_trait(ctx.db, default_trait, &[]));
if impl_default_trait && !missing_fields.is_empty() {
+ // FIXME: This should make use of scope_def like completions so we get all the other goodies
let completion_text = "..Default::default()";
let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
let completion_text =
@@ -79,28 +103,6 @@ fn add_default_update(
}
}
-pub(crate) fn complete_record_expr_func_update(
- acc: &mut Completions,
- ctx: &CompletionContext,
- path_ctx: &PathCompletionCtx,
- expr_ctx: &ExprCtx,
-) {
- if !matches!(path_ctx.qualified, Qualified::No) {
- return;
- }
- if let ExprCtx { is_func_update: Some(record_expr), .. } = expr_ctx {
- let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
-
- match ty.as_ref().and_then(|t| t.original.as_adt()) {
- Some(hir::Adt::Union(_)) => (),
- _ => {
- let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
- add_default_update(acc, ctx, ty, &missing_fields);
- }
- };
- }
-}
-
fn complete_fields(
acc: &mut Completions,
ctx: &CompletionContext,
diff --git a/crates/ide-completion/src/completions/snippet.rs b/crates/ide-completion/src/completions/snippet.rs
index 9992a81fe0..a530f4262e 100644
--- a/crates/ide-completion/src/completions/snippet.rs
+++ b/crates/ide-completion/src/completions/snippet.rs
@@ -9,12 +9,6 @@ use crate::{
CompletionContext, CompletionItem, CompletionItemKind, Completions, SnippetScope,
};
-fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
- let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
- item.insert_snippet(cap, snippet);
- item
-}
-
pub(crate) fn complete_expr_snippet(
acc: &mut Completions,
ctx: &CompletionContext,
@@ -124,6 +118,12 @@ macro_rules! $1 {
}
}
+fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
+ let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
+ item.insert_snippet(cap, snippet);
+ item
+}
+
fn add_custom_completions(
acc: &mut Completions,
ctx: &CompletionContext,
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index c5b65d36ae..616d862154 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -1,7 +1,6 @@
//! Completion of names from the current scope in type position.
use hir::{HirDisplay, ScopeDef};
-use ide_db::FxHashSet;
use syntax::{ast, AstNode};
use crate::{
@@ -52,9 +51,8 @@ pub(crate) fn complete_type_path(
match qualified {
Qualified::Infer => ctx
.traits_in_scope()
- .0
- .into_iter()
- .flat_map(|it| hir::Trait::from(it).items(ctx.sema.db))
+ .iter()
+ .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
.for_each(|item| add_assoc_item(acc, item)),
Qualified::With { resolution: None, .. } => {}
Qualified::With { resolution: Some(resolution), .. } => {
@@ -88,17 +86,9 @@ pub(crate) fn complete_type_path(
// XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
// (where AssocType is defined on a trait, not an inherent impl)
- ty.iterate_path_candidates(
- ctx.db,
- &ctx.scope,
- &ctx.traits_in_scope().0,
- Some(ctx.module),
- None,
- |item| {
- add_assoc_item(acc, item);
- None::<()>
- },
- );
+ ctx.iterate_path_candidates(&ty, |item| {
+ add_assoc_item(acc, item);
+ });
// Iterate assoc types separately
ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
@@ -121,22 +111,9 @@ pub(crate) fn complete_type_path(
_ => return,
};
- let mut seen = FxHashSet::default();
- ty.iterate_path_candidates(
- ctx.db,
- &ctx.scope,
- &ctx.traits_in_scope().0,
- Some(ctx.module),
- None,
- |item| {
- // We might iterate candidates of a trait multiple times here, so deduplicate
- // them.
- if seen.insert(item) {
- add_assoc_item(acc, item);
- }
- None::<()>
- },
- );
+ ctx.iterate_path_candidates(&ty, |item| {
+ add_assoc_item(acc, item);
+ });
}
_ => (),
}
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 8ea03358ae..01a2f96fd1 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -371,7 +371,9 @@ impl<'a> CompletionContext<'a> {
where
I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
{
- self.is_visible_impl(&item.visibility(self.db), &item.attrs(self.db), item.krate(self.db))
+ let vis = item.visibility(self.db);
+ let attrs = item.attrs(self.db);
+ self.is_visible_impl(&vis, &attrs, item.krate(self.db))
}
pub(crate) fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool {
@@ -391,6 +393,7 @@ impl<'a> CompletionContext<'a> {
_ => false,
}
}
+
/// 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() {
@@ -408,6 +411,29 @@ impl<'a> CompletionContext<'a> {
traits_in_scope
}
+ pub(crate) fn iterate_path_candidates(
+ &self,
+ ty: &hir::Type,
+ mut cb: impl FnMut(hir::AssocItem),
+ ) {
+ let mut seen = FxHashSet::default();
+ ty.iterate_path_candidates(
+ self.db,
+ &self.scope,
+ &self.traits_in_scope(),
+ Some(self.module),
+ None,
+ |item| {
+ // We might iterate candidates of a trait multiple times here, so deduplicate
+ // them.
+ if seen.insert(item) {
+ cb(item)
+ }
+ None::<()>
+ },
+ );
+ }
+
/// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
let _p = profile::span("CompletionContext::process_all_names");
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index fe02f05fd1..b806d955d9 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -148,7 +148,7 @@ pub fn completions(
config: &CompletionConfig,
position: FilePosition,
trigger_character: Option<char>,
-) -> Option<Completions> {
+) -> Option<Vec<CompletionItem>> {
let (ctx, analysis) = &CompletionContext::new(db, position, config)?;
let mut completions = Completions::default();
@@ -163,7 +163,7 @@ pub fn completions(
}
}
// prevent `(` from triggering unwanted completion noise
- return Some(completions);
+ return Some(completions.into());
}
{
@@ -197,7 +197,7 @@ pub fn completions(
}
}
- Some(completions)
+ Some(completions.into())
}
/// Resolves additional completion data at the position given.
diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs
index 8953f1b2fd..7169209d81 100644
--- a/crates/ide-completion/src/tests/pattern.rs
+++ b/crates/ide-completion/src/tests/pattern.rs
@@ -399,7 +399,6 @@ fn foo() {
#[test]
fn completes_no_delims_if_existing() {
- // FIXME: We should not complete functions here
check_empty(
r#"
struct Bar(u32);
@@ -410,9 +409,7 @@ fn foo() {
}
"#,
expect![[r#"
- fn foo fn()
st Bar
- bt u32
kw crate::
kw self::
kw super::
@@ -428,9 +425,7 @@ fn foo() {
}
"#,
expect![[r#"
- fn foo fn()
st Foo
- bt u32
kw crate::
kw self::
kw super::