From b0f6d8868ca33a9907e372de2a2f868c3ef8d00c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 4 Jun 2021 13:47:39 +0200 Subject: Reorganize inlay_hints tests --- crates/ide/src/inlay_hints.rs | 1159 ++++++++++++++++++++--------------------- 1 file changed, 565 insertions(+), 594 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index d6dfa0183..9f2f6c80a 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -299,9 +299,8 @@ fn should_not_display_type_hint( // Type of expr should be iterable. return it.in_token().is_none() || it.iterable() - .and_then(|iterable_expr|sema.type_of_expr(&iterable_expr)) - .map(|iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit()) - .unwrap_or(true) + .and_then(|iterable_expr| sema.type_of_expr(&iterable_expr)) + .map_or(true, |iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit()) }, _ => (), } @@ -319,8 +318,8 @@ fn should_hide_param_name_hint( // hide when: // - the parameter name is a suffix of the function's name // - the argument is an enum whose name is equal to the parameter - // - exact argument<->parameter match(ignoring leading underscore) or argument is a prefix/suffix - // of parameter with _ splitting it off + // - exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix + // of argument with _ splitting it off // - param starts with `ra_fixture` // - param is a well known name in an unary function @@ -342,23 +341,22 @@ fn should_hide_param_name_hint( } fn is_argument_similar_to_param_name(argument: &ast::Expr, param_name: &str) -> bool { - match get_string_representation(argument) { - None => false, - Some(argument) => { - let mut res = false; - if let Some(first) = argument.bytes().skip_while(|&c| c == b'_').position(|c| c == b'_') - { - res |= param_name == argument[..first].trim_start_matches('_'); - } - if let Some(last) = - argument.bytes().rev().skip_while(|&c| c == b'_').position(|c| c == b'_') - { - res |= param_name == argument[last..].trim_end_matches('_'); - } - res |= argument == param_name; - res - } + // check whether param_name and argument are the same or + // whether param_name is a prefix/suffix of argument(split at `_`) + let argument = match get_string_representation(argument) { + Some(argument) => argument, + None => return false, + }; + + let param_name = param_name.trim_start_matches('_'); + let argument = argument.trim_start_matches('_'); + if argument.strip_prefix(param_name).map_or(false, |s| s.starts_with('_')) { + return true; + } + if argument.strip_suffix(param_name).map_or(false, |s| s.ends_with('_')) { + return true; } + argument == param_name } /// Hide the parameter name of an unary function if it is a `_` - prefixed suffix of the function's name, or equal. @@ -451,6 +449,42 @@ mod tests { check_with_config(TEST_CONFIG, ra_fixture); } + fn check_params(ra_fixture: &str) { + check_with_config( + InlayHintsConfig { + parameter_hints: true, + type_hints: false, + chaining_hints: false, + max_length: None, + }, + ra_fixture, + ); + } + + fn check_types(ra_fixture: &str) { + check_with_config( + InlayHintsConfig { + parameter_hints: false, + type_hints: true, + chaining_hints: false, + max_length: None, + }, + ra_fixture, + ); + } + + fn check_chains(ra_fixture: &str) { + check_with_config( + InlayHintsConfig { + parameter_hints: false, + type_hints: false, + chaining_hints: true, + max_length: None, + }, + ra_fixture, + ); + } + fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { let ra_fixture = format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); @@ -471,16 +505,27 @@ mod tests { } #[test] - fn param_hints_only() { + fn hints_disabled() { check_with_config( InlayHintsConfig { - parameter_hints: true, type_hints: false, + parameter_hints: false, chaining_hints: false, max_length: None, }, r#" fn foo(a: i32, b: i32) -> i32 { a + b } +fn main() { + let _x = foo(4, 4); +}"#, + ); + } + + #[test] + fn param_hints_only() { + check_params( + r#" +fn foo(a: i32, b: i32) -> i32 { a + b } fn main() { let _x = foo( 4, @@ -494,13 +539,7 @@ fn main() { #[test] fn param_name_similar_to_fn_name_still_hints() { - check_with_config( - InlayHintsConfig { - parameter_hints: true, - type_hints: false, - chaining_hints: false, - max_length: None, - }, + check_params( r#" fn max(x: i32, y: i32) -> i32 { x + y } fn main() { @@ -516,13 +555,7 @@ fn main() { #[test] fn param_name_similar_to_fn_name() { - check_with_config( - InlayHintsConfig { - parameter_hints: true, - type_hints: false, - chaining_hints: false, - max_length: None, - }, + check_params( r#" fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore } fn main() { @@ -535,13 +568,7 @@ fn main() { #[test] fn param_name_same_as_fn_name() { - check_with_config( - InlayHintsConfig { - parameter_hints: true, - type_hints: false, - chaining_hints: false, - max_length: None, - }, + check_params( r#" fn foo(foo: i32) -> i32 { foo } fn main() { @@ -554,13 +581,7 @@ fn main() { #[test] fn never_hide_param_when_multiple_params() { - check_with_config( - InlayHintsConfig { - parameter_hints: true, - type_hints: false, - chaining_hints: false, - max_length: None, - }, + check_params( r#" fn foo(bar: i32, baz: i32) -> i32 { bar + baz } fn main() { @@ -575,285 +596,132 @@ fn main() { } #[test] - fn hints_disabled() { - check_with_config( - InlayHintsConfig { - type_hints: false, - parameter_hints: false, - chaining_hints: false, - max_length: None, - }, + fn hide_param_hints_for_clones() { + check_params( r#" -fn foo(a: i32, b: i32) -> i32 { a + b } +fn foo(bar: i32, baz: String, qux: f32) {} + fn main() { - let _x = foo(4, 4); -}"#, + let bar = 3; + let baz = &"baz"; + let fez = 1.0; + foo(bar.clone(), baz.clone(), fez.clone()); + //^^^^^^^^^^^ qux +} +"#, ); } #[test] - fn type_hints_only() { - check_with_config( - InlayHintsConfig { - type_hints: true, - parameter_hints: false, - chaining_hints: false, - max_length: None, - }, + fn self_param_hints() { + check_params( r#" -fn foo(a: i32, b: i32) -> i32 { a + b } +struct Foo; + +impl Foo { + fn foo(self: Self) {} + fn bar(self: &Self) {} +} + fn main() { - let _x = foo(4, 4); - //^^ i32 -}"#, - ); + Foo::foo(Foo); + //^^^ self + Foo::bar(&Foo); + //^^^^ self +} +"#, + ) } #[test] - fn default_generic_types_should_not_be_displayed() { - check( - r#" -struct Test { k: K, t: T } - + fn param_name_hints_show_for_literals() { + check_params( + r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] } fn main() { - let zz = Test { t: 23u8, k: 33 }; - //^^ Test - let zz_ref = &zz; - //^^^^^^ &Test - let test = || zz; - //^^^^ || -> Test + test( + 0x0fab272b, + //^^^^^^^^^^ a + 0x0fab272b + //^^^^^^^^^^ b + ); }"#, - ); + ) } #[test] - fn let_statement() { + fn function_call_parameter_hint() { check( r#" -#[derive(PartialEq)] enum Option { None, Some(T) } +use Option::*; -#[derive(PartialEq)] -struct Test { a: Option, b: u8 } +struct FileId {} +struct SmolStr {} -fn main() { - struct InnerStruct {} +struct TextRange {} +struct SyntaxKind {} +struct NavigationTarget {} - let test = 54; - //^^^^ i32 - let test: i32 = 33; - let mut test = 33; - //^^^^^^^^ i32 - let _ = 22; - let test = "test"; - //^^^^ &str - let test = InnerStruct {}; - //^^^^ InnerStruct +struct Test {} - let test = unresolved(); +impl Test { + fn method(&self, mut param: i32) -> i32 { param * 2 } - let test = (42, 'a'); - //^^^^ (i32, char) - let (a, (b, (c,)) = (2, (3, (9.2,)); - //^ i32 ^ i32 ^ f64 - let &x = &92; - //^ i32 -}"#, - ); + fn from_syntax( + file_id: FileId, + name: SmolStr, + focus_range: Option, + full_range: TextRange, + kind: SyntaxKind, + docs: Option, + ) -> NavigationTarget { + NavigationTarget {} } +} - #[test] - fn closure_parameters() { - check( - r#" -fn main() { - let mut start = 0; - //^^^^^^^^^ i32 - (0..2).for_each(|increment| { start += increment; }); - //^^^^^^^^^ i32 - - let multiply = - //^^^^^^^^ |…| -> i32 - | a, b| a * b - //^ i32 ^ i32 - ; - - let _: i32 = multiply(1, 2); - let multiply_ref = &multiply; - //^^^^^^^^^^^^ &|…| -> i32 +fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 { + foo + bar +} - let return_42 = || 42; - //^^^^^^^^^ || -> i32 +fn main() { + let not_literal = 1; + //^^^^^^^^^^^ i32 + let _: i32 = test_func(1, 2, "hello", 3, not_literal); + //^ foo ^ bar ^^^^^^^ msg ^^^^^^^^^^^ last + let t: Test = Test {}; + t.method(123); + //^^^ param + Test::method(&t, 3456); + //^^ self ^^^^ param + Test::from_syntax( + FileId {}, + //^^^^^^^^^ file_id + "impl".into(), + //^^^^^^^^^^^^^ name + None, + //^^^^ focus_range + TextRange {}, + //^^^^^^^^^^^^ full_range + SyntaxKind {}, + //^^^^^^^^^^^^^ kind + None, + //^^^^ docs + ); }"#, ); } #[test] - fn if_expr() { - check( + fn omitted_parameters_hints_heuristics() { + check_with_config( + InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, r#" -enum Option { None, Some(T) } -use Option::*; +fn map(f: i32) {} +fn filter(predicate: i32) {} -struct Test { a: Option, b: u8 } - -fn main() { - let test = Some(Test { a: Some(3), b: 1 }); - //^^^^ Option - if let None = &test {}; - if let test = &test {}; - //^^^^ &Option - if let Some(test) = &test {}; - //^^^^ &Test - if let Some(Test { a, b }) = &test {}; - //^ &Option ^ &u8 - if let Some(Test { a: x, b: y }) = &test {}; - //^ &Option ^ &u8 - if let Some(Test { a: Some(x), b: y }) = &test {}; - //^ &u32 ^ &u8 - if let Some(Test { a: None, b: y }) = &test {}; - //^ &u8 - if let Some(Test { b: y, .. }) = &test {}; - //^ &u8 - if test == None {} -}"#, - ); - } - - #[test] - fn while_expr() { - check( - r#" -enum Option { None, Some(T) } -use Option::*; - -struct Test { a: Option, b: u8 } - -fn main() { - let test = Some(Test { a: Some(3), b: 1 }); - //^^^^ Option - while let Some(Test { a: Some(x), b: y }) = &test {}; - //^ &u32 ^ &u8 -}"#, - ); - } - - #[test] - fn match_arm_list() { - check( - r#" -enum Option { None, Some(T) } -use Option::*; - -struct Test { a: Option, b: u8 } - -fn main() { - match Some(Test { a: Some(3), b: 1 }) { - None => (), - test => (), - //^^^^ Option - Some(Test { a: Some(x), b: y }) => (), - //^ u32 ^ u8 - _ => {} - } -}"#, - ); - } - - #[test] - fn hint_truncation() { - check_with_config( - InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, - r#" -struct Smol(T); - -struct VeryLongOuterName(T); - -fn main() { - let a = Smol(0u32); - //^ Smol - let b = VeryLongOuterName(0usize); - //^ VeryLongOuterName<…> - let c = Smol(Smol(0u32)) - //^ Smol> -}"#, - ); - } - - #[test] - fn function_call_parameter_hint() { - check( - r#" -enum Option { None, Some(T) } -use Option::*; - -struct FileId {} -struct SmolStr {} - -struct TextRange {} -struct SyntaxKind {} -struct NavigationTarget {} - -struct Test {} - -impl Test { - fn method(&self, mut param: i32) -> i32 { param * 2 } - - fn from_syntax( - file_id: FileId, - name: SmolStr, - focus_range: Option, - full_range: TextRange, - kind: SyntaxKind, - docs: Option, - ) -> NavigationTarget { - NavigationTarget {} - } -} - -fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 { - foo + bar -} - -fn main() { - let not_literal = 1; - //^^^^^^^^^^^ i32 - let _: i32 = test_func(1, 2, "hello", 3, not_literal); - //^ foo ^ bar ^^^^^^^ msg ^^^^^^^^^^^ last - let t: Test = Test {}; - t.method(123); - //^^^ param - Test::method(&t, 3456); - //^^ self ^^^^ param - Test::from_syntax( - FileId {}, - //^^^^^^^^^ file_id - "impl".into(), - //^^^^^^^^^^^^^ name - None, - //^^^^ focus_range - TextRange {}, - //^^^^^^^^^^^^ full_range - SyntaxKind {}, - //^^^^^^^^^^^^^ kind - None, - //^^^^ docs - ); -}"#, - ); - } - - #[test] - fn omitted_parameters_hints_heuristics() { - check_with_config( - InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, - r#" -fn map(f: i32) {} -fn filter(predicate: i32) {} - -struct TestVarContainer { - test_var: i32, -} +struct TestVarContainer { + test_var: i32, +} impl TestVarContainer { fn test_var(&self) -> i32 { @@ -939,179 +807,255 @@ fn main() { ); } + // Type-Hint tests + #[test] - fn unit_structs_have_no_type_hints() { - check_with_config( - InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, + fn type_hints_only() { + check_types( r#" -enum Result { Ok(T), Err(E) } -use Result::*; - -struct SyntheticSyntax; - +fn foo(a: i32, b: i32) -> i32 { a + b } fn main() { - match Ok(()) { - Ok(_) => (), - Err(SyntheticSyntax) => (), - } + let _x = foo(4, 4); + //^^ i32 }"#, ); } #[test] - fn chaining_hints_ignore_comments() { - check_expect( - InlayHintsConfig { - parameter_hints: false, - type_hints: false, - chaining_hints: true, - max_length: None, - }, + fn default_generic_types_should_not_be_displayed() { + check( r#" -struct A(B); -impl A { fn into_b(self) -> B { self.0 } } -struct B(C); -impl B { fn into_c(self) -> C { self.0 } } -struct C; +struct Test { k: K, t: T } fn main() { - let c = A(B(C)) - .into_b() // This is a comment - // This is another comment - .into_c(); -} -"#, - expect![[r#" - [ - InlayHint { - range: 148..173, - kind: ChainingHint, - label: "B", - }, - InlayHint { - range: 148..155, - kind: ChainingHint, - label: "A", - }, - ] - "#]], + let zz = Test { t: 23u8, k: 33 }; + //^^ Test + let zz_ref = &zz; + //^^^^^^ &Test + let test = || zz; + //^^^^ || -> Test +}"#, ); } #[test] - fn chaining_hints_without_newlines() { - check_with_config( - InlayHintsConfig { - parameter_hints: false, - type_hints: false, - chaining_hints: true, - max_length: None, - }, + fn shorten_iterators_in_associated_params() { + check_types( r#" -struct A(B); -impl A { fn into_b(self) -> B { self.0 } } -struct B(C); -impl B { fn into_c(self) -> C { self.0 } } -struct C; +use core::iter; + +pub struct SomeIter {} + +impl SomeIter { + pub fn new() -> Self { SomeIter {} } + pub fn push(&mut self, t: T) {} +} + +impl Iterator for SomeIter { + type Item = T; + fn next(&mut self) -> Option { + None + } +} fn main() { - let c = A(B(C)).into_b().into_c(); -}"#, + let mut some_iter = SomeIter::new(); + //^^^^^^^^^^^^^ SomeIter>> + some_iter.push(iter::repeat(2).take(2)); + let iter_of_iters = some_iter.take(2); + //^^^^^^^^^^^^^ impl Iterator> +} +"#, ); } #[test] - fn struct_access_chaining_hints() { - check_expect( - InlayHintsConfig { - parameter_hints: false, - type_hints: false, - chaining_hints: true, - max_length: None, - }, + fn infer_call_method_return_associated_types_with_generic() { + check_types( r#" -struct A { pub b: B } -struct B { pub c: C } -struct C(pub bool); -struct D; + pub trait Default { + fn default() -> Self; + } + pub trait Foo { + type Bar: Default; + } -impl D { - fn foo(&self) -> i32 { 42 } + pub fn quux() -> T::Bar { + let y = Default::default(); + //^ ::Bar + + y + } + "#, + ); + } + + #[test] + fn fn_hints() { + check_types( + r#" +trait Sized {} + +fn foo() -> impl Fn() { loop {} } +fn foo1() -> impl Fn(f64) { loop {} } +fn foo2() -> impl Fn(f64, f64) { loop {} } +fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } +fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } +fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } +fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } +fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } + +fn main() { + let foo = foo(); + // ^^^ impl Fn() + let foo = foo1(); + // ^^^ impl Fn(f64) + let foo = foo2(); + // ^^^ impl Fn(f64, f64) + let foo = foo3(); + // ^^^ impl Fn(f64, f64) -> u32 + let foo = foo4(); + // ^^^ &dyn Fn(f64, f64) -> u32 + let foo = foo5(); + // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 + let foo = foo6(); + // ^^^ impl Fn(f64, f64) -> u32 + Sized + let foo = foo7(); + // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized) } +"#, + ) + } + + #[test] + fn unit_structs_have_no_type_hints() { + check_types( + r#" +enum Result { Ok(T), Err(E) } +use Result::*; + +struct SyntheticSyntax; fn main() { - let x = A { b: B { c: C(true) } } - .b - .c - .0; - let x = D - .foo(); + match Ok(()) { + Ok(_) => (), + Err(SyntheticSyntax) => (), + } }"#, - expect![[r#" - [ - InlayHint { - range: 144..191, - kind: ChainingHint, - label: "C", - }, - InlayHint { - range: 144..180, - kind: ChainingHint, - label: "B", - }, - ] - "#]], ); } #[test] - fn generic_chaining_hints() { - check_expect( - InlayHintsConfig { - parameter_hints: false, - type_hints: false, - chaining_hints: true, - max_length: None, - }, + fn let_statement() { + check_types( r#" -struct A(T); -struct B(T); -struct C(T); -struct X(T, R); +#[derive(PartialEq)] +enum Option { None, Some(T) } + +#[derive(PartialEq)] +struct Test { a: Option, b: u8 } -impl A { - fn new(t: T) -> Self { A(t) } - fn into_b(self) -> B { B(self.0) } -} -impl B { - fn into_c(self) -> C { C(self.0) } -} fn main() { - let c = A::new(X(42, true)) - .into_b() - .into_c(); -} -"#, - expect![[r#" - [ - InlayHint { - range: 247..284, - kind: ChainingHint, - label: "B>", - }, - InlayHint { - range: 247..266, - kind: ChainingHint, - label: "A>", - }, - ] - "#]], + struct InnerStruct {} + + let test = 54; + //^^^^ i32 + let test: i32 = 33; + let mut test = 33; + //^^^^^^^^ i32 + let _ = 22; + let test = "test"; + //^^^^ &str + let test = InnerStruct {}; + //^^^^ InnerStruct + + let test = unresolved(); + + let test = (42, 'a'); + //^^^^ (i32, char) + let (a, (b, (c,)) = (2, (3, (9.2,)); + //^ i32 ^ i32 ^ f64 + let &x = &92; + //^ i32 +}"#, + ); + } + + #[test] + fn if_expr() { + check_types( + r#" +enum Option { None, Some(T) } +use Option::*; + +struct Test { a: Option, b: u8 } + +fn main() { + let test = Some(Test { a: Some(3), b: 1 }); + //^^^^ Option + if let None = &test {}; + if let test = &test {}; + //^^^^ &Option + if let Some(test) = &test {}; + //^^^^ &Test + if let Some(Test { a, b }) = &test {}; + //^ &Option ^ &u8 + if let Some(Test { a: x, b: y }) = &test {}; + //^ &Option ^ &u8 + if let Some(Test { a: Some(x), b: y }) = &test {}; + //^ &u32 ^ &u8 + if let Some(Test { a: None, b: y }) = &test {}; + //^ &u8 + if let Some(Test { b: y, .. }) = &test {}; + //^ &u8 + if test == None {} +}"#, + ); + } + + #[test] + fn while_expr() { + check_types( + r#" +enum Option { None, Some(T) } +use Option::*; + +struct Test { a: Option, b: u8 } + +fn main() { + let test = Some(Test { a: Some(3), b: 1 }); + //^^^^ Option + while let Some(Test { a: Some(x), b: y }) = &test {}; + //^ &u32 ^ &u8 +}"#, + ); + } + + #[test] + fn match_arm_list() { + check_types( + r#" +enum Option { None, Some(T) } +use Option::*; + +struct Test { a: Option, b: u8 } + +fn main() { + match Some(Test { a: Some(3), b: 1 }) { + None => (), + test => (), + //^^^^ Option + Some(Test { a: Some(x), b: y }) => (), + //^ u32 ^ u8 + _ => {} + } +}"#, ); } #[test] fn incomplete_for_no_hint() { - check( + check_types( r#" fn main() { let data = &[1i32, 2, 3]; @@ -1146,7 +1090,7 @@ fn main() { #[test] fn complete_for_hint() { - check( + check_types( r#" pub struct Vec {} @@ -1175,13 +1119,7 @@ fn main() { #[test] fn multi_dyn_trait_bounds() { - check_with_config( - InlayHintsConfig { - type_hints: true, - parameter_hints: false, - chaining_hints: false, - max_length: None, - }, + check_types( r#" pub struct Vec {} @@ -1208,13 +1146,7 @@ fn main() { #[test] fn shorten_iterator_hints() { - check_with_config( - InlayHintsConfig { - parameter_hints: false, - type_hints: true, - chaining_hints: false, - max_length: None, - }, + check_types( r#" use core::iter; @@ -1244,55 +1176,87 @@ fn main() { } #[test] - fn shorten_iterator_chaining_hints() { - check_expect( - InlayHintsConfig { - parameter_hints: false, - type_hints: false, - chaining_hints: true, - max_length: None, - }, + fn closures() { + check( r#" -use core::iter; +fn main() { + let mut start = 0; + //^^^^^^^^^ i32 + (0..2).for_each(|increment| { start += increment; }); + //^^^^^^^^^ i32 -struct MyIter; + let multiply = + //^^^^^^^^ |…| -> i32 + | a, b| a * b + //^ i32 ^ i32 + ; -impl Iterator for MyIter { - type Item = (); - fn next(&mut self) -> Option { - None + let _: i32 = multiply(1, 2); + let multiply_ref = &multiply; + //^^^^^^^^^^^^ &|…| -> i32 + + let return_42 = || 42; + //^^^^^^^^^ || -> i32 +}"#, + ); } -} + + #[test] + fn hint_truncation() { + check_with_config( + InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, + r#" +struct Smol(T); + +struct VeryLongOuterName(T); fn main() { - let _x = MyIter.by_ref() - .take(5) - .by_ref() - .take(5) - .by_ref(); + let a = Smol(0u32); + //^ Smol + let b = VeryLongOuterName(0usize); + //^ VeryLongOuterName<…> + let c = Smol(Smol(0u32)) + //^ Smol> +}"#, + ); + } + + // Chaining hint tests + + #[test] + fn chaining_hints_ignore_comments() { + check_expect( + InlayHintsConfig { + parameter_hints: false, + type_hints: false, + chaining_hints: true, + max_length: None, + }, + r#" +struct A(B); +impl A { fn into_b(self) -> B { self.0 } } +struct B(C); +impl B { fn into_c(self) -> C { self.0 } } +struct C; + +fn main() { + let c = A(B(C)) + .into_b() // This is a comment + // This is another comment + .into_c(); } "#, expect![[r#" [ InlayHint { - range: 175..242, - kind: ChainingHint, - label: "impl Iterator", - }, - InlayHint { - range: 175..225, - kind: ChainingHint, - label: "impl Iterator", - }, - InlayHint { - range: 175..207, + range: 148..173, kind: ChainingHint, - label: "impl Iterator", + label: "B", }, InlayHint { - range: 175..190, + range: 148..155, kind: ChainingHint, - label: "&mut MyIter", + label: "A", }, ] "#]], @@ -1300,156 +1264,163 @@ fn main() { } #[test] - fn shorten_iterators_in_associated_params() { - check_with_config( + fn chaining_hints_without_newlines() { + check_chains( + r#" +struct A(B); +impl A { fn into_b(self) -> B { self.0 } } +struct B(C); +impl B { fn into_c(self) -> C { self.0 } } +struct C; + +fn main() { + let c = A(B(C)).into_b().into_c(); +}"#, + ); + } + + #[test] + fn struct_access_chaining_hints() { + check_expect( InlayHintsConfig { parameter_hints: false, - type_hints: true, - chaining_hints: false, + type_hints: false, + chaining_hints: true, max_length: None, }, r#" -use core::iter; - -pub struct SomeIter {} - -impl SomeIter { - pub fn new() -> Self { SomeIter {} } - pub fn push(&mut self, t: T) {} -} +struct A { pub b: B } +struct B { pub c: C } +struct C(pub bool); +struct D; -impl Iterator for SomeIter { - type Item = T; - fn next(&mut self) -> Option { - None - } +impl D { + fn foo(&self) -> i32 { 42 } } fn main() { - let mut some_iter = SomeIter::new(); - //^^^^^^^^^^^^^ SomeIter>> - some_iter.push(iter::repeat(2).take(2)); - let iter_of_iters = some_iter.take(2); - //^^^^^^^^^^^^^ impl Iterator> -} -"#, + let x = A { b: B { c: C(true) } } + .b + .c + .0; + let x = D + .foo(); +}"#, + expect![[r#" + [ + InlayHint { + range: 144..191, + kind: ChainingHint, + label: "C", + }, + InlayHint { + range: 144..180, + kind: ChainingHint, + label: "B", + }, + ] + "#]], ); } #[test] - fn hide_param_hints_for_clones() { - check_with_config( + fn generic_chaining_hints() { + check_expect( InlayHintsConfig { - parameter_hints: true, + parameter_hints: false, type_hints: false, - chaining_hints: false, + chaining_hints: true, max_length: None, }, r#" -fn foo(bar: i32, baz: String, qux: f32) {} +struct A(T); +struct B(T); +struct C(T); +struct X(T, R); +impl A { + fn new(t: T) -> Self { A(t) } + fn into_b(self) -> B { B(self.0) } +} +impl B { + fn into_c(self) -> C { C(self.0) } +} fn main() { - let bar = 3; - let baz = &"baz"; - let fez = 1.0; - foo(bar.clone(), baz.clone(), fez.clone()); - //^^^^^^^^^^^ qux + let c = A::new(X(42, true)) + .into_b() + .into_c(); } "#, + expect![[r#" + [ + InlayHint { + range: 247..284, + kind: ChainingHint, + label: "B>", + }, + InlayHint { + range: 247..266, + kind: ChainingHint, + label: "A>", + }, + ] + "#]], ); } #[test] - fn infer_call_method_return_associated_types_with_generic() { - check( + fn shorten_iterator_chaining_hints() { + check_expect( + InlayHintsConfig { + parameter_hints: false, + type_hints: false, + chaining_hints: true, + max_length: None, + }, r#" - pub trait Default { - fn default() -> Self; - } - pub trait Foo { - type Bar: Default; - } +use core::iter; - pub fn quux() -> T::Bar { - let y = Default::default(); - //^ ::Bar +struct MyIter; - y - } - "#, - ); +impl Iterator for MyIter { + type Item = (); + fn next(&mut self) -> Option { + None } - - #[test] - fn self_param_hints() { - check( - r#" -struct Foo; - -impl Foo { - fn foo(self: Self) {} - fn bar(self: &Self) {} -} - -fn main() { - Foo::foo(Foo); - //^^^ self - Foo::bar(&Foo); - //^^^^ self } -"#, - ) - } - - #[test] - fn fn_hints() { - check( - r#" -trait Sized {} - -fn foo() -> impl Fn() { loop {} } -fn foo1() -> impl Fn(f64) { loop {} } -fn foo2() -> impl Fn(f64, f64) { loop {} } -fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } -fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } -fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } -fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } -fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } fn main() { - let foo = foo(); - // ^^^ impl Fn() - let foo = foo1(); - // ^^^ impl Fn(f64) - let foo = foo2(); - // ^^^ impl Fn(f64, f64) - let foo = foo3(); - // ^^^ impl Fn(f64, f64) -> u32 - let foo = foo4(); - // ^^^ &dyn Fn(f64, f64) -> u32 - let foo = foo5(); - // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 - let foo = foo6(); - // ^^^ impl Fn(f64, f64) -> u32 + Sized - let foo = foo7(); - // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized) + let _x = MyIter.by_ref() + .take(5) + .by_ref() + .take(5) + .by_ref(); } "#, - ) - } - - #[test] - fn param_name_hints_show_for_literals() { - check( - r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] } -fn main() { - test( - 0x0fab272b, - //^^^^^^^^^^ a - 0x0fab272b - //^^^^^^^^^^ b - ); -}"#, - ) + expect![[r#" + [ + InlayHint { + range: 175..242, + kind: ChainingHint, + label: "impl Iterator", + }, + InlayHint { + range: 175..225, + kind: ChainingHint, + label: "impl Iterator", + }, + InlayHint { + range: 175..207, + kind: ChainingHint, + label: "impl Iterator", + }, + InlayHint { + range: 175..190, + kind: ChainingHint, + label: "&mut MyIter", + }, + ] + "#]], + ); } } -- cgit v1.2.3 From 5f1fac44c5714a3d09a4723bf95b2cac71723ff7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 4 Jun 2021 14:09:20 +0200 Subject: Cleanup parameter_hint_heuristics inlay hints test --- crates/ide/src/inlay_hints.rs | 155 ++++++++++++++++++------------------------ 1 file changed, 68 insertions(+), 87 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 9f2f6c80a..821c61403 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -315,6 +315,7 @@ fn should_hide_param_name_hint( param_name: &str, argument: &ast::Expr, ) -> bool { + // These are to be tested in the `parameter_hint_heuristics` test // hide when: // - the parameter name is a suffix of the function's name // - the argument is an enum whose name is equal to the parameter @@ -395,7 +396,7 @@ fn get_string_representation(expr: &ast::Expr) -> Option { ast::Expr::MethodCallExpr(method_call_expr) => { let name_ref = method_call_expr.name_ref()?; match name_ref.text().as_str() { - "clone" => method_call_expr.receiver().map(|rec| rec.to_string()), + "clone" | "as_ref" => method_call_expr.receiver().map(|rec| rec.to_string()), name_ref => Some(name_ref.to_owned()), } } @@ -521,6 +522,8 @@ fn main() { ); } + // Parameter hint tests + #[test] fn param_hints_only() { check_params( @@ -558,6 +561,15 @@ fn main() { check_params( r#" fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore } +fn main() { + let _x = param_with_underscore( + 4, + ); +}"#, + ); + check_params( + r#" +fn param_with_underscore(underscore: i32) -> i32 { underscore } fn main() { let _x = param_with_underscore( 4, @@ -583,30 +595,32 @@ fn main() { fn never_hide_param_when_multiple_params() { check_params( r#" -fn foo(bar: i32, baz: i32) -> i32 { bar + baz } +fn foo(foo: i32, bar: i32) -> i32 { bar + baz } fn main() { let _x = foo( 4, - //^ bar + //^ foo 8, - //^ baz + //^ bar ); }"#, ); } #[test] - fn hide_param_hints_for_clones() { + fn param_hints_look_through_as_ref_and_clone() { check_params( r#" -fn foo(bar: i32, baz: String, qux: f32) {} +fn foo(bar: i32, baz: f32) {} fn main() { let bar = 3; let baz = &"baz"; let fez = 1.0; - foo(bar.clone(), baz.clone(), fez.clone()); - //^^^^^^^^^^^ qux + foo(bar.clone(), bar.clone()); + //^^^^^^^^^^^ baz + foo(bar.as_ref(), bar.as_ref()); + //^^^^^^^^^^^^ baz } "#, ); @@ -639,10 +653,10 @@ fn main() { r#"pub fn test(a: i32, b: i32) -> [i32; 2] { [a, b] } fn main() { test( - 0x0fab272b, - //^^^^^^^^^^ a - 0x0fab272b - //^^^^^^^^^^ b + 0xa_b, + //^^^^^ a + 0xa_b, + //^^^^^ b ); }"#, ) @@ -650,7 +664,7 @@ fn main() { #[test] fn function_call_parameter_hint() { - check( + check_params( r#" enum Option { None, Some(T) } use Option::*; @@ -685,7 +699,6 @@ fn test_func(mut foo: i32, bar: i32, msg: &str, _: i32, last: i32) -> i32 { fn main() { let not_literal = 1; - //^^^^^^^^^^^ i32 let _: i32 = test_func(1, 2, "hello", 3, not_literal); //^ foo ^ bar ^^^^^^^ msg ^^^^^^^^^^^ last let t: Test = Test {}; @@ -712,97 +725,65 @@ fn main() { } #[test] - fn omitted_parameters_hints_heuristics() { - check_with_config( - InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, + fn parameter_hint_heuristics() { + check_params( r#" +fn check(ra_fixture_thing: &str) {} + fn map(f: i32) {} fn filter(predicate: i32) {} -struct TestVarContainer { - test_var: i32, -} - -impl TestVarContainer { - fn test_var(&self) -> i32 { - self.test_var - } -} +fn strip_suffix(suffix: &str) {} +fn stripsuffix(suffix: &str) {} +fn same(same: u32) {} +fn same2(_same2: u32) {} -struct Test {} - -impl Test { - fn map(self, f: i32) -> Self { - self - } - - fn filter(self, predicate: i32) -> Self { - self - } - - fn field(self, value: i32) -> Self { - self - } - - fn no_hints_expected(&self, _: i32, test_var: i32) {} - - fn frob(&self, frob: bool) {} -} - -struct Param {} - -fn different_order(param: &Param) {} -fn different_order_mut(param: &mut Param) {} -fn has_underscore(_param: bool) {} fn enum_matches_param_name(completion_kind: CompletionKind) {} -fn param_destructuring_omitted_1((a, b): (u32, u32)) {} -fn param_destructuring_omitted_2(TestVarContainer { test_var: _ }: TestVarContainer) {} -fn twiddle(twiddle: bool) {} -fn doo(_doo: bool) {} +fn foo(param: u32) {} +fn bar(param_eter: u32) {} enum CompletionKind { Keyword, } -fn main() { - let container: TestVarContainer = TestVarContainer { test_var: 42 }; - let test: Test = Test {}; - - map(22); - filter(33); +fn non_ident_pat((a, b): (u32, u32)) {} - let test_processed: Test = test.map(1).filter(2).field(3); - - let test_var: i32 = 55; - test_processed.no_hints_expected(22, test_var); - test_processed.no_hints_expected(33, container.test_var); - test_processed.no_hints_expected(44, container.test_var()); - test_processed.frob(false); - - twiddle(true); - doo(true); - - const TWIDDLE_UPPERCASE: bool = true; - twiddle(TWIDDLE_UPPERCASE); +fn main() { + check(""); - let mut param_begin: Param = Param {}; - different_order(¶m_begin); - different_order(&mut param_begin); + map(0); + filter(0); - let param: bool = true; - has_underscore(param); + strip_suffix(""); + stripsuffix(""); + //^^ suffix + same(0); + same2(0); enum_matches_param_name(CompletionKind::Keyword); - let a: f64 = 7.0; - let b: f64 = 4.0; - let _: f64 = a.div_euclid(b); - let _: f64 = a.abs_sub(b); - - let range: (u32, u32) = (3, 5); - param_destructuring_omitted_1(range); - param_destructuring_omitted_2(container); + let param = 0; + foo(param); + let param_end = 0; + foo(param_end); + let start_param = 0; + foo(start_param); + let param2 = 0; + foo(param2); + //^^^^^^ param + + let param_eter = 0; + bar(param_eter); + let param_eter_end = 0; + bar(param_eter_end); + let start_param_eter = 0; + bar(start_param_eter); + let param_eter2 = 0; + bar(param_eter2); + //^^^^^^^^^^^ param_eter + + non_ident_pat((0, 0)); }"#, ); } -- cgit v1.2.3