From 6518f18f80d5bf0b5dc66320af8b0924918c97d3 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 4 Jul 2020 09:07:18 +0200 Subject: Cleanup tests --- crates/ra_ide/src/completion/presentation.rs | 234 +++++++-------------------- 1 file changed, 62 insertions(+), 172 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index fd12673b2..8026170da 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -844,189 +844,79 @@ fn f(foo: &Foo) { foo.foo(); } #[test] fn inserts_angle_brackets_for_generics() { mark::check!(inserts_angle_brackets_for_generics); - assert_debug_snapshot!( - do_reference_completion( - r" - struct Vec {} - fn foo(xs: Ve<|>) - " - ), - @r###" - [ - CompletionItem { - label: "Vec<…>", - source_range: 28..30, - delete: 28..30, - insert: "Vec<$0>", - kind: Struct, - lookup: "Vec", - }, - CompletionItem { - label: "foo(…)", - source_range: 28..30, - delete: 28..30, - insert: "foo(${1:xs})$0", - kind: Function, - lookup: "foo", - detail: "fn foo(xs: Ve)", - trigger_call_info: true, - }, - ] - "### + check_edit( + "Vec", + r#" +struct Vec {} +fn foo(xs: Ve<|>) +"#, + r#" +struct Vec {} +fn foo(xs: Vec<$0>) +"#, ); - assert_debug_snapshot!( - do_reference_completion( - r" - type Vec = (T,); - fn foo(xs: Ve<|>) - " - ), - @r###" - [ - CompletionItem { - label: "Vec<…>", - source_range: 31..33, - delete: 31..33, - insert: "Vec<$0>", - kind: TypeAlias, - lookup: "Vec", - }, - CompletionItem { - label: "foo(…)", - source_range: 31..33, - delete: 31..33, - insert: "foo(${1:xs})$0", - kind: Function, - lookup: "foo", - detail: "fn foo(xs: Ve)", - trigger_call_info: true, - }, - ] - "### + check_edit( + "Vec", + r#" +type Vec = (T,); +fn foo(xs: Ve<|>) +"#, + r#" +type Vec = (T,); +fn foo(xs: Vec<$0>) +"#, ); - assert_debug_snapshot!( - do_reference_completion( - r" - struct Vec {} - fn foo(xs: Ve<|>) - " - ), - @r###" - [ - CompletionItem { - label: "Vec", - source_range: 35..37, - delete: 35..37, - insert: "Vec", - kind: Struct, - }, - CompletionItem { - label: "foo(…)", - source_range: 35..37, - delete: 35..37, - insert: "foo(${1:xs})$0", - kind: Function, - lookup: "foo", - detail: "fn foo(xs: Ve)", - trigger_call_info: true, - }, - ] - "### + check_edit( + "Vec", + r#" +struct Vec {} +fn foo(xs: Ve<|>) +"#, + r#" +struct Vec {} +fn foo(xs: Vec) +"#, ); - assert_debug_snapshot!( - do_reference_completion( - r" - struct Vec {} - fn foo(xs: Ve<|>) - " - ), - @r###" - [ - CompletionItem { - label: "Vec", - source_range: 28..30, - delete: 28..30, - insert: "Vec", - kind: Struct, - }, - CompletionItem { - label: "foo(…)", - source_range: 28..30, - delete: 28..30, - insert: "foo(${1:xs})$0", - kind: Function, - lookup: "foo", - detail: "fn foo(xs: Ve)", - trigger_call_info: true, - }, - ] - "### + check_edit( + "Vec", + r#" +struct Vec {} +fn foo(xs: Ve<|>) +"#, + r#" +struct Vec {} +fn foo(xs: Vec) +"#, ); } #[test] fn dont_insert_macro_call_parens_unncessary() { mark::check!(dont_insert_macro_call_parens_unncessary); - assert_debug_snapshot!( - do_reference_completion( - r" - //- /main.rs - use foo::<|>; - - //- /foo/lib.rs - #[macro_export] - macro_rules frobnicate { - () => () - } - " - ), - @r###" - [ - CompletionItem { - label: "frobnicate!", - source_range: 9..9, - delete: 9..9, - insert: "frobnicate", - kind: Macro, - detail: "#[macro_export]\nmacro_rules! frobnicate", - }, - ] - "### + check_edit( + "frobnicate!", + r#" +//- /main.rs +use foo::<|>; +//- /foo/lib.rs +#[macro_export] +macro_rules frobnicate { () => () } +"#, + r#" +use foo::frobnicate; +"#, ); - assert_debug_snapshot!( - do_reference_completion( - r" - //- /main.rs - macro_rules frobnicate { - () => () - } - fn main() { - frob<|>!(); - } - " - ), - @r###" - [ - CompletionItem { - label: "frobnicate!", - source_range: 56..60, - delete: 56..60, - insert: "frobnicate", - kind: Macro, - detail: "macro_rules! frobnicate", - }, - CompletionItem { - label: "main()", - source_range: 56..60, - delete: 56..60, - insert: "main()$0", - kind: Function, - lookup: "main", - detail: "fn main()", - }, - ] - "### + check_edit( + "frobnicate!", + r#" +macro_rules frobnicate { () => () } +fn main() { frob<|>!(); } +"#, + r#" +macro_rules frobnicate { () => () } +fn main() { frobnicate!(); } +"#, ); } -- cgit v1.2.3 From 65768feaff5fad91c5bded8b606de29ed7ef4b12 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 4 Jul 2020 09:08:51 +0200 Subject: Unify naming --- crates/ra_ide/src/completion/test_utils.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs index 145d36c98..329acdc8b 100644 --- a/crates/ra_ide/src/completion/test_utils.rs +++ b/crates/ra_ide/src/completion/test_utils.rs @@ -13,15 +13,15 @@ use crate::{ }; pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec { - do_completion_with_options(code, kind, &CompletionConfig::default()) + do_completion_with_config(code, kind, &CompletionConfig::default()) } -pub(crate) fn do_completion_with_options( +pub(crate) fn do_completion_with_config( code: &str, kind: CompletionKind, - options: &CompletionConfig, + config: &CompletionConfig, ) -> Vec { - let mut kind_completions: Vec = get_all_completion_items(code, options) + let mut kind_completions: Vec = get_all_completion_items(code, config) .into_iter() .filter(|c| c.completion_kind == kind) .collect(); @@ -30,15 +30,15 @@ pub(crate) fn do_completion_with_options( } pub(crate) fn completion_list(code: &str, kind: CompletionKind) -> String { - completion_list_with_options(code, kind, &CompletionConfig::default()) + completion_list_with_config(code, kind, &CompletionConfig::default()) } -pub(crate) fn completion_list_with_options( +pub(crate) fn completion_list_with_config( code: &str, kind: CompletionKind, - options: &CompletionConfig, + config: &CompletionConfig, ) -> String { - let mut kind_completions: Vec = get_all_completion_items(code, options) + let mut kind_completions: Vec = get_all_completion_items(code, config) .into_iter() .filter(|c| c.completion_kind == kind) .collect(); -- cgit v1.2.3 From aaba2300fb14360a00e75da1916b11fd99c0afce Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 4 Jul 2020 09:35:44 +0200 Subject: Modernize completion presentation tests --- crates/ra_ide/src/completion/presentation.rs | 733 +++++++++++++-------------- 1 file changed, 340 insertions(+), 393 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 8026170da..9ec33a050 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -330,14 +330,14 @@ pub(crate) fn compute_score( // FIXME: this should not fall back to string equality. let ty = &ty.display(ctx.db).to_string(); let (active_name, active_type) = if let Some(record_field) = &ctx.record_field_syntax { - mark::hit!(test_struct_field_completion_in_record_lit); + mark::hit!(record_field_type_match); let (struct_field, _local) = ctx.sema.resolve_record_field(record_field)?; ( struct_field.name(ctx.db).to_string(), struct_field.signature_ty(ctx.db).display(ctx.db).to_string(), ) } else if let Some(active_parameter) = &ctx.active_parameter { - mark::hit!(test_struct_field_completion_in_func_call); + mark::hit!(active_param_type_match); (active_parameter.name.clone(), active_parameter.ty.clone()) } else { return None; @@ -461,174 +461,155 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s #[cfg(test)] mod tests { - use insta::assert_debug_snapshot; + use expect::{expect, Expect}; use test_utils::mark; use crate::completion::{ test_utils::{check_edit, check_edit_with_config, do_completion}, - CompletionConfig, CompletionItem, CompletionKind, + CompletionConfig, CompletionKind, }; - fn do_reference_completion(ra_fixture: &str) -> Vec { - do_completion(ra_fixture, CompletionKind::Reference) + fn check(ra_fixture: &str, expect: Expect) { + let actual = do_completion(ra_fixture, CompletionKind::Reference); + expect.assert_debug_eq(&actual); } #[test] - fn enum_detail_includes_names_for_record() { - assert_debug_snapshot!( - do_reference_completion( + fn enum_detail_includes_record_fields() { + check( r#" - enum Foo { - Foo {x: i32, y: i32} - } +enum Foo { Foo { x: i32, y: i32 } } - fn main() { Foo::Fo<|> } - "#, - ), - @r###" - [ - CompletionItem { - label: "Foo", - source_range: 56..58, - delete: 56..58, - insert: "Foo", - kind: EnumVariant, - detail: "{ x: i32, y: i32 }", - }, - ] - "### +fn main() { Foo::Fo<|> } +"#, + expect![[r#" + [ + CompletionItem { + label: "Foo", + source_range: 54..56, + delete: 54..56, + insert: "Foo", + kind: EnumVariant, + detail: "{ x: i32, y: i32 }", + }, + ] + "#]], ); } #[test] - fn enum_detail_doesnt_include_names_for_tuple() { - assert_debug_snapshot!( - do_reference_completion( + fn enum_detail_doesnt_include_tuple_fields() { + check( r#" - enum Foo { - Foo (i32, i32) - } +enum Foo { Foo (i32, i32) } - fn main() { Foo::Fo<|> } - "#, - ), - @r###" - [ - CompletionItem { - label: "Foo(…)", - source_range: 50..52, - delete: 50..52, - insert: "Foo($0)", - kind: EnumVariant, - lookup: "Foo", - detail: "(i32, i32)", - trigger_call_info: true, - }, - ] - "### +fn main() { Foo::Fo<|> } +"#, + expect![[r#" + [ + CompletionItem { + label: "Foo(…)", + source_range: 46..48, + delete: 46..48, + insert: "Foo($0)", + kind: EnumVariant, + lookup: "Foo", + detail: "(i32, i32)", + trigger_call_info: true, + }, + ] + "#]], ); } #[test] fn enum_detail_just_parentheses_for_unit() { - assert_debug_snapshot!( - do_reference_completion( + check( r#" - enum Foo { - Foo - } +enum Foo { Foo } - fn main() { Foo::Fo<|> } - "#, - ), - @r###" - [ - CompletionItem { - label: "Foo", - source_range: 39..41, - delete: 39..41, - insert: "Foo", - kind: EnumVariant, - detail: "()", - }, - ] - "### +fn main() { Foo::Fo<|> } +"#, + expect![[r#" + [ + CompletionItem { + label: "Foo", + source_range: 35..37, + delete: 35..37, + insert: "Foo", + kind: EnumVariant, + detail: "()", + }, + ] + "#]], ); } #[test] fn sets_deprecated_flag_in_completion_items() { - assert_debug_snapshot!( - do_reference_completion( - r#" - #[deprecated] - fn something_deprecated() {} - - #[deprecated(since = "1.0.0")] - fn something_else_deprecated() {} - - fn main() { som<|> } - "#, - ), - @r###" - [ - CompletionItem { - label: "main()", - source_range: 122..125, - delete: 122..125, - insert: "main()$0", - kind: Function, - lookup: "main", - detail: "fn main()", - }, - CompletionItem { - label: "something_deprecated()", - source_range: 122..125, - delete: 122..125, - insert: "something_deprecated()$0", - kind: Function, - lookup: "something_deprecated", - detail: "fn something_deprecated()", - deprecated: true, - }, - CompletionItem { - label: "something_else_deprecated()", - source_range: 122..125, - delete: 122..125, - insert: "something_else_deprecated()$0", - kind: Function, - lookup: "something_else_deprecated", - detail: "fn something_else_deprecated()", - deprecated: true, - }, - ] - "### + check( + r#" +#[deprecated] +fn something_deprecated() {} +#[deprecated(since = "1.0.0")] +fn something_else_deprecated() {} + +fn main() { som<|> } +"#, + expect![[r#" + [ + CompletionItem { + label: "main()", + source_range: 121..124, + delete: 121..124, + insert: "main()$0", + kind: Function, + lookup: "main", + detail: "fn main()", + }, + CompletionItem { + label: "something_deprecated()", + source_range: 121..124, + delete: 121..124, + insert: "something_deprecated()$0", + kind: Function, + lookup: "something_deprecated", + detail: "fn something_deprecated()", + deprecated: true, + }, + CompletionItem { + label: "something_else_deprecated()", + source_range: 121..124, + delete: 121..124, + insert: "something_else_deprecated()$0", + kind: Function, + lookup: "something_else_deprecated", + detail: "fn something_else_deprecated()", + deprecated: true, + }, + ] + "#]], ); - assert_debug_snapshot!(do_reference_completion( + check( r#" -struct A { - #[deprecated] - the_field: u32, -} -fn foo() { - A { the<|> } -} +struct A { #[deprecated] the_field: u32 } +fn foo() { A { the<|> } } "#, - ), - @r###" - [ - CompletionItem { - label: "the_field", - source_range: 69..72, - delete: 69..72, - insert: "the_field", - kind: Field, - detail: "u32", - deprecated: true, - }, - ] - "###); + expect![[r#" + [ + CompletionItem { + label: "the_field", + source_range: 57..60, + delete: 57..60, + insert: "the_field", + kind: Field, + detail: "u32", + deprecated: true, + }, + ] + "#]], + ); } #[test] @@ -921,279 +902,245 @@ fn main() { frobnicate!(); } } #[test] - fn test_struct_field_completion_in_func_call() { - mark::check!(test_struct_field_completion_in_func_call); - assert_debug_snapshot!( - do_reference_completion( - r" - struct A { another_field: i64, the_field: u32, my_string: String } - fn test(my_param: u32) -> u32 { my_param } - fn foo(a: A) { - test(a.<|>) - } - ", - ), - @r###" - [ - CompletionItem { - label: "another_field", - source_range: 136..136, - delete: 136..136, - insert: "another_field", - kind: Field, - detail: "i64", - }, - CompletionItem { - label: "my_string", - source_range: 136..136, - delete: 136..136, - insert: "my_string", - kind: Field, - detail: "{unknown}", - }, - CompletionItem { - label: "the_field", - source_range: 136..136, - delete: 136..136, - insert: "the_field", - kind: Field, - detail: "u32", - score: TypeMatch, - }, - ] - "### + fn active_param_type_match() { + mark::check!(active_param_type_match); + check( + r#" +struct S { foo: i64, bar: u32, baz: () } +fn test(x: u32) { } +fn foo(s: S) { test(s.<|>) } +"#, + expect![[r#" + [ + CompletionItem { + label: "bar", + source_range: 83..83, + delete: 83..83, + insert: "bar", + kind: Field, + detail: "u32", + score: TypeMatch, + }, + CompletionItem { + label: "baz", + source_range: 83..83, + delete: 83..83, + insert: "baz", + kind: Field, + detail: "()", + }, + CompletionItem { + label: "foo", + source_range: 83..83, + delete: 83..83, + insert: "foo", + kind: Field, + detail: "i64", + }, + ] + "#]], ); } #[test] - fn test_struct_field_completion_in_func_call_with_type_and_name() { - assert_debug_snapshot!( - do_reference_completion( - r" - struct A { another_field: i64, another_good_type: u32, the_field: u32 } - fn test(the_field: u32) -> u32 { the_field } - fn foo(a: A) { - test(a.<|>) - } - ", - ), - @r###" - [ - CompletionItem { - label: "another_field", - source_range: 143..143, - delete: 143..143, - insert: "another_field", - kind: Field, - detail: "i64", - }, - CompletionItem { - label: "another_good_type", - source_range: 143..143, - delete: 143..143, - insert: "another_good_type", - kind: Field, - detail: "u32", - score: TypeMatch, - }, - CompletionItem { - label: "the_field", - source_range: 143..143, - delete: 143..143, - insert: "the_field", - kind: Field, - detail: "u32", - score: TypeAndNameMatch, - }, - ] - "### + fn active_param_type_and_name_match() { + check( + r#" +struct S { foo: i64, bar: u32, baz: u32 } +fn test(bar: u32) { } +fn foo(s: S) { test(s.<|>) } +"#, + expect![[r#" + [ + CompletionItem { + label: "bar", + source_range: 86..86, + delete: 86..86, + insert: "bar", + kind: Field, + detail: "u32", + score: TypeAndNameMatch, + }, + CompletionItem { + label: "baz", + source_range: 86..86, + delete: 86..86, + insert: "baz", + kind: Field, + detail: "u32", + score: TypeMatch, + }, + CompletionItem { + label: "foo", + source_range: 86..86, + delete: 86..86, + insert: "foo", + kind: Field, + detail: "i64", + }, + ] + "#]], ); } #[test] - fn test_struct_field_completion_in_record_lit() { - mark::check!(test_struct_field_completion_in_record_lit); - assert_debug_snapshot!( - do_reference_completion( - r" - struct A { another_field: i64, another_good_type: u32, the_field: u32 } - struct B { my_string: String, my_vec: Vec, the_field: u32 } - fn foo(a: A) { - let b = B { - the_field: a.<|> - }; - } - ", - ), - @r###" - [ - CompletionItem { - label: "another_field", - source_range: 189..189, - delete: 189..189, - insert: "another_field", - kind: Field, - detail: "i64", - }, - CompletionItem { - label: "another_good_type", - source_range: 189..189, - delete: 189..189, - insert: "another_good_type", - kind: Field, - detail: "u32", - score: TypeMatch, - }, - CompletionItem { - label: "the_field", - source_range: 189..189, - delete: 189..189, - insert: "the_field", - kind: Field, - detail: "u32", - score: TypeAndNameMatch, - }, - ] - "### - ); + fn record_field_type_match() { + mark::check!(record_field_type_match); + check( + r#" +struct A { foo: i64, bar: u32, baz: u32 } +struct B { x: (), y: f32, bar: u32 } +fn foo(a: A) { B { bar: a.<|> }; } +"#, + expect![[r#" + [ + CompletionItem { + label: "bar", + source_range: 105..105, + delete: 105..105, + insert: "bar", + kind: Field, + detail: "u32", + score: TypeAndNameMatch, + }, + CompletionItem { + label: "baz", + source_range: 105..105, + delete: 105..105, + insert: "baz", + kind: Field, + detail: "u32", + score: TypeMatch, + }, + CompletionItem { + label: "foo", + source_range: 105..105, + delete: 105..105, + insert: "foo", + kind: Field, + detail: "i64", + }, + ] + "#]], + ) } #[test] - fn test_struct_field_completion_in_record_lit_and_fn_call() { - assert_debug_snapshot!( - do_reference_completion( - r" - struct A { another_field: i64, another_good_type: u32, the_field: u32 } - struct B { my_string: String, my_vec: Vec, the_field: u32 } - fn test(the_field: i64) -> i64 { the_field } - fn foo(a: A) { - let b = B { - the_field: test(a.<|>) - }; - } - ", - ), - @r###" - [ - CompletionItem { - label: "another_field", - source_range: 239..239, - delete: 239..239, - insert: "another_field", - kind: Field, - detail: "i64", - score: TypeMatch, - }, - CompletionItem { - label: "another_good_type", - source_range: 239..239, - delete: 239..239, - insert: "another_good_type", - kind: Field, - detail: "u32", - }, - CompletionItem { - label: "the_field", - source_range: 239..239, - delete: 239..239, - insert: "the_field", - kind: Field, - detail: "u32", - }, - ] - "### + fn record_field_type_match_and_fn_call() { + check( + r#" +struct A { foo: i64, bar: u32, baz: u32 } +struct B { x: (), y: f32, bar: u32 } +fn f(foo: i64) { } +fn foo(a: A) { B { bar: f(a.<|>) }; } +"#, + expect![[r#" + [ + CompletionItem { + label: "bar", + source_range: 127..127, + delete: 127..127, + insert: "bar", + kind: Field, + detail: "u32", + }, + CompletionItem { + label: "baz", + source_range: 127..127, + delete: 127..127, + insert: "baz", + kind: Field, + detail: "u32", + }, + CompletionItem { + label: "foo", + source_range: 127..127, + delete: 127..127, + insert: "foo", + kind: Field, + detail: "i64", + score: TypeAndNameMatch, + }, + ] + "#]], ); - } - - #[test] - fn test_struct_field_completion_in_fn_call_and_record_lit() { - assert_debug_snapshot!( - do_reference_completion( - r" - struct A { another_field: i64, another_good_type: u32, the_field: u32 } - struct B { my_string: String, my_vec: Vec, the_field: u32 } - fn test(the_field: i64) -> i64 { the_field } - fn foo(a: A) { - test(B { - the_field: a.<|> - }); - } - ", - ), - @r###" - [ - CompletionItem { - label: "another_field", - source_range: 231..231, - delete: 231..231, - insert: "another_field", - kind: Field, - detail: "i64", - }, - CompletionItem { - label: "another_good_type", - source_range: 231..231, - delete: 231..231, - insert: "another_good_type", - kind: Field, - detail: "u32", - score: TypeMatch, - }, - CompletionItem { - label: "the_field", - source_range: 231..231, - delete: 231..231, - insert: "the_field", - kind: Field, - detail: "u32", - score: TypeAndNameMatch, - }, - ] - "### + check( + r#" +struct A { foo: i64, bar: u32, baz: u32 } +struct B { x: (), y: f32, bar: u32 } +fn f(foo: i64) { } +fn foo(a: A) { f(B { bar: a.<|> }); } +"#, + expect![[r#" + [ + CompletionItem { + label: "bar", + source_range: 127..127, + delete: 127..127, + insert: "bar", + kind: Field, + detail: "u32", + score: TypeAndNameMatch, + }, + CompletionItem { + label: "baz", + source_range: 127..127, + delete: 127..127, + insert: "baz", + kind: Field, + detail: "u32", + score: TypeMatch, + }, + CompletionItem { + label: "foo", + source_range: 127..127, + delete: 127..127, + insert: "foo", + kind: Field, + detail: "i64", + }, + ] + "#]], ); } #[test] fn prioritize_exact_ref_match() { - assert_debug_snapshot!( - do_reference_completion( - r" - struct WorldSnapshot { _f: () }; - fn go(world: &WorldSnapshot) { - go(w<|>) - } - ", - ), - @r###" - [ - CompletionItem { - label: "WorldSnapshot", - source_range: 71..72, - delete: 71..72, - insert: "WorldSnapshot", - kind: Struct, - }, - CompletionItem { - label: "go(…)", - source_range: 71..72, - delete: 71..72, - insert: "go(${1:world})$0", - kind: Function, - lookup: "go", - detail: "fn go(world: &WorldSnapshot)", - trigger_call_info: true, - }, - CompletionItem { - label: "world", - source_range: 71..72, - delete: 71..72, - insert: "world", - kind: Binding, - detail: "&WorldSnapshot", - score: TypeAndNameMatch, - }, - ] - "### + check( + r#" +struct WorldSnapshot { _f: () }; +fn go(world: &WorldSnapshot) { go(w<|>) } +"#, + expect![[r#" + [ + CompletionItem { + label: "WorldSnapshot", + source_range: 67..68, + delete: 67..68, + insert: "WorldSnapshot", + kind: Struct, + }, + CompletionItem { + label: "go(…)", + source_range: 67..68, + delete: 67..68, + insert: "go(${1:world})$0", + kind: Function, + lookup: "go", + detail: "fn go(world: &WorldSnapshot)", + trigger_call_info: true, + }, + CompletionItem { + label: "world", + source_range: 67..68, + delete: 67..68, + insert: "world", + kind: Binding, + detail: "&WorldSnapshot", + score: TypeAndNameMatch, + }, + ] + "#]], ); } } -- cgit v1.2.3 From 5c68dd6b59cd5006a96280217bc88a6e26f90f1f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 4 Jul 2020 09:53:54 +0200 Subject: Better tests for completion scoring --- crates/ra_ide/src/completion/completion_item.rs | 2 +- crates/ra_ide/src/completion/presentation.rs | 246 ++++++------------------ crates/ra_ide/src/completion/test_utils.rs | 5 +- 3 files changed, 61 insertions(+), 192 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 4db371d57..477d6f6f6 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs @@ -95,7 +95,7 @@ impl fmt::Debug for CompletionItem { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)] pub enum CompletionScore { /// If only type match TypeMatch, diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 9ec33a050..ee810b59f 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -461,12 +461,19 @@ fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static s #[cfg(test)] mod tests { + use std::cmp::Reverse; + use expect::{expect, Expect}; use test_utils::mark; - use crate::completion::{ - test_utils::{check_edit, check_edit_with_config, do_completion}, - CompletionConfig, CompletionKind, + use crate::{ + completion::{ + test_utils::{ + check_edit, check_edit_with_config, do_completion, get_all_completion_items, + }, + CompletionConfig, CompletionKind, + }, + CompletionScore, }; fn check(ra_fixture: &str, expect: Expect) { @@ -474,6 +481,29 @@ mod tests { expect.assert_debug_eq(&actual); } + fn check_scores(ra_fixture: &str, expect: Expect) { + fn display_score(score: Option) -> &'static str { + match score { + Some(CompletionScore::TypeMatch) => "[type]", + Some(CompletionScore::TypeAndNameMatch) => "[type+name]", + None => "[]".into(), + } + } + + let mut completions = get_all_completion_items(ra_fixture, &CompletionConfig::default()); + completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string())); + let actual = completions + .into_iter() + .filter(|it| it.completion_kind == CompletionKind::Reference) + .map(|it| { + let tag = it.kind().unwrap().tag(); + let score = display_score(it.score()); + format!("{} {} {}\n", tag, it.label(), score) + }) + .collect::(); + expect.assert_eq(&actual); + } + #[test] fn enum_detail_includes_record_fields() { check( @@ -902,132 +932,42 @@ fn main() { frobnicate!(); } } #[test] - fn active_param_type_match() { + fn active_param_score() { mark::check!(active_param_type_match); - check( - r#" -struct S { foo: i64, bar: u32, baz: () } -fn test(x: u32) { } -fn foo(s: S) { test(s.<|>) } -"#, - expect![[r#" - [ - CompletionItem { - label: "bar", - source_range: 83..83, - delete: 83..83, - insert: "bar", - kind: Field, - detail: "u32", - score: TypeMatch, - }, - CompletionItem { - label: "baz", - source_range: 83..83, - delete: 83..83, - insert: "baz", - kind: Field, - detail: "()", - }, - CompletionItem { - label: "foo", - source_range: 83..83, - delete: 83..83, - insert: "foo", - kind: Field, - detail: "i64", - }, - ] - "#]], - ); - } - - #[test] - fn active_param_type_and_name_match() { - check( + check_scores( r#" struct S { foo: i64, bar: u32, baz: u32 } fn test(bar: u32) { } fn foo(s: S) { test(s.<|>) } "#, expect![[r#" - [ - CompletionItem { - label: "bar", - source_range: 86..86, - delete: 86..86, - insert: "bar", - kind: Field, - detail: "u32", - score: TypeAndNameMatch, - }, - CompletionItem { - label: "baz", - source_range: 86..86, - delete: 86..86, - insert: "baz", - kind: Field, - detail: "u32", - score: TypeMatch, - }, - CompletionItem { - label: "foo", - source_range: 86..86, - delete: 86..86, - insert: "foo", - kind: Field, - detail: "i64", - }, - ] + fd bar [type+name] + fd baz [type] + fd foo [] "#]], ); } #[test] - fn record_field_type_match() { + fn record_field_scores() { mark::check!(record_field_type_match); - check( + check_scores( r#" struct A { foo: i64, bar: u32, baz: u32 } struct B { x: (), y: f32, bar: u32 } fn foo(a: A) { B { bar: a.<|> }; } "#, expect![[r#" - [ - CompletionItem { - label: "bar", - source_range: 105..105, - delete: 105..105, - insert: "bar", - kind: Field, - detail: "u32", - score: TypeAndNameMatch, - }, - CompletionItem { - label: "baz", - source_range: 105..105, - delete: 105..105, - insert: "baz", - kind: Field, - detail: "u32", - score: TypeMatch, - }, - CompletionItem { - label: "foo", - source_range: 105..105, - delete: 105..105, - insert: "foo", - kind: Field, - detail: "i64", - }, - ] + fd bar [type+name] + fd baz [type] + fd foo [] "#]], ) } #[test] - fn record_field_type_match_and_fn_call() { - check( + fn record_field_and_call_scores() { + check_scores( r#" struct A { foo: i64, bar: u32, baz: u32 } struct B { x: (), y: f32, bar: u32 } @@ -1035,36 +975,12 @@ fn f(foo: i64) { } fn foo(a: A) { B { bar: f(a.<|>) }; } "#, expect![[r#" - [ - CompletionItem { - label: "bar", - source_range: 127..127, - delete: 127..127, - insert: "bar", - kind: Field, - detail: "u32", - }, - CompletionItem { - label: "baz", - source_range: 127..127, - delete: 127..127, - insert: "baz", - kind: Field, - detail: "u32", - }, - CompletionItem { - label: "foo", - source_range: 127..127, - delete: 127..127, - insert: "foo", - kind: Field, - detail: "i64", - score: TypeAndNameMatch, - }, - ] + fd foo [type+name] + fd bar [] + fd baz [] "#]], ); - check( + check_scores( r#" struct A { foo: i64, bar: u32, baz: u32 } struct B { x: (), y: f32, bar: u32 } @@ -1072,74 +988,24 @@ fn f(foo: i64) { } fn foo(a: A) { f(B { bar: a.<|> }); } "#, expect![[r#" - [ - CompletionItem { - label: "bar", - source_range: 127..127, - delete: 127..127, - insert: "bar", - kind: Field, - detail: "u32", - score: TypeAndNameMatch, - }, - CompletionItem { - label: "baz", - source_range: 127..127, - delete: 127..127, - insert: "baz", - kind: Field, - detail: "u32", - score: TypeMatch, - }, - CompletionItem { - label: "foo", - source_range: 127..127, - delete: 127..127, - insert: "foo", - kind: Field, - detail: "i64", - }, - ] + fd bar [type+name] + fd baz [type] + fd foo [] "#]], ); } #[test] fn prioritize_exact_ref_match() { - check( + check_scores( r#" struct WorldSnapshot { _f: () }; fn go(world: &WorldSnapshot) { go(w<|>) } "#, expect![[r#" - [ - CompletionItem { - label: "WorldSnapshot", - source_range: 67..68, - delete: 67..68, - insert: "WorldSnapshot", - kind: Struct, - }, - CompletionItem { - label: "go(…)", - source_range: 67..68, - delete: 67..68, - insert: "go(${1:world})$0", - kind: Function, - lookup: "go", - detail: "fn go(world: &WorldSnapshot)", - trigger_call_info: true, - }, - CompletionItem { - label: "world", - source_range: 67..68, - delete: 67..68, - insert: "world", - kind: Binding, - detail: "&WorldSnapshot", - score: TypeAndNameMatch, - }, - ] + bn world [type+name] + st WorldSnapshot [] + fn go(…) [] "#]], ); } diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs index 329acdc8b..cbae1da85 100644 --- a/crates/ra_ide/src/completion/test_utils.rs +++ b/crates/ra_ide/src/completion/test_utils.rs @@ -92,7 +92,10 @@ pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) - .unwrap(); } -fn get_all_completion_items(code: &str, options: &CompletionConfig) -> Vec { +pub(crate) fn get_all_completion_items( + code: &str, + options: &CompletionConfig, +) -> Vec { let (analysis, position) = analysis_and_position(code); analysis.completions(options, position).unwrap().unwrap().into() } -- cgit v1.2.3 From caeddff5435d9cf604aac7af7b53cc4ac8bb4a13 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 4 Jul 2020 10:03:27 +0200 Subject: Comments --- crates/ra_ide/src/completion/complete_dot.rs | 4 ++-- crates/ra_ide/src/completion/presentation.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index ee4e24fca..520652a37 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs @@ -1,6 +1,7 @@ -//! FIXME: write short doc here +//! Completes references after dot (fields and method calls). use hir::{HasVisibility, Type}; +use rustc_hash::FxHashSet; use crate::{ completion::{ @@ -9,7 +10,6 @@ use crate::{ }, CompletionItem, }; -use rustc_hash::FxHashSet; /// Complete dot accesses, i.e. fields or methods (and .await syntax). pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index ee810b59f..bd48156b0 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -1,4 +1,5 @@ //! This modules takes care of rendering various definitions as completion items. +//! It also handles scoring (sorting) completions. use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; use ra_syntax::ast::NameOwner; -- cgit v1.2.3 From f2f6a46aa4751393ae18e8b21aa631c9919c5f43 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 4 Jul 2020 10:36:12 +0200 Subject: Cleanup dot completiont tests --- crates/ra_ide/src/completion/complete_dot.rs | 984 ++++++--------------- crates/ra_ide/src/completion/complete_keyword.rs | 35 + .../src/completion/complete_qualified_path.rs | 39 + crates/ra_ide/src/completion/presentation.rs | 69 ++ 4 files changed, 407 insertions(+), 720 deletions(-) (limited to 'crates/ra_ide/src') diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 520652a37..667a8b949 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs @@ -2,16 +2,11 @@ use hir::{HasVisibility, Type}; use rustc_hash::FxHashSet; +use test_utils::mark; -use crate::{ - completion::{ - completion_context::CompletionContext, - completion_item::{CompletionKind, Completions}, - }, - CompletionItem, -}; +use crate::completion::{completion_context::CompletionContext, completion_item::Completions}; -/// Complete dot accesses, i.e. fields or methods (and .await syntax). +/// Complete dot accesses, i.e. fields or methods. pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { let dot_receiver = match &ctx.dot_receiver { Some(expr) => expr, @@ -23,18 +18,12 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { _ => return, }; - if !ctx.is_call { + if ctx.is_call { + mark::hit!(test_no_struct_field_completion_for_method_call); + } else { complete_fields(acc, ctx, &receiver_ty); } complete_methods(acc, ctx, &receiver_ty); - - // Suggest .await syntax for types that implement Future trait - if receiver_ty.impls_future(ctx.db) { - CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") - .detail("expr.await") - .insert_text("await") - .add_to(acc); - } } fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Type) { @@ -72,801 +61,356 @@ fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: &T #[cfg(test)] mod tests { - use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; - use insta::assert_debug_snapshot; + use expect::{expect, Expect}; + use test_utils::mark; + + use crate::completion::{test_utils::completion_list, CompletionKind}; - fn do_ref_completion(code: &str) -> Vec { - do_completion(code, CompletionKind::Reference) + fn check(ra_fixture: &str, expect: Expect) { + let actual = completion_list(ra_fixture, CompletionKind::Reference); + expect.assert_eq(&actual); } #[test] - fn test_struct_field_completion() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A { the_field: u32 } - fn foo(a: A) { - a.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_field", - source_range: 45..45, - delete: 45..45, - insert: "the_field", - kind: Field, - detail: "u32", - }, - ] - "### + fn test_struct_field_and_method_completion() { + check( + r#" +struct S { foo: u32 } +impl S { + fn bar(&self) {} +} +fn foo(s: S) { s.<|> } +"#, + expect![[r#" + me bar() fn bar(&self) + fd foo u32 + "#]], ); } #[test] fn test_struct_field_completion_self() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A { - /// This is the_field - the_field: (u32,) - } - impl A { - fn foo(self) { - self.<|> - } - } - ", - ), - @r###" - [ - CompletionItem { - label: "foo()", - source_range: 102..102, - delete: 102..102, - insert: "foo()$0", - kind: Method, - lookup: "foo", - detail: "fn foo(self)", - }, - CompletionItem { - label: "the_field", - source_range: 102..102, - delete: 102..102, - insert: "the_field", - kind: Field, - detail: "(u32,)", - documentation: Documentation( - "This is the_field", - ), - }, - ] - "### - ); + check( + r#" +struct S { the_field: (u32,) } +impl S { + fn foo(self) { self.<|> } +} +"#, + expect![[r#" + me foo() fn foo(self) + fd the_field (u32,) + "#]], + ) } #[test] fn test_struct_field_completion_autoderef() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A { the_field: (u32, i32) } - impl A { - fn foo(&self) { - self.<|> - } - } - ", - ), - @r###" - [ - CompletionItem { - label: "foo()", - source_range: 77..77, - delete: 77..77, - insert: "foo()$0", - kind: Method, - lookup: "foo", - detail: "fn foo(&self)", - }, - CompletionItem { - label: "the_field", - source_range: 77..77, - delete: 77..77, - insert: "the_field", - kind: Field, - detail: "(u32, i32)", - }, - ] - "### - ); + check( + r#" +struct A { the_field: (u32, i32) } +impl A { + fn foo(&self) { self.<|> } +} +"#, + expect![[r#" + me foo() fn foo(&self) + fd the_field (u32, i32) + "#]], + ) } #[test] fn test_no_struct_field_completion_for_method_call() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A { the_field: u32 } - fn foo(a: A) { - a.<|>() - } - ", - ), - @"[]" + mark::check!(test_no_struct_field_completion_for_method_call); + check( + r#" +struct A { the_field: u32 } +fn foo(a: A) { a.<|>() } +"#, + expect![[""]], ); } #[test] - fn test_struct_field_visibility_private() { - assert_debug_snapshot!( - do_ref_completion( - r" - mod inner { - struct A { - private_field: u32, - pub pub_field: u32, - pub(crate) crate_field: u32, - pub(super) super_field: u32, - } - } - fn foo(a: inner::A) { - a.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "crate_field", - source_range: 192..192, - delete: 192..192, - insert: "crate_field", - kind: Field, - detail: "u32", - }, - CompletionItem { - label: "pub_field", - source_range: 192..192, - delete: 192..192, - insert: "pub_field", - kind: Field, - detail: "u32", - }, - CompletionItem { - label: "super_field", - source_range: 192..192, - delete: 192..192, - insert: "super_field", - kind: Field, - detail: "u32", - }, - ] - "### - ); + fn test_visibility_filtering() { + check( + r#" +mod inner { + pub struct A { + private_field: u32, + pub pub_field: u32, + pub(crate) crate_field: u32, + pub(super) super_field: u32, } - - #[test] - fn test_union_field_completion() { - assert_debug_snapshot!( - do_ref_completion( - r" - union Un { - field: u8, - other: u16, - } - - fn foo(u: Un) { - u.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "field", - source_range: 67..67, - delete: 67..67, - insert: "field", - kind: Field, - detail: "u8", - }, - CompletionItem { - label: "other", - source_range: 67..67, - delete: 67..67, - insert: "other", - kind: Field, - detail: "u16", - }, - ] - "### +} +fn foo(a: inner::A) { a.<|> } +"#, + expect![[r#" + fd crate_field u32 + fd pub_field u32 + fd super_field u32 + "#]], ); - } - #[test] - fn test_method_completion() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A {} - impl A { - fn the_method(&self) {} - } - fn foo(a: A) { - a.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_method()", - source_range: 71..71, - delete: 71..71, - insert: "the_method()$0", - kind: Method, - lookup: "the_method", - detail: "fn the_method(&self)", - }, - ] - "### + check( + r#" +struct A {} +mod m { + impl super::A { + fn private_method(&self) {} + pub(super) fn the_method(&self) {} + } +} +fn foo(a: A) { a.<|> } +"#, + expect![[r#" + me the_method() pub(super) fn the_method(&self) + "#]], ); } #[test] - fn test_method_completion_only_fitting_impls() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A {} - impl A { - fn the_method(&self) {} - } - impl A { - fn the_other_method(&self) {} - } - fn foo(a: A) { - a.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_method()", - source_range: 134..134, - delete: 134..134, - insert: "the_method()$0", - kind: Method, - lookup: "the_method", - detail: "fn the_method(&self)", - }, - ] - "### + fn test_union_field_completion() { + check( + r#" +union U { field: u8, other: u16 } +fn foo(u: U) { u.<|> } +"#, + expect![[r#" + fd field u8 + fd other u16 + "#]], ); } #[test] - fn test_method_completion_private() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A {} - mod m { - impl super::A { - fn private_method(&self) {} - pub(super) fn the_method(&self) {} - } - } - fn foo(a: A) { - a.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_method()", - source_range: 147..147, - delete: 147..147, - insert: "the_method()$0", - kind: Method, - lookup: "the_method", - detail: "pub(super) fn the_method(&self)", - }, - ] - "### - ); + fn test_method_completion_only_fitting_impls() { + check( + r#" +struct A {} +impl A { + fn the_method(&self) {} +} +impl A { + fn the_other_method(&self) {} +} +fn foo(a: A) { a.<|> } +"#, + expect![[r#" + me the_method() fn the_method(&self) + "#]], + ) } #[test] fn test_trait_method_completion() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A {} - trait Trait { fn the_method(&self); } - impl Trait for A {} - fn foo(a: A) { - a.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_method()", - source_range: 90..90, - delete: 90..90, - insert: "the_method()$0", - kind: Method, - lookup: "the_method", - detail: "fn the_method(&self)", - }, - ] - "### + check( + r#" +struct A {} +trait Trait { fn the_method(&self); } +impl Trait for A {} +fn foo(a: A) { a.<|> } +"#, + expect![[r#" + me the_method() fn the_method(&self) + "#]], ); } #[test] fn test_trait_method_completion_deduplicated() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A {} - trait Trait { fn the_method(&self); } - impl Trait for T {} - fn foo(a: &A) { - a.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_method()", - source_range: 94..94, - delete: 94..94, - insert: "the_method()$0", - kind: Method, - lookup: "the_method", - detail: "fn the_method(&self)", - }, - ] - "### + check( + r" +struct A {} +trait Trait { fn the_method(&self); } +impl Trait for T {} +fn foo(a: &A) { a.<|> } +", + expect![[r#" + me the_method() fn the_method(&self) + "#]], ); } #[test] fn completes_trait_method_from_other_module() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A {} - mod m { - pub trait Trait { fn the_method(&self); } - } - use m::Trait; - impl Trait for A {} - fn foo(a: A) { - a.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_method()", - source_range: 122..122, - delete: 122..122, - insert: "the_method()$0", - kind: Method, - lookup: "the_method", - detail: "fn the_method(&self)", - }, - ] - "### - ); - } - - #[test] - fn test_no_non_self_method() { - assert_debug_snapshot!( - do_ref_completion( + check( r" - struct A {} - impl A { - fn the_method() {} - } - fn foo(a: A) { - a.<|> - } - ", - ), - @"[]" +struct A {} +mod m { + pub trait Trait { fn the_method(&self); } +} +use m::Trait; +impl Trait for A {} +fn foo(a: A) { a.<|> } +", + expect![[r#" + me the_method() fn the_method(&self) + "#]], ); } #[test] - fn test_method_attr_filtering() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A {} - impl A { - #[inline] - fn the_method(&self) { - let x = 1; - let y = 2; - } - } - fn foo(a: A) { - a.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_method()", - source_range: 128..128, - delete: 128..128, - insert: "the_method()$0", - kind: Method, - lookup: "the_method", - detail: "fn the_method(&self)", - }, - ] - "### + fn test_no_non_self_method() { + check( + r#" +struct A {} +impl A { + fn the_method() {} +} +fn foo(a: A) { + a.<|> +} +"#, + expect![[""]], ); } #[test] fn test_tuple_field_completion() { - assert_debug_snapshot!( - do_ref_completion( - r" - fn foo() { - let b = (0, 3.14); - b.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "0", - source_range: 38..38, - delete: 38..38, - insert: "0", - kind: Field, - detail: "i32", - }, - CompletionItem { - label: "1", - source_range: 38..38, - delete: 38..38, - insert: "1", - kind: Field, - detail: "f64", - }, - ] - "### - ); + check( + r#" +fn foo() { + let b = (0, 3.14); + b.<|> +} +"#, + expect![[r#" + fd 0 i32 + fd 1 f64 + "#]], + ) } #[test] fn test_tuple_field_inference() { - assert_debug_snapshot!( - do_ref_completion( - r" - pub struct S; - impl S { - pub fn blah(&self) {} - } + check( + r#" +pub struct S; +impl S { pub fn blah(&self) {} } - struct T(S); +struct T(S); - impl T { - fn foo(&self) { - // FIXME: This doesn't work without the trailing `a` as `0.` is a float - self.0.a<|> - } - } - ", - ), - @r###" - [ - CompletionItem { - label: "blah()", - source_range: 190..191, - delete: 190..191, - insert: "blah()$0", - kind: Method, - lookup: "blah", - detail: "pub fn blah(&self)", - }, - ] - "### - ); +impl T { + fn foo(&self) { + // FIXME: This doesn't work without the trailing `a` as `0.` is a float + self.0.a<|> } - - #[test] - fn test_completion_works_in_consts() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct A { the_field: u32 } - const X: u32 = { - A { the_field: 92 }.<|> - }; - ", - ), - @r###" - [ - CompletionItem { - label: "the_field", - source_range: 69..69, - delete: 69..69, - insert: "the_field", - kind: Field, - detail: "u32", - }, - ] - "### +} +"#, + expect![[r#" + me blah() pub fn blah(&self) + "#]], ); } #[test] - fn test_completion_await_impls_future() { - assert_debug_snapshot!( - do_completion( - r###" - //- /main.rs - use std::future::*; - struct A {} - impl Future for A {} - fn foo(a: A) { - a.<|> - } - - //- /std/lib.rs - pub mod future { - #[lang = "future_trait"] - pub trait Future {} - } - "###, CompletionKind::Keyword), - @r###" - [ - CompletionItem { - label: "await", - source_range: 74..74, - delete: 74..74, - insert: "await", - detail: "expr.await", - }, - ] - "### - ) - } - - #[test] - fn test_super_super_completion() { - assert_debug_snapshot!( - do_ref_completion( - r" - mod a { - const A: usize = 0; - - mod b { - const B: usize = 0; - - mod c { - use super::super::<|> - } - } - } - ", - ), - @r###" - [ - CompletionItem { - label: "A", - source_range: 120..120, - delete: 120..120, - insert: "A", - kind: Const, - }, - CompletionItem { - label: "b", - source_range: 120..120, - delete: 120..120, - insert: "b", - kind: Module, - }, - ] - "### + fn test_completion_works_in_consts() { + check( + r#" +struct A { the_field: u32 } +const X: u32 = { + A { the_field: 92 }.<|> +}; +"#, + expect![[r#" + fd the_field u32 + "#]], ); } #[test] fn works_in_simple_macro_1() { - assert_debug_snapshot!( - do_ref_completion( - r" - macro_rules! m { ($e:expr) => { $e } } - struct A { the_field: u32 } - fn foo(a: A) { - m!(a.x<|>) - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_field", - source_range: 91..92, - delete: 91..92, - insert: "the_field", - kind: Field, - detail: "u32", - }, - ] - "### - ); - } - - #[test] - fn works_in_simple_macro_recursive() { - assert_debug_snapshot!( - do_ref_completion( - r" - macro_rules! m { ($e:expr) => { $e } } - struct A { the_field: u32 } - fn foo(a: A) { - m!(a.x<|>) - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_field", - source_range: 91..92, - delete: 91..92, - insert: "the_field", - kind: Field, - detail: "u32", - }, - ] - "### + check( + r#" +macro_rules! m { ($e:expr) => { $e } } +struct A { the_field: u32 } +fn foo(a: A) { + m!(a.x<|>) +} +"#, + expect![[r#" + fd the_field u32 + "#]], ); } #[test] fn works_in_simple_macro_2() { // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery - assert_debug_snapshot!( - do_ref_completion( - r" - macro_rules! m { ($e:expr) => { $e } } - struct A { the_field: u32 } - fn foo(a: A) { - m!(a.<|>) - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_field", - source_range: 91..91, - delete: 91..91, - insert: "the_field", - kind: Field, - detail: "u32", - }, - ] - "### + check( + r#" +macro_rules! m { ($e:expr) => { $e } } +struct A { the_field: u32 } +fn foo(a: A) { + m!(a.<|>) +} +"#, + expect![[r#" + fd the_field u32 + "#]], ); } #[test] fn works_in_simple_macro_recursive_1() { - assert_debug_snapshot!( - do_ref_completion( - r" - macro_rules! m { ($e:expr) => { $e } } - struct A { the_field: u32 } - fn foo(a: A) { - m!(m!(m!(a.x<|>))) - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_field", - source_range: 97..98, - delete: 97..98, - insert: "the_field", - kind: Field, - detail: "u32", - }, - ] - "### + check( + r#" +macro_rules! m { ($e:expr) => { $e } } +struct A { the_field: u32 } +fn foo(a: A) { + m!(m!(m!(a.x<|>))) +} +"#, + expect![[r#" + fd the_field u32 + "#]], ); } #[test] fn macro_expansion_resilient() { - assert_debug_snapshot!( - do_ref_completion( - r" - macro_rules! dbg { - () => {}; - ($val:expr) => { - match $val { tmp => { tmp } } - }; - // Trailing comma with single argument is ignored - ($val:expr,) => { $crate::dbg!($val) }; - ($($val:expr),+ $(,)?) => { - ($($crate::dbg!($val)),+,) - }; - } - struct A { the_field: u32 } - fn foo(a: A) { - dbg!(a.<|>) - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_field", - source_range: 327..327, - delete: 327..327, - insert: "the_field", - kind: Field, - detail: "u32", - }, - ] - "### + check( + r#" +macro_rules! dbg { + () => {}; + ($val:expr) => { + match $val { tmp => { tmp } } + }; + // Trailing comma with single argument is ignored + ($val:expr,) => { $crate::dbg!($val) }; + ($($val:expr),+ $(,)?) => { + ($($crate::dbg!($val)),+,) + }; +} +struct A { the_field: u32 } +fn foo(a: A) { + dbg!(a.<|>) +} +"#, + expect![[r#" + fd the_field u32 + "#]], ); } #[test] - fn test_method_completion_3547() { - assert_debug_snapshot!( - do_ref_completion( - r" - struct HashSet {} - impl HashSet { - pub fn the_method(&self) {} - } - fn foo() { - let s: HashSet<_>; - s.<|> - } - ", - ), - @r###" - [ - CompletionItem { - label: "the_method()", - source_range: 116..116, - delete: 116..116, - insert: "the_method()$0", - kind: Method, - lookup: "the_method", - detail: "pub fn the_method(&self)", - }, - ] - "### + fn test_method_completion_issue_3547() { + check( + r#" +struct HashSet {} +impl HashSet { + pub fn the_method(&self) {} +} +fn foo() { + let s: HashSet<_>; + s.<|> +} +"#, + expect![[r#" + me the_method() pub fn the_method(&self) + "#]], ); } } diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs index 086b917ce..340d57a49 100644 --- a/crates/ra_ide/src/completion/complete_keyword.rs +++ b/crates/ra_ide/src/completion/complete_keyword.rs @@ -35,6 +35,19 @@ pub(super) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC } _ => {} } + + // Suggest .await syntax for types that implement Future trait + if let Some(receiver) = &ctx.dot_receiver { + if let Some(ty) = ctx.sema.type_of_expr(receiver) { + if ty.impls_future(ctx.db) { + CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") + .kind(CompletionItemKind::Keyword) + .detail("expr.await") + .insert_text("await") + .add_to(acc); + } + }; + } } pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { @@ -490,4 +503,26 @@ Some multi-line comment<|> expect![[""]], ); } + + #[test] + fn test_completion_await_impls_future() { + check( + r#" +//- /main.rs +use std::future::*; +struct A {} +impl Future for A {} +fn foo(a: A) { a.<|> } + +//- /std/lib.rs +pub mod future { + #[lang = "future_trait"] + pub trait Future {} +} +"#, + expect![[r#" + kw await expr.await + "#]], + ) + } } diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs index f133ce3ce..a16866cd2 100644 --- a/crates/ra_ide/src/completion/complete_qualified_path.rs +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs @@ -1205,6 +1205,45 @@ mod tests { ); } + #[test] + fn test_super_super_completion() { + assert_debug_snapshot!( + do_reference_completion( + r" + mod a { + const A: usize = 0; + + mod b { + const B: usize = 0; + + mod c { + use super::super::<|> + } + } + } + ", + ), + @r###" + [ + CompletionItem { + label: "A", + source_range: 120..120, + delete: 120..120, + insert: "A", + kind: Const, + }, + CompletionItem { + label: "b", + source_range: 120..120, + delete: 120..120, + insert: "b", + kind: Module, + }, + ] + "### + ); + } + #[test] fn completes_reexported_items_under_correct_name() { assert_debug_snapshot!( diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index bd48156b0..dc391c46b 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -643,6 +643,75 @@ fn foo() { A { the<|> } } ); } + #[test] + fn renders_docs() { + check( + r#" +struct S { + /// Field docs + foo: +} +impl S { + /// Method docs + fn bar(self) { self.<|> } +}"#, + expect![[r#" + [ + CompletionItem { + label: "bar()", + source_range: 94..94, + delete: 94..94, + insert: "bar()$0", + kind: Method, + lookup: "bar", + detail: "fn bar(self)", + documentation: Documentation( + "Method docs", + ), + }, + CompletionItem { + label: "foo", + source_range: 94..94, + delete: 94..94, + insert: "foo", + kind: Field, + detail: "{unknown}", + documentation: Documentation( + "Field docs", + ), + }, + ] + "#]], + ) + } + + #[test] + fn dont_render_attrs() { + check( + r#" +struct S; +impl S { + #[inline] + fn the_method(&self) { } +} +fn foo(s: S) { s.<|> } +"#, + expect![[r#" + [ + CompletionItem { + label: "the_method()", + source_range: 81..81, + delete: 81..81, + insert: "the_method()$0", + kind: Method, + lookup: "the_method", + detail: "fn the_method(&self)", + }, + ] + "#]], + ) + } + #[test] fn inserts_parens_for_function_calls() { mark::check!(inserts_parens_for_function_calls); -- cgit v1.2.3