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.
This commit is contained in:
Steffen Lyngbaek 2020-03-09 18:10:25 -07:00
parent 1ba03c6995
commit b6d6277362
2 changed files with 120 additions and 3 deletions

View File

@ -3,7 +3,7 @@
use crate::completion::{CompletionContext, Completions};
pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
if !ctx.is_trivial_path {
if !ctx.is_trivial_path && !ctx.is_pat_binding_and_path {
return;
}
@ -20,6 +20,111 @@ fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> {
do_completion(ra_fixture, CompletionKind::Reference)
}
#[test]
fn nested_bind_pat_and_path() {
assert_debug_snapshot!(
do_reference_completion(
r"
enum First {
A,
B,
}
enum Second {
A(First),
B(First),
}
fn quux(x: Option<Option<Second>>>) {
match x {
None => (),
Some(Some(Second(Fi<|>))) => (),
}
}
"
),
@r###"
[
CompletionItem {
label: "First",
source_range: [363; 365),
delete: [363; 365),
insert: "First",
kind: Enum,
},
CompletionItem {
label: "Second",
source_range: [363; 365),
delete: [363; 365),
insert: "Second",
kind: Enum,
},
CompletionItem {
label: "quux(…)",
source_range: [363; 365),
delete: [363; 365),
insert: "quux(${1:x})$0",
kind: Function,
lookup: "quux",
detail: "fn quux(x: Option<Option<Second>>)",
},
]
"###
);
}
#[test]
fn bind_pat_and_path() {
assert_debug_snapshot!(
do_reference_completion(
r"
enum Enum {
A,
B,
}
fn quux(x: Option<Enum>) {
match x {
None => (),
Some(en<|>) => (),
}
}
"
),
@r###"
[
CompletionItem {
label: "Enum",
source_range: [231; 233),
delete: [231; 233),
insert: "Enum",
kind: Enum,
},
CompletionItem {
label: "None",
source_range: [231; 233),
delete: [231; 233),
insert: "None",
kind: Binding,
},
CompletionItem {
label: "quux(…)",
source_range: [231; 233),
delete: [231; 233),
insert: "quux(${1:x})$0",
kind: Function,
lookup: "quux",
detail: "fn quux(x: Option<Enum>)",
},
CompletionItem {
label: "x",
source_range: [231; 233),
delete: [231; 233),
insert: "x",
kind: Binding,
},
]
"###
);
}
#[test]
fn completes_bindings_from_let() {
assert_debug_snapshot!(

View File

@ -36,6 +36,9 @@ pub(crate) struct CompletionContext<'a> {
/// If a name-binding or reference to a const in a pattern.
/// Irrefutable patterns (like let) are excluded.
pub(super) is_pat_binding: bool,
// A bind battern which may also be part of a path.
// if let Some(En<|>) = Some(Enum::A)
pub(super) is_pat_binding_and_path: bool,
/// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
pub(super) is_trivial_path: bool,
/// If not a trivial path, the prefix (qualifier).
@ -95,6 +98,7 @@ pub(super) fn new(
impl_def: None,
is_param: false,
is_pat_binding: false,
is_pat_binding_and_path: false,
is_trivial_path: false,
path_prefix: None,
after_if: false,
@ -186,12 +190,20 @@ fn fill(
// suggest declaration names, see `CompletionKind::Magic`.
if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) {
if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) {
let parent = bind_pat.syntax().parent();
let mut parent = bind_pat.syntax().parent();
if parent.clone().and_then(ast::MatchArm::cast).is_some()
|| parent.and_then(ast::Condition::cast).is_some()
|| parent.clone().and_then(ast::Condition::cast).is_some()
{
self.is_pat_binding = true;
}
while let Some(_) = parent.clone().and_then(ast::TupleStructPat::cast) {
parent = parent.and_then(|p| p.parent());
if parent.clone().and_then(ast::MatchArm::cast).is_some() {
self.is_pat_binding_and_path = true;
break;
}
}
}
if is_node::<ast::Param>(name.syntax()) {
self.is_param = true;