Skip to content

Commit b70ce55

Browse files
committed
Added more unit tests
1 parent c1f9a1a commit b70ce55

File tree

1 file changed

+159
-76
lines changed

1 file changed

+159
-76
lines changed

crates/ra_ide/src/inlay_hints.rs

Lines changed: 159 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,45 @@ pub(crate) fn inlay_hints(
7070
res
7171
}
7272

73+
fn get_chaining_hints(
74+
acc: &mut Vec<InlayHint>,
75+
sema: &Semantics<RootDatabase>,
76+
options: &InlayHintsOptions,
77+
expr: ast::Expr,
78+
) -> Option<()> {
79+
if !options.chaining_hints {
80+
return None;
81+
}
82+
83+
let ty = sema.type_of_expr(&expr)?;
84+
let label = ty.display_truncated(sema.db, options.max_length).to_string();
85+
if ty.is_unknown() {
86+
return None;
87+
}
88+
89+
let mut tokens = expr.syntax()
90+
.siblings_with_tokens(Direction::Next)
91+
.filter_map(NodeOrToken::into_token)
92+
.filter(|t| match t.kind() {
93+
SyntaxKind::WHITESPACE if !t.text().contains('\n') => false,
94+
SyntaxKind::COMMENT => false,
95+
_ => true,
96+
});
97+
98+
// Chaining can be defined as an expression whose next sibling tokens are newline and dot
99+
// Ignoring extra whitespace and comments
100+
let next = tokens.next()?.kind();
101+
let next_next = tokens.next()?.kind();
102+
if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT {
103+
acc.push(InlayHint {
104+
range: expr.syntax().text_range(),
105+
kind: InlayKind::ChainingHint,
106+
label: label.into(),
107+
});
108+
}
109+
Some(())
110+
}
111+
73112
fn get_param_name_hints(
74113
acc: &mut Vec<InlayHint>,
75114
sema: &Semantics<RootDatabase>,
@@ -233,89 +272,13 @@ fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<
233272
}
234273
}
235274

