5
5
//! ```
6
6
use hir:: { Adjust , AutoBorrow , Mutability , OverloadedDeref , PointerCast , Safety , Semantics } ;
7
7
use ide_db:: RootDatabase ;
8
- use syntax:: ast:: { self , AstNode } ;
8
+
9
+ use syntax:: {
10
+ ast:: { self , make, AstNode } ,
11
+ ted,
12
+ } ;
9
13
10
14
use crate :: { AdjustmentHints , InlayHint , InlayHintsConfig , InlayKind } ;
11
15
@@ -32,36 +36,47 @@ pub(super) fn hints(
32
36
return None ;
33
37
}
34
38
35
- let parent = expr. syntax ( ) . parent ( ) . and_then ( ast:: Expr :: cast) ;
36
39
let descended = sema. descend_node_into_attributes ( expr. clone ( ) ) . pop ( ) ;
37
40
let desc_expr = descended. as_ref ( ) . unwrap_or ( expr) ;
38
41
let adjustments = sema. expr_adjustments ( desc_expr) . filter ( |it| !it. is_empty ( ) ) ?;
39
- let needs_parens = match parent {
40
- Some ( parent) => {
41
- match parent {
42
- ast:: Expr :: AwaitExpr ( _)
43
- | ast:: Expr :: CallExpr ( _)
44
- | ast:: Expr :: CastExpr ( _)
45
- | ast:: Expr :: FieldExpr ( _)
46
- | ast:: Expr :: MethodCallExpr ( _)
47
- | ast:: Expr :: TryExpr ( _) => true ,
48
- // FIXME: shorthands need special casing, though not sure if adjustments are even valid there
49
- ast:: Expr :: RecordExpr ( _) => false ,
50
- ast:: Expr :: IndexExpr ( index) => index. base ( ) . as_ref ( ) == Some ( expr) ,
51
- _ => false ,
52
- }
53
- }
54
- None => false ,
55
- } ;
56
- if needs_parens {
42
+
43
+ let ( needs_outer_parens, needs_inner_parens) =
44
+ needs_parens_for_adjustment_hints ( expr, config. adjustment_hints_postfix ) ;
45
+
46
+ if needs_outer_parens {
57
47
acc. push ( InlayHint {
58
48
range : expr. syntax ( ) . text_range ( ) ,
59
49
kind : InlayKind :: OpeningParenthesis ,
60
50
label : "(" . into ( ) ,
61
51
tooltip : None ,
62
52
} ) ;
63
53
}
64
- for adjustment in adjustments. into_iter ( ) . rev ( ) {
54
+
55
+ if config. adjustment_hints_postfix && needs_inner_parens {
56
+ acc. push ( InlayHint {
57
+ range : expr. syntax ( ) . text_range ( ) ,
58
+ kind : InlayKind :: OpeningParenthesis ,
59
+ label : "(" . into ( ) ,
60
+ tooltip : None ,
61
+ } ) ;
62
+ acc. push ( InlayHint {
63
+ range : expr. syntax ( ) . text_range ( ) ,
64
+ kind : InlayKind :: ClosingParenthesis ,
65
+ label : ")" . into ( ) ,
66
+ tooltip : None ,
67
+ } ) ;
68
+ }
69
+
70
+ let ( mut tmp0, mut tmp1) ;
71
+ let iter: & mut dyn Iterator < Item = _ > = if config. adjustment_hints_postfix {
72
+ tmp0 = adjustments. into_iter ( ) ;
73
+ & mut tmp0
74
+ } else {
75
+ tmp1 = adjustments. into_iter ( ) . rev ( ) ;
76
+ & mut tmp1
77
+ } ;
78
+
79
+ for adjustment in iter {
65
80
if adjustment. source == adjustment. target {
66
81
continue ;
67
82
}
@@ -97,12 +112,34 @@ pub(super) fn hints(
97
112
} ;
98
113
acc. push ( InlayHint {
99
114
range : expr. syntax ( ) . text_range ( ) ,
100
- kind : InlayKind :: AdjustmentHint ,
101
- label : text. into ( ) ,
115
+ kind : if config. adjustment_hints_postfix {
116
+ InlayKind :: AdjustmentHintPostfix
117
+ } else {
118
+ InlayKind :: AdjustmentHint
119
+ } ,
120
+ label : if config. adjustment_hints_postfix {
121
+ format ! ( ".{}" , text. trim_end( ) ) . into ( )
122
+ } else {
123
+ text. into ( )
124
+ } ,
102
125
tooltip : None ,
103
126
} ) ;
104
127
}
105
- if needs_parens {
128
+ if !config. adjustment_hints_postfix && needs_inner_parens {
129
+ acc. push ( InlayHint {
130
+ range : expr. syntax ( ) . text_range ( ) ,
131
+ kind : InlayKind :: OpeningParenthesis ,
132
+ label : "(" . into ( ) ,
133
+ tooltip : None ,
134
+ } ) ;
135
+ acc. push ( InlayHint {
136
+ range : expr. syntax ( ) . text_range ( ) ,
137
+ kind : InlayKind :: ClosingParenthesis ,
138
+ label : ")" . into ( ) ,
139
+ tooltip : None ,
140
+ } ) ;
141
+ }
142
+ if needs_outer_parens {
106
143
acc. push ( InlayHint {
107
144
range : expr. syntax ( ) . text_range ( ) ,
108
145
kind : InlayKind :: ClosingParenthesis ,
@@ -113,6 +150,69 @@ pub(super) fn hints(
113
150
Some ( ( ) )
114
151
}
115
152
153
+ /// Returns whatever we need to add paretheses on the inside and/or outside of `expr`,
154
+ /// if we are going to add (`postfix`) adjustments hints to it.
155
+ fn needs_parens_for_adjustment_hints ( expr : & ast:: Expr , postfix : bool ) -> ( bool , bool ) {
156
+ // This is a very miserable pile of hacks...
157
+ //
158
+ // `Expr::needs_parens_in` requires that the expression is the child of the other expression,
159
+ // that is supposed to be its parent.
160
+ //
161
+ // But we want to check what would happen if we add `*`/`.*` to the inner expression.
162
+ // To check for inner we need `` expr.needs_parens_in(`*expr`) ``,
163
+ // to check for outer we need `` `*expr`.needs_parens_in(parent) ``,
164
+ // where "expr" is the `expr` parameter, `*expr` is the editted `expr`,
165
+ // and "parent" is the parent of the original expression...
166
+ //
167
+ // For this we utilize mutable mutable trees, which is a HACK, but it works.
168
+
169
+ // Make `&expr`/`expr?`
170
+ let dummy_expr = {
171
+ // `make::*` function go through a string, so they parse wrongly.
172
+ // for example `` make::expr_try(`|| a`) `` would result in a
173
+ // `|| (a?)` and not `(|| a)?`.
174
+ //
175
+ // Thus we need dummy parens to preserve the relationship we want.
176
+ // The parens are then simply ignored by the following code.
177
+ let dummy_paren = make:: expr_paren ( expr. clone ( ) ) ;
178
+ if postfix {
179
+ make:: expr_try ( dummy_paren)
180
+ } else {
181
+ make:: expr_ref ( dummy_paren, false )
182
+ }
183
+ } ;
184
+
185
+ // Do the dark mutable tree magic.
186
+ // This essentially makes `dummy_expr` and `expr` switch places (families),
187
+ // so that `expr`'s parent is not `dummy_expr`'s parent.
188
+ let dummy_expr = dummy_expr. clone_for_update ( ) ;
189
+ let expr = expr. clone_for_update ( ) ;
190
+ ted:: replace ( expr. syntax ( ) , dummy_expr. syntax ( ) ) ;
191
+
192
+ let parent = dummy_expr. syntax ( ) . parent ( ) ;
193
+ let expr = if postfix {
194
+ let ast:: Expr :: TryExpr ( e) = & dummy_expr else { unreachable ! ( ) } ;
195
+ let Some ( ast:: Expr :: ParenExpr ( e) ) = e. expr ( ) else { unreachable ! ( ) } ;
196
+
197
+ e. expr ( ) . unwrap ( )
198
+ } else {
199
+ let ast:: Expr :: RefExpr ( e) = & dummy_expr else { unreachable ! ( ) } ;
200
+ let Some ( ast:: Expr :: ParenExpr ( e) ) = e. expr ( ) else { unreachable ! ( ) } ;
201
+
202
+ e. expr ( ) . unwrap ( )
203
+ } ;
204
+
205
+ // At this point
206
+ // - `parent` is the parrent of the original expression
207
+ // - `dummy_expr` is the original expression wrapped in the operator we want (`*`/`.*`)
208
+ // - `expr` is the clone of the original expression (with `dummy_expr` as the parent)
209
+
210
+ let needs_outer_parens = parent. map_or ( false , |p| dummy_expr. needs_parens_in ( p) ) ;
211
+ let needs_inner_parens = expr. needs_parens_in ( dummy_expr. syntax ( ) . clone ( ) ) ;
212
+
213
+ ( needs_outer_parens, needs_inner_parens)
214
+ }
215
+
116
216
#[ cfg( test) ]
117
217
mod tests {
118
218
use crate :: {
@@ -125,7 +225,7 @@ mod tests {
125
225
check_with_config (
126
226
InlayHintsConfig { adjustment_hints : AdjustmentHints :: Always , ..DISABLED_CONFIG } ,
127
227
r#"
128
- //- minicore: coerce_unsized
228
+ //- minicore: coerce_unsized, fn
129
229
fn main() {
130
230
let _: u32 = loop {};
131
231
//^^^^^^^<never-to-any>
@@ -148,12 +248,16 @@ fn main() {
148
248
//^^^^<fn-item-to-fn-pointer>
149
249
let _: unsafe fn() = main as fn();
150
250
//^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
251
+ //^^^^^^^^^^^^(
252
+ //^^^^^^^^^^^^)
151
253
let _: fn() = || {};
152
254
//^^^^^<closure-to-fn-pointer>
153
255
let _: unsafe fn() = || {};
154
256
//^^^^^<closure-to-unsafe-fn-pointer>
155
257
let _: *const u32 = &mut 0u32 as *mut u32;
156
258
//^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
259
+ //^^^^^^^^^^^^^^^^^^^^^(
260
+ //^^^^^^^^^^^^^^^^^^^^^)
157
261
let _: &mut [_] = &mut [0; 0];
158
262
//^^^^^^^^^^^<unsize>
159
263
//^^^^^^^^^^^&mut $
@@ -206,6 +310,11 @@ fn main() {
206
310
//^^^^^^^<unsize>
207
311
//^^^^^^^&mut $
208
312
//^^^^^^^*
313
+
314
+ let _: &mut dyn Fn() = &mut || ();
315
+ //^^^^^^^^^^<unsize>
316
+ //^^^^^^^^^^&mut $
317
+ //^^^^^^^^^^*
209
318
}
210
319
211
320
#[derive(Copy, Clone)]
@@ -215,12 +324,101 @@ impl Struct {
215
324
fn by_ref(&self) {}
216
325
fn by_ref_mut(&mut self) {}
217
326
}
218
- trait Trait {}
219
- impl Trait for Struct {}
220
327
"# ,
221
328
)
222
329
}
223
330
331
+ #[ test]
332
+ fn adjustment_hints_postfix ( ) {
333
+ check_with_config (
334
+ InlayHintsConfig {
335
+ adjustment_hints : AdjustmentHints :: Always ,
336
+ adjustment_hints_postfix : true ,
337
+ ..DISABLED_CONFIG
338
+ } ,
339
+ r#"
340
+ //- minicore: coerce_unsized, fn
341
+ fn main() {
342
+
343
+ Struct.consume();
344
+ Struct.by_ref();
345
+ //^^^^^^.&
346
+ Struct.by_ref_mut();
347
+ //^^^^^^.&mut
348
+
349
+ (&Struct).consume();
350
+ //^^^^^^^(
351
+ //^^^^^^^)
352
+ //^^^^^^^.*
353
+ (&Struct).by_ref();
354
+
355
+ (&mut Struct).consume();
356
+ //^^^^^^^^^^^(
357
+ //^^^^^^^^^^^)
358
+ //^^^^^^^^^^^.*
359
+ (&mut Struct).by_ref();
360
+ //^^^^^^^^^^^(
361
+ //^^^^^^^^^^^)
362
+ //^^^^^^^^^^^.*
363
+ //^^^^^^^^^^^.&
364
+ (&mut Struct).by_ref_mut();
365
+
366
+ // Check that block-like expressions don't duplicate hints
367
+ let _: &mut [u32] = (&mut []);
368
+ //^^^^^^^(
369
+ //^^^^^^^)
370
+ //^^^^^^^.*
371
+ //^^^^^^^.&mut
372
+ //^^^^^^^.<unsize>
373
+ let _: &mut [u32] = { &mut [] };
374
+ //^^^^^^^(
375
+ //^^^^^^^)
376
+ //^^^^^^^.*
377
+ //^^^^^^^.&mut
378
+ //^^^^^^^.<unsize>
379
+ let _: &mut [u32] = unsafe { &mut [] };
380
+ //^^^^^^^(
381
+ //^^^^^^^)
382
+ //^^^^^^^.*
383
+ //^^^^^^^.&mut
384
+ //^^^^^^^.<unsize>
385
+ let _: &mut [u32] = if true {
386
+ &mut []
387
+ //^^^^^^^(
388
+ //^^^^^^^)
389
+ //^^^^^^^.*
390
+ //^^^^^^^.&mut
391
+ //^^^^^^^.<unsize>
392
+ } else {
393
+ loop {}
394
+ //^^^^^^^.<never-to-any>
395
+ };
396
+ let _: &mut [u32] = match () { () => &mut [] }
397
+ //^^^^^^^(
398
+ //^^^^^^^)
399
+ //^^^^^^^.*
400
+ //^^^^^^^.&mut
401
+ //^^^^^^^.<unsize>
402
+
403
+ let _: &mut dyn Fn() = &mut || ();
404
+ //^^^^^^^^^^(
405
+ //^^^^^^^^^^)
406
+ //^^^^^^^^^^.*
407
+ //^^^^^^^^^^.&mut
408
+ //^^^^^^^^^^.<unsize>
409
+ }
410
+
411
+ #[derive(Copy, Clone)]
412
+ struct Struct;
413
+ impl Struct {
414
+ fn consume(self) {}
415
+ fn by_ref(&self) {}
416
+ fn by_ref_mut(&mut self) {}
417
+ }
418
+ "# ,
419
+ ) ;
420
+ }
421
+
224
422
#[ test]
225
423
fn never_to_never_is_never_shown ( ) {
226
424
check_with_config (
0 commit comments