Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/completions/record.rs')
-rw-r--r--crates/ide-completion/src/completions/record.rs129
1 files changed, 80 insertions, 49 deletions
diff --git a/crates/ide-completion/src/completions/record.rs b/crates/ide-completion/src/completions/record.rs
index 5ba355f6ae..eaab4cb4ee 100644
--- a/crates/ide-completion/src/completions/record.rs
+++ b/crates/ide-completion/src/completions/record.rs
@@ -1,36 +1,34 @@
//! Complete fields in record literals and patterns.
use ide_db::SymbolKind;
-use syntax::{ast::Expr, T};
+use syntax::{
+ ast::{self, Expr},
+ T,
+};
use crate::{
- context::{
- NameRefContext, NameRefKind, PathCompletionCtx, PathKind, PatternContext, Qualified,
- },
+ context::{PathCompletionCtx, PathKind, PatternContext, Qualified},
CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
CompletionRelevancePostfixMatch, Completions,
};
-pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
- let missing_fields = if let Some(PatternContext { record_pat: Some(record_pat), .. }) =
- &ctx.pattern_ctx
- {
- ctx.sema.record_pattern_missing_fields(record_pat)
- } else if let Some(NameRefContext {
- kind:
- Some(
- NameRefKind::RecordExpr(record_expr)
- | NameRefKind::Path(PathCompletionCtx {
- kind: PathKind::Expr { is_func_update: Some(record_expr), .. },
- qualified: Qualified::No,
- ..
- }),
- ),
- ..
- }) = ctx.nameref_ctx()
- {
- let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
+pub(crate) fn complete_record_pattern_fields(
+ acc: &mut Completions,
+ ctx: &CompletionContext,
+ pattern_ctx: &PatternContext,
+) {
+ if let PatternContext { record_pat: Some(record_pat), .. } = pattern_ctx {
+ complete_fields(acc, ctx, ctx.sema.record_pattern_missing_fields(record_pat));
+ }
+}
+pub(crate) fn complete_record_expr_fields_record_expr(
+ acc: &mut Completions,
+ ctx: &CompletionContext,
+ record_expr: &ast::RecordExpr,
+) {
+ let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
- if let Some(hir::Adt::Union(un)) = ty.as_ref().and_then(|t| t.original.as_adt()) {
+ let missing_fields = match ty.as_ref().and_then(|t| t.original.as_adt()) {
+ Some(hir::Adt::Union(un)) => {
// ctx.sema.record_literal_missing_fields will always return
// an empty Vec on a union literal. This is normally
// reasonable, but here we'd like to present the full list
@@ -40,47 +38,80 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
match were_fields_specified {
false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
- true => vec![],
+ true => return,
}
- } else {
+ }
+ _ => {
let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
- let default_trait = ctx.famous_defs().core_default_Default();
- let impl_default_trait =
- default_trait.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() {
- let completion_text = "..Default::default()";
- let mut item =
- CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
- let completion_text =
- completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
- item.insert_text(completion_text).set_relevance(CompletionRelevance {
- postfix_match: Some(CompletionRelevancePostfixMatch::Exact),
- ..Default::default()
- });
- item.add_to(acc);
- }
+ add_default_update(acc, ctx, ty, &missing_fields);
if ctx.previous_token_is(T![.]) {
let mut item =
CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), "..");
item.insert_text(".");
item.add_to(acc);
- return None;
+ return;
}
missing_fields
}
- } else {
- return None;
};
+ complete_fields(acc, ctx, missing_fields);
+}
+
+fn add_default_update(
+ acc: &mut Completions,
+ ctx: &CompletionContext,
+ ty: Option<hir::TypeInfo>,
+ missing_fields: &[(hir::Field, hir::Type)],
+) {
+ let default_trait = ctx.famous_defs().core_default_Default();
+ let impl_default_trait = default_trait
+ .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() {
+ let completion_text = "..Default::default()";
+ let mut item = CompletionItem::new(SymbolKind::Field, ctx.source_range(), completion_text);
+ let completion_text =
+ completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
+ item.insert_text(completion_text).set_relevance(CompletionRelevance {
+ postfix_match: Some(CompletionRelevancePostfixMatch::Exact),
+ ..Default::default()
+ });
+ item.add_to(acc);
+ }
+}
+
+pub(crate) fn complete_record_expr_func_update(
+ acc: &mut Completions,
+ ctx: &CompletionContext,
+ path_ctx: &PathCompletionCtx,
+) {
+ if let PathCompletionCtx {
+ kind: PathKind::Expr { is_func_update: Some(record_expr), .. },
+ qualified: Qualified::No,
+ ..
+ } = path_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,
+ missing_fields: Vec<(hir::Field, hir::Type)>,
+) {
for (field, ty) in missing_fields {
acc.add_field(ctx, None, field, &ty);
}
-
- Some(())
}
#[cfg(test)]