aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/completion/complete_dot.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-12-27 10:08:34 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-12-27 10:08:34 +0000
commit1d6dcef5c584d0dffdf5386eec993e41daad0210 (patch)
tree1e67675b7031115b1811863d0f186ad1f98b1fce /crates/ra_analysis/src/completion/complete_dot.rs
parent700165cf17290561dea511565278b9869ed61625 (diff)
parentbc745a139674f289386f3081458793f756cab5b9 (diff)
Merge #332
332: Struct types r=matklad a=flodiebold Infer types for struct fields, and add basic field completions. There's also some code for enums, but I focused on getting structs working. There's still ways to go before this becomes useful: There's no autoderef (or even reference types) and no inference for `self`, for example. Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_analysis/src/completion/complete_dot.rs')
-rw-r--r--crates/ra_analysis/src/completion/complete_dot.rs98
1 files changed, 98 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/completion/complete_dot.rs b/crates/ra_analysis/src/completion/complete_dot.rs
new file mode 100644
index 000000000..93d657576
--- /dev/null
+++ b/crates/ra_analysis/src/completion/complete_dot.rs
@@ -0,0 +1,98 @@
1use ra_syntax::ast::AstNode;
2use hir::{Ty, Def};
3
4use crate::Cancelable;
5use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem, CompletionItemKind};
6
7/// Complete dot accesses, i.e. fields or methods (currently only fields).
8pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) -> Cancelable<()> {
9 let module = if let Some(module) = &ctx.module {
10 module
11 } else {
12 return Ok(());
13 };
14 let function = if let Some(fn_def) = ctx.enclosing_fn {
15 hir::source_binder::function_from_module(ctx.db, module, fn_def)
16 } else {
17 return Ok(());
18 };
19 let receiver = if let Some(receiver) = ctx.dot_receiver {
20 receiver
21 } else {
22 return Ok(());
23 };
24 let infer_result = function.infer(ctx.db)?;
25 let receiver_ty = if let Some(ty) = infer_result.type_of_node(receiver.syntax()) {
26 ty
27 } else {
28 return Ok(());
29 };
30 if !ctx.is_method_call {
31 complete_fields(acc, ctx, receiver_ty)?;
32 }
33 Ok(())
34}
35
36fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) -> Cancelable<()> {
37 // TODO: autoderef etc.
38 match receiver {
39 Ty::Adt { def_id, .. } => {
40 match def_id.resolve(ctx.db)? {
41 Def::Struct(s) => {
42 let variant_data = s.variant_data(ctx.db)?;
43 for field in variant_data.fields() {
44 CompletionItem::new(CompletionKind::Reference, field.name().to_string())
45 .kind(CompletionItemKind::Field)
46 .add_to(acc);
47 }
48 }
49 // TODO unions
50 _ => {}
51 }
52 }
53 Ty::Tuple(fields) => {
54 for (i, _ty) in fields.iter().enumerate() {
55 CompletionItem::new(CompletionKind::Reference, i.to_string())
56 .kind(CompletionItemKind::Field)
57 .add_to(acc);
58 }
59 }
60 _ => {}
61 };
62 Ok(())
63}
64
65#[cfg(test)]
66mod tests {
67 use crate::completion::*;
68
69 fn check_ref_completion(code: &str, expected_completions: &str) {
70 check_completion(code, expected_completions, CompletionKind::Reference);
71 }
72
73 #[test]
74 fn test_struct_field_completion() {
75 check_ref_completion(
76 r"
77 struct A { the_field: u32 }
78 fn foo(a: A) {
79 a.<|>
80 }
81 ",
82 r#"the_field"#,
83 );
84 }
85
86 #[test]
87 fn test_no_struct_field_completion_for_method_call() {
88 check_ref_completion(
89 r"
90 struct A { the_field: u32 }
91 fn foo(a: A) {
92 a.<|>()
93 }
94 ",
95 r#""#,
96 );
97 }
98}