1
1
use clippy_utils:: diagnostics:: span_lint_and_sugg;
2
+ use clippy_utils:: get_parent_expr;
2
3
use clippy_utils:: numeric_literal:: NumericLiteral ;
3
4
use clippy_utils:: source:: snippet_opt;
4
5
use if_chain:: if_chain;
@@ -30,8 +31,10 @@ pub(super) fn check<'tcx>(
30
31
}
31
32
}
32
33
34
+ let cast_str = snippet_opt ( cx, cast_expr. span ) . unwrap_or_default ( ) ;
35
+
33
36
if let Some ( lit) = get_numeric_literal ( cast_expr) {
34
- let literal_str = snippet_opt ( cx , cast_expr . span ) . unwrap_or_default ( ) ;
37
+ let literal_str = & cast_str ;
35
38
36
39
if_chain ! {
37
40
if let LitKind :: Int ( n, _) = lit. node;
@@ -49,58 +52,79 @@ pub(super) fn check<'tcx>(
49
52
50
53
match lit. node {
51
54
LitKind :: Int ( _, LitIntType :: Unsuffixed ) if cast_to. is_integral ( ) => {
52
- lint_unnecessary_cast ( cx, expr, & literal_str, cast_from, cast_to) ;
55
+ lint_unnecessary_cast ( cx, expr, literal_str, cast_from, cast_to) ;
56
+ return false ;
53
57
} ,
54
58
LitKind :: Float ( _, LitFloatType :: Unsuffixed ) if cast_to. is_floating_point ( ) => {
55
- lint_unnecessary_cast ( cx, expr, & literal_str, cast_from, cast_to) ;
59
+ lint_unnecessary_cast ( cx, expr, literal_str, cast_from, cast_to) ;
60
+ return false ;
61
+ } ,
62
+ LitKind :: Int ( _, LitIntType :: Unsuffixed ) | LitKind :: Float ( _, LitFloatType :: Unsuffixed ) => {
63
+ return false ;
56
64
} ,
57
- LitKind :: Int ( _, LitIntType :: Unsuffixed ) | LitKind :: Float ( _, LitFloatType :: Unsuffixed ) => { } ,
58
65
LitKind :: Int ( _, LitIntType :: Signed ( _) | LitIntType :: Unsigned ( _) )
59
66
| LitKind :: Float ( _, LitFloatType :: Suffixed ( _) )
60
67
if cast_from. kind ( ) == cast_to. kind ( ) =>
61
68
{
62
69
if let Some ( src) = snippet_opt ( cx, cast_expr. span ) {
63
70
if let Some ( num_lit) = NumericLiteral :: from_lit_kind ( & src, & lit. node ) {
64
71
lint_unnecessary_cast ( cx, expr, num_lit. integer , cast_from, cast_to) ;
72
+ return true ;
65
73
}
66
74
}
67
75
} ,
68
- _ => {
69
- if cast_from. kind ( ) == cast_to. kind ( ) && !in_external_macro ( cx. sess ( ) , expr. span ) {
70
- span_lint_and_sugg (
71
- cx,
72
- UNNECESSARY_CAST ,
73
- expr. span ,
74
- & format ! ( "casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)" ) ,
75
- "try" ,
76
- literal_str,
77
- Applicability :: MachineApplicable ,
78
- ) ;
79
- return true ;
80
- }
81
- } ,
76
+ _ => { } ,
82
77
}
83
78
}
84
79
80
+ if cast_from. kind ( ) == cast_to. kind ( ) && !in_external_macro ( cx. sess ( ) , expr. span ) {
81
+ span_lint_and_sugg (
82
+ cx,
83
+ UNNECESSARY_CAST ,
84
+ expr. span ,
85
+ & format ! ( "casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)" ) ,
86
+ "try" ,
87
+ cast_str,
88
+ Applicability :: MachineApplicable ,
89
+ ) ;
90
+ return true ;
91
+ }
92
+
85
93
false
86
94
}
87
95
88
- fn lint_unnecessary_cast ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , literal_str : & str , cast_from : Ty < ' _ > , cast_to : Ty < ' _ > ) {
96
+ fn lint_unnecessary_cast (
97
+ cx : & LateContext < ' _ > ,
98
+ expr : & Expr < ' _ > ,
99
+ raw_literal_str : & str ,
100
+ cast_from : Ty < ' _ > ,
101
+ cast_to : Ty < ' _ > ,
102
+ ) {
89
103
let literal_kind_name = if cast_from. is_integral ( ) { "integer" } else { "float" } ;
90
- let replaced_literal;
91
- let matchless = if literal_str. contains ( [ '(' , ')' ] ) {
92
- replaced_literal = literal_str. replace ( [ '(' , ')' ] , "" ) ;
93
- & replaced_literal
94
- } else {
95
- literal_str
104
+ // first we remove all matches so `-(1)` become `-1`, and remove trailing dots, so `1.` become `1`
105
+ let literal_str = raw_literal_str
106
+ . replace ( [ '(' , ')' ] , "" )
107
+ . trim_end_matches ( '.' )
108
+ . to_string ( ) ;
109
+ // we know need to check if the parent is a method call, to add parenthesis accordingly (eg:
110
+ // (-1).foo() instead of -1.foo())
111
+ let sugg = if let Some ( parent_expr) = get_parent_expr ( cx, expr)
112
+ && let ExprKind :: MethodCall ( ..) = parent_expr. kind
113
+ && literal_str. starts_with ( '-' )
114
+ {
115
+ format ! ( "({literal_str}_{cast_to})" )
116
+
117
+ } else {
118
+ format ! ( "{literal_str}_{cast_to}" )
96
119
} ;
120
+
97
121
span_lint_and_sugg (
98
122
cx,
99
123
UNNECESSARY_CAST ,
100
124
expr. span ,
101
125
& format ! ( "casting {literal_kind_name} literal to `{cast_to}` is unnecessary" ) ,
102
126
"try" ,
103
- format ! ( "{}_{cast_to}" , matchless . trim_end_matches ( '.' ) ) ,
127
+ sugg ,
104
128
Applicability :: MachineApplicable ,
105
129
) ;
106
130
}
0 commit comments