Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide/src/inlay_hints.rs27
-rw-r--r--crates/ide_completion/src/completions.rs90
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs2
-rw-r--r--crates/ide_completion/src/completions/pattern.rs28
-rw-r--r--crates/ide_completion/src/completions/record.rs9
-rw-r--r--crates/ide_completion/src/context.rs3
-rw-r--r--crates/ide_completion/src/render.rs88
-rw-r--r--crates/ide_completion/src/render/enum_variant.rs101
-rw-r--r--crates/ide_completion/src/render/function.rs28
-rw-r--r--crates/ide_completion/src/render/literal.rs174
-rw-r--r--crates/ide_completion/src/render/macro_.rs18
-rw-r--r--crates/ide_completion/src/render/pattern.rs102
-rw-r--r--crates/ide_completion/src/render/struct_literal.rs91
-rw-r--r--crates/ide_completion/src/render/union_literal.rs7
-rw-r--r--crates/ide_completion/src/render/variant.rs (renamed from crates/ide_completion/src/render/compound.rs)36
-rw-r--r--crates/ide_completion/src/tests/pattern.rs68
-rw-r--r--crates/ide_completion/src/tests/record.rs2
17 files changed, 498 insertions, 376 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 322a9b820a..428b8d1109 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -69,24 +69,17 @@ pub(crate) fn inlay_hints(
let mut hints = Vec::new();
- if let Some(range_limit) = range_limit {
- let range_limit = range_limit.range;
- match file.covering_element(range_limit) {
+ let get_hints = |node| get_hints(&mut hints, &sema, config, node);
+ match range_limit {
+ Some(FileRange { range, .. }) => match file.covering_element(range) {
NodeOrToken::Token(_) => return hints,
- NodeOrToken::Node(n) => {
- for node in n
- .descendants()
- .filter(|descendant| range_limit.contains_range(descendant.text_range()))
- {
- get_hints(&mut hints, &sema, config, node);
- }
- }
- }
- } else {
- for node in file.descendants() {
- get_hints(&mut hints, &sema, config, node);
- }
- }
+ NodeOrToken::Node(n) => n
+ .descendants()
+ .filter(|descendant| range.contains_range(descendant.text_range()))
+ .for_each(get_hints),
+ },
+ None => file.descendants().for_each(get_hints),
+ };
hints
}
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index 91e6b84294..867e6bcf48 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -29,11 +29,11 @@ use crate::{
item::Builder,
render::{
const_::render_const,
- enum_variant::render_variant,
function::{render_fn, render_method},
+ literal::{render_struct_literal, render_variant_lit},
+ macro_::render_macro,
pattern::{render_struct_pat, render_variant_pat},
- render_field, render_resolution, render_tuple_field,
- struct_literal::render_struct_literal,
+ render_field, render_resolution, render_resolution_simple, render_tuple_field,
type_alias::{render_type_alias, render_type_alias_with_eq},
union_literal::render_union_literal,
RenderContext,
@@ -124,7 +124,37 @@ impl Completions {
cov_mark::hit!(qualified_path_doc_hidden);
return;
}
- self.add(render_resolution(RenderContext::new(ctx, false), local_name, resolution));
+ self.add(render_resolution(RenderContext::new(ctx), local_name, resolution));
+ }
+
+ pub(crate) fn add_resolution_simple(
+ &mut self,
+ ctx: &CompletionContext,
+ local_name: hir::Name,
+ resolution: hir::ScopeDef,
+ ) {
+ if ctx.is_scope_def_hidden(resolution) {
+ return;
+ }
+ self.add(render_resolution_simple(RenderContext::new(ctx), local_name, resolution));
+ }
+
+ pub(crate) fn add_macro(
+ &mut self,
+ ctx: &CompletionContext,
+ 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(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ local_name,
+ mac,
+ ));
}
pub(crate) fn add_function(
@@ -138,7 +168,11 @@ impl Completions {
Visible::Editable => true,
Visible::No => return,
};
- self.add(render_fn(RenderContext::new(ctx, is_private_editable), None, local_name, func));
+ self.add(render_fn(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ local_name,
+ func,
+ ));
}
pub(crate) fn add_method(
@@ -154,8 +188,7 @@ impl Completions {
Visible::No => return,
};
self.add(render_method(
- RenderContext::new(ctx, is_private_editable),
- None,
+ RenderContext::new(ctx).private_editable(is_private_editable),
receiver,
local_name,
func,
@@ -168,7 +201,10 @@ impl Completions {
Visible::Editable => true,
Visible::No => return,
};
- self.add_opt(render_const(RenderContext::new(ctx, is_private_editable), konst));
+ self.add_opt(render_const(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ konst,
+ ));
}
pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
@@ -177,7 +213,10 @@ impl Completions {
Visible::Editable => true,
Visible::No => return,
};
- self.add_opt(render_type_alias(RenderContext::new(ctx, is_private_editable), type_alias));
+ self.add_opt(render_type_alias(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ type_alias,
+ ));
}
pub(crate) fn add_type_alias_with_eq(
@@ -185,7 +224,7 @@ impl Completions {
ctx: &CompletionContext,
type_alias: hir::TypeAlias,
) {
- self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx, false), type_alias));
+ self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias));
}
pub(crate) fn add_qualified_enum_variant(
@@ -194,8 +233,7 @@ impl Completions {
variant: hir::Variant,
path: hir::ModPath,
) {
- let item = render_variant(RenderContext::new(ctx, false), None, None, variant, Some(path));
- self.add(item);
+ self.add_opt(render_variant_lit(RenderContext::new(ctx), None, variant, Some(path)));
}
pub(crate) fn add_enum_variant(
@@ -204,8 +242,7 @@ impl Completions {
variant: hir::Variant,
local_name: Option<hir::Name>,
) {
- let item = render_variant(RenderContext::new(ctx, false), None, local_name, variant, None);
- self.add(item);
+ self.add_opt(render_variant_lit(RenderContext::new(ctx), local_name, variant, None));
}
pub(crate) fn add_field(
@@ -220,7 +257,12 @@ impl Completions {
Visible::Editable => true,
Visible::No => return,
};
- let item = render_field(RenderContext::new(ctx, is_private_editable), receiver, field, ty);
+ let item = render_field(
+ RenderContext::new(ctx).private_editable(is_private_editable),
+ receiver,
+ field,
+ ty,
+ );
self.add(item);
}
@@ -231,7 +273,7 @@ impl Completions {
path: Option<hir::ModPath>,
local_name: Option<hir::Name>,
) {
- let item = render_struct_literal(RenderContext::new(ctx, false), strukt, path, local_name);
+ let item = render_struct_literal(RenderContext::new(ctx), strukt, path, local_name);
self.add_opt(item);
}
@@ -242,7 +284,7 @@ impl Completions {
path: Option<hir::ModPath>,
local_name: Option<hir::Name>,
) {
- let item = render_union_literal(RenderContext::new(ctx, false), un, path, local_name);
+ let item = render_union_literal(RenderContext::new(ctx), un, path, local_name);
self.add_opt(item);
}
@@ -253,7 +295,7 @@ impl Completions {
field: usize,
ty: &hir::Type,
) {
- let item = render_tuple_field(RenderContext::new(ctx, false), receiver, field, ty);
+ let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty);
self.add(item);
}
@@ -272,7 +314,12 @@ impl Completions {
variant: hir::Variant,
local_name: Option<hir::Name>,
) {
- self.add_opt(render_variant_pat(RenderContext::new(ctx, false), variant, local_name, None));
+ self.add_opt(render_variant_pat(
+ RenderContext::new(ctx),
+ variant,
+ local_name.clone(),
+ None,
+ ));
}
pub(crate) fn add_qualified_variant_pat(
@@ -281,7 +328,8 @@ impl Completions {
variant: hir::Variant,
path: hir::ModPath,
) {
- self.add_opt(render_variant_pat(RenderContext::new(ctx, false), variant, None, Some(path)));
+ let path = Some(&path);
+ self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, path));
}
pub(crate) fn add_struct_pat(
@@ -290,7 +338,7 @@ impl Completions {
strukt: hir::Struct,
local_name: Option<hir::Name>,
) {
- self.add_opt(render_struct_pat(RenderContext::new(ctx, false), strukt, local_name));
+ self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name));
}
}
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index aee2bbb53c..6c8878a7bb 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -198,7 +198,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
})
.filter_map(|import| {
render_resolution_with_import(
- RenderContext::new(ctx, false),
+ RenderContext::new(ctx),
ImportEdit { import, scope: import_scope.clone() },
)
}),
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index 958c892b8d..6c17da07d6 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -54,8 +54,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
{
if refutable || single_variant_enum(e) {
super::enum_variants_with_paths(acc, ctx, e, |acc, ctx, variant, path| {
- acc.add_qualified_variant_pat(ctx, variant, path.clone());
- acc.add_qualified_enum_variant(ctx, variant, path);
+ acc.add_qualified_variant_pat(ctx, variant, path);
});
}
}
@@ -63,7 +62,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
// FIXME: ideally, we should look at the type we are matching against and
// suggest variants + auto-imports
ctx.process_all_names(&mut |name, res| {
- let add_resolution = match res {
+ let add_simple_path = match res {
hir::ScopeDef::ModuleDef(def) => match def {
hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => {
acc.add_struct_pat(ctx, strukt, Some(name.clone()));
@@ -76,8 +75,11 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
true
}
hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
- hir::ModuleDef::Const(..) | hir::ModuleDef::Module(..) => refutable,
- hir::ModuleDef::Macro(mac) => mac.is_fn_like(ctx.db),
+ hir::ModuleDef::Const(..) => refutable,
+ hir::ModuleDef::Module(..) => true,
+ hir::ModuleDef::Macro(mac) if mac.is_fn_like(ctx.db) => {
+ return acc.add_macro(ctx, mac, name)
+ }
_ => false,
},
hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() {
@@ -85,13 +87,19 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
acc.add_struct_pat(ctx, strukt, Some(name.clone()));
true
}
- Some(hir::Adt::Enum(_)) => refutable,
- _ => true,
+ Some(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
+ Some(hir::Adt::Union(_)) => true,
+ _ => false,
},
- _ => false,
+ ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => true,
+ ScopeDef::GenericParam(_)
+ | ScopeDef::AdtSelfType(_)
+ | ScopeDef::Local(_)
+ | ScopeDef::Label(_)
+ | ScopeDef::Unknown => false,
};
- if add_resolution {
- acc.add_resolution(ctx, name, res);
+ if add_simple_path {
+ acc.add_resolution_simple(ctx, name, res);
}
});
}
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs
index 264b3784bf..5509ec922f 100644
--- a/crates/ide_completion/src/completions/record.rs
+++ b/crates/ide_completion/src/completions/record.rs
@@ -84,13 +84,16 @@ pub(crate) fn complete_record_literal(
match ctx.expected_type.as_ref()?.as_adt()? {
hir::Adt::Struct(strukt) if ctx.path_qual().is_none() => {
let module = if let Some(module) = ctx.module { module } else { strukt.module(ctx.db) };
- let path = module.find_use_path(ctx.db, hir::ModuleDef::from(strukt));
+ let path = module
+ .find_use_path(ctx.db, hir::ModuleDef::from(strukt))
+ .filter(|it| it.len() > 1);
acc.add_struct_literal(ctx, strukt, path, None);
}
hir::Adt::Union(un) if ctx.path_qual().is_none() => {
let module = if let Some(module) = ctx.module { module } else { un.module(ctx.db) };
- let path = module.find_use_path(ctx.db, hir::ModuleDef::from(un));
+ let path =
+ module.find_use_path(ctx.db, hir::ModuleDef::from(un)).filter(|it| it.len() > 1);
acc.add_union_literal(ctx, un, path, None);
}
@@ -132,7 +135,7 @@ fn baz() {
#[test]
fn literal_struct_completion_from_sub_modules() {
check_edit(
- "Struct {…}",
+ "submod::Struct {…}",
r#"
mod submod {
pub struct Struct {
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 1ad233494a..ed59eb6bd3 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -58,7 +58,7 @@ pub(super) enum PathKind {
#[derive(Debug)]
pub(crate) struct PathCompletionCtx {
- /// If this is a call with () already there
+ /// If this is a call with () already there (or {} in case of record patterns)
pub(super) has_call_parens: bool,
/// Whether this path stars with a `::`.
pub(super) is_absolute_path: bool,
@@ -890,6 +890,7 @@ impl<'a> CompletionContext<'a> {
Some(PathKind::Pat)
},
ast::RecordPat(it) => {
+ path_ctx.has_call_parens = true;
pat_ctx = Some(pattern_context_for(original_file, it.into()));
Some(PathKind::Pat)
},
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 0ed346c55e..10211cd971 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -3,13 +3,12 @@
pub(crate) mod macro_;
pub(crate) mod function;
-pub(crate) mod enum_variant;
pub(crate) mod const_;
pub(crate) mod pattern;
pub(crate) mod type_alias;
-pub(crate) mod struct_literal;
-pub(crate) mod compound;
+pub(crate) mod variant;
pub(crate) mod union_literal;
+pub(crate) mod literal;
use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef};
use ide_db::{helpers::item_name, RootDatabase, SnippetCap, SymbolKind};
@@ -18,22 +17,30 @@ use syntax::{SmolStr, SyntaxKind, TextRange};
use crate::{
context::{PathCompletionCtx, PathKind},
item::{CompletionRelevanceTypeMatch, ImportEdit},
- render::{enum_variant::render_variant, function::render_fn, macro_::render_macro},
+ render::{function::render_fn, literal::render_variant_lit, macro_::render_macro},
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
};
/// Interface for data and methods required for items rendering.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub(crate) struct RenderContext<'a> {
completion: &'a CompletionContext<'a>,
is_private_editable: bool,
+ import_to_add: Option<ImportEdit>,
}
impl<'a> RenderContext<'a> {
- pub(crate) fn new(
- completion: &'a CompletionContext<'a>,
- is_private_editable: bool,
- ) -> RenderContext<'a> {
- RenderContext { completion, is_private_editable }
+ pub(crate) fn new(completion: &'a CompletionContext<'a>) -> RenderContext<'a> {
+ RenderContext { completion, is_private_editable: false, import_to_add: None }
+ }
+
+ pub(crate) fn private_editable(mut self, private_editable: bool) -> Self {
+ self.is_private_editable = private_editable;
+ self
+ }
+
+ pub(crate) fn import_to_add(mut self, import_to_add: Option<ImportEdit>) -> Self {
+ self.import_to_add = import_to_add;
+ self
}
fn snippet_cap(&self) -> Option<SnippetCap> {
@@ -139,6 +146,14 @@ pub(crate) fn render_resolution(
render_resolution_(ctx, local_name, None, resolution)
}
+pub(crate) fn render_resolution_simple(
+ ctx: RenderContext<'_>,
+ local_name: hir::Name,
+ resolution: ScopeDef,
+) -> CompletionItem {
+ render_resolution_simple_(ctx, local_name, None, resolution)
+}
+
pub(crate) fn render_resolution_with_import(
ctx: RenderContext<'_>,
import_edit: ImportEdit,
@@ -162,31 +177,42 @@ fn render_resolution_(
let _p = profile::span("render_resolution");
use hir::ModuleDef::*;
- let db = ctx.db();
-
- let kind = match resolution {
+ match resolution {
+ ScopeDef::ModuleDef(Macro(mac)) => {
+ let ctx = ctx.import_to_add(import_to_add);
+ return render_macro(ctx, local_name, mac);
+ }
ScopeDef::ModuleDef(Function(func)) => {
- return render_fn(ctx, import_to_add, Some(local_name), func);
+ let ctx = ctx.import_to_add(import_to_add);
+ return render_fn(ctx, Some(local_name), func);
}
ScopeDef::ModuleDef(Variant(var)) if ctx.completion.pattern_ctx.is_none() => {
- return render_variant(ctx, import_to_add, Some(local_name), var, None);
- }
- ScopeDef::ModuleDef(Macro(mac)) => {
- return render_macro(ctx, import_to_add, local_name, mac)
- }
- ScopeDef::Unknown => {
- let mut item = CompletionItem::new(
- CompletionItemKind::UnresolvedReference,
- ctx.source_range(),
- local_name.to_smol_str(),
- );
- if let Some(import_to_add) = import_to_add {
- item.add_import(import_to_add);
+ let ctx = ctx.clone().import_to_add(import_to_add.clone());
+ if let Some(item) = render_variant_lit(ctx, Some(local_name.clone()), var, None) {
+ return item;
}
- return item.build();
}
+ _ => (),
+ }
+ render_resolution_simple_(ctx, local_name, import_to_add, resolution)
+}
+
+fn render_resolution_simple_(
+ ctx: RenderContext<'_>,
+ local_name: hir::Name,
+ import_to_add: Option<ImportEdit>,
+ resolution: ScopeDef,
+) -> CompletionItem {
+ let _p = profile::span("render_resolution");
+ use hir::ModuleDef::*;
+ let db = ctx.db();
+ let ctx = ctx.import_to_add(import_to_add);
+ let kind = match resolution {
+ ScopeDef::Unknown => CompletionItemKind::UnresolvedReference,
+ ScopeDef::ModuleDef(Function(_)) => CompletionItemKind::SymbolKind(SymbolKind::Function),
ScopeDef::ModuleDef(Variant(_)) => CompletionItemKind::SymbolKind(SymbolKind::Variant),
+ ScopeDef::ModuleDef(Macro(_)) => CompletionItemKind::SymbolKind(SymbolKind::Macro),
ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
hir::Adt::Struct(_) => SymbolKind::Struct,
@@ -253,7 +279,7 @@ fn render_resolution_(
item.set_documentation(scope_def_docs(db, resolution))
.set_deprecated(scope_def_is_deprecated(&ctx, resolution));
- if let Some(import_to_add) = import_to_add {
+ if let Some(import_to_add) = ctx.import_to_add {
item.add_import(import_to_add);
}
item.build()
@@ -577,7 +603,7 @@ fn main() { let _: m::Spam = S$0 }
kind: SymbolKind(
Variant,
),
- lookup: "Spam::Bar",
+ lookup: "Spam::Bar(…)",
detail: "m::Spam::Bar(i32)",
relevance: CompletionRelevance {
exact_name_match: false,
@@ -1156,6 +1182,7 @@ fn main() {
"#,
expect![[r#"
lc s [type+name+local]
+ st S [type]
st S []
fn main() []
fn foo(…) []
@@ -1172,6 +1199,7 @@ fn main() {
"#,
expect![[r#"
lc ssss [type+local]
+ st S [type]
st S []
fn main() []
fn foo(…) []
diff --git a/crates/ide_completion/src/render/enum_variant.rs b/crates/ide_completion/src/render/enum_variant.rs
deleted file mode 100644
index 5b485005d3..0000000000
--- a/crates/ide_completion/src/render/enum_variant.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-//! Renderer for `enum` variants.
-
-use hir::{HasAttrs, StructKind};
-use ide_db::SymbolKind;
-use syntax::SmolStr;
-
-use crate::{
- item::{CompletionItem, ImportEdit},
- render::{
- compound::{format_literal_label, render_record, render_tuple, RenderedCompound},
- compute_ref_match, compute_type_match, RenderContext,
- },
- CompletionRelevance,
-};
-
-pub(crate) fn render_variant(
- ctx: RenderContext<'_>,
- import_to_add: Option<ImportEdit>,
- local_name: Option<hir::Name>,
- variant: hir::Variant,
- path: Option<hir::ModPath>,
-) -> CompletionItem {
- let _p = profile::span("render_enum_variant");
- render(ctx, local_name, variant, path, import_to_add)
-}
-
-fn render(
- ctx @ RenderContext { completion, .. }: RenderContext<'_>,
- local_name: Option<hir::Name>,
- variant: hir::Variant,
- path: Option<hir::ModPath>,
- import_to_add: Option<ImportEdit>,
-) -> CompletionItem {
- let db = completion.db;
- let name = local_name.unwrap_or_else(|| variant.name(db));
- let variant_kind = variant.kind(db);
-
- let (qualified_name, short_qualified_name, qualified) = match path {
- Some(path) => {
- let short = hir::ModPath::from_segments(
- hir::PathKind::Plain,
- path.segments().iter().skip(path.segments().len().saturating_sub(2)).cloned(),
- );
- (path, short, true)
- }
- None => (name.clone().into(), name.into(), false),
- };
- let qualified_name = qualified_name.to_string();
- let short_qualified_name: SmolStr = short_qualified_name.to_string().into();
-
- let mut rendered = match variant_kind {
- StructKind::Tuple => {
- render_tuple(db, ctx.snippet_cap(), &variant.fields(db), Some(&qualified_name))
- }
- StructKind::Record => {
- render_record(db, ctx.snippet_cap(), &variant.fields(db), Some(&qualified_name))
- }
- StructKind::Unit => {
- RenderedCompound { literal: qualified_name.clone(), detail: qualified_name.clone() }
- }
- };
-
- if ctx.snippet_cap().is_some() {
- rendered.literal.push_str("$0");
- }
-
- let mut item = CompletionItem::new(
- SymbolKind::Variant,
- ctx.source_range(),
- format_literal_label(&qualified_name, variant_kind),
- );
-
- item.set_documentation(variant.docs(db))
- .set_deprecated(ctx.is_deprecated(variant))
- .detail(rendered.detail);
-
- match ctx.snippet_cap() {
- Some(snippet_cap) => item.insert_snippet(snippet_cap, rendered.literal),
- None => item.insert_text(rendered.literal),
- };
-
- if let Some(import_to_add) = import_to_add {
- item.add_import(import_to_add);
- }
-
- if qualified {
- item.lookup_by(short_qualified_name);
- }
-
- let ty = variant.parent_enum(completion.db).ty(completion.db);
- item.set_relevance(CompletionRelevance {
- type_match: compute_type_match(completion, &ty),
- ..ctx.completion_relevance()
- });
-
- if let Some(ref_match) = compute_ref_match(completion, &ty) {
- item.ref_match(ref_match);
- }
-
- item.build()
-}
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index 2b9f82fc54..7df13988ad 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -8,7 +8,7 @@ use syntax::SmolStr;
use crate::{
context::{CompletionContext, PathCompletionCtx, PathKind},
- item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance, ImportEdit},
+ item::{Builder, CompletionItem, CompletionItemKind, CompletionRelevance},
patterns::ImmediateLocation,
render::{compute_exact_name_match, compute_ref_match, compute_type_match, RenderContext},
};
@@ -20,23 +20,21 @@ enum FuncKind {
pub(crate) fn render_fn(
ctx: RenderContext<'_>,
- import_to_add: Option<ImportEdit>,
local_name: Option<hir::Name>,
func: hir::Function,
) -> CompletionItem {
let _p = profile::span("render_fn");
- render(ctx, local_name, func, FuncKind::Function, import_to_add)
+ render(ctx, local_name, func, FuncKind::Function)
}
pub(crate) fn render_method(
ctx: RenderContext<'_>,
- import_to_add: Option<ImportEdit>,
receiver: Option<hir::Name>,
local_name: Option<hir::Name>,
func: hir::Function,
) -> CompletionItem {
let _p = profile::span("render_method");
- render(ctx, local_name, func, FuncKind::Method(receiver), import_to_add)
+ render(ctx, local_name, func, FuncKind::Method(receiver))
}
fn render(
@@ -44,7 +42,6 @@ fn render(
local_name: Option<hir::Name>,
func: hir::Function,
func_kind: FuncKind,
- import_to_add: Option<ImportEdit>,
) -> CompletionItem {
let db = completion.db;
@@ -98,17 +95,18 @@ fn render(
_ => (),
}
- if import_to_add.is_none() {
- if let Some(actm) = func.as_assoc_item(db) {
- if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
- item.trait_name(trt.name(db).to_smol_str());
+ match ctx.import_to_add {
+ Some(import_to_add) => {
+ item.add_import(import_to_add);
+ }
+ None => {
+ if let Some(actm) = func.as_assoc_item(db) {
+ if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
+ item.trait_name(trt.name(db).to_smol_str());
+ }
}
}
}
-
- if let Some(import_to_add) = import_to_add {
- item.add_import(import_to_add);
- }
item.build()
}
@@ -192,7 +190,7 @@ fn should_add_parens(ctx: &CompletionContext) -> bool {
Some(PathCompletionCtx { kind: Some(PathKind::Expr), has_call_parens: true, .. }) => {
return false
}
- Some(PathCompletionCtx { kind: Some(PathKind::Use), .. }) => {
+ Some(PathCompletionCtx { kind: Some(PathKind::Use | PathKind::Type), .. }) => {
cov_mark::hit!(no_parens_in_use_item);
return false;
}
diff --git a/crates/ide_completion/src/render/literal.rs b/crates/ide_completion/src/render/literal.rs
new file mode 100644
index 0000000000..d91e80f90c
--- /dev/null
+++ b/crates/ide_completion/src/render/literal.rs
@@ -0,0 +1,174 @@
+//! Renderer for `enum` variants.
+
+use hir::{db::HirDatabase, Documentation, HasAttrs, StructKind};
+use ide_db::SymbolKind;
+
+use crate::{
+ context::{CompletionContext, PathCompletionCtx},
+ item::CompletionItem,
+ render::{
+ compute_ref_match, compute_type_match,
+ variant::{
+ format_literal_label, render_record_lit, render_tuple_lit, visible_fields,
+ RenderedLiteral,
+ },
+ RenderContext,
+ },
+ CompletionItemKind, CompletionRelevance,
+};
+
+pub(crate) fn render_variant_lit(
+ ctx: RenderContext<'_>,
+ local_name: Option<hir::Name>,
+ variant: hir::Variant,
+ path: Option<hir::ModPath>,
+) -> Option<CompletionItem> {
+ let _p = profile::span("render_enum_variant");
+ let db = ctx.db();
+
+ let name = local_name.unwrap_or_else(|| variant.name(db));
+ render(ctx, Variant::EnumVariant(variant), name, path)
+}
+
+pub(crate) fn render_struct_literal(
+ ctx: RenderContext<'_>,
+ strukt: hir::Struct,
+ path: Option<hir::ModPath>,
+ local_name: Option<hir::Name>,
+) -> Option<CompletionItem> {
+ let _p = profile::span("render_struct_literal");
+ let db = ctx.db();
+
+ let name = local_name.unwrap_or_else(|| strukt.name(db));
+ render(ctx, Variant::Struct(strukt), name, path)
+}
+
+fn render(
+ ctx @ RenderContext { completion, .. }: RenderContext<'_>,
+ thing: Variant,
+ name: hir::Name,
+ path: Option<hir::ModPath>,
+) -> Option<CompletionItem> {
+ if let Some(PathCompletionCtx { has_call_parens: true, .. }) = completion.path_context {
+ return None;
+ }
+ let db = completion.db;
+ let fields = thing.fields(completion)?;
+
+ let (qualified_name, short_qualified_name, qualified) = match path {
+ Some(path) => {
+ let short = hir::ModPath::from_segments(
+ hir::PathKind::Plain,
+ path.segments().iter().skip(path.segments().len().saturating_sub(2)).cloned(),
+ );
+ (path, short, true)
+ }
+ None => (name.clone().into(), name.into(), false),
+ };
+ let qualified_name = qualified_name.to_string();
+ let snippet_cap = ctx.snippet_cap();
+
+ let kind = thing.kind(db);
+ let mut rendered = match kind {
+ StructKind::Tuple => render_tuple_lit(db, snippet_cap, &fields, &qualified_name),
+ StructKind::Record => render_record_lit(db, snippet_cap, &fields, &qualified_name),
+ StructKind::Unit => {
+ RenderedLiteral { literal: qualified_name.clone(), detail: qualified_name.clone() }
+ }
+ };
+
+ if snippet_cap.is_some() {
+ rendered.literal.push_str("$0");
+ }
+
+ let mut item = CompletionItem::new(
+ CompletionItemKind::SymbolKind(thing.symbol_kind()),
+ ctx.source_range(),
+ format_literal_label(&qualified_name, kind),
+ );
+
+ item.detail(rendered.detail);
+
+ match snippet_cap {
+ Some(snippet_cap) => item.insert_snippet(snippet_cap, rendered.literal),
+ None => item.insert_text(rendered.literal),
+ };
+
+ if qualified {
+ item.lookup_by(format_literal_label(&short_qualified_name.to_string(), kind));
+ }
+ item.set_documentation(thing.docs(db)).set_deprecated(thing.is_deprecated(&ctx));
+
+ let ty = thing.ty(db);
+ item.set_relevance(CompletionRelevance {
+ type_match: compute_type_match(ctx.completion, &ty),
+ ..ctx.completion_relevance()
+ });
+ if let Some(ref_match) = compute_ref_match(completion, &ty) {
+ item.ref_match(ref_match);
+ }
+
+ if let Some(import_to_add) = ctx.import_to_add {
+ item.add_import(import_to_add);
+ }
+ Some(item.build())
+}
+
+#[derive(Clone, Copy)]
+enum Variant {
+ Struct(hir::Struct),
+ EnumVariant(hir::Variant),
+}
+
+impl Variant {
+ fn fields(self, ctx: &CompletionContext) -> Option<Vec<hir::Field>> {
+ let fields = match self {
+ Variant::Struct(it) => it.fields(ctx.db),
+ Variant::EnumVariant(it) => it.fields(ctx.db),
+ };
+ let (visible_fields, fields_omitted) = match self {
+ Variant::Struct(it) => visible_fields(ctx, &fields, it)?,
+ Variant::EnumVariant(it) => visible_fields(ctx, &fields, it)?,
+ };
+ if !fields_omitted {
+ Some(visible_fields)
+ } else {
+ None
+ }
+ }
+
+ fn kind(self, db: &dyn HirDatabase) -> StructKind {
+ match self {
+ Variant::Struct(it) => it.kind(db),
+ Variant::EnumVariant(it) => it.kind(db),
+ }
+ }
+
+ fn symbol_kind(self) -> SymbolKind {
+ match self {
+ Variant::Struct(_) => SymbolKind::Struct,
+ Variant::EnumVariant(_) => SymbolKind::Variant,
+ }
+ }
+
+ fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
+ match self {
+ Variant::Struct(it) => it.docs(db),
+ Variant::EnumVariant(it) => it.docs(db),
+ }
+ }
+
+ fn is_deprecated(self, ctx: &RenderContext<'_>) -> bool {
+ match self {
+ Variant::Struct(it) => ctx.is_deprecated(it),
+ Variant::EnumVariant(it) => ctx.is_deprecated(it),
+ }
+ }
+
+ fn ty(self, db: &dyn HirDatabase) -> hir::Type {
+ match self {
+ Variant::Struct(it) => it.ty(db),
+ Variant::EnumVariant(it) => it.parent_enum(db).ty(db),
+ }
+ }
+}
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index d3b0de429c..9f848febeb 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -4,27 +4,21 @@ use hir::{Documentation, HirDisplay};
use ide_db::SymbolKind;
use syntax::SmolStr;
-use crate::{
- context::PathKind,
- item::{CompletionItem, ImportEdit},
- render::RenderContext,
-};
+use crate::{context::PathKind, item::CompletionItem, render::RenderContext};
pub(crate) fn render_macro(
ctx: RenderContext<'_>,
- import_to_add: Option<ImportEdit>,
name: hir::Name,
macro_: hir::Macro,
) -> CompletionItem {
let _p = profile::span("render_macro");
- render(ctx, name, macro_, import_to_add)
+ render(ctx, name, macro_)
}
fn render(
ctx @ RenderContext { completion, .. }: RenderContext<'_>,
name: hir::Name,
macro_: hir::Macro,
- import_to_add: Option<ImportEdit>,
) -> CompletionItem {
let source_range = if completion.is_immediately_after_macro_bang() {
cov_mark::hit!(completes_macro_call_if_cursor_at_bang_token);
@@ -52,12 +46,7 @@ fn render(
.set_documentation(docs)
.set_relevance(ctx.completion_relevance());
- if let Some(import_to_add) = import_to_add {
- item.add_import(import_to_add);
- }
-
let name = &*name;
-
match ctx.snippet_cap() {
Some(cap) if needs_bang && !completion.path_is_call() => {
let snippet = format!("{}!{}$0{}", name, bra, ket);
@@ -73,6 +62,9 @@ fn render(
item.insert_text(name);
}
};
+ if let Some(import_to_add) = ctx.import_to_add {
+ item.add_import(import_to_add);
+ }
item.build()
}
diff --git a/crates/ide_completion/src/render/pattern.rs b/crates/ide_completion/src/render/pattern.rs
index c2d51b1252..efceb85718 100644
--- a/crates/ide_completion/src/render/pattern.rs
+++ b/crates/ide_completion/src/render/pattern.rs
@@ -1,13 +1,13 @@
//! Renderer for patterns.
-use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind};
+use hir::{db::HirDatabase, HasAttrs, Name, StructKind};
use ide_db::SnippetCap;
use itertools::Itertools;
use syntax::SmolStr;
use crate::{
context::{ParamKind, PatternContext},
- render::RenderContext,
+ render::{variant::visible_fields, RenderContext},
CompletionItem, CompletionItemKind,
};
@@ -19,7 +19,7 @@ pub(crate) fn render_struct_pat(
let _p = profile::span("render_struct_pat");
let fields = strukt.fields(ctx.db());
- let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, strukt)?;
+ let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, strukt)?;
if visible_fields.is_empty() {
// Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields
@@ -36,14 +36,14 @@ pub(crate) fn render_variant_pat(
ctx: RenderContext<'_>,
variant: hir::Variant,
local_name: Option<Name>,
- path: Option<hir::ModPath>,
+ path: Option<&hir::ModPath>,
) -> Option<CompletionItem> {
let _p = profile::span("render_variant_pat");
let fields = variant.fields(ctx.db());
- let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, variant)?;
+ let (visible_fields, fields_omitted) = visible_fields(ctx.completion, &fields, variant)?;
- let name = match &path {
+ let name = match path {
Some(path) => path.to_string().into(),
None => local_name.unwrap_or_else(|| variant.name(ctx.db())).to_smol_str(),
};
@@ -78,9 +78,7 @@ fn render_pat(
fields_omitted: bool,
) -> Option<String> {
let mut pat = match kind {
- StructKind::Tuple if ctx.snippet_cap().is_some() => {
- render_tuple_as_pat(fields, name, fields_omitted)
- }
+ StructKind::Tuple => render_tuple_as_pat(ctx.snippet_cap(), fields, name, fields_omitted),
StructKind::Record => {
render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted)
}
@@ -113,49 +111,53 @@ fn render_record_as_pat(
fields_omitted: bool,
) -> String {
let fields = fields.iter();
- if snippet_cap.is_some() {
- format!(
- "{name} {{ {}{} }}",
- fields
- .enumerate()
- .map(|(idx, field)| format!("{}${}", field.name(db), idx + 1))
- .format(", "),
- if fields_omitted { ", .." } else { "" },
- name = name
- )
- } else {
- format!(
- "{name} {{ {}{} }}",
- fields.map(|field| field.name(db)).format(", "),
- if fields_omitted { ", .." } else { "" },
- name = name
- )
+ match snippet_cap {
+ Some(_) => {
+ format!(
+ "{name} {{ {}{} }}",
+ fields.enumerate().format_with(", ", |(idx, field), f| {
+ f(&format_args!("{}${}", field.name(db), idx + 1))
+ }),
+ if fields_omitted { ", .." } else { "" },
+ name = name
+ )
+ }
+ None => {
+ format!(
+ "{name} {{ {}{} }}",
+ fields.map(|field| field.name(db)).format(", "),
+ if fields_omitted { ", .." } else { "" },
+ name = name
+ )
+ }
}
}
-fn render_tuple_as_pat(fields: &[hir::Field], name: &str, fields_omitted: bool) -> String {
- format!(
- "{name}({}{})",
- fields.iter().enumerate().map(|(idx, _)| format!("${}", idx + 1)).format(", "),
- if fields_omitted { ", .." } else { "" },
- name = name
- )
-}
-
-fn visible_fields(
- ctx: &RenderContext<'_>,
+fn render_tuple_as_pat(
+ snippet_cap: Option<SnippetCap>,
fields: &[hir::Field],
- item: impl HasAttrs,
-) -> Option<(Vec<hir::Field>, bool)> {
- let module = ctx.completion.module?;
- let n_fields = fields.len();
- let fields = fields
- .iter()
- .filter(|field| field.is_visible_from(ctx.db(), module))
- .copied()
- .collect::<Vec<_>>();
-
- let fields_omitted =
- n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists();
- Some((fields, fields_omitted))
+ name: &str,
+ fields_omitted: bool,
+) -> String {
+ let fields = fields.iter();
+ match snippet_cap {
+ Some(_) => {
+ format!(
+ "{name}({}{})",
+ fields
+ .enumerate()
+ .format_with(", ", |(idx, _), f| { f(&format_args!("${}", idx + 1)) }),
+ if fields_omitted { ", .." } else { "" },
+ name = name
+ )
+ }
+ None => {
+ format!(
+ "{name}({}{})",
+ fields.enumerate().map(|(idx, _)| idx).format(", "),
+ if fields_omitted { ", .." } else { "" },
+ name = name
+ )
+ }
+ }
}
diff --git a/crates/ide_completion/src/render/struct_literal.rs b/crates/ide_completion/src/render/struct_literal.rs
deleted file mode 100644
index a686be6691..0000000000
--- a/crates/ide_completion/src/render/struct_literal.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-//! Renderer for `struct` literal.
-
-use hir::{HasAttrs, Name, StructKind};
-use syntax::SmolStr;
-
-use crate::{
- render::compound::{
- format_literal_label, render_record, render_tuple, visible_fields, RenderedCompound,
- },
- render::RenderContext,
- CompletionItem, CompletionItemKind,
-};
-
-pub(crate) fn render_struct_literal(
- ctx: RenderContext<'_>,
- strukt: hir::Struct,
- path: Option<hir::ModPath>,
- local_name: Option<Name>,
-) -> Option<CompletionItem> {
- let _p = profile::span("render_struct_literal");
-
- let fields = strukt.fields(ctx.db());
- let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, strukt)?;
-
- if fields_omitted {
- // If some fields are private you can't make `struct` literal.
- return None;
- }
-
- let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_smol_str();
-
- let rendered = render_literal(&ctx, path, &name, strukt.kind(ctx.db()), &visible_fields)?;
-
- Some(build_completion(&ctx, name, rendered, strukt.kind(ctx.db()), strukt))
-}
-
-fn build_completion(
- ctx: &RenderContext<'_>,
- name: SmolStr,
- rendered: RenderedCompound,
- kind: StructKind,
- def: impl HasAttrs + Copy,
-) -> CompletionItem {
- let mut item = CompletionItem::new(
- CompletionItemKind::Snippet,
- ctx.source_range(),
- format_literal_label(&name, kind),
- );
-
- item.set_documentation(ctx.docs(def))
- .set_deprecated(ctx.is_deprecated(def))
- .detail(&rendered.detail)
- .set_relevance(ctx.completion_relevance());
- match ctx.snippet_cap() {
- Some(snippet_cap) => item.insert_snippet(snippet_cap, rendered.literal),
- None => item.insert_text(rendered.literal),
- };
- item.build()
-}
-
-fn render_literal(
- ctx: &RenderContext<'_>,
- path: Option<hir::ModPath>,
- name: &str,
- kind: StructKind,
- fields: &[hir::Field],
-) -> Option<RenderedCompound> {
- let path_string;
-
- let qualified_name = if let Some(path) = path {
- path_string = path.to_string();
- &path_string
- } else {
- name
- };
-
- let mut rendered = match kind {
- StructKind::Tuple if ctx.snippet_cap().is_some() => {
- render_tuple(ctx.db(), ctx.snippet_cap(), fields, Some(qualified_name))
- }
- StructKind::Record => {
- render_record(ctx.db(), ctx.snippet_cap(), fields, Some(qualified_name))
- }
- _ => return None,
- };
-
- if ctx.snippet_cap().is_some() {
- rendered.literal.push_str("$0");
- }
- Some(rendered)
-}
diff --git a/crates/ide_completion/src/render/union_literal.rs b/crates/ide_completion/src/render/union_literal.rs
index 80499e102b..aafedaf5aa 100644
--- a/crates/ide_completion/src/render/union_literal.rs
+++ b/crates/ide_completion/src/render/union_literal.rs
@@ -1,11 +1,12 @@
//! Renderer for `union` literals.
use hir::{HirDisplay, Name, StructKind};
+use ide_db::SymbolKind;
use itertools::Itertools;
use crate::{
render::{
- compound::{format_literal_label, visible_fields},
+ variant::{format_literal_label, visible_fields},
RenderContext,
},
CompletionItem, CompletionItemKind,
@@ -25,13 +26,13 @@ pub(crate) fn render_union_literal(
};
let mut item = CompletionItem::new(
- CompletionItemKind::Snippet,
+ CompletionItemKind::SymbolKind(SymbolKind::Union),
ctx.source_range(),
format_literal_label(&name, StructKind::Record),
);
let fields = un.fields(ctx.db());
- let (fields, fields_omitted) = visible_fields(&ctx, &fields, un)?;
+ let (fields, fields_omitted) = visible_fields(ctx.completion, &fields, un)?;
if fields.is_empty() {
return None;
diff --git a/crates/ide_completion/src/render/compound.rs b/crates/ide_completion/src/render/variant.rs
index c7f3bd1f79..a37b4237c4 100644
--- a/crates/ide_completion/src/render/compound.rs
+++ b/crates/ide_completion/src/render/variant.rs
@@ -1,6 +1,6 @@
//! Code common to structs, unions, and enum variants.
-use crate::render::RenderContext;
+use crate::context::CompletionContext;
use hir::{db::HirDatabase, HasAttrs, HasVisibility, HirDisplay, StructKind};
use ide_db::SnippetCap;
use itertools::Itertools;
@@ -9,19 +9,19 @@ use syntax::SmolStr;
/// A rendered struct, union, or enum variant, split into fields for actual
/// auto-completion (`literal`, using `field: ()`) and display in the
/// completions menu (`detail`, using `field: type`).
-pub(crate) struct RenderedCompound {
+pub(crate) struct RenderedLiteral {
pub(crate) literal: String,
pub(crate) detail: String,
}
/// Render a record type (or sub-type) to a `RenderedCompound`. Use `None` for
/// the `name` argument for an anonymous type.
-pub(crate) fn render_record(
+pub(crate) fn render_record_lit(
db: &dyn HirDatabase,
snippet_cap: Option<SnippetCap>,
fields: &[hir::Field],
- name: Option<&str>,
-) -> RenderedCompound {
+ path: &str,
+) -> RenderedLiteral {
let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| {
if snippet_cap.is_some() {
f(&format_args!("{}: ${{{}:()}}", field.name(db), idx + 1))
@@ -34,20 +34,20 @@ pub(crate) fn render_record(
f(&format_args!("{}: {}", field.name(db), field.ty(db).display(db)))
});
- RenderedCompound {
- literal: format!("{} {{ {} }}", name.unwrap_or(""), completions),
- detail: format!("{} {{ {} }}", name.unwrap_or(""), types),
+ RenderedLiteral {
+ literal: format!("{} {{ {} }}", path, completions),
+ detail: format!("{} {{ {} }}", path, types),
}
}
/// Render a tuple type (or sub-type) to a `RenderedCompound`. Use `None` for
/// the `name` argument for an anonymous type.
-pub(crate) fn render_tuple(
+pub(crate) fn render_tuple_lit(
db: &dyn HirDatabase,
snippet_cap: Option<SnippetCap>,
fields: &[hir::Field],
- name: Option<&str>,
-) -> RenderedCompound {
+ path: &str,
+) -> RenderedLiteral {
let completions = fields.iter().enumerate().format_with(", ", |(idx, _), f| {
if snippet_cap.is_some() {
f(&format_args!("${{{}:()}}", idx + 1))
@@ -58,9 +58,9 @@ pub(crate) fn render_tuple(
let types = fields.iter().format_with(", ", |field, f| f(&field.ty(db).display(db)));
- RenderedCompound {
- literal: format!("{}({})", name.unwrap_or(""), completions),
- detail: format!("{}({})", name.unwrap_or(""), types),
+ RenderedLiteral {
+ literal: format!("{}({})", path, completions),
+ detail: format!("{}({})", path, types),
}
}
@@ -68,20 +68,20 @@ pub(crate) fn render_tuple(
/// fields, plus a boolean for whether the list is comprehensive (contains no
/// private fields and its item is not marked `#[non_exhaustive]`).
pub(crate) fn visible_fields(
- ctx: &RenderContext<'_>,
+ ctx: &CompletionContext,
fields: &[hir::Field],
item: impl HasAttrs,
) -> Option<(Vec<hir::Field>, bool)> {
- let module = ctx.completion.module?;
+ let module = ctx.module?;
let n_fields = fields.len();
let fields = fields
.iter()
- .filter(|field| field.is_visible_from(ctx.db(), module))
+ .filter(|field| field.is_visible_from(ctx.db, module))
.copied()
.collect::<Vec<_>>();
let fields_omitted =
- n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists();
+ n_fields - fields.len() > 0 || item.attrs(ctx.db).by_key("non_exhaustive").exists();
Some((fields, fields_omitted))
}
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs
index 891c1346df..50d5e01979 100644
--- a/crates/ide_completion/src/tests/pattern.rs
+++ b/crates/ide_completion/src/tests/pattern.rs
@@ -150,6 +150,7 @@ fn foo() {
bn Tuple Tuple($1)$0
st Tuple
ev Variant
+ md module
en SingleVariantEnum
st Unit
ma makro!(…) macro_rules! makro
@@ -171,6 +172,7 @@ fn foo(a$0) {
st Record
bn Tuple Tuple($1): Tuple$0
st Tuple
+ md module
st Unit
ma makro!(…) macro_rules! makro
"#]],
@@ -187,6 +189,7 @@ fn foo(a$0: Tuple) {
st Record
bn Tuple Tuple($1)$0
st Tuple
+ md module
st Unit
ma makro!(…) macro_rules! makro
"#]],
@@ -228,7 +231,6 @@ fn foo() {
expect![[r#"
kw ref
kw mut
- ev E::X E::X
en E
ma m!(…) macro_rules! m
"#]],
@@ -378,3 +380,67 @@ fn foo() {
"#]],
)
}
+
+#[test]
+fn completes_no_delims_if_existing() {
+ check_empty(
+ r#"
+struct Bar(u32);
+fn foo() {
+ match Bar(0) {
+ B$0(b) => {}
+ }
+}
+"#,
+ expect![[r#"
+ kw self::
+ kw super::
+ kw crate::
+ "#]],
+ );
+ check_empty(
+ r#"
+struct Foo { bar: u32 }
+fn foo() {
+ match Foo { bar: 0 } {
+ F$0 { bar } => {}
+ }
+}
+"#,
+ expect![[r#"
+ kw return
+ kw self
+ kw super
+ kw crate
+ st Foo
+ fn foo() fn()
+ bt u32
+ "#]],
+ );
+ check_empty(
+ r#"
+enum Enum {
+ TupleVariant(u32)
+}
+fn foo() {
+ match Enum::TupleVariant(0) {
+ Enum::T$0(b) => {}
+ }
+}
+"#,
+ expect![[r#""#]],
+ );
+ check_empty(
+ r#"
+enum Enum {
+ RecordVariant { field: u32 }
+}
+fn foo() {
+ match (Enum::RecordVariant { field: 0 }) {
+ Enum::RecordV$0 { field } => {}
+ }
+}
+"#,
+ expect![[r#""#]],
+ );
+}
diff --git a/crates/ide_completion/src/tests/record.rs b/crates/ide_completion/src/tests/record.rs
index 5e9367960f..0322ecbe39 100644
--- a/crates/ide_completion/src/tests/record.rs
+++ b/crates/ide_completion/src/tests/record.rs
@@ -166,7 +166,7 @@ fn main() {
kw true
kw false
kw return
- sn Foo {…} Foo { foo1: u32, foo2: u32 }
+ st Foo {…} Foo { foo1: u32, foo2: u32 }
fd ..Default::default()
fd foo1 u32
fd foo2 u32