2020-04-01 00:50:45 +03:00
|
|
|
//! Complete fields in record literals and patterns.
|
2021-01-20 18:38:12 +01:00
|
|
|
use ide_db::{helpers::FamousDefs, SymbolKind};
|
2020-11-13 17:17:16 +01:00
|
|
|
use syntax::ast::Expr;
|
|
|
|
|
2021-01-20 18:38:12 +01:00
|
|
|
use crate::{item::CompletionKind, CompletionContext, CompletionItem, Completions};
|
2020-04-07 15:07:18 +02:00
|
|
|
|
2020-10-25 10:59:15 +03:00
|
|
|
pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
|
2020-04-11 23:33:17 +02:00
|
|
|
let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
|
2020-04-07 17:09:02 +02:00
|
|
|
(None, None) => return None,
|
|
|
|
(Some(_), Some(_)) => unreachable!("A record cannot be both a literal and a pattern"),
|
|
|
|
(Some(record_pat), _) => ctx.sema.record_pattern_missing_fields(record_pat),
|
2020-11-13 17:17:16 +01:00
|
|
|
(_, Some(record_lit)) => {
|
|
|
|
let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_lit.clone()));
|
|
|
|
let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default();
|
|
|
|
let impl_default_trait = default_trait
|
2021-05-27 03:47:20 +02:00
|
|
|
.zip(ty)
|
|
|
|
.map_or(false, |(default_trait, ty)| ty.impls_trait(ctx.db, default_trait, &[]));
|
2020-11-13 17:17:16 +01:00
|
|
|
|
|
|
|
let missing_fields = ctx.sema.record_literal_missing_fields(record_lit);
|
|
|
|
if impl_default_trait && !missing_fields.is_empty() {
|
2021-01-01 11:17:15 +11:00
|
|
|
let completion_text = "..Default::default()";
|
2021-03-12 12:12:32 +03:00
|
|
|
let mut item = CompletionItem::new(
|
2021-03-11 17:46:41 +02:00
|
|
|
CompletionKind::Snippet,
|
|
|
|
ctx.source_range(),
|
2021-05-27 03:47:20 +02:00
|
|
|
completion_text,
|
2020-11-13 17:17:16 +01:00
|
|
|
);
|
2021-05-27 03:47:20 +02:00
|
|
|
let completion_text =
|
|
|
|
completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
|
2021-03-12 12:12:32 +03:00
|
|
|
item.insert_text(completion_text).kind(SymbolKind::Field);
|
|
|
|
item.add_to(acc);
|
2020-11-13 17:17:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
missing_fields
|
|
|
|
}
|
2020-04-07 17:09:02 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
for (field, ty) in missing_fields {
|
2020-11-13 17:17:16 +01:00
|
|
|
acc.add_field(ctx, field, &ty);
|
2020-04-01 00:50:45 +03:00
|
|
|
}
|
|
|
|
|
2020-04-07 17:09:02 +02:00
|
|
|
Some(())
|
2020-04-01 00:50:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2020-08-21 13:19:31 +02:00
|
|
|
use expect_test::{expect, Expect};
|
2020-11-28 16:30:39 +02:00
|
|
|
use ide_db::helpers::FamousDefs;
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2021-01-01 11:10:02 +11:00
|
|
|
use crate::{
|
|
|
|
test_utils::{self, completion_list},
|
|
|
|
CompletionKind,
|
|
|
|
};
|
2020-04-07 15:07:18 +02:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
fn check(ra_fixture: &str, expect: Expect) {
|
|
|
|
let actual = completion_list(ra_fixture, CompletionKind::Reference);
|
|
|
|
expect.assert_eq(&actual);
|
|
|
|
}
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-11-13 17:17:16 +01:00
|
|
|
fn check_snippet(ra_fixture: &str, expect: Expect) {
|
|
|
|
let actual = completion_list(
|
|
|
|
&format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE),
|
|
|
|
CompletionKind::Snippet,
|
|
|
|
);
|
|
|
|
expect.assert_eq(&actual);
|
|
|
|
}
|
|
|
|
|
2021-01-01 11:10:02 +11:00
|
|
|
fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
|
|
|
|
test_utils::check_edit(
|
|
|
|
what,
|
|
|
|
&format!(
|
|
|
|
"//- /main.rs crate:main deps:core{}\n{}",
|
|
|
|
ra_fixture_before,
|
|
|
|
FamousDefs::FIXTURE,
|
|
|
|
),
|
|
|
|
&(ra_fixture_after.to_owned() + "\n"),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-11-13 17:17:16 +01:00
|
|
|
#[test]
|
|
|
|
fn test_record_literal_field_default() {
|
|
|
|
let test_code = r#"
|
|
|
|
struct S { foo: u32, bar: usize }
|
|
|
|
|
|
|
|
impl core::default::Default for S {
|
|
|
|
fn default() -> Self {
|
|
|
|
S {
|
|
|
|
foo: 0,
|
|
|
|
bar: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process(f: S) {
|
|
|
|
let other = S {
|
|
|
|
foo: 5,
|
2021-01-06 20:15:48 +00:00
|
|
|
.$0
|
2020-11-13 17:17:16 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
"#;
|
|
|
|
check(
|
|
|
|
test_code,
|
|
|
|
expect![[r#"
|
|
|
|
fd bar usize
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
|
|
|
|
check_snippet(
|
|
|
|
test_code,
|
|
|
|
expect![[r#"
|
2020-12-19 13:18:40 +02:00
|
|
|
fd ..Default::default()
|
2020-11-13 17:17:16 +01:00
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-01-01 11:10:02 +11:00
|
|
|
#[test]
|
|
|
|
fn test_record_literal_field_default_completion() {
|
|
|
|
check_edit(
|
|
|
|
"..Default::default()",
|
|
|
|
r#"
|
|
|
|
struct S { foo: u32, bar: usize }
|
|
|
|
|
|
|
|
impl core::default::Default for S {
|
|
|
|
fn default() -> Self {
|
|
|
|
S {
|
|
|
|
foo: 0,
|
|
|
|
bar: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process(f: S) {
|
|
|
|
let other = S {
|
|
|
|
foo: 5,
|
2021-01-06 20:15:48 +00:00
|
|
|
.$0
|
2021-01-01 11:10:02 +11:00
|
|
|
};
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
r#"
|
|
|
|
struct S { foo: u32, bar: usize }
|
|
|
|
|
|
|
|
impl core::default::Default for S {
|
|
|
|
fn default() -> Self {
|
|
|
|
S {
|
|
|
|
foo: 0,
|
|
|
|
bar: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process(f: S) {
|
|
|
|
let other = S {
|
|
|
|
foo: 5,
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-11-13 17:17:16 +01:00
|
|
|
#[test]
|
|
|
|
fn test_record_literal_field_without_default() {
|
|
|
|
let test_code = r#"
|
|
|
|
struct S { foo: u32, bar: usize }
|
|
|
|
|
|
|
|
fn process(f: S) {
|
|
|
|
let other = S {
|
|
|
|
foo: 5,
|
2021-01-06 20:15:48 +00:00
|
|
|
.$0
|
2020-11-13 17:17:16 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
"#;
|
|
|
|
check(
|
|
|
|
test_code,
|
|
|
|
expect![[r#"
|
|
|
|
fd bar usize
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
|
2021-05-25 11:42:16 -03:00
|
|
|
check_snippet(test_code, expect![[r#""#]]);
|
2020-11-13 17:17:16 +01:00
|
|
|
}
|
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
#[test]
|
|
|
|
fn test_record_pattern_field() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct S { foo: u32 }
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
fn process(f: S) {
|
|
|
|
match f {
|
2021-01-06 20:15:48 +00:00
|
|
|
S { f$0: 92 } => (),
|
2020-07-03 11:48:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd foo u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
#[test]
|
|
|
|
fn test_record_pattern_enum_variant() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
enum E { S { foo: u32, bar: () } }
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
fn process(e: E) {
|
|
|
|
match e {
|
2021-01-06 20:15:48 +00:00
|
|
|
E::S { $0 } => (),
|
2020-07-03 11:48:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd foo u32
|
2020-12-19 13:18:40 +02:00
|
|
|
fd bar ()
|
2020-07-03 11:48:48 +02:00
|
|
|
"#]],
|
|
|
|
);
|
2020-04-01 00:50:45 +03:00
|
|
|
}
|
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
#[test]
|
|
|
|
fn test_record_pattern_field_in_simple_macro() {
|
|
|
|
check(
|
|
|
|
r"
|
|
|
|
macro_rules! m { ($e:expr) => { $e } }
|
|
|
|
struct S { foo: u32 }
|
|
|
|
|
|
|
|
fn process(f: S) {
|
|
|
|
m!(match f {
|
2021-01-06 20:15:48 +00:00
|
|
|
S { f$0: 92 } => (),
|
2020-07-03 11:48:48 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
",
|
|
|
|
expect![[r#"
|
|
|
|
fd foo u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2020-04-07 15:07:18 +02:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
#[test]
|
|
|
|
fn only_missing_fields_are_completed_in_destruct_pats() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct S {
|
|
|
|
foo1: u32, foo2: u32,
|
|
|
|
bar: u32, baz: u32,
|
|
|
|
}
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
fn main() {
|
|
|
|
let s = S {
|
|
|
|
foo1: 1, foo2: 2,
|
|
|
|
bar: 3, baz: 4,
|
|
|
|
};
|
2021-01-06 20:15:48 +00:00
|
|
|
if let S { foo1, foo2: a, $0 } = s {}
|
2020-07-03 11:48:48 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd bar u32
|
|
|
|
fd baz u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
#[test]
|
|
|
|
fn test_record_literal_field() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct A { the_field: u32 }
|
|
|
|
fn foo() {
|
2021-01-06 20:15:48 +00:00
|
|
|
A { the$0 }
|
2020-07-03 11:48:48 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd the_field u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
#[test]
|
|
|
|
fn test_record_literal_enum_variant() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
enum E { A { a: u32 } }
|
|
|
|
fn foo() {
|
2021-01-06 20:15:48 +00:00
|
|
|
let _ = E::A { $0 }
|
2020-07-03 11:48:48 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd a u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
#[test]
|
|
|
|
fn test_record_literal_two_structs() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct A { a: u32 }
|
|
|
|
struct B { b: u32 }
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
fn foo() {
|
2021-01-06 20:15:48 +00:00
|
|
|
let _: A = B { $0 }
|
2020-07-03 11:48:48 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd b u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
#[test]
|
|
|
|
fn test_record_literal_generic_struct() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct A<T> { a: T }
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
fn foo() {
|
2021-01-06 20:15:48 +00:00
|
|
|
let _: A<u32> = A { $0 }
|
2020-07-03 11:48:48 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd a u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
#[test]
|
|
|
|
fn test_record_literal_field_in_simple_macro() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
macro_rules! m { ($e:expr) => { $e } }
|
|
|
|
struct A { the_field: u32 }
|
|
|
|
fn foo() {
|
2021-01-06 20:15:48 +00:00
|
|
|
m!(A { the$0 })
|
2020-07-03 11:48:48 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd the_field u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
#[test]
|
|
|
|
fn only_missing_fields_are_completed() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct S {
|
|
|
|
foo1: u32, foo2: u32,
|
|
|
|
bar: u32, baz: u32,
|
|
|
|
}
|
2020-04-01 00:50:45 +03:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
fn main() {
|
|
|
|
let foo1 = 1;
|
2021-01-06 20:15:48 +00:00
|
|
|
let s = S { foo1, foo2: 5, $0 }
|
2020-07-03 11:48:48 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd bar u32
|
|
|
|
fd baz u32
|
|
|
|
"#]],
|
|
|
|
);
|
|
|
|
}
|
2020-04-07 18:25:47 +02:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
#[test]
|
|
|
|
fn completes_functional_update() {
|
|
|
|
check(
|
|
|
|
r#"
|
|
|
|
struct S { foo1: u32, foo2: u32 }
|
2020-04-07 18:25:47 +02:00
|
|
|
|
2020-07-03 11:48:48 +02:00
|
|
|
fn main() {
|
|
|
|
let foo1 = 1;
|
2021-01-06 20:15:48 +00:00
|
|
|
let s = S { foo1, $0 .. loop {} }
|
2020-07-03 11:48:48 +02:00
|
|
|
}
|
|
|
|
"#,
|
|
|
|
expect![[r#"
|
|
|
|
fd foo2 u32
|
|
|
|
"#]],
|
|
|
|
);
|
2020-04-01 00:50:45 +03:00
|
|
|
}
|
|
|
|
}
|