aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/completion')
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs36
-rw-r--r--crates/ra_ide_api/src/completion/complete_postfix.rs16
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_literal.rs7
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_pattern.rs7
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs39
5 files changed, 38 insertions, 67 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index 5a3f9b5f6..b6fe48627 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Adt, Ty, TypeCtor}; 3use hir::Type;
4 4
5use crate::completion::completion_item::CompletionKind; 5use crate::completion::completion_item::CompletionKind;
6use crate::{ 6use crate::{
@@ -22,12 +22,12 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
22 }; 22 };
23 23
24 if !ctx.is_call { 24 if !ctx.is_call {
25 complete_fields(acc, ctx, receiver_ty.clone()); 25 complete_fields(acc, ctx, &receiver_ty);
26 } 26 }
27 complete_methods(acc, ctx, receiver_ty.clone()); 27 complete_methods(acc, ctx, &receiver_ty);
28 28
29 // Suggest .await syntax for types that implement Future trait 29 // Suggest .await syntax for types that implement Future trait
30 if ctx.analyzer.impls_future(ctx.db, receiver_ty) { 30 if ctx.analyzer.impls_future(ctx.db, receiver_ty.into_ty()) {
31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") 31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
32 .detail("expr.await") 32 .detail("expr.await")
33 .insert_text("await") 33 .insert_text("await")
@@ -35,28 +35,18 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
35 } 35 }
36} 36}
37 37
38fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { 38fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
39 for receiver in ctx.analyzer.autoderef(ctx.db, receiver) { 39 for receiver in receiver.autoderef(ctx.db) {
40 if let Ty::Apply(a_ty) = receiver { 40 for (field, ty) in receiver.fields(ctx.db) {
41 match a_ty.ctor { 41 acc.add_field(ctx, field, &ty);
42 TypeCtor::Adt(Adt::Struct(s)) => { 42 }
43 for field in s.fields(ctx.db) { 43 for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
44 acc.add_field(ctx, field, &a_ty.parameters); 44 acc.add_tuple_field(ctx, i, &ty);
45 } 45 }
46 }
47 // FIXME unions
48 TypeCtor::Tuple { .. } => {
49 for (i, ty) in a_ty.parameters.iter().enumerate() {
50 acc.add_tuple_field(ctx, i, ty);
51 }
52 }
53 _ => {}
54 }
55 };
56 } 46 }
57} 47}
58 48
59fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { 49fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
60 let mut seen_methods = FxHashSet::default(); 50 let mut seen_methods = FxHashSet::default();
61 ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| { 51 ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| {
62 if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) { 52 if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) {
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs
index 17b75cf7e..646a30c76 100644
--- a/crates/ra_ide_api/src/completion/complete_postfix.rs
+++ b/crates/ra_ide_api/src/completion/complete_postfix.rs
@@ -1,6 +1,5 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Ty, TypeCtor};
4use ra_syntax::{ast::AstNode, TextRange, TextUnit}; 3use ra_syntax::{ast::AstNode, TextRange, TextUnit};
5use ra_text_edit::TextEdit; 4use ra_text_edit::TextEdit;
6 5
@@ -30,9 +29,12 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
30 dot_receiver.syntax().text().to_string() 29 dot_receiver.syntax().text().to_string()
31 }; 30 };
32 31
33 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); 32 let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) {
33 Some(it) => it,
34 None => return,
35 };
34 36
35 if is_bool_or_unknown(receiver_ty) { 37 if receiver_ty.is_bool() || receiver_ty.is_unknown() {
36 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) 38 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
37 .add_to(acc); 39 .add_to(acc);
38 postfix_snippet( 40 postfix_snippet(
@@ -75,14 +77,6 @@ fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet:
75 .snippet_edit(edit) 77 .snippet_edit(edit)
76} 78}
77 79
78fn is_bool_or_unknown(ty: Option<Ty>) -> bool {
79 match &ty {
80 Some(Ty::Apply(app)) if app.ctor == TypeCtor::Bool => true,
81 Some(Ty::Unknown) | None => true,
82 Some(_) => false,
83 }
84}
85
86#[cfg(test)] 80#[cfg(test)]
87mod tests { 81mod tests {
88 use insta::assert_debug_snapshot; 82 use insta::assert_debug_snapshot;
diff --git a/crates/ra_ide_api/src/completion/complete_record_literal.rs b/crates/ra_ide_api/src/completion/complete_record_literal.rs
index 45a4a9738..577c394d2 100644
--- a/crates/ra_ide_api/src/completion/complete_record_literal.rs
+++ b/crates/ra_ide_api/src/completion/complete_record_literal.rs
@@ -1,7 +1,5 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::Substs;
4
5use crate::completion::{CompletionContext, Completions}; 3use crate::completion::{CompletionContext, Completions};
6 4
7/// Complete fields in fields literals. 5/// Complete fields in fields literals.
@@ -15,10 +13,9 @@ pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionCon
15 Some(it) => it, 13 Some(it) => it,
16 _ => return, 14 _ => return,
17 }; 15 };
18 let substs = &ty.substs().unwrap_or_else(Substs::empty);
19 16
20 for field in variant.fields(ctx.db) { 17 for (field, field_ty) in ty.variant_fields(ctx.db, variant) {
21 acc.add_field(ctx, field, substs); 18 acc.add_field(ctx, field, &field_ty);
22 } 19 }
23} 20}
24 21
diff --git a/crates/ra_ide_api/src/completion/complete_record_pattern.rs b/crates/ra_ide_api/src/completion/complete_record_pattern.rs
index aa0fd6d24..a56c7e3a1 100644
--- a/crates/ra_ide_api/src/completion/complete_record_pattern.rs
+++ b/crates/ra_ide_api/src/completion/complete_record_pattern.rs
@@ -1,7 +1,5 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::Substs;
4
5use crate::completion::{CompletionContext, Completions}; 3use crate::completion::{CompletionContext, Completions};
6 4
7pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionContext) {
@@ -14,10 +12,9 @@ pub(super) fn complete_record_pattern(acc: &mut Completions, ctx: &CompletionCon
14 Some(it) => it, 12 Some(it) => it,
15 _ => return, 13 _ => return,
16 }; 14 };
17 let substs = &ty.substs().unwrap_or_else(Substs::empty);
18 15
19 for field in variant.fields(ctx.db) { 16 for (field, field_ty) in ty.variant_fields(ctx.db, variant) {
20 acc.add_field(ctx, field, substs); 17 acc.add_field(ctx, field, &field_ty);
21 } 18 }
22} 19}
23 20
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 85b053a6e..5f056730a 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -1,12 +1,12 @@
1//! This modules takes care of rendering various definitions as completion items. 1//! This modules takes care of rendering various definitions as completion items.
2 2
3use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; 3use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, Type};
4use join_to_string::join; 4use join_to_string::join;
5use ra_syntax::ast::NameOwner; 5use ra_syntax::ast::NameOwner;
6use test_utils::tested_by; 6use test_utils::tested_by;
7 7
8use crate::completion::{ 8use crate::completion::{
9 db, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 9 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
10}; 10};
11 11
12use crate::display::{const_label, function_label, macro_label, type_label}; 12use crate::display::{const_label, function_label, macro_label, type_label};
@@ -16,7 +16,7 @@ impl Completions {
16 &mut self, 16 &mut self,
17 ctx: &CompletionContext, 17 ctx: &CompletionContext,
18 field: hir::StructField, 18 field: hir::StructField,
19 substs: &hir::Substs, 19 ty: &Type,
20 ) { 20 ) {
21 let is_deprecated = is_deprecated(field, ctx.db); 21 let is_deprecated = is_deprecated(field, ctx.db);
22 CompletionItem::new( 22 CompletionItem::new(
@@ -25,13 +25,13 @@ impl Completions {
25 field.name(ctx.db).to_string(), 25 field.name(ctx.db).to_string(),
26 ) 26 )
27 .kind(CompletionItemKind::Field) 27 .kind(CompletionItemKind::Field)
28 .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string()) 28 .detail(ty.display(ctx.db).to_string())
29 .set_documentation(field.docs(ctx.db)) 29 .set_documentation(field.docs(ctx.db))
30 .set_deprecated(is_deprecated) 30 .set_deprecated(is_deprecated)
31 .add_to(self); 31 .add_to(self);
32 } 32 }
33 33
34 pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &hir::Ty) { 34 pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) {
35 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string()) 35 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string())
36 .kind(CompletionItemKind::Field) 36 .kind(CompletionItemKind::Field)
37 .detail(ty.display(ctx.db).to_string()) 37 .detail(ty.display(ctx.db).to_string())
@@ -98,7 +98,7 @@ impl Completions {
98 CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone()); 98 CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
99 if let ScopeDef::Local(local) = resolution { 99 if let ScopeDef::Local(local) = resolution {
100 let ty = local.ty(ctx.db); 100 let ty = local.ty(ctx.db);
101 if ty != Ty::Unknown { 101 if !ty.is_unknown() {
102 completion_item = completion_item.detail(ty.display(ctx.db).to_string()); 102 completion_item = completion_item.detail(ty.display(ctx.db).to_string());
103 } 103 }
104 }; 104 };
@@ -108,19 +108,17 @@ impl Completions {
108 && !ctx.has_type_args 108 && !ctx.has_type_args
109 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") 109 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
110 { 110 {
111 let generic_def: Option<hir::GenericDef> = match resolution { 111 let has_non_default_type_params = match resolution {
112 ScopeDef::ModuleDef(Adt(it)) => Some((*it).into()), 112 ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db),
113 ScopeDef::ModuleDef(TypeAlias(it)) => Some((*it).into()), 113 ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db),
114 _ => None, 114 _ => false,
115 }; 115 };
116 if let Some(def) = generic_def { 116 if has_non_default_type_params {
117 if has_non_default_type_params(def, ctx.db) { 117 tested_by!(inserts_angle_brackets_for_generics);
118 tested_by!(inserts_angle_brackets_for_generics); 118 completion_item = completion_item
119 completion_item = completion_item 119 .lookup_by(local_name.clone())
120 .lookup_by(local_name.clone()) 120 .label(format!("{}<…>", local_name))
121 .label(format!("{}<…>", local_name)) 121 .insert_snippet(format!("{}<$0>", local_name));
122 .insert_snippet(format!("{}<$0>", local_name));
123 }
124 } 122 }
125 } 123 }
126 124
@@ -291,11 +289,6 @@ fn is_deprecated(node: impl HasAttrs, db: &impl HirDatabase) -> bool {
291 node.attrs(db).by_key("deprecated").exists() 289 node.attrs(db).by_key("deprecated").exists()
292} 290}
293 291
294fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool {
295 let subst = db.generic_defaults(def.into());
296 subst.iter().any(|ty| ty == &Ty::Unknown)
297}
298
299#[cfg(test)] 292#[cfg(test)]
300mod tests { 293mod tests {
301 use insta::assert_debug_snapshot; 294 use insta::assert_debug_snapshot;