From b0f6d8868ca33a9907e372de2a2f868c3ef8d00c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 4 Jun 2021 13:47:39 +0200 Subject: [PATCH 1/2] Reorganize inlay_hints tests --- crates/ide/src/inlay_hints.rs | 1083 ++++++++++++++++----------------- 1 file changed, 527 insertions(+), 556 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index d6dfa018398..9f2f6c80a59 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 @@ fn check(ra_fixture: &str) { 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); @@ -470,110 +504,6 @@ fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { expect.assert_debug_eq(&inlay_hints) } - #[test] - fn param_hints_only() { - check_with_config( - InlayHintsConfig { - parameter_hints: true, - type_hints: false, - chaining_hints: false, - max_length: None, - }, - r#" -fn foo(a: i32, b: i32) -> i32 { a + b } -fn main() { - let _x = foo( - 4, - //^ a - 4, - //^ b - ); -}"#, - ); - } - - #[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, - }, - r#" -fn max(x: i32, y: i32) -> i32 { x + y } -fn main() { - let _x = max( - 4, - //^ x - 4, - //^ y - ); -}"#, - ); - } - - #[test] - fn param_name_similar_to_fn_name() { - check_with_config( - InlayHintsConfig { - parameter_hints: true, - type_hints: false, - chaining_hints: false, - max_length: None, - }, - r#" -fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore } -fn main() { - let _x = param_with_underscore( - 4, - ); -}"#, - ); - } - - #[test] - fn param_name_same_as_fn_name() { - check_with_config( - InlayHintsConfig { - parameter_hints: true, - type_hints: false, - chaining_hints: false, - max_length: None, - }, - r#" -fn foo(foo: i32) -> i32 { foo } -fn main() { - let _x = foo( - 4, - ); -}"#, - ); - } - - #[test] - fn never_hide_param_when_multiple_params() { - check_with_config( - InlayHintsConfig { - parameter_hints: true, - type_hints: false, - chaining_hints: false, - max_length: None, - }, - r#" -fn foo(bar: i32, baz: i32) -> i32 { bar + baz } -fn main() { - let _x = foo( - 4, - //^ bar - 8, - //^ baz - ); -}"#, - ); - } - #[test] fn hints_disabled() { check_with_config( @@ -592,192 +522,130 @@ fn main() { } #[test] - fn type_hints_only() { - check_with_config( - InlayHintsConfig { - type_hints: true, - parameter_hints: false, - chaining_hints: false, - max_length: None, - }, + fn param_hints_only() { + check_params( r#" fn foo(a: i32, b: i32) -> i32 { a + b } fn main() { - let _x = foo(4, 4); - //^^ i32 + let _x = foo( + 4, + //^ a + 4, + //^ b + ); }"#, ); } #[test] - fn default_generic_types_should_not_be_displayed() { - check( + fn param_name_similar_to_fn_name_still_hints() { + check_params( r#" -struct Test { k: K, t: T } - +fn max(x: i32, y: i32) -> i32 { x + y } fn main() { - let zz = Test { t: 23u8, k: 33 }; - //^^ Test - let zz_ref = &zz; - //^^^^^^ &Test - let test = || zz; - //^^^^ || -> Test + let _x = max( + 4, + //^ x + 4, + //^ y + ); }"#, ); } #[test] - fn let_statement() { - check( + fn param_name_similar_to_fn_name() { + check_params( r#" -#[derive(PartialEq)] -enum Option { None, Some(T) } - -#[derive(PartialEq)] -struct Test { a: Option, b: u8 } - +fn param_with_underscore(with_underscore: i32) -> i32 { with_underscore } fn main() { - 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 + let _x = param_with_underscore( + 4, + ); }"#, ); } #[test] - fn closure_parameters() { - check( + fn param_name_same_as_fn_name() { + check_params( r#" +fn foo(foo: i32) -> i32 { foo } 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 - - let return_42 = || 42; - //^^^^^^^^^ || -> i32 + let _x = foo( + 4, + ); }"#, ); } #[test] - fn if_expr() { - check( + fn never_hide_param_when_multiple_params() { + check_params( r#" -enum Option { None, Some(T) } -use Option::*; - -struct Test { a: Option, b: u8 } - +fn foo(bar: i32, baz: i32) -> i32 { bar + baz } 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 {} + let _x = foo( + 4, + //^ bar + 8, + //^ baz + ); }"#, ); } #[test] - fn while_expr() { - check( + fn hide_param_hints_for_clones() { + check_params( r#" -enum Option { None, Some(T) } -use Option::*; - -struct Test { a: Option, b: u8 } +fn foo(bar: i32, baz: String, qux: f32) {} fn main() { - let test = Some(Test { a: Some(3), b: 1 }); - //^^^^ Option - while let Some(Test { a: Some(x), b: y }) = &test {}; - //^ &u32 ^ &u8 -}"#, + let bar = 3; + let baz = &"baz"; + let fez = 1.0; + foo(bar.clone(), baz.clone(), fez.clone()); + //^^^^^^^^^^^ qux +} +"#, ); } #[test] - fn match_arm_list() { - check( + fn self_param_hints() { + check_params( r#" -enum Option { None, Some(T) } -use Option::*; +struct Foo; -struct Test { a: Option, b: u8 } +impl Foo { + fn foo(self: Self) {} + fn bar(self: &Self) {} +} fn main() { - match Some(Test { a: Some(3), b: 1 }) { - None => (), - test => (), - //^^^^ Option - Some(Test { a: Some(x), b: y }) => (), - //^ u32 ^ u8 - _ => {} - } -}"#, - ); + Foo::foo(Foo); + //^^^ self + Foo::bar(&Foo); + //^^^^ self +} +"#, + ) } #[test] - fn hint_truncation() { - check_with_config( - InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, - r#" -struct Smol(T); - -struct VeryLongOuterName(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 a = Smol(0u32); - //^ Smol - let b = VeryLongOuterName(0usize); - //^ VeryLongOuterName<…> - let c = Smol(Smol(0u32)) - //^ Smol> + test( + 0x0fab272b, + //^^^^^^^^^^ a + 0x0fab272b + //^^^^^^^^^^ b + ); }"#, - ); + ) } #[test] @@ -939,10 +807,129 @@ fn main() { ); } + // Type-Hint tests + + #[test] + fn type_hints_only() { + check_types( + r#" +fn foo(a: i32, b: i32) -> i32 { a + b } +fn main() { + let _x = foo(4, 4); + //^^ i32 +}"#, + ); + } + + #[test] + fn default_generic_types_should_not_be_displayed() { + check( + r#" +struct Test { k: K, t: T } + +fn main() { + let zz = Test { t: 23u8, k: 33 }; + //^^ Test + let zz_ref = &zz; + //^^^^^^ &Test + let test = || zz; + //^^^^ || -> Test +}"#, + ); + } + + #[test] + fn shorten_iterators_in_associated_params() { + check_types( + r#" +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 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 infer_call_method_return_associated_types_with_generic() { + check_types( + r#" + pub trait Default { + fn default() -> Self; + } + pub trait Foo { + type Bar: Default; + } + + 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_with_config( - InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, + check_types( r#" enum Result { Ok(T), Err(E) } use Result::*; @@ -958,6 +945,284 @@ fn main() { ); } + #[test] + fn let_statement() { + check_types( + r#" +#[derive(PartialEq)] +enum Option { None, Some(T) } + +#[derive(PartialEq)] +struct Test { a: Option, b: u8 } + +fn main() { + 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_types( + r#" +fn main() { + let data = &[1i32, 2, 3]; + //^^^^ &[i32; 3] + for i +}"#, + ); + check( + r#" +pub struct Vec {} + +impl Vec { + pub fn new() -> Self { Vec {} } + pub fn push(&mut self, t: T) {} +} + +impl IntoIterator for Vec { + type Item=T; +} + +fn main() { + let mut data = Vec::new(); + //^^^^^^^^ Vec<&str> + data.push("foo"); + for i in + + println!("Unit expr"); +} +"#, + ); + } + + #[test] + fn complete_for_hint() { + check_types( + r#" +pub struct Vec {} + +impl Vec { + pub fn new() -> Self { Vec {} } + pub fn push(&mut self, t: T) {} +} + +impl IntoIterator for Vec { + type Item=T; +} + +fn main() { + let mut data = Vec::new(); + //^^^^^^^^ Vec<&str> + data.push("foo"); + for i in data { + //^ &str + let z = i; + //^ &str + } +} +"#, + ); + } + + #[test] + fn multi_dyn_trait_bounds() { + check_types( + r#" +pub struct Vec {} + +impl Vec { + pub fn new() -> Self { Vec {} } +} + +pub struct Box {} + +trait Display {} +trait Sync {} + +fn main() { + let _v = Vec::>::new(); + //^^ Vec> + let _v = Vec::>::new(); + //^^ Vec> + let _v = Vec::>::new(); + //^^ Vec> +} +"#, + ); + } + + #[test] + fn shorten_iterator_hints() { + check_types( + r#" +use core::iter; + +struct MyIter; + +impl Iterator for MyIter { + type Item = (); + fn next(&mut self) -> Option { + None + } +} + +fn main() { + let _x = MyIter; + //^^ MyIter + let _x = iter::repeat(0); + //^^ impl Iterator + fn generic(t: T) { + let _x = iter::repeat(t); + //^^ impl Iterator + let _chained = iter::repeat(t).take(10); + //^^^^^^^^ impl Iterator + } +} +"#, + ); + } + + #[test] + fn closures() { + 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 + + 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 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( @@ -1000,13 +1265,7 @@ fn main() { #[test] fn chaining_hints_without_newlines() { - check_with_config( - InlayHintsConfig { - parameter_hints: false, - type_hints: false, - chaining_hints: true, - max_length: None, - }, + check_chains( r#" struct A(B); impl A { fn into_b(self) -> B { self.0 } } @@ -1109,140 +1368,6 @@ fn main() { ); } - #[test] - fn incomplete_for_no_hint() { - check( - r#" -fn main() { - let data = &[1i32, 2, 3]; - //^^^^ &[i32; 3] - for i -}"#, - ); - check( - r#" -pub struct Vec {} - -impl Vec { - pub fn new() -> Self { Vec {} } - pub fn push(&mut self, t: T) {} -} - -impl IntoIterator for Vec { - type Item=T; -} - -fn main() { - let mut data = Vec::new(); - //^^^^^^^^ Vec<&str> - data.push("foo"); - for i in - - println!("Unit expr"); -} -"#, - ); - } - - #[test] - fn complete_for_hint() { - check( - r#" -pub struct Vec {} - -impl Vec { - pub fn new() -> Self { Vec {} } - pub fn push(&mut self, t: T) {} -} - -impl IntoIterator for Vec { - type Item=T; -} - -fn main() { - let mut data = Vec::new(); - //^^^^^^^^ Vec<&str> - data.push("foo"); - for i in data { - //^ &str - let z = i; - //^ &str - } -} -"#, - ); - } - - #[test] - fn multi_dyn_trait_bounds() { - check_with_config( - InlayHintsConfig { - type_hints: true, - parameter_hints: false, - chaining_hints: false, - max_length: None, - }, - r#" -pub struct Vec {} - -impl Vec { - pub fn new() -> Self { Vec {} } -} - -pub struct Box {} - -trait Display {} -trait Sync {} - -fn main() { - let _v = Vec::>::new(); - //^^ Vec> - let _v = Vec::>::new(); - //^^ Vec> - let _v = Vec::>::new(); - //^^ Vec> -} -"#, - ); - } - - #[test] - fn shorten_iterator_hints() { - check_with_config( - InlayHintsConfig { - parameter_hints: false, - type_hints: true, - chaining_hints: false, - max_length: None, - }, - r#" -use core::iter; - -struct MyIter; - -impl Iterator for MyIter { - type Item = (); - fn next(&mut self) -> Option { - None - } -} - -fn main() { - let _x = MyIter; - //^^ MyIter - let _x = iter::repeat(0); - //^^ impl Iterator - fn generic(t: T) { - let _x = iter::repeat(t); - //^^ impl Iterator - let _chained = iter::repeat(t).take(10); - //^^^^^^^^ impl Iterator - } -} -"#, - ); - } - #[test] fn shorten_iterator_chaining_hints() { check_expect( @@ -1298,158 +1423,4 @@ fn main() { "#]], ); } - - #[test] - fn shorten_iterators_in_associated_params() { - check_with_config( - InlayHintsConfig { - parameter_hints: false, - type_hints: true, - chaining_hints: false, - max_length: None, - }, - r#" -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 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 hide_param_hints_for_clones() { - check_with_config( - InlayHintsConfig { - parameter_hints: true, - type_hints: false, - chaining_hints: false, - max_length: None, - }, - r#" -fn foo(bar: i32, baz: String, qux: f32) {} - -fn main() { - let bar = 3; - let baz = &"baz"; - let fez = 1.0; - foo(bar.clone(), baz.clone(), fez.clone()); - //^^^^^^^^^^^ qux -} -"#, - ); - } - - #[test] - fn infer_call_method_return_associated_types_with_generic() { - check( - r#" - pub trait Default { - fn default() -> Self; - } - pub trait Foo { - type Bar: Default; - } - - pub fn quux() -> T::Bar { - let y = Default::default(); - //^ ::Bar - - y - } - "#, - ); - } - - #[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) -} -"#, - ) - } - - #[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 - ); -}"#, - ) - } } From 5f1fac44c5714a3d09a4723bf95b2cac71723ff7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 4 Jun 2021 14:09:20 +0200 Subject: [PATCH 2/2] Cleanup parameter_hint_heuristics inlay hints test --- crates/ide/src/inlay_hints.rs | 153 +++++++++++++++------------------- 1 file changed, 67 insertions(+), 86 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 9f2f6c80a59..821c61403bd 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 param_name_similar_to_fn_name() { 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 param_name_hints_show_for_literals() { 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, -} +fn strip_suffix(suffix: &str) {} +fn stripsuffix(suffix: &str) {} +fn same(same: u32) {} +fn same2(_same2: u32) {} -impl TestVarContainer { - fn test_var(&self) -> i32 { - self.test_var - } -} - -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 non_ident_pat((a, b): (u32, u32)) {} + fn main() { - let container: TestVarContainer = TestVarContainer { test_var: 42 }; - let test: Test = Test {}; + check(""); - map(22); - filter(33); + map(0); + filter(0); - 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); - - let mut param_begin: Param = Param {}; - different_order(¶m_begin); - different_order(&mut param_begin); - - 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 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 range: (u32, u32) = (3, 5); - param_destructuring_omitted_1(range); - param_destructuring_omitted_2(container); + 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)); }"#, ); }