aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion/complete_dot.rs
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-11-27 18:32:33 +0000
committerAleksey Kladov <[email protected]>2019-11-27 18:35:06 +0000
commit757e593b253b4df7e6fc8bf15a4d4f34c9d484c5 (patch)
treed972d3a7e6457efdb5e0c558a8350db1818d07ae /crates/ra_ide/src/completion/complete_dot.rs
parentd9a36a736bfb91578a36505e7237212959bb55fe (diff)
rename ra_ide_api -> ra_ide
Diffstat (limited to 'crates/ra_ide/src/completion/complete_dot.rs')
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs456
1 files changed, 456 insertions, 0 deletions
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
new file mode 100644
index 000000000..b6fe48627
--- /dev/null
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -0,0 +1,456 @@
1//! FIXME: write short doc here
2
3use hir::Type;
4
5use crate::completion::completion_item::CompletionKind;
6use crate::{
7 completion::{completion_context::CompletionContext, completion_item::Completions},
8 CompletionItem,
9};
10use rustc_hash::FxHashSet;
11
12/// Complete dot accesses, i.e. fields or methods (and .await syntax).
13pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
14 let dot_receiver = match &ctx.dot_receiver {
15 Some(expr) => expr,
16 _ => return,
17 };
18
19 let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) {
20 Some(ty) => ty,
21 _ => return,
22 };
23
24 if !ctx.is_call {
25 complete_fields(acc, ctx, &receiver_ty);
26 }
27 complete_methods(acc, ctx, &receiver_ty);
28
29 // Suggest .await syntax for types that implement Future trait
30 if ctx.analyzer.impls_future(ctx.db, receiver_ty.into_ty()) {
31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
32 .detail("expr.await")
33 .insert_text("await")
34 .add_to(acc);
35 }
36}
37
38fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
39 for receiver in receiver.autoderef(ctx.db) {
40 for (field, ty) in receiver.fields(ctx.db) {
41 acc.add_field(ctx, field, &ty);
42 }
43 for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
44 acc.add_tuple_field(ctx, i, &ty);
45 }
46 }
47}
48
49fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) {
50 let mut seen_methods = FxHashSet::default();
51 ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| {
52 if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) {
53 acc.add_function(ctx, func);
54 }
55 None::<()>
56 });
57}
58
59#[cfg(test)]
60mod tests {
61 use crate::completion::{do_completion, CompletionItem, CompletionKind};
62 use insta::assert_debug_snapshot;
63
64 fn do_ref_completion(code: &str) -> Vec<CompletionItem> {
65 do_completion(code, CompletionKind::Reference)
66 }
67
68 #[test]
69 fn test_struct_field_completion() {
70 assert_debug_snapshot!(
71 do_ref_completion(
72 r"
73 struct A { the_field: u32 }
74 fn foo(a: A) {
75 a.<|>
76 }
77 ",
78 ),
79 @r###"
80 [
81 CompletionItem {
82 label: "the_field",
83 source_range: [94; 94),
84 delete: [94; 94),
85 insert: "the_field",
86 kind: Field,
87 detail: "u32",
88 },
89 ]
90 "###
91 );
92 }
93
94 #[test]
95 fn test_struct_field_completion_self() {
96 assert_debug_snapshot!(
97 do_ref_completion(
98 r"
99 struct A {
100 /// This is the_field
101 the_field: (u32,)
102 }
103 impl A {
104 fn foo(self) {
105 self.<|>
106 }
107 }
108 ",
109 ),
110 @r###"
111 [
112 CompletionItem {
113 label: "foo()",
114 source_range: [187; 187),
115 delete: [187; 187),
116 insert: "foo()$0",
117 kind: Method,
118 lookup: "foo",
119 detail: "fn foo(self)",
120 },
121 CompletionItem {
122 label: "the_field",
123 source_range: [187; 187),
124 delete: [187; 187),
125 insert: "the_field",
126 kind: Field,
127 detail: "(u32,)",
128 documentation: Documentation(
129 "This is the_field",
130 ),
131 },
132 ]
133 "###
134 );
135 }
136
137 #[test]
138 fn test_struct_field_completion_autoderef() {
139 assert_debug_snapshot!(
140 do_ref_completion(
141 r"
142 struct A { the_field: (u32, i32) }
143 impl A {
144 fn foo(&self) {
145 self.<|>
146 }
147 }
148 ",
149 ),
150 @r###"
151 [
152 CompletionItem {
153 label: "foo()",
154 source_range: [126; 126),
155 delete: [126; 126),
156 insert: "foo()$0",
157 kind: Method,
158 lookup: "foo",
159 detail: "fn foo(&self)",
160 },
161 CompletionItem {
162 label: "the_field",
163 source_range: [126; 126),
164 delete: [126; 126),
165 insert: "the_field",
166 kind: Field,
167 detail: "(u32, i32)",
168 },
169 ]
170 "###
171 );
172 }
173
174 #[test]
175 fn test_no_struct_field_completion_for_method_call() {
176 assert_debug_snapshot!(
177 do_ref_completion(
178 r"
179 struct A { the_field: u32 }
180 fn foo(a: A) {
181 a.<|>()
182 }
183 ",
184 ),
185 @"[]"
186 );
187 }
188
189 #[test]
190 fn test_method_completion() {
191 assert_debug_snapshot!(
192 do_ref_completion(
193 r"
194 struct A {}
195 impl A {
196 fn the_method(&self) {}
197 }
198 fn foo(a: A) {
199 a.<|>
200 }
201 ",
202 ),
203 @r###"
204 [
205 CompletionItem {
206 label: "the_method()",
207 source_range: [144; 144),
208 delete: [144; 144),
209 insert: "the_method()$0",
210 kind: Method,
211 lookup: "the_method",
212 detail: "fn the_method(&self)",
213 },
214 ]
215 "###
216 );
217 }
218
219 #[test]
220 fn test_trait_method_completion() {
221 assert_debug_snapshot!(
222 do_ref_completion(
223 r"
224 struct A {}
225 trait Trait { fn the_method(&self); }
226 impl Trait for A {}
227 fn foo(a: A) {
228 a.<|>
229 }
230 ",
231 ),
232 @r###"
233 [
234 CompletionItem {
235 label: "the_method()",
236 source_range: [151; 151),
237 delete: [151; 151),
238 insert: "the_method()$0",
239 kind: Method,
240 lookup: "the_method",
241 detail: "fn the_method(&self)",
242 },
243 ]
244 "###
245 );
246 }
247
248 #[test]
249 fn test_trait_method_completion_deduplicated() {
250 assert_debug_snapshot!(
251 do_ref_completion(
252 r"
253 struct A {}
254 trait Trait { fn the_method(&self); }
255 impl<T> Trait for T {}
256 fn foo(a: &A) {
257 a.<|>
258 }
259 ",
260 ),
261 @r###"
262 [
263 CompletionItem {
264 label: "the_method()",
265 source_range: [155; 155),
266 delete: [155; 155),
267 insert: "the_method()$0",
268 kind: Method,
269 lookup: "the_method",
270 detail: "fn the_method(&self)",
271 },
272 ]
273 "###
274 );
275 }
276
277 #[test]
278 fn test_no_non_self_method() {
279 assert_debug_snapshot!(
280 do_ref_completion(
281 r"
282 struct A {}
283 impl A {
284 fn the_method() {}
285 }
286 fn foo(a: A) {
287 a.<|>
288 }
289 ",
290 ),
291 @"[]"
292 );
293 }
294
295 #[test]
296 fn test_method_attr_filtering() {
297 assert_debug_snapshot!(
298 do_ref_completion(
299 r"
300 struct A {}
301 impl A {
302 #[inline]
303 fn the_method(&self) {
304 let x = 1;
305 let y = 2;
306 }
307 }
308 fn foo(a: A) {
309 a.<|>
310 }
311 ",
312 ),
313 @r###"
314 [
315 CompletionItem {
316 label: "the_method()",
317 source_range: [249; 249),
318 delete: [249; 249),
319 insert: "the_method()$0",
320 kind: Method,
321 lookup: "the_method",
322 detail: "fn the_method(&self)",
323 },
324 ]
325 "###
326 );
327 }
328
329 #[test]
330 fn test_tuple_field_completion() {
331 assert_debug_snapshot!(
332 do_ref_completion(
333 r"
334 fn foo() {
335 let b = (0, 3.14);
336 b.<|>
337 }
338 ",
339 ),
340 @r###"
341 [
342 CompletionItem {
343 label: "0",
344 source_range: [75; 75),
345 delete: [75; 75),
346 insert: "0",
347 kind: Field,
348 detail: "i32",
349 },
350 CompletionItem {
351 label: "1",
352 source_range: [75; 75),
353 delete: [75; 75),
354 insert: "1",
355 kind: Field,
356 detail: "f64",
357 },
358 ]
359 "###
360 );
361 }
362
363 #[test]
364 fn test_tuple_field_inference() {
365 assert_debug_snapshot!(
366 do_ref_completion(
367 r"
368 pub struct S;
369 impl S {
370 pub fn blah(&self) {}
371 }
372
373 struct T(S);
374
375 impl T {
376 fn foo(&self) {
377 // FIXME: This doesn't work without the trailing `a` as `0.` is a float
378 self.0.a<|>
379 }
380 }
381 ",
382 ),
383 @r###"
384 [
385 CompletionItem {
386 label: "blah()",
387 source_range: [299; 300),
388 delete: [299; 300),
389 insert: "blah()$0",
390 kind: Method,
391 lookup: "blah",
392 detail: "pub fn blah(&self)",
393 },
394 ]
395 "###
396 );
397 }
398
399 #[test]
400 fn test_completion_works_in_consts() {
401 assert_debug_snapshot!(
402 do_ref_completion(
403 r"
404 struct A { the_field: u32 }
405 const X: u32 = {
406 A { the_field: 92 }.<|>
407 };
408 ",
409 ),
410 @r###"
411 [
412 CompletionItem {
413 label: "the_field",
414 source_range: [106; 106),
415 delete: [106; 106),
416 insert: "the_field",
417 kind: Field,
418 detail: "u32",
419 },
420 ]
421 "###
422 );
423 }
424
425 #[test]
426 fn test_completion_await_impls_future() {
427 assert_debug_snapshot!(
428 do_completion(
429 r###"
430 //- /main.rs
431 use std::future::*;
432 struct A {}
433 impl Future for A {}
434 fn foo(a: A) {
435 a.<|>
436 }
437
438 //- /std/lib.rs
439 pub mod future {
440 pub trait Future {}
441 }
442 "###, CompletionKind::Keyword),
443 @r###"
444 [
445 CompletionItem {
446 label: "await",
447 source_range: [74; 74),
448 delete: [74; 74),
449 insert: "await",
450 detail: "expr.await",
451 },
452 ]
453 "###
454 )
455 }
456}