diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-24 14:39:38 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-24 14:39:38 +0000 |
commit | 67528c4b3943a2027839a25770d079132a9ea130 (patch) | |
tree | 571b1729dd66b3597736069834529ba88460f2fe /crates/ra_ide_api/src | |
parent | c52c8c2c5bd8b054eee5946ce5e5bd7ecfe9998a (diff) | |
parent | 6285fcc39b70bc92de5188a5eb64ee8d73fa8970 (diff) |
Merge #891
891: Field completion r=matklad a=matklad
bors r+
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r-- | crates/ra_ide_api/src/completion.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_struct_literal.rs | 73 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/completion_context.rs | 6 |
3 files changed, 81 insertions, 0 deletions
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs index 4a38d62bb..d92e01bfb 100644 --- a/crates/ra_ide_api/src/completion.rs +++ b/crates/ra_ide_api/src/completion.rs | |||
@@ -2,6 +2,7 @@ mod completion_item; | |||
2 | mod completion_context; | 2 | mod completion_context; |
3 | 3 | ||
4 | mod complete_dot; | 4 | mod complete_dot; |
5 | mod complete_struct_literal; | ||
5 | mod complete_fn_param; | 6 | mod complete_fn_param; |
6 | mod complete_keyword; | 7 | mod complete_keyword; |
7 | mod complete_snippet; | 8 | mod complete_snippet; |
@@ -59,6 +60,7 @@ pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Opti | |||
59 | complete_path::complete_path(&mut acc, &ctx); | 60 | complete_path::complete_path(&mut acc, &ctx); |
60 | complete_scope::complete_scope(&mut acc, &ctx); | 61 | complete_scope::complete_scope(&mut acc, &ctx); |
61 | complete_dot::complete_dot(&mut acc, &ctx); | 62 | complete_dot::complete_dot(&mut acc, &ctx); |
63 | complete_struct_literal::complete_struct_literal(&mut acc, &ctx); | ||
62 | complete_postfix::complete_postfix(&mut acc, &ctx); | 64 | complete_postfix::complete_postfix(&mut acc, &ctx); |
63 | Some(acc) | 65 | Some(acc) |
64 | } | 66 | } |
diff --git a/crates/ra_ide_api/src/completion/complete_struct_literal.rs b/crates/ra_ide_api/src/completion/complete_struct_literal.rs new file mode 100644 index 000000000..f8dd2baad --- /dev/null +++ b/crates/ra_ide_api/src/completion/complete_struct_literal.rs | |||
@@ -0,0 +1,73 @@ | |||
1 | use hir::{Ty, AdtDef, Docs}; | ||
2 | |||
3 | use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionItemKind}; | ||
4 | use crate::completion::completion_item::CompletionKind; | ||
5 | |||
6 | /// Complete fields in fields literals. | ||
7 | pub(super) fn complete_struct_literal(acc: &mut Completions, ctx: &CompletionContext) { | ||
8 | let (function, struct_lit) = match (&ctx.function, ctx.struct_lit_syntax) { | ||
9 | (Some(function), Some(struct_lit)) => (function, struct_lit), | ||
10 | _ => return, | ||
11 | }; | ||
12 | let infer_result = function.infer(ctx.db); | ||
13 | let syntax_mapping = function.body_syntax_mapping(ctx.db); | ||
14 | let expr = match syntax_mapping.node_expr(struct_lit.into()) { | ||
15 | Some(expr) => expr, | ||
16 | None => return, | ||
17 | }; | ||
18 | let ty = infer_result[expr].clone(); | ||
19 | let (adt, substs) = match ty { | ||
20 | Ty::Adt { def_id, ref substs, .. } => (def_id, substs), | ||
21 | _ => return, | ||
22 | }; | ||
23 | match adt { | ||
24 | AdtDef::Struct(s) => { | ||
25 | for field in s.fields(ctx.db) { | ||
26 | CompletionItem::new( | ||
27 | CompletionKind::Reference, | ||
28 | ctx.source_range(), | ||
29 | field.name(ctx.db).to_string(), | ||
30 | ) | ||
31 | .kind(CompletionItemKind::Field) | ||
32 | .detail(field.ty(ctx.db).subst(substs).to_string()) | ||
33 | .set_documentation(field.docs(ctx.db)) | ||
34 | .add_to(acc); | ||
35 | } | ||
36 | } | ||
37 | |||
38 | // TODO unions | ||
39 | AdtDef::Enum(_) => (), | ||
40 | }; | ||
41 | } | ||
42 | |||
43 | #[cfg(test)] | ||
44 | mod tests { | ||
45 | use insta::assert_debug_snapshot_matches; | ||
46 | use crate::completion::{CompletionItem, CompletionKind}; | ||
47 | |||
48 | fn complete(code: &str) -> Vec<CompletionItem> { | ||
49 | crate::completion::completion_item::do_completion(code, CompletionKind::Reference) | ||
50 | } | ||
51 | |||
52 | #[test] | ||
53 | fn test_struct_literal_field() { | ||
54 | let completions = complete( | ||
55 | r" | ||
56 | struct A { the_field: u32 } | ||
57 | fn foo() { | ||
58 | A { the<|> } | ||
59 | } | ||
60 | ", | ||
61 | ); | ||
62 | assert_debug_snapshot_matches!(completions, @r###"[ | ||
63 | CompletionItem { | ||
64 | label: "the_field", | ||
65 | source_range: [83; 86), | ||
66 | delete: [83; 86), | ||
67 | insert: "the_field", | ||
68 | kind: Field, | ||
69 | detail: "u32" | ||
70 | } | ||
71 | ]"###); | ||
72 | } | ||
73 | } | ||
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index b9f0abe19..d351be054 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs | |||
@@ -21,6 +21,7 @@ pub(crate) struct CompletionContext<'a> { | |||
21 | pub(super) function: Option<hir::Function>, | 21 | pub(super) function: Option<hir::Function>, |
22 | pub(super) function_syntax: Option<&'a ast::FnDef>, | 22 | pub(super) function_syntax: Option<&'a ast::FnDef>, |
23 | pub(super) use_item_syntax: Option<&'a ast::UseItem>, | 23 | pub(super) use_item_syntax: Option<&'a ast::UseItem>, |
24 | pub(super) struct_lit_syntax: Option<&'a ast::StructLit>, | ||
24 | pub(super) is_param: bool, | 25 | pub(super) is_param: bool, |
25 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. | 26 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. |
26 | pub(super) is_trivial_path: bool, | 27 | pub(super) is_trivial_path: bool, |
@@ -55,6 +56,7 @@ impl<'a> CompletionContext<'a> { | |||
55 | function: None, | 56 | function: None, |
56 | function_syntax: None, | 57 | function_syntax: None, |
57 | use_item_syntax: None, | 58 | use_item_syntax: None, |
59 | struct_lit_syntax: None, | ||
58 | is_param: false, | 60 | is_param: false, |
59 | is_trivial_path: false, | 61 | is_trivial_path: false, |
60 | path_prefix: None, | 62 | path_prefix: None, |
@@ -108,6 +110,10 @@ impl<'a> CompletionContext<'a> { | |||
108 | } | 110 | } |
109 | fn classify_name_ref(&mut self, original_file: &'a SourceFile, name_ref: &ast::NameRef) { | 111 | fn classify_name_ref(&mut self, original_file: &'a SourceFile, name_ref: &ast::NameRef) { |
110 | let name_range = name_ref.syntax().range(); | 112 | let name_range = name_ref.syntax().range(); |
113 | if name_ref.syntax().parent().and_then(ast::NamedField::cast).is_some() { | ||
114 | self.struct_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset); | ||
115 | } | ||
116 | |||
111 | let top_node = | 117 | let top_node = |
112 | name_ref.syntax().ancestors().take_while(|it| it.range() == name_range).last().unwrap(); | 118 | name_ref.syntax().ancestors().take_while(|it| it.range() == name_range).last().unwrap(); |
113 | 119 | ||