mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 21:54:42 +00:00
Added more unit tests
This commit is contained in:
parent
c1f9a1a1c5
commit
b70ce559b8
1 changed files with 159 additions and 76 deletions
|
@ -70,6 +70,45 @@ pub(crate) fn inlay_hints(
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_chaining_hints(
|
||||||
|
acc: &mut Vec<InlayHint>,
|
||||||
|
sema: &Semantics<RootDatabase>,
|
||||||
|
options: &InlayHintsOptions,
|
||||||
|
expr: ast::Expr,
|
||||||
|
) -> Option<()> {
|
||||||
|
if !options.chaining_hints {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty = sema.type_of_expr(&expr)?;
|
||||||
|
let label = ty.display_truncated(sema.db, options.max_length).to_string();
|
||||||
|
if ty.is_unknown() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tokens = expr.syntax()
|
||||||
|
.siblings_with_tokens(Direction::Next)
|
||||||
|
.filter_map(NodeOrToken::into_token)
|
||||||
|
.filter(|t| match t.kind() {
|
||||||
|
SyntaxKind::WHITESPACE if !t.text().contains('\n') => false,
|
||||||
|
SyntaxKind::COMMENT => false,
|
||||||
|
_ => true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Chaining can be defined as an expression whose next sibling tokens are newline and dot
|
||||||
|
// Ignoring extra whitespace and comments
|
||||||
|
let next = tokens.next()?.kind();
|
||||||
|
let next_next = tokens.next()?.kind();
|
||||||
|
if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT {
|
||||||
|
acc.push(InlayHint {
|
||||||
|
range: expr.syntax().text_range(),
|
||||||
|
kind: InlayKind::ChainingHint,
|
||||||
|
label: label.into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
fn get_param_name_hints(
|
fn get_param_name_hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
|
@ -233,45 +272,6 @@ fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_chaining_hints(
|
|
||||||
acc: &mut Vec<InlayHint>,
|
|
||||||
sema: &Semantics<RootDatabase>,
|
|
||||||
options: &InlayHintsOptions,
|
|
||||||
expr: ast::Expr,
|
|
||||||
) -> Option<()> {
|
|
||||||
if !options.chaining_hints {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ty = sema.type_of_expr(&expr)?;
|
|
||||||
let label = ty.display_truncated(sema.db, options.max_length).to_string();
|
|
||||||
if ty.is_unknown() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tokens = expr.syntax()
|
|
||||||
.siblings_with_tokens(Direction::Next)
|
|
||||||
.filter_map(NodeOrToken::into_token)
|
|
||||||
.filter(|t| match t.kind() {
|
|
||||||
SyntaxKind::WHITESPACE if !t.text().contains('\n') => false,
|
|
||||||
SyntaxKind::COMMENT => false,
|
|
||||||
_ => true,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Chaining can be defined as an expression whose next sibling tokens are newline and dot
|
|
||||||
// Ignoring extra whitespace and comments
|
|
||||||
let next = tokens.next()?.kind();
|
|
||||||
let next_next = tokens.next()?.kind();
|
|
||||||
if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT {
|
|
||||||
acc.push(InlayHint {
|
|
||||||
range: expr.syntax().text_range(),
|
|
||||||
kind: InlayKind::ChainingHint,
|
|
||||||
label: label.into(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Some(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::inlay_hints::InlayHintsOptions;
|
use crate::inlay_hints::InlayHintsOptions;
|
||||||
|
@ -279,43 +279,6 @@ mod tests {
|
||||||
|
|
||||||
use crate::mock_analysis::single_file;
|
use crate::mock_analysis::single_file;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn generic_chaining_hints() {
|
|
||||||
let (analysis, file_id) = single_file(
|
|
||||||
r#"
|
|
||||||
struct A<T>(T);
|
|
||||||
struct B<T>(T);
|
|
||||||
struct C<T>(T);
|
|
||||||
struct X<T,R>(T, R);
|
|
||||||
|
|
||||||
impl<T> A<T> {
|
|
||||||
fn new(t: T) -> Self { A(t) }
|
|
||||||
fn into_b(self) -> B<T> { B(self.0) }
|
|
||||||
}
|
|
||||||
impl<T> B<T> {
|
|
||||||
fn into_c(self) -> C<T> { C(self.0) }
|
|
||||||
}
|
|
||||||
fn test() {
|
|
||||||
let c = A::new(X(42, true))
|
|
||||||
.into_b() // All the from A -> B -> C
|
|
||||||
.into_c();
|
|
||||||
}"#,
|
|
||||||
);
|
|
||||||
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
|
|
||||||
[
|
|
||||||
InlayHint {
|
|
||||||
range: [416; 465),
|
|
||||||
kind: ChainingHint,
|
|
||||||
label: "B<X<i32, bool>>",
|
|
||||||
},
|
|
||||||
InlayHint {
|
|
||||||
range: [416; 435),
|
|
||||||
kind: ChainingHint,
|
|
||||||
label: "A<X<i32, bool>>",
|
|
||||||
},
|
|
||||||
]"###);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn param_hints_only() {
|
fn param_hints_only() {
|
||||||
let (analysis, file_id) = single_file(
|
let (analysis, file_id) = single_file(
|
||||||
|
@ -1139,4 +1102,124 @@ fn main() {
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn chaining_hints_ignore_comments() {
|
||||||
|
let (analysis, file_id) = single_file(
|
||||||
|
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
|
||||||
|
.into_c();
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
|
||||||
|
[
|
||||||
|
InlayHint {
|
||||||
|
range: [231; 268),
|
||||||
|
kind: ChainingHint,
|
||||||
|
label: "B",
|
||||||
|
},
|
||||||
|
InlayHint {
|
||||||
|
range: [231; 238),
|
||||||
|
kind: ChainingHint,
|
||||||
|
label: "A",
|
||||||
|
},
|
||||||
|
]"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn chaining_hints_without_newlines() {
|
||||||
|
let (analysis, file_id) = single_file(
|
||||||
|
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();
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn struct_access_chaining_hints() {
|
||||||
|
let (analysis, file_id) = single_file(
|
||||||
|
r#"
|
||||||
|
struct A { pub b: B }
|
||||||
|
struct B { pub c: C }
|
||||||
|
struct C(pub bool);
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = A { b: B { c: C(true) } }
|
||||||
|
.b
|
||||||
|
.c
|
||||||
|
.0;
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
|
||||||
|
[
|
||||||
|
InlayHint {
|
||||||
|
range: [150; 221),
|
||||||
|
kind: ChainingHint,
|
||||||
|
label: "C",
|
||||||
|
},
|
||||||
|
InlayHint {
|
||||||
|
range: [150; 198),
|
||||||
|
kind: ChainingHint,
|
||||||
|
label: "B",
|
||||||
|
},
|
||||||
|
InlayHint {
|
||||||
|
range: [150; 175),
|
||||||
|
kind: ChainingHint,
|
||||||
|
label: "A",
|
||||||
|
},
|
||||||
|
]"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generic_chaining_hints() {
|
||||||
|
let (analysis, file_id) = single_file(
|
||||||
|
r#"
|
||||||
|
struct A<T>(T);
|
||||||
|
struct B<T>(T);
|
||||||
|
struct C<T>(T);
|
||||||
|
struct X<T,R>(T, R);
|
||||||
|
|
||||||
|
impl<T> A<T> {
|
||||||
|
fn new(t: T) -> Self { A(t) }
|
||||||
|
fn into_b(self) -> B<T> { B(self.0) }
|
||||||
|
}
|
||||||
|
impl<T> B<T> {
|
||||||
|
fn into_c(self) -> C<T> { C(self.0) }
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let c = A::new(X(42, true))
|
||||||
|
.into_b()
|
||||||
|
.into_c();
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
|
||||||
|
[
|
||||||
|
InlayHint {
|
||||||
|
range: [416; 465),
|
||||||
|
kind: ChainingHint,
|
||||||
|
label: "B<X<i32, bool>>",
|
||||||
|
},
|
||||||
|
InlayHint {
|
||||||
|
range: [416; 435),
|
||||||
|
kind: ChainingHint,
|
||||||
|
label: "A<X<i32, bool>>",
|
||||||
|
},
|
||||||
|
]"###);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue