11use clippy_utils:: diagnostics:: span_lint_and_sugg;
2+ use clippy_utils:: get_parent_expr;
23use clippy_utils:: numeric_literal:: NumericLiteral ;
34use clippy_utils:: source:: snippet_opt;
45use if_chain:: if_chain;
@@ -30,8 +31,10 @@ pub(super) fn check<'tcx>(
3031 }
3132 }
3233
34+ let cast_str = snippet_opt ( cx, cast_expr. span ) . unwrap_or_default ( ) ;
35+
3336 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 ;
3538
3639 if_chain ! {
3740 if let LitKind :: Int ( n, _) = lit. node;
@@ -49,58 +52,79 @@ pub(super) fn check<'tcx>(
4952
5053 match lit. node {
5154 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 ;
5357 } ,
5458 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 ;
5664 } ,
57- LitKind :: Int ( _, LitIntType :: Unsuffixed ) | LitKind :: Float ( _, LitFloatType :: Unsuffixed ) => { } ,
5865 LitKind :: Int ( _, LitIntType :: Signed ( _) | LitIntType :: Unsigned ( _) )
5966 | LitKind :: Float ( _, LitFloatType :: Suffixed ( _) )
6067 if cast_from. kind ( ) == cast_to. kind ( ) =>
6168 {
6269 if let Some ( src) = snippet_opt ( cx, cast_expr. span ) {
6370 if let Some ( num_lit) = NumericLiteral :: from_lit_kind ( & src, & lit. node ) {
6471 lint_unnecessary_cast ( cx, expr, num_lit. integer , cast_from, cast_to) ;
72+ return true ;
6573 }
6674 }
6775 } ,
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+ _ => { } ,
8277 }
8378 }
8479
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+
8593 false
8694}
8795
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+ ) {
89103 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}" )
96119 } ;
120+
97121 span_lint_and_sugg (
98122 cx,
99123 UNNECESSARY_CAST ,
100124 expr. span ,
101125 & format ! ( "casting {literal_kind_name} literal to `{cast_to}` is unnecessary" ) ,
102126 "try" ,
103- format ! ( "{}_{cast_to}" , matchless . trim_end_matches ( '.' ) ) ,
127+ sugg ,
104128 Applicability :: MachineApplicable ,
105129 ) ;
106130}
0 commit comments