236-
fn get_chaining_hints(
237-
acc: &mut Vec<InlayHint>,
238-
sema: &Semantics<RootDatabase>,
239-
options: &InlayHintsOptions,
240-
expr: ast::Expr,
241-
) -> Option<()> {
242-
if !options.chaining_hints {
243-
return None;
244-
}
245-
246-
let ty = sema.type_of_expr(&expr)?;
247-
let label = ty.display_truncated(sema.db, options.max_length).to_string();
248-
if ty.is_unknown() {
249-
return None;
250-
}
251-
252-
let mut tokens = expr.syntax()
253-
.siblings_with_tokens(Direction::Next)
254-
.filter_map(NodeOrToken::into_token)
255-
.filter(|t| match t.kind() {
256-
SyntaxKind::WHITESPACE if !t.text().contains('\n') => false,
257-
SyntaxKind::COMMENT => false,
258-
_ => true,
259-
});
260-
261-
// Chaining can be defined as an expression whose next sibling tokens are newline and dot
262-
// Ignoring extra whitespace and comments
263-
let next = tokens.next()?.kind();
264-
let next_next = tokens.next()?.kind();
265-
if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT {
266-
acc.push(InlayHint {
267-
range: expr.syntax().text_range(),
268-
kind: InlayKind::ChainingHint,
269-
label: label.into(),
270-
});
271-
}
272-
Some(())
273-
}
274-
275275
#[cfg(test)]
276276
mod tests {
277277
use crate::inlay_hints::InlayHintsOptions;
278278
use insta::assert_debug_snapshot;
279279

280280
use crate::mock_analysis::single_file;
281281

282-
#[test]
283-
fn generic_chaining_hints() {
284-
let (analysis, file_id) = single_file(
285-
r#"
286-
struct A<T>(T);
287-
struct B<T>(T);
288-
struct C<T>(T);
289-
struct X<T,R>(T, R);
290-
291-
impl<T> A<T> {
292-
fn new(t: T) -> Self { A(t) }
293-
fn into_b(self) -> B<T> { B(self.0) }
294-
}
295-
impl<T> B<T> {
296-
fn into_c(self) -> C<T> { C(self.0) }
297-
}
298-
fn test() {
299-
let c = A::new(X(42, true))
300-
.into_b() // All the from A -> B -> C
301-
.into_c();
302-
}"#,
303-
);
304-
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
305-
[
306-
InlayHint {
307-
range: [416; 465),
308-
kind: ChainingHint,
309-
label: "B<X<i32, bool>>",
310-
},
311-
InlayHint {
312-
range: [416; 435),
313-
kind: ChainingHint,
314-
label: "A<X<i32, bool>>",
315-
},
316-
]"###);
317-
}
318-
319282
#[test]
320283
fn param_hints_only() {
321284
let (analysis, file_id) = single_file(
@@ -1139,4 +1102,124 @@ fn main() {
11391102
"###
11401103
);
11411104
}
1105+
1106+
#[test]
1107+
fn chaining_hints_ignore_comments() {
1108+
let (analysis, file_id) = single_file(
1109+
r#"
1110+
struct A(B);
1111+
impl A { fn into_b(self) -> B { self.0 } }
1112+
struct B(C)
1113+
impl B { fn into_c(self) -> C { self.0 } }
1114+
struct C;
1115+
1116+
fn main() {
1117+
let c = A(B(C))
1118+
.into_b() // This is a comment
1119+
.into_c();
1120+
}"#,
1121+
);
1122+
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1123+
[
1124+
InlayHint {
1125+
range: [231; 268),
1126+
kind: ChainingHint,
1127+
label: "B",
1128+
},
1129+
InlayHint {
1130+
range: [231; 238),
1131+
kind: ChainingHint,
1132+
label: "A",
1133+
},
1134+
]"###);
1135+
}
1136+
1137+
#[test]
1138+
fn chaining_hints_without_newlines() {
1139+
let (analysis, file_id) = single_file(
1140+
r#"
1141+
struct A(B);
1142+
impl A { fn into_b(self) -> B { self.0 } }
1143+
struct B(C)
1144+
impl B { fn into_c(self) -> C { self.0 } }
1145+
struct C;
1146+
1147+
fn main() {
1148+
let c = A(B(C)).into_b().into_c();
1149+
}"#,
1150+
);
1151+
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###);
1152+
}
1153+
1154+
#[test]
1155+
fn struct_access_chaining_hints() {
1156+
let (analysis, file_id) = single_file(
1157+
r#"
1158+
struct A { pub b: B }
1159+
struct B { pub c: C }
1160+
struct C(pub bool);
1161+
1162+
fn main() {
1163+
let x = A { b: B { c: C(true) } }
1164+
.b
1165+
.c
1166+
.0;
1167+
}"#,
1168+
);
1169+
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1170+
[
1171+
InlayHint {
1172+
range: [150; 221),
1173+
kind: ChainingHint,
1174+
label: "C",
1175+
},
1176+
InlayHint {
1177+
range: [150; 198),
1178+
kind: ChainingHint,
1179+
label: "B",
1180+
},
1181+
InlayHint {
1182+
range: [150; 175),
1183+
kind: ChainingHint,
1184+
label: "A",
1185+
},
1186+
]"###);
1187+
}
1188+
1189+
#[test]
1190+
fn generic_chaining_hints() {
1191+
let (analysis, file_id) = single_file(
1192+
r#"
1193+
struct A<T>(T);
1194+
struct B<T>(T);
1195+
struct C<T>(T);
1196+
struct X<T,R>(T, R);
1197+
1198+
impl<T> A<T> {
1199+
fn new(t: T) -> Self { A(t) }
1200+
fn into_b(self) -> B<T> { B(self.0) }
1201+
}
1202+
impl<T> B<T> {
1203+
fn into_c(self) -> C<T> { C(self.0) }
1204+
}
1205+
fn main() {
1206+
let c = A::new(X(42, true))
1207+
.into_b()
1208+
.into_c();
1209+
}"#,
1210+
);
1211+
assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1212+
[
1213+
InlayHint {
1214+
range: [416; 465),
1215+
kind: ChainingHint,
1216+
label: "B<X<i32, bool>>",
1217+
},
1218+
InlayHint {
1219+
range: [416; 435),
1220+
kind: ChainingHint,
1221+
label: "A<X<i32, bool>>",
1222+
},
1223+
]"###);
1224+
}
11421225
}

0 commit comments

Comments
 (0)