Reimplement the fn_to_numeric_cast lint

This commit is contained in:
Philipp Hansch 2018-10-03 12:02:06 +02:00
parent 913a5c9b56
commit f42272102a
No known key found for this signature in database
GPG Key ID: B6FA06A6E0E2665B
5 changed files with 98 additions and 1 deletions

View File

@ -688,6 +688,7 @@ All notable changes to this project will be documented in this file.
[`float_arithmetic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#float_arithmetic
[`float_cmp`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#float_cmp
[`float_cmp_const`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#float_cmp_const
[`fn_to_numeric_cast`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
[`for_kv_map`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#for_kv_map
[`for_loop_over_option`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#for_loop_over_option
[`for_loop_over_result`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#for_loop_over_result

View File

@ -9,7 +9,7 @@ We are currently in the process of discussing Clippy 1.0 via the RFC process in
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
[There are 277 lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)
[There are 278 lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:

View File

@ -697,6 +697,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
types::CAST_LOSSLESS,
types::CAST_PTR_ALIGNMENT,
types::CHAR_LIT_AS_U8,
types::FN_TO_NUMERIC_CAST,
types::IMPLICIT_HASHER,
types::LET_UNIT_VALUE,
types::OPTION_OPTION,
@ -789,6 +790,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
returns::LET_AND_RETURN,
returns::NEEDLESS_RETURN,
strings::STRING_LIT_AS_BYTES,
types::FN_TO_NUMERIC_CAST,
types::IMPLICIT_HASHER,
types::LET_UNIT_VALUE,
unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,

View File

@ -719,6 +719,30 @@ fn is_unit_literal(expr: &Expr) -> bool {
"cast from a pointer to a more-strictly-aligned pointer"
}
/// **What it does:** Checks for casts of function pointers to something other than usize
///
/// **Why is this bad?**
/// Depending on the system architechture, casting a function pointer to something other than
/// `usize` will result in incorrect pointer addresses.
/// `usize` will always be able to store the function pointer on the given architechture.
///
/// **Example**
///
/// ```rust
/// // Bad
/// fn fun() -> i32 {}
/// let a = fun as i64;
///
/// // Good
/// fn fun2() -> i32 {}
/// let a = fun2 as usize;
/// ```
declare_clippy_lint! {
pub FN_TO_NUMERIC_CAST,
style,
"casting a function pointer to a numeric type other than usize"
}
/// Returns the size in bits of an integral type.
/// Will return 0 if the type is not an int or uint variant
fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_, '_, '_>) -> u64 {
@ -913,6 +937,7 @@ fn get_lints(&self) -> LintArray {
CAST_LOSSLESS,
UNNECESSARY_CAST,
CAST_PTR_ALIGNMENT,
FN_TO_NUMERIC_CAST
)
}
}
@ -921,6 +946,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CastPass {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if let ExprKind::Cast(ref ex, _) = expr.node {
let (cast_from, cast_to) = (cx.tables.expr_ty(ex), cx.tables.expr_ty(expr));
lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
if let ExprKind::Lit(ref lit) = ex.node {
use crate::syntax::ast::{LitIntType, LitKind};
match lit.node {
@ -1021,6 +1047,25 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
}
}
fn lint_fn_to_numeric_cast(cx: &LateContext<'_, '_>, expr: &Expr, cast_expr: &Expr, cast_from: Ty, cast_to: Ty) {
match cast_from.sty {
ty::FnDef(..) | ty::FnPtr(_) => {
let from_snippet = snippet(cx, cast_expr.span, "x");
if cast_to.sty != ty::Uint(UintTy::Usize) {
span_lint_and_sugg(
cx,
FN_TO_NUMERIC_CAST,
expr.span,
&format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
"try",
format!("{} as usize", from_snippet)
);
}
},
_ => {}
}
}
/// **What it does:** Checks for types used in structs, parameters and `let`
/// declarations above a certain complexity threshold.
///

View File

@ -0,0 +1,49 @@
#![feature(tool_lints)]
#[warn(clippy::fn_to_numeric_cast)]
fn foo() -> String { String::new() }
fn test_function_to_numeric_cast() {
let _ = foo as i8;
let _ = foo as i16;
let _ = foo as i32;
let _ = foo as i64;
let _ = foo as i128;
let _ = foo as isize;
let _ = foo as u8;
let _ = foo as u16;
let _ = foo as u32;
let _ = foo as u64;
let _ = foo as u128;
// Casting to usize is OK and should not warn
let _ = foo as usize;
}
fn test_function_var_to_numeric_cast() {
let abc: fn() -> String = foo;
let _ = abc as i8;
let _ = abc as i16;
let _ = abc as i32;
let _ = abc as i64;
let _ = abc as i128;
let _ = abc as isize;
let _ = abc as u8;
let _ = abc as u16;
let _ = abc as u32;
let _ = abc as u64;
let _ = abc as u128;
// Casting to usize is OK and should not warn
let _ = abc as usize;
}
fn fn_with_fn_args(f: fn(i32) -> i32) -> i32 {
f as i32
}
fn main() {}