@@ -11,7 +11,7 @@ use rustc_hir as hir;
11
11
use rustc_hir:: intravisit:: { walk_body, walk_expr, walk_ty, FnKind , NestedVisitorMap , Visitor } ;
12
12
use rustc_hir:: {
13
13
BinOpKind , Block , Body , Expr , ExprKind , FnDecl , FnRetTy , FnSig , GenericArg , GenericParamKind , HirId , ImplItem ,
14
- ImplItemKind , Item , ItemKind , Lifetime , Local , MatchSource , MutTy , Mutability , Node , QPath , Stmt , StmtKind ,
14
+ ImplItemKind , Item , ItemKind , Lifetime , Lit , Local , MatchSource , MutTy , Mutability , Node , QPath , Stmt , StmtKind ,
15
15
TraitFn , TraitItem , TraitItemKind , TyKind , UnOp ,
16
16
} ;
17
17
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
@@ -1224,7 +1224,8 @@ declare_clippy_lint! {
1224
1224
}
1225
1225
1226
1226
declare_clippy_lint ! {
1227
- /// **What it does:** Checks for casts to the same type.
1227
+ /// **What it does:** Checks for casts to the same type, casts of int literals to integer types
1228
+ /// and casts of float literals to float types.
1228
1229
///
1229
1230
/// **Why is this bad?** It's just unnecessary.
1230
1231
///
@@ -1233,6 +1234,14 @@ declare_clippy_lint! {
1233
1234
/// **Example:**
1234
1235
/// ```rust
1235
1236
/// let _ = 2i32 as i32;
1237
+ /// let _ = 0.5 as f32;
1238
+ /// ```
1239
+ ///
1240
+ /// Better:
1241
+ ///
1242
+ /// ```rust
1243
+ /// let _ = 2_i32;
1244
+ /// let _ = 0.5_f32;
1236
1245
/// ```
1237
1246
pub UNNECESSARY_CAST ,
1238
1247
complexity,
@@ -1598,7 +1607,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
1598
1607
if let ExprKind :: Cast ( ref ex, _) = expr. kind {
1599
1608
let ( cast_from, cast_to) = ( cx. typeck_results ( ) . expr_ty ( ex) , cx. typeck_results ( ) . expr_ty ( expr) ) ;
1600
1609
lint_fn_to_numeric_cast ( cx, expr, ex, cast_from, cast_to) ;
1601
- if let ExprKind :: Lit ( ref lit) = ex. kind {
1610
+ if let Some ( lit) = get_numeric_literal ( ex) {
1611
+ let literal_str = snippet_opt ( cx, ex. span ) . unwrap_or_default ( ) ;
1612
+
1602
1613
if_chain ! {
1603
1614
if let LitKind :: Int ( n, _) = lit. node;
1604
1615
if let Some ( src) = snippet_opt( cx, lit. span) ;
@@ -1608,19 +1619,19 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
1608
1619
let to_nbits = fp_ty_mantissa_nbits( cast_to) ;
1609
1620
if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit. is_decimal( ) ;
1610
1621
then {
1611
- span_lint_and_sugg(
1612
- cx,
1613
- UNNECESSARY_CAST ,
1614
- expr. span,
1615
- & format!( "casting integer literal to `{}` is unnecessary" , cast_to) ,
1616
- "try" ,
1617
- format!( "{}_{}" , n, cast_to) ,
1618
- Applicability :: MachineApplicable ,
1619
- ) ;
1622
+ let literal_str = if is_unary_neg( ex) { format!( "-{}" , num_lit. integer) } else { num_lit. integer. into( ) } ;
1623
+ show_unnecessary_cast( cx, expr, & literal_str, cast_from, cast_to) ;
1620
1624
return ;
1621
1625
}
1622
1626
}
1627
+
1623
1628
match lit. node {
1629
+ LitKind :: Int ( _, LitIntType :: Unsuffixed ) if cast_to. is_integral ( ) => {
1630
+ show_unnecessary_cast ( cx, expr, & literal_str, cast_from, cast_to) ;
1631
+ } ,
1632
+ LitKind :: Float ( _, LitFloatType :: Unsuffixed ) if cast_to. is_floating_point ( ) => {
1633
+ show_unnecessary_cast ( cx, expr, & literal_str, cast_from, cast_to) ;
1634
+ } ,
1624
1635
LitKind :: Int ( _, LitIntType :: Unsuffixed ) | LitKind :: Float ( _, LitFloatType :: Unsuffixed ) => { } ,
1625
1636
_ => {
1626
1637
if cast_from. kind ( ) == cast_to. kind ( ) && !in_external_macro ( cx. sess ( ) , expr. span ) {
@@ -1646,6 +1657,37 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
1646
1657
}
1647
1658
}
1648
1659
1660
+ fn is_unary_neg ( expr : & Expr < ' _ > ) -> bool {
1661
+ matches ! ( expr. kind, ExprKind :: Unary ( UnOp :: UnNeg , _) )
1662
+ }
1663
+
1664
+ fn get_numeric_literal < ' e > ( expr : & ' e Expr < ' e > ) -> Option < & ' e Lit > {
1665
+ match expr. kind {
1666
+ ExprKind :: Lit ( ref lit) => Some ( lit) ,
1667
+ ExprKind :: Unary ( UnOp :: UnNeg , e) => {
1668
+ if let ExprKind :: Lit ( ref lit) = e. kind {
1669
+ Some ( lit)
1670
+ } else {
1671
+ None
1672
+ }
1673
+ } ,
1674
+ _ => None ,
1675
+ }
1676
+ }
1677
+
1678
+ fn show_unnecessary_cast ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , literal_str : & str , cast_from : Ty < ' _ > , cast_to : Ty < ' _ > ) {
1679
+ let literal_kind_name = if cast_from. is_integral ( ) { "integer" } else { "float" } ;
1680
+ span_lint_and_sugg (
1681
+ cx,
1682
+ UNNECESSARY_CAST ,
1683
+ expr. span ,
1684
+ & format ! ( "casting {} literal to `{}` is unnecessary" , literal_kind_name, cast_to) ,
1685
+ "try" ,
1686
+ format ! ( "{}_{}" , literal_str, cast_to) ,
1687
+ Applicability :: MachineApplicable ,
1688
+ ) ;
1689
+ }
1690
+
1649
1691
fn lint_numeric_casts < ' tcx > (
1650
1692
cx : & LateContext < ' tcx > ,
1651
1693
expr : & Expr < ' tcx > ,
0 commit comments