Reimplement the fn_to_numeric_cast_with_truncation
lint
This commit is contained in:
parent
7adf24ebb0
commit
c0ab8b2531
@ -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
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![feature(tool_lints)]
|
||||
|
||||
#[warn(clippy::fn_to_numeric_cast)]
|
||||
#![warn(clippy::fn_to_numeric_cast)]
|
||||
|
||||
fn foo() -> String { String::new() }
|
||||
|
||||
|
142
tests/ui/fn_to_numeric_cast.stderr
Normal file
142
tests/ui/fn_to_numeric_cast.stderr
Normal 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
|
||||
|
23
tests/ui/fn_to_numeric_cast_with_truncation.rs
Normal file
23
tests/ui/fn_to_numeric_cast_with_truncation.rs
Normal 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() {}
|
40
tests/ui/fn_to_numeric_cast_with_truncation.stderr
Normal file
40
tests/ui/fn_to_numeric_cast_with_truncation.stderr
Normal 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
|
||||
|
Loading…
Reference in New Issue
Block a user