Skip to content

Commit b6d6277

Browse files
committed
Completition for type name? #3418
Iterate through TupleStructPat's until a MatchArm if one exists. Store in a new is_pat_bind_and_path bool and allow the `complete_scope` to find matches. Added some tests to ensure it works in simple and nested cases.
1 parent 1ba03c6 commit b6d6277

File tree

2 files changed

+120
-3
lines changed

2 files changed

+120
-3
lines changed

crates/ra_ide/src/completion/complete_scope.rs

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::completion::{CompletionContext, Completions};
44

55
pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
6-
if !ctx.is_trivial_path {
6+
if !ctx.is_trivial_path && !ctx.is_pat_binding_and_path {
77
return;
88
}
99

@@ -20,6 +20,111 @@ mod tests {
2020
do_completion(ra_fixture, CompletionKind::Reference)
2121
}
2222

23+
#[test]
24+
fn nested_bind_pat_and_path() {
25+
assert_debug_snapshot!(
26+
do_reference_completion(
27+
r"
28+
enum First {
29+
A,
30+
B,
31+
}
32+
enum Second {
33+
A(First),
34+
B(First),
35+
}
36+
fn quux(x: Option<Option<Second>>>) {
37+
match x {
38+
None => (),
39+
Some(Some(Second(Fi<|>))) => (),
40+
}
41+
}
42+
"
43+
),
44+
@r###"
45+
[
46+
CompletionItem {
47+
label: "First",
48+
source_range: [363; 365),
49+
delete: [363; 365),
50+
insert: "First",
51+
kind: Enum,
52+
},
53+
CompletionItem {
54+
label: "Second",
55+
source_range: [363; 365),
56+
delete: [363; 365),
57+
insert: "Second",
58+
kind: Enum,
59+
},
60+
CompletionItem {
61+
label: "quux(…)",
62+
source_range: [363; 365),
63+
delete: [363; 365),
64+
insert: "quux(${1:x})$0",
65+
kind: Function,
66+
lookup: "quux",
67+
detail: "fn quux(x: Option<Option<Second>>)",
68+
},
69+
]
70+
"###
71+
);
72+
}
73+
74+
#[test]
75+
fn bind_pat_and_path() {
76+
assert_debug_snapshot!(
77+
do_reference_completion(
78+
r"
79+
enum Enum {
80+
A,
81+
B,
82+
}
83+
fn quux(x: Option<Enum>) {
84+
match x {
85+
None => (),
86+
Some(en<|>) => (),
87+
}
88+
}
89+
"
90+
),
91+
@r###"
92+
[
93+
CompletionItem {
94+
label: "Enum",
95+
source_range: [231; 233),
96+
delete: [231; 233),
97+
insert: "Enum",
98+
kind: Enum,
99+
},
100+
CompletionItem {
101+
label: "None",
102+
source_range: [231; 233),
103+
delete: [231; 233),
104+
insert: "None",
105+
kind: Binding,
106+
},
107+
CompletionItem {
108+
label: "quux(…)",
109+
source_range: [231; 233),
110+
delete: [231; 233),
111+
insert: "quux(${1:x})$0",
112+
kind: Function,
113+
lookup: "quux",
114+
detail: "fn quux(x: Option<Enum>)",
115+
},
116+
CompletionItem {
117+
label: "x",
118+
source_range: [231; 233),
119+
delete: [231; 233),
120+
insert: "x",
121+
kind: Binding,
122+
},
123+
]
124+
"###
125+
);
126+
}
127+
23128
#[test]
24129
fn completes_bindings_from_let() {
25130
assert_debug_snapshot!(

crates/ra_ide/src/completion/completion_context.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ pub(crate) struct CompletionContext<'a> {
3636
/// If a name-binding or reference to a const in a pattern.
3737
/// Irrefutable patterns (like let) are excluded.
3838
pub(super) is_pat_binding: bool,
39+
// A bind battern which may also be part of a path.
40+
// if let Some(En<|>) = Some(Enum::A)
41+
pub(super) is_pat_binding_and_path: bool,
3942
/// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
4043
pub(super) is_trivial_path: bool,
4144
/// If not a trivial path, the prefix (qualifier).
@@ -95,6 +98,7 @@ impl<'a> CompletionContext<'a> {
9598
impl_def: None,
9699
is_param: false,
97100
is_pat_binding: false,
101+
is_pat_binding_and_path: false,
98102
is_trivial_path: false,
99103
path_prefix: None,
100104
after_if: false,
@@ -186,12 +190,20 @@ impl<'a> CompletionContext<'a> {
186190
// suggest declaration names, see `CompletionKind::Magic`.
187191
if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) {
188192
if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) {
189-
let parent = bind_pat.syntax().parent();
193+
let mut parent = bind_pat.syntax().parent();
190194
if parent.clone().and_then(ast::MatchArm::cast).is_some()
191-
|| parent.and_then(ast::Condition::cast).is_some()
195+
|| parent.clone().and_then(ast::Condition::cast).is_some()
192196
{
193197
self.is_pat_binding = true;
194198
}
199+
200+
while let Some(_) = parent.clone().and_then(ast::TupleStructPat::cast) {
201+
parent = parent.and_then(|p| p.parent());
202+
if parent.clone().and_then(ast::MatchArm::cast).is_some() {
203+
self.is_pat_binding_and_path = true;
204+
break;
205+
}
206+
}
195207
}
196208
if is_node::<ast::Param>(name.syntax()) {
197209
self.is_param = true;

0 commit comments

Comments
 (0)