use ide_db::{helpers::FamousDefs, SymbolKind};
use syntax::ast::Expr;
-use crate::{item::CompletionKind, CompletionContext, CompletionItem, Completions};
+use crate::{
+ item::CompletionKind, patterns::ImmediateLocation, CompletionContext, CompletionItem,
+ Completions,
+};
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 missing_fields = match &ctx.completion_location {
+ Some(ImmediateLocation::RecordExpr(record_expr)) => {
+ let ty = ctx.sema.type_of_expr(&Expr::RecordExpr(record_expr.clone()));
let default_trait = FamousDefs(&ctx.sema, ctx.krate).core_default_Default();
- let impl_default_trait = default_trait
- .and_then(|default_trait| ty.map(|ty| ty.impls_trait(ctx.db, default_trait, &[])))
- .unwrap_or(false);
+ let impl_default_trait = default_trait.zip(ty).map_or(false, |(default_trait, ty)| {
+ ty.original.impls_trait(ctx.db, default_trait, &[])
+ });
- let missing_fields = ctx.sema.record_literal_missing_fields(record_lit);
+ let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
if impl_default_trait && !missing_fields.is_empty() {
let completion_text = "..Default::default()";
- let completion_text = completion_text
- .strip_prefix(ctx.token.to_string().as_str())
- .unwrap_or(completion_text);
let mut item = CompletionItem::new(
CompletionKind::Snippet,
ctx.source_range(),
- "..Default::default()",
+ completion_text,
);
+ let completion_text =
+ completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
item.insert_text(completion_text).kind(SymbolKind::Field);
item.add_to(acc);
}
missing_fields
}
+ Some(ImmediateLocation::RecordPat(record_pat)) => {
+ ctx.sema.record_pattern_missing_fields(record_pat)
+ }
+ _ => return None,
};
for (field, ty) in missing_fields {
- acc.add_field(ctx, field, &ty);
+ acc.add_field(ctx, None, field, &ty);
}
Some(())
#[cfg(test)]
mod tests {
- use expect_test::{expect, Expect};
- use ide_db::helpers::FamousDefs;
-
- use crate::{
- test_utils::{self, completion_list},
- CompletionKind,
- };
-
- 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,
- .$0
- };
-}
-"#;
- check(
- test_code,
- expect![[r#"
- fd bar usize
- "#]],
- );
-
- check_snippet(
- test_code,
- expect![[r#"
- fd ..Default::default()
- "#]],
- );
- }
+ use crate::tests::check_edit;
#[test]
- fn test_record_literal_field_default_completion() {
+ fn default_completion_edit() {
check_edit(
"..Default::default()",
r#"
-struct S { foo: u32, bar: usize }
+//- minicore: default
+struct Struct { foo: u32, bar: usize }
-impl core::default::Default for S {
- fn default() -> Self {
- S {
- foo: 0,
- bar: 0,
- }
- }
+impl Default for Struct {
+ fn default() -> Self {}
}
-fn process(f: S) {
- let other = S {
+fn foo() {
+ let other = Struct {
foo: 5,
.$0
};
}
"#,
r#"
-struct S { foo: u32, bar: usize }
+struct Struct { foo: u32, bar: usize }
-impl core::default::Default for S {
- fn default() -> Self {
- S {
- foo: 0,
- bar: 0,
- }
- }
+impl Default for Struct {
+ fn default() -> Self {}
}
-fn process(f: S) {
- let other = S {
+fn foo() {
+ let other = Struct {
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,
- .$0
- };
-}
-"#;
- check(
- test_code,
- expect![[r#"
- fd bar usize
- "#]],
- );
-
- check_snippet(test_code, expect![[r#""#]]);
- }
-
- #[test]
- fn test_record_pattern_field() {
- check(
- r#"
-struct S { foo: u32 }
-
-fn process(f: S) {
- match f {
- S { f$0: 92 } => (),
- }
-}
-"#,
- expect![[r#"
- fd foo u32
- "#]],
- );
- }
-
- #[test]
- fn test_record_pattern_enum_variant() {
- check(
- r#"
-enum E { S { foo: u32, bar: () } }
-
-fn process(e: E) {
- match e {
- E::S { $0 } => (),
- }
-}
-"#,
- expect![[r#"
- fd foo u32
- fd bar ()
- "#]],
- );
- }
-
- #[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 {
- S { f$0: 92 } => (),
- })
-}
-",
- expect![[r#"
- fd foo u32
- "#]],
- );
- }
-
- #[test]
- fn only_missing_fields_are_completed_in_destruct_pats() {
- check(
- 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, $0 } = s {}
-}
-"#,
- expect![[r#"
- fd bar u32
- fd baz u32
- "#]],
- );
- }
-
- #[test]
- fn test_record_literal_field() {
- check(
+ check_edit(
+ "..Default::default()",
r#"
-struct A { the_field: u32 }
-fn foo() {
- A { the$0 }
-}
-"#,
- expect![[r#"
- fd the_field u32
- "#]],
- );
- }
+//- minicore: default
+struct Struct { foo: u32, bar: usize }
- #[test]
- fn test_record_literal_enum_variant() {
- check(
- r#"
-enum E { A { a: u32 } }
-fn foo() {
- let _ = E::A { $0 }
+impl Default for Struct {
+ fn default() -> Self {}
}
-"#,
- expect![[r#"
- fd a u32
- "#]],
- );
- }
-
- #[test]
- fn test_record_literal_two_structs() {
- check(
- r#"
-struct A { a: u32 }
-struct B { b: u32 }
fn foo() {
- let _: A = B { $0 }
+ let other = Struct {
+ foo: 5,
+ $0
+ };
}
"#,
- expect![[r#"
- fd b u32
- "#]],
- );
- }
-
- #[test]
- fn test_record_literal_generic_struct() {
- check(
r#"
-struct A<T> { a: T }
+struct Struct { foo: u32, bar: usize }
-fn foo() {
- let _: A<u32> = A { $0 }
+impl Default for Struct {
+ fn default() -> Self {}
}
-"#,
- expect![[r#"
- fd a u32
- "#]],
- );
- }
- #[test]
- fn test_record_literal_field_in_simple_macro() {
- check(
- r#"
-macro_rules! m { ($e:expr) => { $e } }
-struct A { the_field: u32 }
fn foo() {
- m!(A { the$0 })
-}
-"#,
- expect![[r#"
- fd the_field u32
- "#]],
- );
- }
-
- #[test]
- fn only_missing_fields_are_completed() {
- check(
- r#"
-struct S {
- foo1: u32, foo2: u32,
- bar: u32, baz: u32,
-}
-
-fn main() {
- let foo1 = 1;
- let s = S { foo1, foo2: 5, $0 }
-}
-"#,
- expect![[r#"
- fd bar u32
- fd baz u32
- "#]],
- );
- }
-
- #[test]
- fn completes_functional_update() {
- check(
- r#"
-struct S { foo1: u32, foo2: u32 }
-
-fn main() {
- let foo1 = 1;
- let s = S { foo1, $0 .. loop {} }
+ let other = Struct {
+ foo: 5,
+ ..Default::default()
+ };
}
"#,
- expect![[r#"
- fd foo2 u32
- "#]],
);
}
}