379 lines
7.5 KiB
Rust
Raw Normal View History

//! Complete fields in record literals and patterns.
use ide_db::{helpers::FamousDefs, SymbolKind};
use syntax::ast::Expr;
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<()> {
let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
(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),
(_, 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, &[]));
let missing_fields = ctx.sema.record_literal_missing_fields(record_lit);
if impl_default_trait && !missing_fields.is_empty() {
let completion_text = "..Default::default()";
2021-03-12 12:12:32 +03:00
let mut item = CompletionItem::new(
CompletionKind::Snippet,
ctx.source_range(),
2021-05-27 03:47:20 +02:00
completion_text,
);
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);
}
missing_fields
}
};
for (field, ty) in missing_fields {
acc.add_field(ctx, field, &ty);
}
Some(())
}
#[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;
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);
}
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);
}
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"),
);
}
#[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
};
}
"#;
check(
test_code,
expect![[r#"
fd bar usize
"#]],
);
check_snippet(
test_code,
expect![[r#"
fd ..Default::default()
"#]],
);
}
#[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
};
}
"#,
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()
};
}
"#,
);
}
#[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
};
}
"#;
check(
test_code,
expect![[r#"
fd bar usize
"#]],
);
check_snippet(test_code, expect![[r#""#]]);
}
2020-07-03 11:48:48 +02:00
#[test]
fn test_record_pattern_field() {
check(
r#"
struct S { foo: u32 }
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-07-03 11:48:48 +02:00
#[test]
fn test_record_pattern_enum_variant() {
check(
r#"
enum E { S { foo: u32, bar: () } }
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
fd bar ()
2020-07-03 11:48:48 +02: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-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-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-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-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-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-07-03 11:48:48 +02:00
#[test]
fn test_record_literal_generic_struct() {
check(
r#"
struct A<T> { a: T }
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-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-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-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
"#]],
);
}
}