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