aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r--crates/ra_ide_api/src/completion/complete_postfix.rs109
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs27
2 files changed, 70 insertions, 66 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs
index 60ed3518b..4f9565441 100644
--- a/crates/ra_ide_api/src/completion/complete_postfix.rs
+++ b/crates/ra_ide_api/src/completion/complete_postfix.rs
@@ -1,5 +1,9 @@
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};
5use ra_text_edit::TextEdit;
6
3use crate::{ 7use crate::{
4 completion::{ 8 completion::{
5 completion_context::CompletionContext, 9 completion_context::CompletionContext,
@@ -7,9 +11,53 @@ use crate::{
7 }, 11 },
8 CompletionItem, 12 CompletionItem,
9}; 13};
10use hir::{Ty, TypeCtor}; 14
11use ra_syntax::{ast::AstNode, TextRange, TextUnit}; 15pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
12use ra_text_edit::TextEdit; 16 let dot_receiver = match &ctx.dot_receiver {
17 Some(it) => it,
18 None => return,
19 };
20
21 let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal {
22 let text = dot_receiver.syntax().text();
23 let without_dot = ..text.len() - TextUnit::of_char('.');
24 text.slice(without_dot).to_string()
25 } else {
26 dot_receiver.syntax().text().to_string()
27 };
28
29 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver);
30
31 if is_bool_or_unknown(receiver_ty) {
32 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
33 .add_to(acc);
34 postfix_snippet(
35 ctx,
36 "while",
37 "while expr {}",
38 &format!("while {} {{\n$0\n}}", receiver_text),
39 )
40 .add_to(acc);
41 }
42
43 postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc);
44
45 postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc);
46 postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc);
47
48 postfix_snippet(
49 ctx,
50 "match",
51 "match expr {}",
52 &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text),
53 )
54 .add_to(acc);
55
56 postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc);
57
58 postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text))
59 .add_to(acc);
60}
13 61
14fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { 62fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
15 let edit = { 63 let edit = {
@@ -24,62 +72,19 @@ fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet:
24} 72}
25 73
26fn is_bool_or_unknown(ty: Option<Ty>) -> bool { 74fn is_bool_or_unknown(ty: Option<Ty>) -> bool {
27 if let Some(ty) = ty { 75 match &ty {
28 match ty { 76 Some(Ty::Apply(app)) if app.ctor == TypeCtor::Bool => true,
29 Ty::Apply(at) => match at.ctor { 77 Some(Ty::Unknown) | None => true,
30 TypeCtor::Bool => true, 78 Some(_) => false,
31 _ => false,
32 },
33 Ty::Unknown => true,
34 _ => false,
35 }
36 } else {
37 true
38 }
39}
40
41pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
42 if let Some(dot_receiver) = &ctx.dot_receiver {
43 let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal {
44 let text = dot_receiver.syntax().text();
45 let without_dot = ..text.len() - TextUnit::of_char('.');
46 text.slice(without_dot).to_string()
47 } else {
48 dot_receiver.syntax().text().to_string()
49 };
50 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver);
51 if is_bool_or_unknown(receiver_ty) {
52 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
53 .add_to(acc);
54 postfix_snippet(
55 ctx,
56 "while",
57 "while expr {}",
58 &format!("while {} {{\n$0\n}}", receiver_text),
59 )
60 .add_to(acc);
61 }
62 postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc);
63 postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc);
64 postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc);
65 postfix_snippet(
66 ctx,
67 "match",
68 "match expr {}",
69 &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text),
70 )
71 .add_to(acc);
72 postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc);
73 postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text))
74 .add_to(acc);
75 } 79 }
76} 80}
77 81
78#[cfg(test)] 82#[cfg(test)]
79mod tests { 83mod tests {
80 use crate::completion::{do_completion, CompletionItem, CompletionKind};
81 use insta::assert_debug_snapshot; 84 use insta::assert_debug_snapshot;
82 85
86 use crate::completion::{do_completion, CompletionItem, CompletionKind};
87
83 fn do_postfix_completion(code: &str) -> Vec<CompletionItem> { 88 fn do_postfix_completion(code: &str) -> Vec<CompletionItem> {
84 do_completion(code, CompletionKind::Postfix) 89 do_completion(code, CompletionKind::Postfix)
85 } 90 }
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index cb55d1875..d861303b7 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -1,8 +1,8 @@
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, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; 3use hir::{db::HirDatabase, Attrs, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk};
4use join_to_string::join; 4use join_to_string::join;
5use ra_syntax::ast::{AttrsOwner, NameOwner}; 5use ra_syntax::ast::NameOwner;
6use test_utils::tested_by; 6use test_utils::tested_by;
7 7
8use crate::completion::{ 8use crate::completion::{
@@ -18,11 +18,7 @@ impl Completions {
18 field: hir::StructField, 18 field: hir::StructField,
19 substs: &hir::Substs, 19 substs: &hir::Substs,
20 ) { 20 ) {
21 let ast_node = field.source(ctx.db).ast; 21 let is_deprecated = is_deprecated(field, ctx.db);
22 let is_deprecated = match ast_node {
23 hir::FieldSource::Named(m) => is_deprecated(m),
24 hir::FieldSource::Pos(m) => is_deprecated(m),
25 };
26 CompletionItem::new( 22 CompletionItem::new(
27 CompletionKind::Reference, 23 CompletionKind::Reference,
28 ctx.source_range(), 24 ctx.source_range(),
@@ -185,7 +181,7 @@ impl Completions {
185 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), &macro_declaration) 181 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), &macro_declaration)
186 .kind(CompletionItemKind::Macro) 182 .kind(CompletionItemKind::Macro)
187 .set_documentation(docs.clone()) 183 .set_documentation(docs.clone())
188 .set_deprecated(is_deprecated(ast_node)) 184 .set_deprecated(is_deprecated(macro_, ctx.db))
189 .detail(detail); 185 .detail(detail);
190 186
191 builder = if ctx.use_item_syntax.is_some() { 187 builder = if ctx.use_item_syntax.is_some() {
@@ -218,7 +214,7 @@ impl Completions {
218 CompletionItemKind::Function 214 CompletionItemKind::Function
219 }) 215 })
220 .set_documentation(func.docs(ctx.db)) 216 .set_documentation(func.docs(ctx.db))
221 .set_deprecated(is_deprecated(ast_node)) 217 .set_deprecated(is_deprecated(func, ctx.db))
222 .detail(detail); 218 .detail(detail);
223 219
224 // Add `<>` for generic types 220 // Add `<>` for generic types
@@ -250,7 +246,7 @@ impl Completions {
250 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) 246 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
251 .kind(CompletionItemKind::Const) 247 .kind(CompletionItemKind::Const)
252 .set_documentation(constant.docs(ctx.db)) 248 .set_documentation(constant.docs(ctx.db))
253 .set_deprecated(is_deprecated(ast_node)) 249 .set_deprecated(is_deprecated(constant, ctx.db))
254 .detail(detail) 250 .detail(detail)
255 .add_to(self); 251 .add_to(self);
256 } 252 }
@@ -266,13 +262,13 @@ impl Completions {
266 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) 262 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string())
267 .kind(CompletionItemKind::TypeAlias) 263 .kind(CompletionItemKind::TypeAlias)
268 .set_documentation(type_alias.docs(ctx.db)) 264 .set_documentation(type_alias.docs(ctx.db))
269 .set_deprecated(is_deprecated(type_def)) 265 .set_deprecated(is_deprecated(type_alias, ctx.db))
270 .detail(detail) 266 .detail(detail)
271 .add_to(self); 267 .add_to(self);
272 } 268 }
273 269
274 pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { 270 pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) {
275 let is_deprecated = is_deprecated(variant.source(ctx.db).ast); 271 let is_deprecated = is_deprecated(variant, ctx.db);
276 let name = match variant.name(ctx.db) { 272 let name = match variant.name(ctx.db) {
277 Some(it) => it, 273 Some(it) => it,
278 None => return, 274 None => return,
@@ -291,8 +287,11 @@ impl Completions {
291 } 287 }
292} 288}
293 289
294fn is_deprecated(node: impl AttrsOwner) -> bool { 290fn is_deprecated(node: impl Attrs, db: &impl HirDatabase) -> bool {
295 node.attrs().filter_map(|x| x.simple_name()).any(|x| x == "deprecated") 291 match node.attrs(db) {
292 None => false,
293 Some(attrs) => attrs.iter().any(|x| x.is_simple_atom("deprecated")),
294 }
296} 295}
297 296
298fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { 297fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool {