aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs80
1 files changed, 70 insertions, 10 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index 536ba36df..b6579be63 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -1,19 +1,49 @@
1use hir::{AdtDef, Ty, TypeCtor}; 1use hir::{AdtDef, Ty, TypeCtor};
2 2
3use crate::completion::{CompletionContext, Completions}; 3use crate::{completion::{
4 completion_context::CompletionContext,
5 completion_item::Completions,
6}, CompletionItem};
7use ra_syntax::ast::AstNode;
8use ra_text_edit::TextEditBuilder;
4use rustc_hash::FxHashSet; 9use rustc_hash::FxHashSet;
10use crate::completion::completion_item::{Builder, CompletionKind};
11use ra_syntax::TextRange;
5 12
6/// Complete dot accesses, i.e. fields or methods (currently only fields). 13/// Applies postfix edition but with CompletionKind::Reference
14fn postfix_reference(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
15 let edit = {
16 let receiver_range =
17 ctx.dot_receiver.as_ref().expect("no receiver available").syntax().text_range();
18 let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end());
19 let mut builder = TextEditBuilder::default();
20 builder.replace(delete_range, snippet.to_string());
21 builder.finish()
22 };
23 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), label)
24 .detail(detail)
25 .snippet_edit(edit)
26}
27
28/// Complete dot accesses, i.e. fields or methods (and .await syntax).
7pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 29pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
8 let receiver_ty = 30 if let Some(dot_receiver) = &ctx.dot_receiver {
9 match ctx.dot_receiver.as_ref().and_then(|it| ctx.analyzer.type_of(ctx.db, it)) { 31 let receiver_text = dot_receiver.syntax().text().to_string();
10 Some(it) => it, 32 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver);
11 None => return, 33
12 }; 34 if let Some(receiver_ty) = receiver_ty {
13 if !ctx.is_call { 35 if !ctx.is_call {
14 complete_fields(acc, ctx, receiver_ty.clone()); 36 complete_fields(acc, ctx, receiver_ty.clone());
37 }
38 complete_methods(acc, ctx, receiver_ty.clone());
39
40 // Suggest .await syntax for types that implement std::future::Future
41 if ctx.analyzer.impls_future(ctx.db, receiver_ty) {
42 postfix_reference(ctx, ".await", "expr.await", &format!("{}.await", receiver_text))
43 .add_to(acc);
44 }
45 }
15 } 46 }
16 complete_methods(acc, ctx, receiver_ty);
17} 47}
18 48
19fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { 49fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
@@ -406,4 +436,34 @@ mod tests {
406 "### 436 "###
407 ); 437 );
408 } 438 }
439
440 #[test]
441 fn test_completion_await_impls_future() {
442 assert_debug_snapshot_matches!(
443 do_ref_completion(
444 r"
445 // Mock Future trait from stdlib
446 pub mod std { pub mod future { pub trait Future {} } }
447
448 use std::future::*;
449 struct A {}
450 impl Future for A {}
451
452 fn foo(a: A) {
453 a.<|>
454 }
455 "),
456 @r###"
457 ⋮[
458 ⋮ CompletionItem {
459 ⋮ label: ".await",
460 ⋮ source_range: [249; 249),
461 ⋮ delete: [247; 249),
462 ⋮ insert: "a.await",
463 ⋮ detail: "expr.await",
464 ⋮ },
465 ⋮]
466 "###
467 )
468 }
409} 469}