]>
Commit | Line | Data |
---|---|---|
9c376795 FG |
1 | //! Implementation of "adjustment" inlay hints: |
2 | //! ```no_run | |
3 | //! let _: u32 = /* <never-to-any> */ loop {}; | |
4 | //! let _: &u32 = /* &* */ &mut 0; | |
5 | //! ``` | |
9ffffee4 | 6 | use hir::{Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, PointerCast, Safety, Semantics}; |
9c376795 FG |
7 | use ide_db::RootDatabase; |
8 | ||
9ffffee4 | 9 | use stdx::never; |
9c376795 FG |
10 | use syntax::{ |
11 | ast::{self, make, AstNode}, | |
12 | ted, | |
13 | }; | |
14 | ||
9ffffee4 FG |
15 | use crate::{ |
16 | AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind, | |
17 | InlayTooltip, | |
18 | }; | |
9c376795 FG |
19 | |
20 | pub(super) fn hints( | |
21 | acc: &mut Vec<InlayHint>, | |
22 | sema: &Semantics<'_, RootDatabase>, | |
23 | config: &InlayHintsConfig, | |
24 | expr: &ast::Expr, | |
25 | ) -> Option<()> { | |
26 | if config.adjustment_hints_hide_outside_unsafe && !sema.is_inside_unsafe(expr) { | |
27 | return None; | |
28 | } | |
29 | ||
30 | if config.adjustment_hints == AdjustmentHints::Never { | |
31 | return None; | |
32 | } | |
33 | ||
353b0b11 FG |
34 | // ParenExpr resolve to their contained expressions HIR so they will dupe these hints |
35 | if let ast::Expr::ParenExpr(_) = expr { | |
9c376795 FG |
36 | return None; |
37 | } | |
353b0b11 FG |
38 | if let ast::Expr::BlockExpr(b) = expr { |
39 | if !b.is_standalone() { | |
40 | return None; | |
41 | } | |
42 | } | |
9c376795 FG |
43 | |
44 | let descended = sema.descend_node_into_attributes(expr.clone()).pop(); | |
45 | let desc_expr = descended.as_ref().unwrap_or(expr); | |
46 | let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?; | |
47 | ||
353b0b11 FG |
48 | if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr { |
49 | if let [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), source: _, target }] = | |
50 | &*adjustments | |
51 | { | |
52 | // Don't show unnecessary reborrows for these, they will just repeat the inner ones again | |
53 | if source == target { | |
54 | return None; | |
55 | } | |
56 | } | |
57 | } | |
58 | ||
9c376795 FG |
59 | let (postfix, needs_outer_parens, needs_inner_parens) = |
60 | mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode); | |
61 | ||
62 | if needs_outer_parens { | |
9ffffee4 | 63 | acc.push(InlayHint::opening_paren(expr.syntax().text_range())); |
9c376795 FG |
64 | } |
65 | ||
66 | if postfix && needs_inner_parens { | |
9ffffee4 FG |
67 | acc.push(InlayHint::opening_paren(expr.syntax().text_range())); |
68 | acc.push(InlayHint::closing_paren(expr.syntax().text_range())); | |
9c376795 FG |
69 | } |
70 | ||
71 | let (mut tmp0, mut tmp1); | |
72 | let iter: &mut dyn Iterator<Item = _> = if postfix { | |
73 | tmp0 = adjustments.into_iter(); | |
74 | &mut tmp0 | |
75 | } else { | |
76 | tmp1 = adjustments.into_iter().rev(); | |
77 | &mut tmp1 | |
78 | }; | |
79 | ||
9ffffee4 FG |
80 | for Adjustment { source, target, kind } in iter { |
81 | if source == target { | |
353b0b11 | 82 | cov_mark::hit!(same_type_adjustment); |
9c376795 FG |
83 | continue; |
84 | } | |
85 | ||
86 | // FIXME: Add some nicer tooltips to each of these | |
9ffffee4 | 87 | let (text, coercion) = match kind { |
9c376795 | 88 | Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => { |
9ffffee4 FG |
89 | ("<never-to-any>", "never to any") |
90 | } | |
91 | Adjust::Deref(_) => ("*", "dereference"), | |
92 | Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => ("&", "borrow"), | |
93 | Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => ("&mut ", "unique borrow"), | |
94 | Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => { | |
95 | ("&raw const ", "const pointer borrow") | |
96 | } | |
97 | Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => { | |
98 | ("&raw mut ", "mut pointer borrow") | |
9c376795 | 99 | } |
9c376795 FG |
100 | // some of these could be represented via `as` casts, but that's not too nice and |
101 | // handling everything as a prefix expr makes the `(` and `)` insertion easier | |
102 | Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => { | |
103 | match cast { | |
9ffffee4 FG |
104 | PointerCast::ReifyFnPointer => { |
105 | ("<fn-item-to-fn-pointer>", "fn item to fn pointer") | |
106 | } | |
107 | PointerCast::UnsafeFnPointer => ( | |
108 | "<safe-fn-pointer-to-unsafe-fn-pointer>", | |
109 | "safe fn pointer to unsafe fn pointer", | |
110 | ), | |
9c376795 | 111 | PointerCast::ClosureFnPointer(Safety::Unsafe) => { |
9ffffee4 FG |
112 | ("<closure-to-unsafe-fn-pointer>", "closure to unsafe fn pointer") |
113 | } | |
114 | PointerCast::ClosureFnPointer(Safety::Safe) => { | |
115 | ("<closure-to-fn-pointer>", "closure to fn pointer") | |
9c376795 | 116 | } |
9ffffee4 FG |
117 | PointerCast::MutToConstPointer => { |
118 | ("<mut-ptr-to-const-ptr>", "mut ptr to const ptr") | |
119 | } | |
120 | PointerCast::ArrayToPointer => ("<array-ptr-to-element-ptr>", ""), | |
121 | PointerCast::Unsize => ("<unsize>", "unsize"), | |
9c376795 FG |
122 | } |
123 | } | |
124 | _ => continue, | |
125 | }; | |
126 | acc.push(InlayHint { | |
127 | range: expr.syntax().text_range(), | |
9ffffee4 FG |
128 | kind: if postfix { InlayKind::AdjustmentPostfix } else { InlayKind::Adjustment }, |
129 | label: InlayHintLabel::simple( | |
130 | if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() }, | |
131 | Some(InlayTooltip::Markdown(format!( | |
132 | "`{}` → `{}` ({coercion} coercion)", | |
133 | source.display(sema.db), | |
134 | target.display(sema.db), | |
135 | ))), | |
136 | None, | |
137 | ), | |
9c376795 FG |
138 | }); |
139 | } | |
140 | if !postfix && needs_inner_parens { | |
9ffffee4 FG |
141 | acc.push(InlayHint::opening_paren(expr.syntax().text_range())); |
142 | acc.push(InlayHint::closing_paren(expr.syntax().text_range())); | |
9c376795 FG |
143 | } |
144 | if needs_outer_parens { | |
9ffffee4 | 145 | acc.push(InlayHint::closing_paren(expr.syntax().text_range())); |
9c376795 FG |
146 | } |
147 | Some(()) | |
148 | } | |
149 | ||
150 | /// Returns whatever the hint should be postfix and if we need to add paretheses on the inside and/or outside of `expr`, | |
151 | /// if we are going to add (`postfix`) adjustments hints to it. | |
152 | fn mode_and_needs_parens_for_adjustment_hints( | |
153 | expr: &ast::Expr, | |
154 | mode: AdjustmentHintsMode, | |
155 | ) -> (bool, bool, bool) { | |
156 | use {std::cmp::Ordering::*, AdjustmentHintsMode::*}; | |
157 | ||
158 | match mode { | |
159 | Prefix | Postfix => { | |
160 | let postfix = matches!(mode, Postfix); | |
161 | let (inside, outside) = needs_parens_for_adjustment_hints(expr, postfix); | |
162 | (postfix, inside, outside) | |
163 | } | |
164 | PreferPrefix | PreferPostfix => { | |
165 | let prefer_postfix = matches!(mode, PreferPostfix); | |
166 | ||
167 | let (pre_inside, pre_outside) = needs_parens_for_adjustment_hints(expr, false); | |
168 | let prefix = (false, pre_inside, pre_outside); | |
169 | let pre_count = pre_inside as u8 + pre_outside as u8; | |
170 | ||
171 | let (post_inside, post_outside) = needs_parens_for_adjustment_hints(expr, true); | |
172 | let postfix = (true, post_inside, post_outside); | |
173 | let post_count = post_inside as u8 + post_outside as u8; | |
174 | ||
175 | match pre_count.cmp(&post_count) { | |
176 | Less => prefix, | |
177 | Greater => postfix, | |
178 | Equal if prefer_postfix => postfix, | |
179 | Equal => prefix, | |
180 | } | |
181 | } | |
182 | } | |
183 | } | |
184 | ||
185 | /// Returns whatever we need to add paretheses on the inside and/or outside of `expr`, | |
186 | /// if we are going to add (`postfix`) adjustments hints to it. | |
187 | fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, bool) { | |
188 | // This is a very miserable pile of hacks... | |
189 | // | |
190 | // `Expr::needs_parens_in` requires that the expression is the child of the other expression, | |
191 | // that is supposed to be its parent. | |
192 | // | |
193 | // But we want to check what would happen if we add `*`/`.*` to the inner expression. | |
194 | // To check for inner we need `` expr.needs_parens_in(`*expr`) ``, | |
195 | // to check for outer we need `` `*expr`.needs_parens_in(parent) ``, | |
196 | // where "expr" is the `expr` parameter, `*expr` is the editted `expr`, | |
197 | // and "parent" is the parent of the original expression... | |
198 | // | |
199 | // For this we utilize mutable mutable trees, which is a HACK, but it works. | |
200 | // | |
201 | // FIXME: comeup with a better API for `needs_parens_in`, so that we don't have to do *this* | |
202 | ||
203 | // Make `&expr`/`expr?` | |
204 | let dummy_expr = { | |
205 | // `make::*` function go through a string, so they parse wrongly. | |
206 | // for example `` make::expr_try(`|| a`) `` would result in a | |
207 | // `|| (a?)` and not `(|| a)?`. | |
208 | // | |
209 | // Thus we need dummy parens to preserve the relationship we want. | |
210 | // The parens are then simply ignored by the following code. | |
211 | let dummy_paren = make::expr_paren(expr.clone()); | |
212 | if postfix { | |
213 | make::expr_try(dummy_paren) | |
214 | } else { | |
215 | make::expr_ref(dummy_paren, false) | |
216 | } | |
217 | }; | |
218 | ||
219 | // Do the dark mutable tree magic. | |
220 | // This essentially makes `dummy_expr` and `expr` switch places (families), | |
221 | // so that `expr`'s parent is not `dummy_expr`'s parent. | |
222 | let dummy_expr = dummy_expr.clone_for_update(); | |
223 | let expr = expr.clone_for_update(); | |
224 | ted::replace(expr.syntax(), dummy_expr.syntax()); | |
225 | ||
226 | let parent = dummy_expr.syntax().parent(); | |
9ffffee4 FG |
227 | let Some(expr) = (|| { |
228 | if postfix { | |
229 | let ast::Expr::TryExpr(e) = &dummy_expr else { return None }; | |
230 | let Some(ast::Expr::ParenExpr(e)) = e.expr() else { return None }; | |
9c376795 | 231 | |
9ffffee4 FG |
232 | e.expr() |
233 | } else { | |
234 | let ast::Expr::RefExpr(e) = &dummy_expr else { return None }; | |
235 | let Some(ast::Expr::ParenExpr(e)) = e.expr() else { return None }; | |
9c376795 | 236 | |
9ffffee4 FG |
237 | e.expr() |
238 | } | |
239 | })() else { | |
240 | never!("broken syntax tree?\n{:?}\n{:?}", expr, dummy_expr); | |
241 | return (true, true) | |
9c376795 FG |
242 | }; |
243 | ||
244 | // At this point | |
245 | // - `parent` is the parrent of the original expression | |
246 | // - `dummy_expr` is the original expression wrapped in the operator we want (`*`/`.*`) | |
247 | // - `expr` is the clone of the original expression (with `dummy_expr` as the parent) | |
248 | ||
249 | let needs_outer_parens = parent.map_or(false, |p| dummy_expr.needs_parens_in(p)); | |
250 | let needs_inner_parens = expr.needs_parens_in(dummy_expr.syntax().clone()); | |
251 | ||
252 | (needs_outer_parens, needs_inner_parens) | |
253 | } | |
254 | ||
255 | #[cfg(test)] | |
256 | mod tests { | |
257 | use crate::{ | |
258 | inlay_hints::tests::{check_with_config, DISABLED_CONFIG}, | |
259 | AdjustmentHints, AdjustmentHintsMode, InlayHintsConfig, | |
260 | }; | |
261 | ||
262 | #[test] | |
263 | fn adjustment_hints() { | |
264 | check_with_config( | |
265 | InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, | |
266 | r#" | |
353b0b11 | 267 | //- minicore: coerce_unsized, fn, eq |
9c376795 FG |
268 | fn main() { |
269 | let _: u32 = loop {}; | |
270 | //^^^^^^^<never-to-any> | |
271 | let _: &u32 = &mut 0; | |
272 | //^^^^^^& | |
273 | //^^^^^^* | |
274 | let _: &mut u32 = &mut 0; | |
275 | //^^^^^^&mut $ | |
276 | //^^^^^^* | |
277 | let _: *const u32 = &mut 0; | |
278 | //^^^^^^&raw const $ | |
279 | //^^^^^^* | |
280 | let _: *mut u32 = &mut 0; | |
281 | //^^^^^^&raw mut $ | |
282 | //^^^^^^* | |
283 | let _: fn() = main; | |
284 | //^^^^<fn-item-to-fn-pointer> | |
285 | let _: unsafe fn() = main; | |
286 | //^^^^<safe-fn-pointer-to-unsafe-fn-pointer> | |
287 | //^^^^<fn-item-to-fn-pointer> | |
288 | let _: unsafe fn() = main as fn(); | |
289 | //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer> | |
290 | //^^^^^^^^^^^^( | |
291 | //^^^^^^^^^^^^) | |
292 | let _: fn() = || {}; | |
293 | //^^^^^<closure-to-fn-pointer> | |
294 | let _: unsafe fn() = || {}; | |
295 | //^^^^^<closure-to-unsafe-fn-pointer> | |
296 | let _: *const u32 = &mut 0u32 as *mut u32; | |
297 | //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr> | |
298 | //^^^^^^^^^^^^^^^^^^^^^( | |
299 | //^^^^^^^^^^^^^^^^^^^^^) | |
300 | let _: &mut [_] = &mut [0; 0]; | |
301 | //^^^^^^^^^^^<unsize> | |
302 | //^^^^^^^^^^^&mut $ | |
303 | //^^^^^^^^^^^* | |
304 | ||
305 | Struct.consume(); | |
306 | Struct.by_ref(); | |
307 | //^^^^^^( | |
308 | //^^^^^^& | |
309 | //^^^^^^) | |
310 | Struct.by_ref_mut(); | |
311 | //^^^^^^( | |
312 | //^^^^^^&mut $ | |
313 | //^^^^^^) | |
314 | ||
315 | (&Struct).consume(); | |
316 | //^^^^^^^* | |
317 | (&Struct).by_ref(); | |
318 | ||
319 | (&mut Struct).consume(); | |
320 | //^^^^^^^^^^^* | |
321 | (&mut Struct).by_ref(); | |
322 | //^^^^^^^^^^^& | |
323 | //^^^^^^^^^^^* | |
324 | (&mut Struct).by_ref_mut(); | |
325 | ||
326 | // Check that block-like expressions don't duplicate hints | |
327 | let _: &mut [u32] = (&mut []); | |
328 | //^^^^^^^<unsize> | |
329 | //^^^^^^^&mut $ | |
330 | //^^^^^^^* | |
331 | let _: &mut [u32] = { &mut [] }; | |
332 | //^^^^^^^<unsize> | |
333 | //^^^^^^^&mut $ | |
334 | //^^^^^^^* | |
335 | let _: &mut [u32] = unsafe { &mut [] }; | |
336 | //^^^^^^^<unsize> | |
337 | //^^^^^^^&mut $ | |
338 | //^^^^^^^* | |
339 | let _: &mut [u32] = if true { | |
340 | &mut [] | |
341 | //^^^^^^^<unsize> | |
342 | //^^^^^^^&mut $ | |
343 | //^^^^^^^* | |
344 | } else { | |
345 | loop {} | |
346 | //^^^^^^^<never-to-any> | |
347 | }; | |
353b0b11 | 348 | let _: &mut [u32] = match () { () => &mut [] }; |
9c376795 FG |
349 | //^^^^^^^<unsize> |
350 | //^^^^^^^&mut $ | |
351 | //^^^^^^^* | |
352 | ||
353 | let _: &mut dyn Fn() = &mut || (); | |
354 | //^^^^^^^^^^<unsize> | |
355 | //^^^^^^^^^^&mut $ | |
356 | //^^^^^^^^^^* | |
353b0b11 FG |
357 | () == (); |
358 | // ^^& | |
359 | // ^^& | |
360 | (()) == {()}; | |
361 | // ^^& | |
362 | // ^^^^& | |
9c376795 FG |
363 | } |
364 | ||
365 | #[derive(Copy, Clone)] | |
366 | struct Struct; | |
367 | impl Struct { | |
368 | fn consume(self) {} | |
369 | fn by_ref(&self) {} | |
370 | fn by_ref_mut(&mut self) {} | |
371 | } | |
372 | "#, | |
373 | ) | |
374 | } | |
375 | ||
376 | #[test] | |
377 | fn adjustment_hints_postfix() { | |
378 | check_with_config( | |
379 | InlayHintsConfig { | |
380 | adjustment_hints: AdjustmentHints::Always, | |
381 | adjustment_hints_mode: AdjustmentHintsMode::Postfix, | |
382 | ..DISABLED_CONFIG | |
383 | }, | |
384 | r#" | |
353b0b11 | 385 | //- minicore: coerce_unsized, fn, eq |
9c376795 FG |
386 | fn main() { |
387 | ||
388 | Struct.consume(); | |
389 | Struct.by_ref(); | |
390 | //^^^^^^.& | |
391 | Struct.by_ref_mut(); | |
392 | //^^^^^^.&mut | |
393 | ||
394 | (&Struct).consume(); | |
395 | //^^^^^^^( | |
396 | //^^^^^^^) | |
397 | //^^^^^^^.* | |
398 | (&Struct).by_ref(); | |
399 | ||
400 | (&mut Struct).consume(); | |
401 | //^^^^^^^^^^^( | |
402 | //^^^^^^^^^^^) | |
403 | //^^^^^^^^^^^.* | |
404 | (&mut Struct).by_ref(); | |
405 | //^^^^^^^^^^^( | |
406 | //^^^^^^^^^^^) | |
407 | //^^^^^^^^^^^.* | |
408 | //^^^^^^^^^^^.& | |
409 | (&mut Struct).by_ref_mut(); | |
410 | ||
411 | // Check that block-like expressions don't duplicate hints | |
412 | let _: &mut [u32] = (&mut []); | |
413 | //^^^^^^^( | |
414 | //^^^^^^^) | |
415 | //^^^^^^^.* | |
416 | //^^^^^^^.&mut | |
417 | //^^^^^^^.<unsize> | |
418 | let _: &mut [u32] = { &mut [] }; | |
419 | //^^^^^^^( | |
420 | //^^^^^^^) | |
421 | //^^^^^^^.* | |
422 | //^^^^^^^.&mut | |
423 | //^^^^^^^.<unsize> | |
424 | let _: &mut [u32] = unsafe { &mut [] }; | |
425 | //^^^^^^^( | |
426 | //^^^^^^^) | |
427 | //^^^^^^^.* | |
428 | //^^^^^^^.&mut | |
429 | //^^^^^^^.<unsize> | |
430 | let _: &mut [u32] = if true { | |
431 | &mut [] | |
432 | //^^^^^^^( | |
433 | //^^^^^^^) | |
434 | //^^^^^^^.* | |
435 | //^^^^^^^.&mut | |
436 | //^^^^^^^.<unsize> | |
437 | } else { | |
438 | loop {} | |
439 | //^^^^^^^.<never-to-any> | |
440 | }; | |
353b0b11 | 441 | let _: &mut [u32] = match () { () => &mut [] }; |
9c376795 FG |
442 | //^^^^^^^( |
443 | //^^^^^^^) | |
444 | //^^^^^^^.* | |
445 | //^^^^^^^.&mut | |
446 | //^^^^^^^.<unsize> | |
447 | ||
448 | let _: &mut dyn Fn() = &mut || (); | |
449 | //^^^^^^^^^^( | |
450 | //^^^^^^^^^^) | |
451 | //^^^^^^^^^^.* | |
452 | //^^^^^^^^^^.&mut | |
453 | //^^^^^^^^^^.<unsize> | |
353b0b11 FG |
454 | () == (); |
455 | // ^^.& | |
456 | // ^^.& | |
457 | (()) == {()}; | |
458 | // ^^.& | |
459 | // ^^^^.& | |
9c376795 FG |
460 | } |
461 | ||
462 | #[derive(Copy, Clone)] | |
463 | struct Struct; | |
464 | impl Struct { | |
465 | fn consume(self) {} | |
466 | fn by_ref(&self) {} | |
467 | fn by_ref_mut(&mut self) {} | |
468 | } | |
469 | "#, | |
470 | ); | |
471 | } | |
472 | ||
473 | #[test] | |
474 | fn adjustment_hints_prefer_prefix() { | |
475 | check_with_config( | |
476 | InlayHintsConfig { | |
477 | adjustment_hints: AdjustmentHints::Always, | |
478 | adjustment_hints_mode: AdjustmentHintsMode::PreferPrefix, | |
479 | ..DISABLED_CONFIG | |
480 | }, | |
481 | r#" | |
482 | fn main() { | |
483 | let _: u32 = loop {}; | |
484 | //^^^^^^^<never-to-any> | |
485 | ||
486 | Struct.by_ref(); | |
487 | //^^^^^^.& | |
488 | ||
489 | let (): () = return (); | |
490 | //^^^^^^^^^<never-to-any> | |
491 | ||
492 | struct Struct; | |
493 | impl Struct { fn by_ref(&self) {} } | |
494 | } | |
495 | "#, | |
496 | ) | |
497 | } | |
498 | ||
499 | #[test] | |
500 | fn adjustment_hints_prefer_postfix() { | |
501 | check_with_config( | |
502 | InlayHintsConfig { | |
503 | adjustment_hints: AdjustmentHints::Always, | |
504 | adjustment_hints_mode: AdjustmentHintsMode::PreferPostfix, | |
505 | ..DISABLED_CONFIG | |
506 | }, | |
507 | r#" | |
508 | fn main() { | |
509 | let _: u32 = loop {}; | |
510 | //^^^^^^^.<never-to-any> | |
511 | ||
512 | Struct.by_ref(); | |
513 | //^^^^^^.& | |
514 | ||
515 | let (): () = return (); | |
516 | //^^^^^^^^^<never-to-any> | |
517 | ||
518 | struct Struct; | |
519 | impl Struct { fn by_ref(&self) {} } | |
520 | } | |
521 | "#, | |
522 | ) | |
523 | } | |
524 | ||
525 | #[test] | |
526 | fn never_to_never_is_never_shown() { | |
353b0b11 | 527 | cov_mark::check!(same_type_adjustment); |
9c376795 FG |
528 | check_with_config( |
529 | InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, | |
530 | r#" | |
531 | fn never() -> ! { | |
532 | return loop {}; | |
533 | } | |
534 | ||
535 | fn or_else() { | |
536 | let () = () else { return }; | |
537 | } | |
538 | "#, | |
539 | ) | |
540 | } | |
541 | ||
542 | #[test] | |
543 | fn adjustment_hints_unsafe_only() { | |
544 | check_with_config( | |
545 | InlayHintsConfig { | |
546 | adjustment_hints: AdjustmentHints::Always, | |
547 | adjustment_hints_hide_outside_unsafe: true, | |
548 | ..DISABLED_CONFIG | |
549 | }, | |
550 | r#" | |
551 | unsafe fn enabled() { | |
552 | f(&&()); | |
553 | //^^^^& | |
554 | //^^^^* | |
555 | //^^^^* | |
556 | } | |
557 | ||
558 | fn disabled() { | |
559 | f(&&()); | |
560 | } | |
561 | ||
562 | fn mixed() { | |
563 | f(&&()); | |
564 | ||
565 | unsafe { | |
566 | f(&&()); | |
567 | //^^^^& | |
568 | //^^^^* | |
569 | //^^^^* | |
570 | } | |
571 | } | |
572 | ||
573 | const _: () = { | |
574 | f(&&()); | |
575 | ||
576 | unsafe { | |
577 | f(&&()); | |
578 | //^^^^& | |
579 | //^^^^* | |
580 | //^^^^* | |
581 | } | |
582 | }; | |
583 | ||
584 | static STATIC: () = { | |
585 | f(&&()); | |
586 | ||
587 | unsafe { | |
588 | f(&&()); | |
589 | //^^^^& | |
590 | //^^^^* | |
591 | //^^^^* | |
592 | } | |
593 | }; | |
594 | ||
595 | enum E { | |
596 | Disable = { f(&&()); 0 }, | |
597 | Enable = unsafe { f(&&()); 1 }, | |
598 | //^^^^& | |
599 | //^^^^* | |
600 | //^^^^* | |
601 | } | |
602 | ||
603 | const fn f(_: &()) {} | |
604 | "#, | |
605 | ) | |
606 | } | |
607 | ||
608 | #[test] | |
609 | fn adjustment_hints_unsafe_only_with_item() { | |
610 | check_with_config( | |
611 | InlayHintsConfig { | |
612 | adjustment_hints: AdjustmentHints::Always, | |
613 | adjustment_hints_hide_outside_unsafe: true, | |
614 | ..DISABLED_CONFIG | |
615 | }, | |
616 | r#" | |
617 | fn a() { | |
618 | struct Struct; | |
619 | impl Struct { | |
620 | fn by_ref(&self) {} | |
621 | } | |
622 | ||
623 | _ = Struct.by_ref(); | |
624 | ||
625 | _ = unsafe { Struct.by_ref() }; | |
626 | //^^^^^^( | |
627 | //^^^^^^& | |
628 | //^^^^^^) | |
629 | } | |
630 | "#, | |
631 | ); | |
632 | } | |
633 | ||
634 | #[test] | |
353b0b11 | 635 | fn let_stmt_explicit_ty() { |
9c376795 FG |
636 | check_with_config( |
637 | InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, | |
638 | r#" | |
639 | fn main() { | |
9c376795 | 640 | let () = return; |
353b0b11 | 641 | //^^^^^^<never-to-any> |
9c376795 FG |
642 | let (): () = return; |
643 | //^^^^^^<never-to-any> | |
644 | } | |
645 | "#, | |
646 | ) | |
647 | } | |
648 | } |