X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=crates%2Fide_completion%2Fsrc%2Fcompletions%2Frecord.rs;h=78d06231060d766dd78629e562792fcc6b23b51b;hb=24255e5b3dbabe7eaec1a42668d50d96d6b1aa0f;hp=e876337f12941ffa925e7760c6511b5a0191fc56;hpb=08c220ab2c4651f38d3029898706f2a996bf2c6b;p=rust.git diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs index e876337f129..78d06231060 100644 --- a/crates/ide_completion/src/completions/record.rs +++ b/crates/ide_completion/src/completions/record.rs @@ -1,35 +1,44 @@ //! Complete fields in record literals and patterns. -use ide_db::{helpers::FamousDefs, SymbolKind}; -use syntax::ast::Expr; +use ide_db::SymbolKind; +use syntax::{ast::Expr, T}; use crate::{ - item::CompletionKind, patterns::ImmediateLocation, CompletionContext, CompletionItem, - Completions, + patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, + CompletionRelevance, Completions, }; pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { let missing_fields = match &ctx.completion_location { - Some(ImmediateLocation::RecordExpr(record_expr)) => { + Some( + ImmediateLocation::RecordExpr(record_expr) + | ImmediateLocation::RecordExprUpdate(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 - .zip(ty) - .map_or(false, |(default_trait, ty)| ty.impls_trait(ctx.db, default_trait, &[])); + let default_trait = ctx.famous_defs().core_default_Default(); + 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_expr); - if impl_default_trait && !missing_fields.is_empty() { + if impl_default_trait && !missing_fields.is_empty() && ctx.path_qual().is_none() { let completion_text = "..Default::default()"; - let mut item = CompletionItem::new( - CompletionKind::Snippet, - ctx.source_range(), - completion_text, - ); + let mut item = + CompletionItem::new(SymbolKind::Field, ctx.source_range(), 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.insert_text(completion_text).set_relevance(CompletionRelevance { + exact_postfix_snippet_match: true, + ..Default::default() + }); item.add_to(acc); } - + if ctx.previous_token_is(T![.]) { + let mut item = + CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), ".."); + item.insert_text("."); + item.add_to(acc); + return None; + } missing_fields } Some(ImmediateLocation::RecordPat(record_pat)) => { @@ -45,324 +54,212 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Some(()) } -#[cfg(test)] -mod tests { - use expect_test::{expect, Expect}; - - use crate::{ - tests::{check_edit, filtered_completion_list}, - CompletionKind, - }; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = filtered_completion_list(ra_fixture, CompletionKind::Reference); - expect.assert_eq(&actual); +pub(crate) fn complete_record_literal( + acc: &mut Completions, + ctx: &CompletionContext, +) -> Option<()> { + if !ctx.expects_expression() { + return None; } - fn check_snippet(ra_fixture: &str, expect: Expect) { - let actual = filtered_completion_list(ra_fixture, CompletionKind::Snippet); - expect.assert_eq(&actual); - } + if let hir::Adt::Struct(strukt) = ctx.expected_type.as_ref()?.as_adt()? { + if ctx.path_qual().is_none() { + let module = if let Some(module) = ctx.module { module } else { strukt.module(ctx.db) }; + let path = module.find_use_path(ctx.db, hir::ModuleDef::from(strukt)); - #[test] - fn test_record_literal_field_default() { - let test_code = r#" -//- minicore: default -struct S { foo: u32, bar: usize } - -impl Default for S { - fn default() -> Self { - S { - foo: 0, - bar: 0, + acc.add_struct_literal(ctx, strukt, path, None); } } -} -fn process(f: S) { - let other = S { - foo: 5, - .$0 - }; + Some(()) } -"#; - check( - test_code, - expect![[r#" - fd bar usize - "#]], - ); - check_snippet( - test_code, - expect![[r#" - fd ..Default::default() - "#]], - ); - } +#[cfg(test)] +mod tests { + use crate::tests::check_edit; #[test] - fn test_record_literal_field_default_completion() { + fn literal_struct_completion_edit() { check_edit( - "..Default::default()", + "FooDesc {…}", r#" -//- minicore: default -struct S { foo: u32, bar: usize } +struct FooDesc { pub bar: bool } -impl Default for S { - fn default() -> Self { - S { - foo: 0, - bar: 0, - } - } -} +fn create_foo(foo_desc: &FooDesc) -> () { () } -fn process(f: S) { - let other = S { - foo: 5, - .$0 - }; +fn baz() { + let foo = create_foo(&$0); } -"#, + "#, r#" -struct S { foo: u32, bar: usize } +struct FooDesc { pub bar: bool } -impl Default for S { - fn default() -> Self { - S { - foo: 0, - bar: 0, - } - } -} +fn create_foo(foo_desc: &FooDesc) -> () { () } -fn process(f: S) { - let other = S { - foo: 5, - ..Default::default() - }; +fn baz() { + let foo = create_foo(&FooDesc { bar: ${1:()} }$0); } -"#, - ); + "#, + ) } #[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#""#]]); + fn literal_struct_completion_from_sub_modules() { + check_edit( + "Struct {…}", + r#" +mod submod { + pub struct Struct { + pub a: u64, } +} - #[test] - fn test_record_pattern_field() { - check( +fn f() -> submod::Struct { + Stru$0 +} + "#, r#" -struct S { foo: u32 } - -fn process(f: S) { - match f { - S { f$0: 92 } => (), +mod submod { + pub struct Struct { + pub a: u64, } } -"#, - expect![[r#" - fd foo u32 - "#]], - ); + +fn f() -> submod::Struct { + submod::Struct { a: ${1:()} }$0 +} + "#, + ) } #[test] - fn test_record_pattern_enum_variant() { - check( + fn literal_struct_complexion_module() { + check_edit( + "FooDesc {…}", r#" -enum E { S { foo: u32, bar: () } } +mod _69latrick { + pub struct FooDesc { pub six: bool, pub neuf: Vec, pub bar: bool } + pub fn create_foo(foo_desc: &FooDesc) -> () { () } +} -fn process(e: E) { - match e { - E::S { $0 } => (), - } +fn baz() { + use _69latrick::*; + + let foo = create_foo(&$0); +} + "#, + r#" +mod _69latrick { + pub struct FooDesc { pub six: bool, pub neuf: Vec, pub bar: bool } + pub fn create_foo(foo_desc: &FooDesc) -> () { () } } -"#, - 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 } => (), - }) +fn baz() { + use _69latrick::*; + + let foo = create_foo(&FooDesc { six: ${1:()}, neuf: ${2:()}, bar: ${3:()} }$0); } -", - expect![[r#" - fd foo u32 - "#]], + "#, ); } #[test] - fn only_missing_fields_are_completed_in_destruct_pats() { - check( + fn default_completion_edit() { + check_edit( + "..Default::default()", r#" -struct S { - foo1: u32, foo2: u32, - bar: u32, baz: u32, +//- minicore: default +struct Struct { foo: u32, bar: usize } + +impl Default for Struct { + fn default() -> Self {} } -fn main() { - let s = S { - foo1: 1, foo2: 2, - bar: 3, baz: 4, +fn foo() { + let other = Struct { + foo: 5, + .$0 }; - if let S { foo1, foo2: a, $0 } = s {} } "#, - expect![[r#" - fd bar u32 - fd baz u32 - "#]], - ); - } - - #[test] - fn test_record_literal_field() { - check( r#" -struct A { the_field: u32 } -fn foo() { - A { the$0 } +struct Struct { foo: u32, bar: usize } + +impl Default for Struct { + fn default() -> Self {} } -"#, - expect![[r#" - fd the_field u32 - "#]], - ); - } - #[test] - fn test_record_literal_enum_variant() { - check( - r#" -enum E { A { a: u32 } } fn foo() { - let _ = E::A { $0 } + let other = Struct { + foo: 5, + ..Default::default() + }; } "#, - expect![[r#" - fd a u32 - "#]], ); - } - - #[test] - fn test_record_literal_two_structs() { - check( + check_edit( + "..Default::default()", r#" -struct A { a: u32 } -struct B { b: u32 } +//- minicore: default +struct Struct { foo: u32, bar: usize } + +impl Default for Struct { + fn default() -> Self {} +} 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 { a: T } +struct Struct { foo: u32, bar: usize } -fn foo() { - let _: A = 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 }) + let other = Struct { + foo: 5, + ..Default::default() + }; } "#, - expect![[r#" - fd the_field u32 - "#]], ); - } - - #[test] - fn only_missing_fields_are_completed() { - check( + check_edit( + "..Default::default()", r#" -struct S { - foo1: u32, foo2: u32, - bar: u32, baz: u32, +//- minicore: default +struct Struct { foo: u32, bar: usize } + +impl Default for Struct { + fn default() -> Self {} } -fn main() { - let foo1 = 1; - let s = S { foo1, foo2: 5, $0 } +fn foo() { + let other = Struct { + foo: 5, + ..$0 + }; } "#, - expect![[r#" - fd bar u32 - fd baz u32 - "#]], - ); - } - - #[test] - fn completes_functional_update() { - check( r#" -struct S { foo1: u32, foo2: u32 } +struct Struct { foo: u32, bar: usize } + +impl Default for Struct { + fn default() -> Self {} +} -fn main() { - let foo1 = 1; - let s = S { foo1, $0 .. loop {} } +fn foo() { + let other = Struct { + foo: 5, + ..Default::default() + }; } "#, - expect![[r#" - fd foo2 u32 - "#]], ); } }