Unite record completion logic into a single module
This commit is contained in:
parent
d35b943520
commit
1335608dae
4 changed files with 413 additions and 450 deletions
|
@ -5,8 +5,7 @@ mod completion_context;
|
||||||
mod presentation;
|
mod presentation;
|
||||||
|
|
||||||
mod complete_dot;
|
mod complete_dot;
|
||||||
mod complete_record_literal;
|
mod complete_record;
|
||||||
mod complete_record_pattern;
|
|
||||||
mod complete_pattern;
|
mod complete_pattern;
|
||||||
mod complete_fn_param;
|
mod complete_fn_param;
|
||||||
mod complete_keyword;
|
mod complete_keyword;
|
||||||
|
@ -32,12 +31,6 @@ use crate::{
|
||||||
pub use crate::completion::completion_item::{
|
pub use crate::completion::completion_item::{
|
||||||
CompletionItem, CompletionItemKind, InsertTextFormat,
|
CompletionItem, CompletionItemKind, InsertTextFormat,
|
||||||
};
|
};
|
||||||
use either::Either;
|
|
||||||
use hir::{StructField, Type};
|
|
||||||
use ra_syntax::{
|
|
||||||
ast::{self, NameOwner},
|
|
||||||
SmolStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct CompletionConfig {
|
pub struct CompletionConfig {
|
||||||
|
@ -95,8 +88,7 @@ pub(crate) fn completions(
|
||||||
complete_path::complete_path(&mut acc, &ctx);
|
complete_path::complete_path(&mut acc, &ctx);
|
||||||
complete_scope::complete_scope(&mut acc, &ctx);
|
complete_scope::complete_scope(&mut acc, &ctx);
|
||||||
complete_dot::complete_dot(&mut acc, &ctx);
|
complete_dot::complete_dot(&mut acc, &ctx);
|
||||||
complete_record_literal::complete_record_literal(&mut acc, &ctx);
|
complete_record::complete_record(&mut acc, &ctx);
|
||||||
complete_record_pattern::complete_record_pattern(&mut acc, &ctx);
|
|
||||||
complete_pattern::complete_pattern(&mut acc, &ctx);
|
complete_pattern::complete_pattern(&mut acc, &ctx);
|
||||||
complete_postfix::complete_postfix(&mut acc, &ctx);
|
complete_postfix::complete_postfix(&mut acc, &ctx);
|
||||||
complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
|
complete_macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
|
||||||
|
@ -104,57 +96,3 @@ pub(crate) fn completions(
|
||||||
|
|
||||||
Some(acc)
|
Some(acc)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_missing_fields(
|
|
||||||
ctx: &CompletionContext,
|
|
||||||
record: Either<&ast::RecordLit, &ast::RecordPat>,
|
|
||||||
) -> Option<Vec<(StructField, Type)>> {
|
|
||||||
let (ty, variant) = match record {
|
|
||||||
Either::Left(record_lit) => (
|
|
||||||
ctx.sema.type_of_expr(&record_lit.clone().into())?,
|
|
||||||
ctx.sema.resolve_record_literal(record_lit)?,
|
|
||||||
),
|
|
||||||
Either::Right(record_pat) => (
|
|
||||||
ctx.sema.type_of_pat(&record_pat.clone().into())?,
|
|
||||||
ctx.sema.resolve_record_pattern(record_pat)?,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
let already_present_names = get_already_present_names(record);
|
|
||||||
Some(
|
|
||||||
ty.variant_fields(ctx.db, variant)
|
|
||||||
.into_iter()
|
|
||||||
.filter(|(field, _)| {
|
|
||||||
!already_present_names.contains(&SmolStr::from(field.name(ctx.db).to_string()))
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_already_present_names(record: Either<&ast::RecordLit, &ast::RecordPat>) -> Vec<SmolStr> {
|
|
||||||
// TODO kb have a single match
|
|
||||||
match record {
|
|
||||||
Either::Left(record_lit) => record_lit
|
|
||||||
.record_field_list()
|
|
||||||
.map(|field_list| field_list.fields())
|
|
||||||
.map(|fields| {
|
|
||||||
fields
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|field| field.name_ref())
|
|
||||||
.map(|name_ref| name_ref.text().clone())
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.unwrap_or_default(),
|
|
||||||
Either::Right(record_pat) => record_pat
|
|
||||||
.record_field_pat_list()
|
|
||||||
.map(|pat_list| pat_list.bind_pats())
|
|
||||||
.map(|bind_pats| {
|
|
||||||
bind_pats
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|pat| pat.name())
|
|
||||||
.map(|name| name.text().clone())
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.unwrap_or_default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
411
crates/ra_ide/src/completion/complete_record.rs
Normal file
411
crates/ra_ide/src/completion/complete_record.rs
Normal file
|
@ -0,0 +1,411 @@
|
||||||
|
//! Complete fields in record literals and patterns.
|
||||||
|
use crate::completion::{CompletionContext, Completions};
|
||||||
|
use ra_syntax::{ast, ast::NameOwner, SmolStr};
|
||||||
|
|
||||||
|
pub(super) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
|
||||||
|
let (ty, variant, already_present_fields) =
|
||||||
|
match (ctx.record_lit_pat.as_ref(), ctx.record_lit_syntax.as_ref()) {
|
||||||
|
(None, None) => return None,
|
||||||
|
(Some(_), Some(_)) => panic!("A record cannot be both a literal and a pattern"),
|
||||||
|
(Some(record_pat), _) => (
|
||||||
|
ctx.sema.type_of_pat(&record_pat.clone().into())?,
|
||||||
|
ctx.sema.resolve_record_pattern(record_pat)?,
|
||||||
|
pattern_ascribed_fields(record_pat),
|
||||||
|
),
|
||||||
|
(_, Some(record_lit)) => (
|
||||||
|
ctx.sema.type_of_expr(&record_lit.clone().into())?,
|
||||||
|
ctx.sema.resolve_record_literal(record_lit)?,
|
||||||
|
literal_ascribed_fields(record_lit),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (field, field_ty) in ty.variant_fields(ctx.db, variant).into_iter().filter(|(field, _)| {
|
||||||
|
// FIXME: already_present_names better be `Vec<hir::Name>`
|
||||||
|
!already_present_fields.contains(&SmolStr::from(field.name(ctx.db).to_string()))
|
||||||
|
}) {
|
||||||
|
acc.add_field(ctx, field, &field_ty);
|
||||||
|
}
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn literal_ascribed_fields(record_lit: &ast::RecordLit) -> Vec<SmolStr> {
|
||||||
|
record_lit
|
||||||
|
.record_field_list()
|
||||||
|
.map(|field_list| field_list.fields())
|
||||||
|
.map(|fields| {
|
||||||
|
fields
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|field| field.name_ref())
|
||||||
|
.map(|name_ref| name_ref.text().clone())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pattern_ascribed_fields(record_pat: &ast::RecordPat) -> Vec<SmolStr> {
|
||||||
|
record_pat
|
||||||
|
.record_field_pat_list()
|
||||||
|
.map(|pat_list| {
|
||||||
|
pat_list
|
||||||
|
.record_field_pats()
|
||||||
|
.filter_map(|fild_pat| fild_pat.name())
|
||||||
|
.chain(pat_list.bind_pats().filter_map(|bind_pat| bind_pat.name()))
|
||||||
|
.map(|name| name.text().clone())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
mod record_lit_tests {
|
||||||
|
use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
|
||||||
|
use insta::assert_debug_snapshot;
|
||||||
|
|
||||||
|
fn complete(code: &str) -> Vec<CompletionItem> {
|
||||||
|
do_completion(code, CompletionKind::Reference)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_pattern_field() {
|
||||||
|
let completions = complete(
|
||||||
|
r"
|
||||||
|
struct S { foo: u32 }
|
||||||
|
|
||||||
|
fn process(f: S) {
|
||||||
|
match f {
|
||||||
|
S { f<|>: 92 } => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(completions, @r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "foo",
|
||||||
|
source_range: [117; 118),
|
||||||
|
delete: [117; 118),
|
||||||
|
insert: "foo",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_pattern_enum_variant() {
|
||||||
|
let completions = complete(
|
||||||
|
r"
|
||||||
|
enum E {
|
||||||
|
S { foo: u32, bar: () }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process(e: E) {
|
||||||
|
match e {
|
||||||
|
E::S { <|> } => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(completions, @r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "bar",
|
||||||
|
source_range: [161; 161),
|
||||||
|
delete: [161; 161),
|
||||||
|
insert: "bar",
|
||||||
|
kind: Field,
|
||||||
|
detail: "()",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "foo",
|
||||||
|
source_range: [161; 161),
|
||||||
|
delete: [161; 161),
|
||||||
|
insert: "foo",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_pattern_field_in_simple_macro() {
|
||||||
|
let completions = complete(
|
||||||
|
r"
|
||||||
|
macro_rules! m { ($e:expr) => { $e } }
|
||||||
|
struct S { foo: u32 }
|
||||||
|
|
||||||
|
fn process(f: S) {
|
||||||
|
m!(match f {
|
||||||
|
S { f<|>: 92 } => (),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(completions, @r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "foo",
|
||||||
|
source_range: [171; 172),
|
||||||
|
delete: [171; 172),
|
||||||
|
insert: "foo",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn only_missing_fields_are_completed_in_destruct_pats() {
|
||||||
|
let completions = complete(
|
||||||
|
r"
|
||||||
|
struct S {
|
||||||
|
foo1: u32,
|
||||||
|
foo2: u32,
|
||||||
|
bar: u32,
|
||||||
|
baz: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = S {
|
||||||
|
foo1: 1,
|
||||||
|
foo2: 2,
|
||||||
|
bar: 3,
|
||||||
|
baz: 4,
|
||||||
|
};
|
||||||
|
if let S { foo1, foo2: a, <|> } = s {}
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(completions, @r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "bar",
|
||||||
|
source_range: [372; 372),
|
||||||
|
delete: [372; 372),
|
||||||
|
insert: "bar",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "baz",
|
||||||
|
source_range: [372; 372),
|
||||||
|
delete: [372; 372),
|
||||||
|
insert: "baz",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod record_pat_tests {
|
||||||
|
use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
|
||||||
|
use insta::assert_debug_snapshot;
|
||||||
|
|
||||||
|
fn complete(code: &str) -> Vec<CompletionItem> {
|
||||||
|
do_completion(code, CompletionKind::Reference)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_literal_deprecated_field() {
|
||||||
|
let completions = complete(
|
||||||
|
r"
|
||||||
|
struct A {
|
||||||
|
#[deprecated]
|
||||||
|
the_field: u32,
|
||||||
|
}
|
||||||
|
fn foo() {
|
||||||
|
A { the<|> }
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(completions, @r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "the_field",
|
||||||
|
source_range: [142; 145),
|
||||||
|
delete: [142; 145),
|
||||||
|
insert: "the_field",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
deprecated: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_literal_field() {
|
||||||
|
let completions = complete(
|
||||||
|
r"
|
||||||
|
struct A { the_field: u32 }
|
||||||
|
fn foo() {
|
||||||
|
A { the<|> }
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(completions, @r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "the_field",
|
||||||
|
source_range: [83; 86),
|
||||||
|
delete: [83; 86),
|
||||||
|
insert: "the_field",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_literal_enum_variant() {
|
||||||
|
let completions = complete(
|
||||||
|
r"
|
||||||
|
enum E {
|
||||||
|
A { a: u32 }
|
||||||
|
}
|
||||||
|
fn foo() {
|
||||||
|
let _ = E::A { <|> }
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(completions, @r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "a",
|
||||||
|
source_range: [119; 119),
|
||||||
|
delete: [119; 119),
|
||||||
|
insert: "a",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_literal_two_structs() {
|
||||||
|
let completions = complete(
|
||||||
|
r"
|
||||||
|
struct A { a: u32 }
|
||||||
|
struct B { b: u32 }
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
let _: A = B { <|> }
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(completions, @r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "b",
|
||||||
|
source_range: [119; 119),
|
||||||
|
delete: [119; 119),
|
||||||
|
insert: "b",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_literal_generic_struct() {
|
||||||
|
let completions = complete(
|
||||||
|
r"
|
||||||
|
struct A<T> { a: T }
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
let _: A<u32> = A { <|> }
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(completions, @r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "a",
|
||||||
|
source_range: [93; 93),
|
||||||
|
delete: [93; 93),
|
||||||
|
insert: "a",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_literal_field_in_simple_macro() {
|
||||||
|
let completions = complete(
|
||||||
|
r"
|
||||||
|
macro_rules! m { ($e:expr) => { $e } }
|
||||||
|
struct A { the_field: u32 }
|
||||||
|
fn foo() {
|
||||||
|
m!(A { the<|> })
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(completions, @r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "the_field",
|
||||||
|
source_range: [137; 140),
|
||||||
|
delete: [137; 140),
|
||||||
|
insert: "the_field",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn only_missing_fields_are_completed() {
|
||||||
|
let completions = complete(
|
||||||
|
r"
|
||||||
|
struct S {
|
||||||
|
foo1: u32,
|
||||||
|
foo2: u32,
|
||||||
|
bar: u32,
|
||||||
|
baz: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo1 = 1;
|
||||||
|
let s = S {
|
||||||
|
foo1,
|
||||||
|
foo2: 5,
|
||||||
|
<|>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
",
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(completions, @r###"
|
||||||
|
[
|
||||||
|
CompletionItem {
|
||||||
|
label: "bar",
|
||||||
|
source_range: [302; 302),
|
||||||
|
delete: [302; 302),
|
||||||
|
insert: "bar",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
CompletionItem {
|
||||||
|
label: "baz",
|
||||||
|
source_range: [302; 302),
|
||||||
|
delete: [302; 302),
|
||||||
|
insert: "baz",
|
||||||
|
kind: Field,
|
||||||
|
detail: "u32",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,224 +0,0 @@
|
||||||
//! FIXME: write short doc here
|
|
||||||
|
|
||||||
use super::get_missing_fields;
|
|
||||||
use crate::completion::{CompletionContext, Completions};
|
|
||||||
use either::Either;
|
|
||||||
|
|
||||||
/// Complete fields in fields literals.
|
|
||||||
pub(super) fn complete_record_literal(
|
|
||||||
acc: &mut Completions,
|
|
||||||
ctx: &CompletionContext,
|
|
||||||
) -> Option<()> {
|
|
||||||
let record_lit = ctx.record_lit_syntax.as_ref()?;
|
|
||||||
for (field, field_ty) in get_missing_fields(ctx, Either::Left(record_lit))? {
|
|
||||||
acc.add_field(ctx, field, &field_ty);
|
|
||||||
}
|
|
||||||
Some(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
|
|
||||||
use insta::assert_debug_snapshot;
|
|
||||||
|
|
||||||
fn complete(code: &str) -> Vec<CompletionItem> {
|
|
||||||
do_completion(code, CompletionKind::Reference)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_record_literal_deprecated_field() {
|
|
||||||
let completions = complete(
|
|
||||||
r"
|
|
||||||
struct A {
|
|
||||||
#[deprecated]
|
|
||||||
the_field: u32,
|
|
||||||
}
|
|
||||||
fn foo() {
|
|
||||||
A { the<|> }
|
|
||||||
}
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(completions, @r###"
|
|
||||||
[
|
|
||||||
CompletionItem {
|
|
||||||
label: "the_field",
|
|
||||||
source_range: [142; 145),
|
|
||||||
delete: [142; 145),
|
|
||||||
insert: "the_field",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
deprecated: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_record_literal_field() {
|
|
||||||
let completions = complete(
|
|
||||||
r"
|
|
||||||
struct A { the_field: u32 }
|
|
||||||
fn foo() {
|
|
||||||
A { the<|> }
|
|
||||||
}
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(completions, @r###"
|
|
||||||
[
|
|
||||||
CompletionItem {
|
|
||||||
label: "the_field",
|
|
||||||
source_range: [83; 86),
|
|
||||||
delete: [83; 86),
|
|
||||||
insert: "the_field",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_record_literal_enum_variant() {
|
|
||||||
let completions = complete(
|
|
||||||
r"
|
|
||||||
enum E {
|
|
||||||
A { a: u32 }
|
|
||||||
}
|
|
||||||
fn foo() {
|
|
||||||
let _ = E::A { <|> }
|
|
||||||
}
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(completions, @r###"
|
|
||||||
[
|
|
||||||
CompletionItem {
|
|
||||||
label: "a",
|
|
||||||
source_range: [119; 119),
|
|
||||||
delete: [119; 119),
|
|
||||||
insert: "a",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_record_literal_two_structs() {
|
|
||||||
let completions = complete(
|
|
||||||
r"
|
|
||||||
struct A { a: u32 }
|
|
||||||
struct B { b: u32 }
|
|
||||||
|
|
||||||
fn foo() {
|
|
||||||
let _: A = B { <|> }
|
|
||||||
}
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(completions, @r###"
|
|
||||||
[
|
|
||||||
CompletionItem {
|
|
||||||
label: "b",
|
|
||||||
source_range: [119; 119),
|
|
||||||
delete: [119; 119),
|
|
||||||
insert: "b",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_record_literal_generic_struct() {
|
|
||||||
let completions = complete(
|
|
||||||
r"
|
|
||||||
struct A<T> { a: T }
|
|
||||||
|
|
||||||
fn foo() {
|
|
||||||
let _: A<u32> = A { <|> }
|
|
||||||
}
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(completions, @r###"
|
|
||||||
[
|
|
||||||
CompletionItem {
|
|
||||||
label: "a",
|
|
||||||
source_range: [93; 93),
|
|
||||||
delete: [93; 93),
|
|
||||||
insert: "a",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_record_literal_field_in_simple_macro() {
|
|
||||||
let completions = complete(
|
|
||||||
r"
|
|
||||||
macro_rules! m { ($e:expr) => { $e } }
|
|
||||||
struct A { the_field: u32 }
|
|
||||||
fn foo() {
|
|
||||||
m!(A { the<|> })
|
|
||||||
}
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(completions, @r###"
|
|
||||||
[
|
|
||||||
CompletionItem {
|
|
||||||
label: "the_field",
|
|
||||||
source_range: [137; 140),
|
|
||||||
delete: [137; 140),
|
|
||||||
insert: "the_field",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn only_missing_fields_are_completed() {
|
|
||||||
let completions = complete(
|
|
||||||
r"
|
|
||||||
struct S {
|
|
||||||
foo1: u32,
|
|
||||||
foo2: u32,
|
|
||||||
bar: u32,
|
|
||||||
baz: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let foo1 = 1;
|
|
||||||
let s = S {
|
|
||||||
foo1,
|
|
||||||
foo2: 5,
|
|
||||||
<|>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(completions, @r###"
|
|
||||||
[
|
|
||||||
CompletionItem {
|
|
||||||
label: "bar",
|
|
||||||
source_range: [302; 302),
|
|
||||||
delete: [302; 302),
|
|
||||||
insert: "bar",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
CompletionItem {
|
|
||||||
label: "baz",
|
|
||||||
source_range: [302; 302),
|
|
||||||
delete: [302; 302),
|
|
||||||
insert: "baz",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,162 +0,0 @@
|
||||||
//! FIXME: write short doc here
|
|
||||||
|
|
||||||
use super::get_missing_fields;
|
|
||||||
use crate::completion::{CompletionContext, Completions};
|
|
||||||
use either::Either;
|
|
||||||
|
|
||||||
pub(super) fn complete_record_pattern(
|
|
||||||
acc: &mut Completions,
|
|
||||||
ctx: &CompletionContext,
|
|
||||||
) -> Option<()> {
|
|
||||||
let record_pat = ctx.record_lit_pat.as_ref()?;
|
|
||||||
for (field, field_ty) in get_missing_fields(ctx, Either::Right(record_pat))? {
|
|
||||||
acc.add_field(ctx, field, &field_ty);
|
|
||||||
}
|
|
||||||
Some(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind};
|
|
||||||
use insta::assert_debug_snapshot;
|
|
||||||
|
|
||||||
fn complete(code: &str) -> Vec<CompletionItem> {
|
|
||||||
do_completion(code, CompletionKind::Reference)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_record_pattern_field() {
|
|
||||||
let completions = complete(
|
|
||||||
r"
|
|
||||||
struct S { foo: u32 }
|
|
||||||
|
|
||||||
fn process(f: S) {
|
|
||||||
match f {
|
|
||||||
S { f<|>: 92 } => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(completions, @r###"
|
|
||||||
[
|
|
||||||
CompletionItem {
|
|
||||||
label: "foo",
|
|
||||||
source_range: [117; 118),
|
|
||||||
delete: [117; 118),
|
|
||||||
insert: "foo",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_record_pattern_enum_variant() {
|
|
||||||
let completions = complete(
|
|
||||||
r"
|
|
||||||
enum E {
|
|
||||||
S { foo: u32, bar: () }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process(e: E) {
|
|
||||||
match e {
|
|
||||||
E::S { <|> } => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(completions, @r###"
|
|
||||||
[
|
|
||||||
CompletionItem {
|
|
||||||
label: "bar",
|
|
||||||
source_range: [161; 161),
|
|
||||||
delete: [161; 161),
|
|
||||||
insert: "bar",
|
|
||||||
kind: Field,
|
|
||||||
detail: "()",
|
|
||||||
},
|
|
||||||
CompletionItem {
|
|
||||||
label: "foo",
|
|
||||||
source_range: [161; 161),
|
|
||||||
delete: [161; 161),
|
|
||||||
insert: "foo",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_record_pattern_field_in_simple_macro() {
|
|
||||||
let completions = complete(
|
|
||||||
r"
|
|
||||||
macro_rules! m { ($e:expr) => { $e } }
|
|
||||||
struct S { foo: u32 }
|
|
||||||
|
|
||||||
fn process(f: S) {
|
|
||||||
m!(match f {
|
|
||||||
S { f<|>: 92 } => (),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(completions, @r###"
|
|
||||||
[
|
|
||||||
CompletionItem {
|
|
||||||
label: "foo",
|
|
||||||
source_range: [171; 172),
|
|
||||||
delete: [171; 172),
|
|
||||||
insert: "foo",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn only_missing_fields_are_completed_in_destruct_pats() {
|
|
||||||
let completions = complete(
|
|
||||||
r"
|
|
||||||
struct S {
|
|
||||||
foo1: u32,
|
|
||||||
foo2: u32,
|
|
||||||
bar: u32,
|
|
||||||
baz: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let s = S {
|
|
||||||
foo1: 1,
|
|
||||||
foo2: 2,
|
|
||||||
bar: 3,
|
|
||||||
baz: 4,
|
|
||||||
};
|
|
||||||
if let S { foo1, foo2: a, <|> } = s {}
|
|
||||||
}
|
|
||||||
",
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(completions, @r###"
|
|
||||||
[
|
|
||||||
CompletionItem {
|
|
||||||
label: "bar",
|
|
||||||
source_range: [372; 372),
|
|
||||||
delete: [372; 372),
|
|
||||||
insert: "bar",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
CompletionItem {
|
|
||||||
label: "baz",
|
|
||||||
source_range: [372; 372),
|
|
||||||
delete: [372; 372),
|
|
||||||
insert: "baz",
|
|
||||||
kind: Field,
|
|
||||||
detail: "u32",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
"###);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue