4
4
use crate :: source:: { snippet, snippet_opt, snippet_with_applicability, snippet_with_context} ;
5
5
use crate :: ty:: expr_sig;
6
6
use crate :: { get_parent_expr_for_hir, higher} ;
7
- use rustc_ast:: ast;
8
7
use rustc_ast:: util:: parser:: AssocOp ;
8
+ use rustc_ast:: { UnOp , ast} ;
9
9
use rustc_data_structures:: fx:: FxHashSet ;
10
10
use rustc_errors:: Applicability ;
11
11
use rustc_hir:: { self as hir, Closure , ExprKind , HirId , MutTy , Node , TyKind } ;
@@ -29,6 +29,11 @@ pub enum Sugg<'a> {
29
29
/// A binary operator expression, including `as`-casts and explicit type
30
30
/// coercion.
31
31
BinOp ( AssocOp , Cow < ' a , str > , Cow < ' a , str > ) ,
32
+ /// A unary operator expression. This is used to sometimes represent `!`
33
+ /// or `-`, but only if the type with and without the operator is kept identical.
34
+ /// It means that doubling the operator can be used to remove it instead, in
35
+ /// order to provide better suggestions.
36
+ UnOp ( UnOp , Box < Sugg < ' a > > ) ,
32
37
}
33
38
34
39
/// Literal constant `0`, for convenience.
@@ -40,9 +45,10 @@ pub const EMPTY: Sugg<'static> = Sugg::NonParen(Cow::Borrowed(""));
40
45
41
46
impl Display for Sugg < ' _ > {
42
47
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> Result < ( ) , fmt:: Error > {
43
- match * self {
44
- Sugg :: NonParen ( ref s) | Sugg :: MaybeParen ( ref s) => s. fmt ( f) ,
45
- Sugg :: BinOp ( op, ref lhs, ref rhs) => binop_to_string ( op, lhs, rhs) . fmt ( f) ,
48
+ match self {
49
+ Sugg :: NonParen ( s) | Sugg :: MaybeParen ( s) => s. fmt ( f) ,
50
+ Sugg :: BinOp ( op, lhs, rhs) => binop_to_string ( * op, lhs, rhs) . fmt ( f) ,
51
+ Sugg :: UnOp ( op, expr) => write ! ( f, "{}{}" , op. as_str( ) , expr. clone( ) . maybe_inner_paren( * op) ) ,
46
52
}
47
53
}
48
54
}
@@ -100,9 +106,19 @@ impl<'a> Sugg<'a> {
100
106
applicability : & mut Applicability ,
101
107
) -> Self {
102
108
if expr. span . ctxt ( ) == ctxt {
103
- Self :: hir_from_snippet ( expr, |span| {
104
- snippet_with_context ( cx, span, ctxt, default, applicability) . 0
105
- } )
109
+ if let ExprKind :: Unary ( op, inner) = expr. kind
110
+ && matches ! ( op, UnOp :: Neg | UnOp :: Not )
111
+ && cx. typeck_results ( ) . expr_ty ( expr) == cx. typeck_results ( ) . expr_ty ( inner)
112
+ {
113
+ Sugg :: UnOp (
114
+ op,
115
+ Box :: new ( Self :: hir_with_context ( cx, inner, ctxt, default, applicability) ) ,
116
+ )
117
+ } else {
118
+ Self :: hir_from_snippet ( expr, |span| {
119
+ snippet_with_context ( cx, span, ctxt, default, applicability) . 0
120
+ } )
121
+ }
106
122
} else {
107
123
let ( snip, _) = snippet_with_context ( cx, expr. span , ctxt, default, applicability) ;
108
124
Sugg :: NonParen ( snip)
@@ -281,8 +297,9 @@ impl<'a> Sugg<'a> {
281
297
}
282
298
283
299
/// Convenience method to create the `*<expr>` suggestion.
284
- pub fn deref ( self ) -> Sugg < ' static > {
285
- make_unop ( "*" , self )
300
+ #[ must_use]
301
+ pub fn deref ( self ) -> Self {
302
+ Sugg :: UnOp ( UnOp :: Deref , Box :: new ( self ) )
286
303
}
287
304
288
305
/// Convenience method to create the `&*<expr>` suggestion. Currently this
@@ -341,13 +358,24 @@ impl<'a> Sugg<'a> {
341
358
let sugg = binop_to_string ( op, & lhs, & rhs) ;
342
359
Sugg :: NonParen ( format ! ( "({sugg})" ) . into ( ) )
343
360
} ,
361
+ Sugg :: UnOp ( op, expr) => Sugg :: NonParen ( format ! ( "({}{})" , op. as_str( ) , expr. maybe_inner_paren( op) ) . into ( ) ) ,
344
362
}
345
363
}
346
364
347
365
pub fn into_string ( self ) -> String {
348
366
match self {
349
367
Sugg :: NonParen ( p) | Sugg :: MaybeParen ( p) => p. into_owned ( ) ,
350
368
Sugg :: BinOp ( b, l, r) => binop_to_string ( b, & l, & r) ,
369
+ Sugg :: UnOp ( op, expr) => format ! ( "{}{}" , op. as_str( ) , expr. maybe_inner_paren( op) ) ,
370
+ }
371
+ }
372
+
373
+ /// Call `maybe_paren` on `self` if it doesn't start with the same unary operator as `op`,
374
+ /// don't touch it otherwise.
375
+ fn maybe_inner_paren ( self , op : UnOp ) -> Self {
376
+ match & self {
377
+ Sugg :: UnOp ( o, _) if * o == op => self ,
378
+ _ => self . maybe_paren ( ) ,
351
379
}
352
380
}
353
381
}
@@ -430,10 +458,11 @@ impl Sub for &Sugg<'_> {
430
458
forward_binop_impls_to_ref ! ( impl Add , add for Sugg <' _>, type Output = Sugg <' static >) ;
431
459
forward_binop_impls_to_ref ! ( impl Sub , sub for Sugg <' _>, type Output = Sugg <' static >) ;
432
460
433
- impl Neg for Sugg < ' _ > {
434
- type Output = Sugg < ' static > ;
435
- fn neg ( self ) -> Sugg < ' static > {
436
- match & self {
461
+ impl < ' a > Neg for Sugg < ' a > {
462
+ type Output = Sugg < ' a > ;
463
+ fn neg ( self ) -> Self :: Output {
464
+ match self {
465
+ Self :: UnOp ( UnOp :: Neg , sugg) => * sugg,
437
466
Self :: BinOp ( AssocOp :: Cast , ..) => Sugg :: MaybeParen ( format ! ( "-({self})" ) . into ( ) ) ,
438
467
_ => make_unop ( "-" , self ) ,
439
468
}
@@ -446,19 +475,21 @@ impl<'a> Not for Sugg<'a> {
446
475
use AssocOp :: Binary ;
447
476
use ast:: BinOpKind :: { Eq , Ge , Gt , Le , Lt , Ne } ;
448
477
449
- if let Sugg :: BinOp ( op, lhs, rhs) = self {
450
- let to_op = match op {
451
- Binary ( Eq ) => Binary ( Ne ) ,
452
- Binary ( Ne ) => Binary ( Eq ) ,
453
- Binary ( Lt ) => Binary ( Ge ) ,
454
- Binary ( Ge ) => Binary ( Lt ) ,
455
- Binary ( Gt ) => Binary ( Le ) ,
456
- Binary ( Le ) => Binary ( Gt ) ,
457
- _ => return make_unop ( "!" , Sugg :: BinOp ( op, lhs, rhs) ) ,
458
- } ;
459
- Sugg :: BinOp ( to_op, lhs, rhs)
460
- } else {
461
- make_unop ( "!" , self )
478
+ match self {
479
+ Sugg :: BinOp ( op, lhs, rhs) => {
480
+ let to_op = match op {
481
+ Binary ( Eq ) => Binary ( Ne ) ,
482
+ Binary ( Ne ) => Binary ( Eq ) ,
483
+ Binary ( Lt ) => Binary ( Ge ) ,
484
+ Binary ( Ge ) => Binary ( Lt ) ,
485
+ Binary ( Gt ) => Binary ( Le ) ,
486
+ Binary ( Le ) => Binary ( Gt ) ,
487
+ _ => return make_unop ( "!" , Sugg :: BinOp ( op, lhs, rhs) ) ,
488
+ } ;
489
+ Sugg :: BinOp ( to_op, lhs, rhs)
490
+ } ,
491
+ Sugg :: UnOp ( UnOp :: Not , expr) => * expr,
492
+ _ => make_unop ( "!" , self ) ,
462
493
}
463
494
}
464
495
}
0 commit comments