@@ -11,7 +11,7 @@ use rustc_hir as hir;
1111use rustc_hir:: intravisit:: { walk_body, walk_expr, walk_ty, FnKind , NestedVisitorMap , Visitor } ;
1212use rustc_hir:: {
1313 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 ,
1515 TraitFn , TraitItem , TraitItemKind , TyKind , UnOp ,
1616} ;
1717use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
@@ -1224,7 +1224,8 @@ declare_clippy_lint! {
12241224}
12251225
12261226declare_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.
12281229 ///
12291230 /// **Why is this bad?** It's just unnecessary.
12301231 ///
@@ -1233,6 +1234,14 @@ declare_clippy_lint! {
12331234 /// **Example:**
12341235 /// ```rust
12351236 /// 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;
12361245 /// ```
12371246 pub UNNECESSARY_CAST ,
12381247 complexity,
@@ -1598,7 +1607,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
15981607 if let ExprKind :: Cast ( ref ex, _) = expr. kind {
15991608 let ( cast_from, cast_to) = ( cx. typeck_results ( ) . expr_ty ( ex) , cx. typeck_results ( ) . expr_ty ( expr) ) ;
16001609 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+
16021613 if_chain ! {
16031614 if let LitKind :: Int ( n, _) = lit. node;
16041615 if let Some ( src) = snippet_opt( cx, lit. span) ;
@@ -1608,19 +1619,19 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
16081619 let to_nbits = fp_ty_mantissa_nbits( cast_to) ;
16091620 if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit. is_decimal( ) ;
16101621 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) ;
16201624 return ;
16211625 }
16221626 }
1627+
16231628 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+ } ,
16241635 LitKind :: Int ( _, LitIntType :: Unsuffixed ) | LitKind :: Float ( _, LitFloatType :: Unsuffixed ) => { } ,
16251636 _ => {
16261637 if cast_from. kind ( ) == cast_to. kind ( ) && !in_external_macro ( cx. sess ( ) , expr. span ) {
@@ -1646,6 +1657,37 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
16461657 }
16471658}
16481659
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+
16491691fn lint_numeric_casts < ' tcx > (
16501692 cx : & LateContext < ' tcx > ,
16511693 expr : & Expr < ' tcx > ,
0 commit comments