Simplify most of the inlay hints tests

This commit is contained in:
Aleksey Kladov 2020-06-30 18:04:25 +02:00
parent 0954d31bee
commit 442c13ba17
2 changed files with 199 additions and 631 deletions

View file

@ -3,7 +3,7 @@ use ra_ide_db::RootDatabase;
use ra_prof::profile;
use ra_syntax::{
ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner},
match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange,
match_ast, Direction, NodeOrToken, SmolStr, SyntaxKind, TextRange, T,
};
use crate::{FileId, FunctionSignature};
@ -112,7 +112,7 @@ fn get_chaining_hints(
// Ignoring extra whitespace and comments
let next = tokens.next()?.kind();
let next_next = tokens.next()?.kind();
if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT {
if next == SyntaxKind::WHITESPACE && next_next == T![.] {
let ty = sema.type_of_expr(&expr)?;
if ty.is_unknown() {
return None;
@ -345,583 +345,245 @@ fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<
#[cfg(test)]
mod tests {
use crate::inlay_hints::InlayHintsConfig;
use insta::assert_debug_snapshot;
use test_utils::extract_annotations;
use crate::mock_analysis::single_file;
use crate::{inlay_hints::InlayHintsConfig, mock_analysis::single_file};
fn check(ra_fixture: &str) {
check_with_config(ra_fixture, InlayHintsConfig::default());
}
fn check_with_config(ra_fixture: &str, config: InlayHintsConfig) {
let (analysis, file_id) = single_file(ra_fixture);
let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
let inlay_hints = analysis.inlay_hints(file_id, &config).unwrap();
let actual =
inlay_hints.into_iter().map(|it| (it.range, it.label.to_string())).collect::<Vec<_>>();
assert_eq!(expected, actual);
}
#[test]
fn param_hints_only() {
let (analysis, file_id) = single_file(
check_with_config(
r#"
fn foo(a: i32, b: i32) -> i32 { a + b }
fn main() {
let _x = foo(4, 4);
}"#,
let _x = foo(
4,
//^ a
4,
//^ b
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: true, type_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"
[
InlayHint {
range: 69..70,
kind: ParameterHint,
label: "a",
}"#,
InlayHintsConfig {
parameter_hints: true,
type_hints: false,
chaining_hints: false,
max_length: None,
},
InlayHint {
range: 72..73,
kind: ParameterHint,
label: "b",
},
]
"###);
);
}
#[test]
fn hints_disabled() {
let (analysis, file_id) = single_file(
check_with_config(
r#"
fn foo(a: i32, b: i32) -> i32 { a + b }
fn main() {
let _x = foo(4, 4);
}"#,
InlayHintsConfig {
type_hints: false,
parameter_hints: false,
chaining_hints: false,
max_length: None,
},
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: false, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"[]"###);
}
#[test]
fn type_hints_only() {
let (analysis, file_id) = single_file(
check_with_config(
r#"
fn foo(a: i32, b: i32) -> i32 { a + b }
fn main() {
let _x = foo(4, 4);
//^^ i32
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: true, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"
[
InlayHint {
range: 60..62,
kind: TypeHint,
label: "i32",
InlayHintsConfig {
type_hints: true,
parameter_hints: false,
chaining_hints: false,
max_length: None,
},
]
"###);
);
}
#[test]
fn default_generic_types_should_not_be_displayed() {
let (analysis, file_id) = single_file(
check(
r#"
struct Test<K, T = u8> {
k: K,
t: T,
}
struct Test<K, T = u8> { k: K, t: T }
fn main() {
let zz = Test { t: 23u8, k: 33 };
//^^ Test<i32>
let zz_ref = &zz;
//^^^^^^ &Test<i32>
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
[
InlayHint {
range: 68..70,
kind: TypeHint,
label: "Test<i32>",
},
InlayHint {
range: 106..112,
kind: TypeHint,
label: "&Test<i32>",
},
]
"###
);
}
#[test]
fn let_statement() {
let (analysis, file_id) = single_file(
check(
r#"
#[derive(PartialEq)]
enum CustomOption<T> {
None,
Some(T),
}
enum Option<T> { None, Some(T) }
#[derive(PartialEq)]
struct Test {
a: CustomOption<u32>,
b: u8,
}
struct Test { a: Option<u32>, 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 {};
let test = vec![222];
let test: Vec<_> = (0..3).collect();
let test = (0..3).collect::<Vec<i128>>();
let test = (0..3).collect::<Vec<_>>();
let mut test = Vec::new();
test.push(333);
let test = unresolved();
let test = (42, 'a');
let (a, (b, c, (d, e), f)) = (2, (3, 4, (6.6, 7.7), 5));
//^^^^ (i32, char)
let (a, (b, (c,)) = (2, (3, (9.2,));
//^ i32 ^ i32 ^ f64
let &x = &92;
//^ i32
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
[
InlayHint {
range: 192..196,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 235..243,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 274..278,
kind: TypeHint,
label: "&str",
},
InlayHint {
range: 538..542,
kind: TypeHint,
label: "(i32, char)",
},
InlayHint {
range: 565..566,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 569..570,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 572..573,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 576..577,
kind: TypeHint,
label: "f64",
},
InlayHint {
range: 579..580,
kind: TypeHint,
label: "f64",
},
InlayHint {
range: 583..584,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 626..627,
kind: TypeHint,
label: "i32",
},
]
"###
);
}
#[test]
fn closure_parameters() {
let (analysis, file_id) = single_file(
check(
r#"
fn main() {
let mut start = 0;
(0..2).for_each(|increment| {
start += increment;
});
//^^^^^^^^^ i32
(0..2).for_each(|increment| { start += increment; });
//^^^^^^^^^ i32
let multiply = |a, b, c, d| a * b * c * d;
let _: i32 = multiply(1, 2, 3, 4);
let multiply =
//^^^^^^^^ |…| -> i32
| a, b| a * b
//^ i32 ^ i32
;
let _: i32 = multiply(1, 2);
let multiply_ref = &multiply;
//^^^^^^^^^^^^ &|…| -> i32
let return_42 = || 42;
//^^^^^^^^^ || -> i32
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
[
InlayHint {
range: 20..29,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 56..65,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 114..122,
kind: TypeHint,
label: "|…| -> i32",
},
InlayHint {
range: 126..127,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 129..130,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 132..133,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 135..136,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 200..212,
kind: TypeHint,
label: "&|…| -> i32",
},
InlayHint {
range: 235..244,
kind: TypeHint,
label: "|| -> i32",
},
]
"###
);
}
#[test]
fn for_expression() {
let (analysis, file_id) = single_file(
check(
r#"
fn main() {
let mut start = 0;
for increment in 0..2 {
start += increment;
}
//^^^^^^^^^ i32
for increment in 0..2 { start += increment; }
//^^^^^^^^^ i32
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
[
InlayHint {
range: 20..29,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 43..52,
kind: TypeHint,
label: "i32",
},
]
"###
);
}
#[test]
fn if_expr() {
let (analysis, file_id) = single_file(
check(
r#"
#[derive(PartialEq)]
enum CustomOption<T> {
None,
Some(T),
}
enum Option<T> { None, Some(T) }
use Option::*;
#[derive(PartialEq)]
struct Test {
a: CustomOption<u32>,
b: u8,
}
use CustomOption::*;
struct Test { a: Option<u32>, b: u8 }
fn main() {
let test = Some(Test { a: Some(3), b: 1 });
//^^^^ Option<Test>
if let None = &test {};
if let test = &test {};
//^^^^ &Option<Test>
if let Some(test) = &test {};
//^^^^ &Test
if let Some(Test { a, b }) = &test {};
//^ &Option<u32> ^ &u8
if let Some(Test { a: x, b: y }) = &test {};
//^ &Option<u32> ^ &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 {}
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
[
InlayHint {
range: 187..191,
kind: TypeHint,
label: "CustomOption<Test>",
},
InlayHint {
range: 266..270,
kind: TypeHint,
label: "&CustomOption<Test>",
},
InlayHint {
range: 299..303,
kind: TypeHint,
label: "&Test",
},
InlayHint {
range: 340..341,
kind: TypeHint,
label: "&CustomOption<u32>",
},
InlayHint {
range: 343..344,
kind: TypeHint,
label: "&u8",
},
InlayHint {
range: 386..387,
kind: TypeHint,
label: "&CustomOption<u32>",
},
InlayHint {
range: 392..393,
kind: TypeHint,
label: "&u8",
},
InlayHint {
range: 440..441,
kind: TypeHint,
label: "&u32",
},
InlayHint {
range: 447..448,
kind: TypeHint,
label: "&u8",
},
InlayHint {
range: 499..500,
kind: TypeHint,
label: "&u8",
},
InlayHint {
range: 542..543,
kind: TypeHint,
label: "&u8",
},
]
"###
);
}
#[test]
fn while_expr() {
let (analysis, file_id) = single_file(
check(
r#"
#[derive(PartialEq)]
enum CustomOption<T> {
None,
Some(T),
}
enum Option<T> { None, Some(T) }
use Option::*;
#[derive(PartialEq)]
struct Test {
a: CustomOption<u32>,
b: u8,
}
use CustomOption::*;
struct Test { a: Option<u32>, b: u8 }
fn main() {
let test = Some(Test { a: Some(3), b: 1 });
while let None = &test {};
while let test = &test {};
while let Some(test) = &test {};
while let Some(Test { a, b }) = &test {};
while let Some(Test { a: x, b: y }) = &test {};
//^^^^ Option<Test>
while let Some(Test { a: Some(x), b: y }) = &test {};
while let Some(Test { a: None, b: y }) = &test {};
while let Some(Test { b: y, .. }) = &test {};
while test == None {}
//^ &u32 ^ &u8
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
[
InlayHint {
range: 187..191,
kind: TypeHint,
label: "CustomOption<Test>",
},
InlayHint {
range: 272..276,
kind: TypeHint,
label: "&CustomOption<Test>",
},
InlayHint {
range: 308..312,
kind: TypeHint,
label: "&Test",
},
InlayHint {
range: 352..353,
kind: TypeHint,
label: "&CustomOption<u32>",
},
InlayHint {
range: 355..356,
kind: TypeHint,
label: "&u8",
},
InlayHint {
range: 401..402,
kind: TypeHint,
label: "&CustomOption<u32>",
},
InlayHint {
range: 407..408,
kind: TypeHint,
label: "&u8",
},
InlayHint {
range: 458..459,
kind: TypeHint,
label: "&u32",
},
InlayHint {
range: 465..466,
kind: TypeHint,
label: "&u8",
},
InlayHint {
range: 520..521,
kind: TypeHint,
label: "&u8",
},
InlayHint {
range: 566..567,
kind: TypeHint,
label: "&u8",
},
]
"###
);
}
#[test]
fn match_arm_list() {
let (analysis, file_id) = single_file(
check(
r#"
#[derive(PartialEq)]
enum CustomOption<T> {
None,
Some(T),
}
enum Option<T> { None, Some(T) }
use Option::*;
#[derive(PartialEq)]
struct Test {
a: CustomOption<u32>,
b: u8,
}
use CustomOption::*;
struct Test { a: Option<u32>, b: u8 }
fn main() {
match Some(Test { a: Some(3), b: 1 }) {
None => (),
test => (),
Some(test) => (),
Some(Test { a, b }) => (),
Some(Test { a: x, b: y }) => (),
//^^^^ Option<Test>
Some(Test { a: Some(x), b: y }) => (),
Some(Test { a: None, b: y }) => (),
Some(Test { b: y, .. }) => (),
//^ u32 ^ u8
_ => {}
}
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
[
InlayHint {
range: 251..255,
kind: TypeHint,
label: "CustomOption<Test>",
},
InlayHint {
range: 276..280,
kind: TypeHint,
label: "Test",
},
InlayHint {
range: 309..310,
kind: TypeHint,
label: "CustomOption<u32>",
},
InlayHint {
range: 312..313,
kind: TypeHint,
label: "u8",
},
InlayHint {
range: 347..348,
kind: TypeHint,
label: "CustomOption<u32>",
},
InlayHint {
range: 353..354,
kind: TypeHint,
label: "u8",
},
InlayHint {
range: 393..394,
kind: TypeHint,
label: "u32",
},
InlayHint {
range: 400..401,
kind: TypeHint,
label: "u8",
},
InlayHint {
range: 444..445,
kind: TypeHint,
label: "u8",
},
InlayHint {
range: 479..480,
kind: TypeHint,
label: "u8",
},
]
"###
);
}
#[test]
fn hint_truncation() {
let (analysis, file_id) = single_file(
check_with_config(
r#"
struct Smol<T>(T);
@ -929,52 +591,26 @@ struct VeryLongOuterName<T>(T);
fn main() {
let a = Smol(0u32);
//^ Smol<u32>
let b = VeryLongOuterName(0usize);
//^ VeryLongOuterName<…>
let c = Smol(Smol(0u32))
//^ Smol<Smol<…>>
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
[
InlayHint {
range: 73..74,
kind: TypeHint,
label: "Smol<u32>",
},
InlayHint {
range: 97..98,
kind: TypeHint,
label: "VeryLongOuterName<…>",
},
InlayHint {
range: 136..137,
kind: TypeHint,
label: "Smol<Smol<…>>",
},
]
"###
InlayHintsConfig { max_length: Some(8), ..Default::default() },
);
}
#[test]
fn function_call_parameter_hint() {
let (analysis, file_id) = single_file(
check(
r#"
enum CustomOption<T> {
None,
Some(T),
}
use CustomOption::*;
enum Option<T> { None, Some(T) }
use Option::*;
struct FileId {}
struct SmolStr {}
impl From<&str> for SmolStr {
fn from(_: &str) -> Self {
unimplemented!()
}
}
struct TextRange {}
struct SyntaxKind {}
struct NavigationTarget {}
@ -982,18 +618,15 @@ struct NavigationTarget {}
struct Test {}
impl Test {
fn method(&self, mut param: i32) -> i32 {
param * 2
}
fn method(&self, mut param: i32) -> i32 { param * 2 }
fn from_syntax(
file_id: FileId,
name: SmolStr,
focus_range: CustomOption<TextRange>,
focus_range: Option<TextRange>,
full_range: TextRange,
kind: SyntaxKind,
docs: CustomOption<String>,
description: CustomOption<String>,
docs: Option<String>,
) -> NavigationTarget {
NavigationTarget {}
}
@ -1005,108 +638,35 @@ 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 {};
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,
None,
//^^^^ docs
);
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
[
InlayHint {
range: 797..808,
kind: TypeHint,
label: "i32",
},
InlayHint {
range: 841..842,
kind: ParameterHint,
label: "foo",
},
InlayHint {
range: 844..845,
kind: ParameterHint,
label: "bar",
},
InlayHint {
range: 847..854,
kind: ParameterHint,
label: "msg",
},
InlayHint {
range: 859..870,
kind: ParameterHint,
label: "last",
},
InlayHint {
range: 913..916,
kind: ParameterHint,
label: "param",
},
InlayHint {
range: 936..938,
kind: ParameterHint,
label: "&self",
},
InlayHint {
range: 940..944,
kind: ParameterHint,
label: "param",
},
InlayHint {
range: 979..988,
kind: ParameterHint,
label: "file_id",
},
InlayHint {
range: 998..1011,
kind: ParameterHint,
label: "name",
},
InlayHint {
range: 1021..1025,
kind: ParameterHint,
label: "focus_range",
},
InlayHint {
range: 1035..1047,
kind: ParameterHint,
label: "full_range",
},
InlayHint {
range: 1057..1070,
kind: ParameterHint,
label: "kind",
},
InlayHint {
range: 1080..1084,
kind: ParameterHint,
label: "docs",
},
InlayHint {
range: 1094..1098,
kind: ParameterHint,
label: "description",
},
]
"###
);
}
#[test]
fn omitted_parameters_hints_heuristics() {
let (analysis, file_id) = single_file(
check_with_config(
r#"
fn map(f: i32) {}
fn filter(predicate: i32) {}
@ -1187,23 +747,16 @@ fn main() {
let _: f64 = a.div_euclid(b);
let _: f64 = a.abs_sub(b);
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
[]
"###
InlayHintsConfig { max_length: Some(8), ..Default::default() },
);
}
#[test]
fn unit_structs_have_no_type_hints() {
let (analysis, file_id) = single_file(
check_with_config(
r#"
enum CustomResult<T, E> {
Ok(T),
Err(E),
}
use CustomResult::*;
enum Result<T, E> { Ok(T), Err(E) }
use Result::*;
struct SyntheticSyntax;
@ -1213,11 +766,7 @@ fn main() {
Err(SyntheticSyntax) => (),
}
}"#,
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
[]
"###
InlayHintsConfig { max_length: Some(8), ..Default::default() },
);
}
@ -1255,7 +804,7 @@ fn main() {
#[test]
fn chaining_hints_without_newlines() {
let (analysis, file_id) = single_file(
check_with_config(
r#"
struct A(B);
impl A { fn into_b(self) -> B { self.0 } }
@ -1266,8 +815,13 @@ fn main() {
fn main() {
let c = A(B(C)).into_b().into_c();
}"#,
InlayHintsConfig {
parameter_hints: false,
type_hints: false,
chaining_hints: true,
max_length: None,
},
);
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###);
}
#[test]

View file

@ -11,7 +11,7 @@ pub mod mark;
mod fixture;
use std::{
convert::TryInto,
convert::{TryFrom, TryInto},
env, fs,
path::{Path, PathBuf},
};
@ -169,10 +169,9 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
for line in lines_with_ends(text) {
if let Some(idx) = line.find("//^") {
let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]);
let marker_and_data = &line[idx + "//".len()..];
let len = marker_and_data.chars().take_while(|&it| it == '^').count();
let data = marker_and_data[len..].trim().to_string();
res.push((TextRange::at(offset, len.try_into().unwrap()), data))
for (line_range, text) in extract_line_annotations(&line[idx + "//".len()..]) {
res.push((line_range + offset, text))
}
}
prev_line_start = Some(line_start);
line_start += TextSize::of(line);
@ -180,13 +179,28 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
res
}
fn extract_line_annotations(mut line: &str) -> Vec<(TextRange, String)> {
let mut res = Vec::new();
let mut offset: TextSize = 0.into();
while !line.is_empty() {
let len = line.chars().take_while(|&it| it == '^').count();
assert!(len > 0);
let range = TextRange::at(offset, len.try_into().unwrap());
let next = line[len..].find('^').map_or(line.len(), |it| it + len);
res.push((range, line[len..][..next - len].trim().to_string()));
line = &line[next..];
offset += TextSize::try_from(next).unwrap();
}
res
}
#[test]
fn test_extract_annotations() {
let text = stdx::trim_indent(
r#"
fn main() {
let x = 92;
//^ def
let (x, y) = (9, 2);
//^ def ^ def
zoo + 1
} //^^^ i32
"#,
@ -195,7 +209,7 @@ fn main() {
.into_iter()
.map(|(range, ann)| (&text[range], ann))
.collect::<Vec<_>>();
assert_eq!(res, vec![("x", "def".into()), ("zoo", "i32".into()),]);
assert_eq!(res, vec![("x", "def".into()), ("y", "def".into()), ("zoo", "i32".into()),]);
}
// Comparison functionality borrowed from cargo: