Reimplement the fn_to_numeric_cast_with_truncation lint

This commit is contained in:
Philipp Hansch 2018-10-04 21:44:16 +02:00
parent 7adf24ebb0
commit c0ab8b2531
No known key found for this signature in database
GPG Key ID: B6FA06A6E0E2665B
8 changed files with 249 additions and 3 deletions

View File

@ -689,6 +689,7 @@ All notable changes to this project will be documented in this file.
[`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
[`fn_to_numeric_cast_with_truncation`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
[`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 278 lints included in this crate!](https://rust-lang-nursery.github.io/rust-clippy/master/index.html)
[There are 279 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

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

View File

@ -746,6 +746,32 @@ fn is_unit_literal(expr: &Expr) -> bool {
"casting a function pointer to a numeric type other than usize"
}
/// **What it does:** Checks for casts of a function pointer to a numeric type not wide enough to
/// store address.
///
/// **Why is this bad?**
/// Such a cast discards some bits of the function's address. If this is intended, it would be more
/// clearly expressed by casting to usize first, then casting the usize to the intended type (with
/// a comment) to perform the truncation.
///
/// **Example**
///
/// ```rust
/// // Bad
/// fn fn1() -> i16 { 1 };
/// let _ = fn1 as i32;
///
/// // Better: Cast to usize first, then comment with the reason for the truncation
/// fn fn2() -> i16 { 1 };
/// let fn_ptr = fn2 as usize;
/// let fn_ptr_truncated = fn_ptr as i32;
/// ```
declare_clippy_lint! {
pub FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
style,
"casting a function pointer to a numeric type not wide enough to store the address"
}
/// 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 {
@ -1054,7 +1080,19 @@ fn lint_fn_to_numeric_cast(cx: &LateContext<'_, '_>, expr: &Expr, cast_expr: &Ex
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) {
let to_nbits = int_ty_to_nbits(cast_to, cx.tcx);
if to_nbits < cx.tcx.data_layout.pointer_size.bits() {
span_lint_and_sugg(
cx,
FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
expr.span,
&format!("casting function pointer `{}` to `{}`, which truncates the value", from_snippet, cast_to),
"try",
format!("{} as usize", from_snippet)
);
} else if cast_to.sty != ty::Uint(UintTy::Usize) {
span_lint_and_sugg(
cx,
FN_TO_NUMERIC_CAST,

View File

@ -1,6 +1,6 @@
#![feature(tool_lints)]
#[warn(clippy::fn_to_numeric_cast)]
#![warn(clippy::fn_to_numeric_cast)]
fn foo() -> String { String::new() }

View File

@ -0,0 +1,142 @@
error: casting function pointer `foo` to `i8`
--> $DIR/fn_to_numeric_cast.rs:8:13
|
8 | let _ = foo as i8;
| ^^^^^^^^^ help: try: `foo as usize`
|
= note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings`
error: casting function pointer `foo` to `i16`
--> $DIR/fn_to_numeric_cast.rs:9:13
|
9 | let _ = foo as i16;
| ^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `i32`
--> $DIR/fn_to_numeric_cast.rs:10:13
|
10 | let _ = foo as i32;
| ^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `i64`
--> $DIR/fn_to_numeric_cast.rs:11:13
|
11 | let _ = foo as i64;
| ^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `i128`
--> $DIR/fn_to_numeric_cast.rs:12:13
|
12 | let _ = foo as i128;
| ^^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `isize`
--> $DIR/fn_to_numeric_cast.rs:13:13
|
13 | let _ = foo as isize;
| ^^^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `u8`
--> $DIR/fn_to_numeric_cast.rs:15:13
|
15 | let _ = foo as u8;
| ^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `u16`
--> $DIR/fn_to_numeric_cast.rs:16:13
|
16 | let _ = foo as u16;
| ^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `u32`
--> $DIR/fn_to_numeric_cast.rs:17:13
|
17 | let _ = foo as u32;
| ^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `u64`
--> $DIR/fn_to_numeric_cast.rs:18:13
|
18 | let _ = foo as u64;
| ^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `u128`
--> $DIR/fn_to_numeric_cast.rs:19:13
|
19 | let _ = foo as u128;
| ^^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `abc` to `i8`
--> $DIR/fn_to_numeric_cast.rs:28:13
|
28 | let _ = abc as i8;
| ^^^^^^^^^ help: try: `abc as usize`
error: casting function pointer `abc` to `i16`
--> $DIR/fn_to_numeric_cast.rs:29:13
|
29 | let _ = abc as i16;
| ^^^^^^^^^^ help: try: `abc as usize`
error: casting function pointer `abc` to `i32`
--> $DIR/fn_to_numeric_cast.rs:30:13
|
30 | let _ = abc as i32;
| ^^^^^^^^^^ help: try: `abc as usize`
error: casting function pointer `abc` to `i64`
--> $DIR/fn_to_numeric_cast.rs:31:13
|
31 | let _ = abc as i64;
| ^^^^^^^^^^ help: try: `abc as usize`
error: casting function pointer `abc` to `i128`
--> $DIR/fn_to_numeric_cast.rs:32:13
|
32 | let _ = abc as i128;
| ^^^^^^^^^^^ help: try: `abc as usize`
error: casting function pointer `abc` to `isize`
--> $DIR/fn_to_numeric_cast.rs:33:13
|
33 | let _ = abc as isize;
| ^^^^^^^^^^^^ help: try: `abc as usize`
error: casting function pointer `abc` to `u8`
--> $DIR/fn_to_numeric_cast.rs:35:13
|
35 | let _ = abc as u8;
| ^^^^^^^^^ help: try: `abc as usize`
error: casting function pointer `abc` to `u16`
--> $DIR/fn_to_numeric_cast.rs:36:13
|
36 | let _ = abc as u16;
| ^^^^^^^^^^ help: try: `abc as usize`
error: casting function pointer `abc` to `u32`
--> $DIR/fn_to_numeric_cast.rs:37:13
|
37 | let _ = abc as u32;
| ^^^^^^^^^^ help: try: `abc as usize`
error: casting function pointer `abc` to `u64`
--> $DIR/fn_to_numeric_cast.rs:38:13
|
38 | let _ = abc as u64;
| ^^^^^^^^^^ help: try: `abc as usize`
error: casting function pointer `abc` to `u128`
--> $DIR/fn_to_numeric_cast.rs:39:13
|
39 | let _ = abc as u128;
| ^^^^^^^^^^^ help: try: `abc as usize`
error: casting function pointer `f` to `i32`
--> $DIR/fn_to_numeric_cast.rs:46:5
|
46 | f as i32
| ^^^^^^^^ help: try: `f as usize`
error: aborting due to 23 previous errors

View File

@ -0,0 +1,23 @@
#![feature(tool_lints)]
#![warn(clippy::fn_to_numeric_cast_with_truncation)]
#![allow(clippy::fn_to_numeric_cast)]
fn foo() -> String { String::new() }
fn test_fn_to_numeric_cast_with_truncation() {
let _ = foo as i8;
let _ = foo as i16;
let _ = foo as i32;
let _ = foo as u8;
let _ = foo as u16;
let _ = foo as u32;
// TODO: Is it bad to have these tests?
// Running the tests on a different architechture will
// produce different results
let _ = foo as u64;
let _ = foo as i64;
}
fn main() {}

View File

@ -0,0 +1,40 @@
error: casting function pointer `foo` to `i8`, which truncates the value
--> $DIR/fn_to_numeric_cast_with_truncation.rs:9:13
|
9 | let _ = foo as i8;
| ^^^^^^^^^ help: try: `foo as usize`
|
= note: `-D clippy::fn-to-numeric-cast-with-truncation` implied by `-D warnings`
error: casting function pointer `foo` to `i16`, which truncates the value
--> $DIR/fn_to_numeric_cast_with_truncation.rs:10:13
|
10 | let _ = foo as i16;
| ^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `i32`, which truncates the value
--> $DIR/fn_to_numeric_cast_with_truncation.rs:11:13
|
11 | let _ = foo as i32;
| ^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `u8`, which truncates the value
--> $DIR/fn_to_numeric_cast_with_truncation.rs:12:13
|
12 | let _ = foo as u8;
| ^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `u16`, which truncates the value
--> $DIR/fn_to_numeric_cast_with_truncation.rs:13:13
|
13 | let _ = foo as u16;
| ^^^^^^^^^^ help: try: `foo as usize`
error: casting function pointer `foo` to `u32`, which truncates the value
--> $DIR/fn_to_numeric_cast_with_truncation.rs:14:13
|
14 | let _ = foo as u32;
| ^^^^^^^^^^ help: try: `foo as usize`
error: aborting due to 6 previous errors