|
1 | 1 | use rustc::lint::*;
|
2 | 2 | use rustc::ty::{self, Ty};
|
3 | 3 | use rustc::hir::*;
|
| 4 | +use std::borrow::Cow; |
| 5 | +use syntax::ast; |
4 | 6 | use utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then};
|
5 | 7 | use utils::{sugg, opt_def_id};
|
6 | 8 |
|
@@ -76,11 +78,73 @@ declare_lint! {
|
76 | 78 | "transmutes from a pointer to a reference type"
|
77 | 79 | }
|
78 | 80 |
|
| 81 | +/// **What it does:** Checks for transmutes from an integer to a `char`. |
| 82 | +/// |
| 83 | +/// **Why is this bad?** Not every integer is a unicode scalar value. |
| 84 | +/// |
| 85 | +/// **Known problems:** None. |
| 86 | +/// |
| 87 | +/// **Example:** |
| 88 | +/// ```rust |
| 89 | +/// let _: char = std::mem::transmute(x); // where x: u32 |
| 90 | +/// // should be: |
| 91 | +/// let _: Option<char> = std::char::from_u32(x); |
| 92 | +/// ``` |
| 93 | +declare_lint! { |
| 94 | + pub TRANSMUTE_INT_TO_CHAR, |
| 95 | + Warn, |
| 96 | + "transmutes from an integer to a `char`" |
| 97 | +} |
| 98 | + |
| 99 | +/// **What it does:** Checks for transmutes from an integer to a `bool`. |
| 100 | +/// |
| 101 | +/// **Why is this bad?** This might result in an invalid in-memory representation of a `bool`. |
| 102 | +/// |
| 103 | +/// **Known problems:** None. |
| 104 | +/// |
| 105 | +/// **Example:** |
| 106 | +/// ```rust |
| 107 | +/// let _: bool = std::mem::transmute(x); // where x: u8 |
| 108 | +/// // should be: |
| 109 | +/// let _: bool = x != 0; |
| 110 | +/// ``` |
| 111 | +declare_lint! { |
| 112 | + pub TRANSMUTE_INT_TO_BOOL, |
| 113 | + Warn, |
| 114 | + "transmutes from an integer to a `bool`" |
| 115 | +} |
| 116 | + |
| 117 | +/// **What it does:** Checks for transmutes from an integer to a float. |
| 118 | +/// |
| 119 | +/// **Why is this bad?** This might result in an invalid in-memory representation of a float. |
| 120 | +/// |
| 121 | +/// **Known problems:** None. |
| 122 | +/// |
| 123 | +/// **Example:** |
| 124 | +/// ```rust |
| 125 | +/// let _: f32 = std::mem::transmute(x); // where x: u32 |
| 126 | +/// // should be: |
| 127 | +/// let _: f32 = f32::from_bits(x); |
| 128 | +/// ``` |
| 129 | +declare_lint! { |
| 130 | + pub TRANSMUTE_INT_TO_FLOAT, |
| 131 | + Warn, |
| 132 | + "transmutes from an integer to a float" |
| 133 | +} |
| 134 | + |
79 | 135 | pub struct Transmute;
|
80 | 136 |
|
81 | 137 | impl LintPass for Transmute {
|
82 | 138 | fn get_lints(&self) -> LintArray {
|
83 |
| - lint_array!(CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE, WRONG_TRANSMUTE) |
| 139 | + lint_array!( |
| 140 | + CROSSPOINTER_TRANSMUTE, |
| 141 | + TRANSMUTE_PTR_TO_REF, |
| 142 | + USELESS_TRANSMUTE, |
| 143 | + WRONG_TRANSMUTE, |
| 144 | + TRANSMUTE_INT_TO_CHAR, |
| 145 | + TRANSMUTE_INT_TO_BOOL, |
| 146 | + TRANSMUTE_INT_TO_FLOAT |
| 147 | + ) |
84 | 148 | }
|
85 | 149 | }
|
86 | 150 |
|
@@ -177,6 +241,50 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
|
177 | 241 | db.span_suggestion(e.span, "try", sugg::make_unop(deref, arg).to_string());
|
178 | 242 | },
|
179 | 243 | ),
|
| 244 | + (&ty::TyInt(ast::IntTy::I32), &ty::TyChar) | |
| 245 | + (&ty::TyUint(ast::UintTy::U32), &ty::TyChar) => span_lint_and_then( |
| 246 | + cx, |
| 247 | + TRANSMUTE_INT_TO_CHAR, |
| 248 | + e.span, |
| 249 | + &format!("transmute from a `{}` to a `char`", from_ty), |
| 250 | + |db| { |
| 251 | + let arg = sugg::Sugg::hir(cx, &args[0], ".."); |
| 252 | + let arg = if let ty::TyInt(_) = from_ty.sty { |
| 253 | + arg.as_ty(ty::TyUint(ast::UintTy::U32)) |
| 254 | + } else { |
| 255 | + arg |
| 256 | + }; |
| 257 | + db.span_suggestion(e.span, "consider using", format!("std::char::from_u32({})", arg.to_string())); |
| 258 | + } |
| 259 | + ), |
| 260 | + (&ty::TyInt(ast::IntTy::I8), &ty::TyBool) | |
| 261 | + (&ty::TyUint(ast::UintTy::U8), &ty::TyBool) => span_lint_and_then( |
| 262 | + cx, |
| 263 | + TRANSMUTE_INT_TO_BOOL, |
| 264 | + e.span, |
| 265 | + &format!("transmute from a `{}` to a `bool`", from_ty), |
| 266 | + |db| { |
| 267 | + let arg = sugg::Sugg::hir(cx, &args[0], ".."); |
| 268 | + let zero = sugg::Sugg::NonParen(Cow::from("0")); |
| 269 | + db.span_suggestion(e.span, "consider using", sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string()); |
| 270 | + } |
| 271 | + ), |
| 272 | + (&ty::TyInt(_), &ty::TyFloat(_)) | |
| 273 | + (&ty::TyUint(_), &ty::TyFloat(_)) => span_lint_and_then( |
| 274 | + cx, |
| 275 | + TRANSMUTE_INT_TO_FLOAT, |
| 276 | + e.span, |
| 277 | + &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), |
| 278 | + |db| { |
| 279 | + let arg = sugg::Sugg::hir(cx, &args[0], ".."); |
| 280 | + let arg = if let ty::TyInt(int_ty) = from_ty.sty { |
| 281 | + arg.as_ty(format!("u{}", int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string()))) |
| 282 | + } else { |
| 283 | + arg |
| 284 | + }; |
| 285 | + db.span_suggestion(e.span, "consider using", format!("{}::from_bits({})", to_ty, arg.to_string())); |
| 286 | + } |
| 287 | + ), |
180 | 288 | _ => return,
|
181 | 289 | };
|
182 | 290 | }
|
|
0 commit comments