@@ -190,6 +190,28 @@ declare_clippy_lint! {
190
190
"transmutes from an integer to a float"
191
191
}
192
192
193
+ declare_clippy_lint ! {
194
+ /// **What it does:** Checks for transmutes from a float to an integer.
195
+ ///
196
+ /// **Why is this bad?** Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive
197
+ /// and safe.
198
+ ///
199
+ /// **Known problems:** None.
200
+ ///
201
+ /// **Example:**
202
+ /// ```rust
203
+ /// unsafe {
204
+ /// let _: u32 = std::mem::transmute(1f32);
205
+ /// }
206
+ ///
207
+ /// // should be:
208
+ /// let _: u32 = 1f32.to_bits();
209
+ /// ```
210
+ pub TRANSMUTE_FLOAT_TO_INT ,
211
+ nursery,
212
+ "transmutes from a float to an integer"
213
+ }
214
+
193
215
declare_clippy_lint ! {
194
216
/// **What it does:** Checks for transmutes from a pointer to a pointer, or
195
217
/// from a reference to a reference.
@@ -254,6 +276,7 @@ declare_lint_pass!(Transmute => [
254
276
TRANSMUTE_BYTES_TO_STR ,
255
277
TRANSMUTE_INT_TO_BOOL ,
256
278
TRANSMUTE_INT_TO_FLOAT ,
279
+ TRANSMUTE_FLOAT_TO_INT ,
257
280
UNSOUND_COLLECTION_TRANSMUTE ,
258
281
] ) ;
259
282
@@ -520,6 +543,50 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
520
543
) ;
521
544
} ,
522
545
) ,
546
+ ( & ty:: Float ( float_ty) , & ty:: Int ( _) ) | ( & ty:: Float ( float_ty) , & ty:: Uint ( _) ) => span_lint_and_then(
547
+ cx,
548
+ TRANSMUTE_FLOAT_TO_INT ,
549
+ e. span,
550
+ & format!( "transmute from a `{}` to a `{}`" , from_ty, to_ty) ,
551
+ |db| {
552
+ let mut expr = & args[ 0 ] ;
553
+ let mut arg = sugg:: Sugg :: hir( cx, expr, ".." ) ;
554
+
555
+ if let ExprKind :: Unary ( UnOp :: UnNeg , inner_expr) = & expr. kind {
556
+ expr = & inner_expr;
557
+ }
558
+
559
+ if_chain! {
560
+ // if the expression is a float literal and it is unsuffixed then
561
+ // add a suffix so the suggestion is valid and unambiguous
562
+ let op = format!( "{}{}" , arg, float_ty. name_str( ) ) . into( ) ;
563
+ if let ExprKind :: Lit ( lit) = & expr. kind;
564
+ if let ast:: LitKind :: Float ( _, ast:: LitFloatType :: Unsuffixed ) = lit. node;
565
+ then {
566
+ match arg {
567
+ sugg:: Sugg :: MaybeParen ( _) => arg = sugg:: Sugg :: MaybeParen ( op) ,
568
+ _ => arg = sugg:: Sugg :: NonParen ( op)
569
+ }
570
+ }
571
+ }
572
+
573
+ arg = sugg:: Sugg :: NonParen ( format!( "{}.to_bits()" , arg. maybe_par( ) ) . into( ) ) ;
574
+
575
+ // cast the result of `to_bits` if `to_ty` is signed
576
+ arg = if let ty:: Int ( int_ty) = to_ty. kind {
577
+ arg. as_ty( int_ty. name_str( ) . to_string( ) )
578
+ } else {
579
+ arg
580
+ } ;
581
+
582
+ db. span_suggestion(
583
+ e. span,
584
+ "consider using" ,
585
+ arg. to_string( ) ,
586
+ Applicability :: Unspecified ,
587
+ ) ;
588
+ } ,
589
+ ) ,
523
590
( & ty:: Adt ( ref from_adt, ref from_substs) , & ty:: Adt ( ref to_adt, ref to_substs) ) => {
524
591
if from_adt. did != to_adt. did ||
525
592
!COLLECTIONS . iter( ) . any( |path| match_def_path( cx, to_adt. did, path) ) {
0 commit comments