-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add fn_to_numeric_cast_usize
lint
#5914
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1100,6 +1100,31 @@ declare_clippy_lint! { | |
"casting a function pointer to a numeric type other than usize" | ||
} | ||
|
||
declare_clippy_lint! { | ||
/// **What it does:** Checks for casts of function directly to a usize | ||
/// | ||
/// **Why is this bad?** | ||
/// Casting a function directly to a usize is likely a mistake. Most likely, the intended behavior | ||
/// is calling the function. If casting to a usize is intended, it would be more clearly expressed | ||
/// by casting to a function pointer, then to a usize. | ||
/// | ||
/// **Example** | ||
/// | ||
/// ```rust | ||
/// // Bad | ||
/// fn fun() -> usize { 1 } | ||
/// let a: usize = fun as usize; | ||
/// | ||
/// // Good | ||
/// fn fun2() -> usize { 1 } | ||
/// let a: usize = fun2 as fn() -> usize as usize; | ||
/// let b: usize = fun2(); | ||
/// ``` | ||
pub FN_TO_NUMERIC_CAST_USIZE, | ||
style, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be |
||
"casting a function to a usize" | ||
} | ||
|
||
declare_clippy_lint! { | ||
/// **What it does:** Checks for casts of a function pointer to a numeric type not wide enough to | ||
/// store address. | ||
|
@@ -1374,6 +1399,7 @@ declare_lint_pass!(Casts => [ | |
UNNECESSARY_CAST, | ||
CAST_PTR_ALIGNMENT, | ||
FN_TO_NUMERIC_CAST, | ||
FN_TO_NUMERIC_CAST_USIZE, | ||
FN_TO_NUMERIC_CAST_WITH_TRUNCATION, | ||
]); | ||
|
||
|
@@ -1558,15 +1584,55 @@ fn lint_fn_to_numeric_cast( | |
) { | ||
// We only want to check casts to `ty::Uint` or `ty::Int` | ||
match cast_to.kind { | ||
ty::Uint(_) | ty::Int(..) => { /* continue on */ }, | ||
ty::Uint(_) | ty::Int(_) => { /* continue on */ }, | ||
_ => return, | ||
} | ||
match cast_from.kind { | ||
ty::FnDef(..) | ty::FnPtr(_) => { | ||
let mut applicability = Applicability::MaybeIncorrect; | ||
let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); | ||
|
||
let to_nbits = int_ty_to_nbits(cast_to, cx.tcx); | ||
let is_def = matches!(cast_from.kind, ty::FnDef(..)); | ||
let is_ptr = matches!(cast_from.kind, ty::FnPtr(_)); | ||
|
||
if is_def || is_ptr { | ||
let mut applicability = Applicability::MaybeIncorrect; | ||
let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); | ||
|
||
let to_nbits = int_ty_to_nbits(cast_to, cx.tcx); | ||
|
||
if is_def { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This repeats too much code. match cast_from.kind {
ty::FnDef(..) if cast_to.kind == ty::Uint(UintTy::Usize) => { /* lint FN_TO_NUMERIC_CAST_USIZE */ },
ty::FnDef(..) | ty::FnPtr(_) => { /* keep old code */ },
.. => {},
} |
||
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 *pointer* to function `{}` as `{}`, which truncates the value", | ||
from_snippet, cast_to | ||
), | ||
"try", | ||
format!("{}() as {}", from_snippet, cast_to), | ||
applicability, | ||
); | ||
} else if cast_to.kind == ty::Uint(UintTy::Usize) { | ||
span_lint_and_sugg( | ||
cx, | ||
FN_TO_NUMERIC_CAST_USIZE, | ||
expr.span, | ||
&format!("casting *pointer* to function `{}` as `{}`", from_snippet, cast_to), | ||
"try", | ||
format!("{}() as {}", from_snippet, cast_to), | ||
applicability, | ||
); | ||
} else { | ||
span_lint_and_sugg( | ||
cx, | ||
FN_TO_NUMERIC_CAST, | ||
expr.span, | ||
&format!("casting *pointer* to function `{}` as `{}`", from_snippet, cast_to), | ||
"try", | ||
format!("{}() as {}", from_snippet, cast_to), | ||
Comment on lines
+1629
to
+1631
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we should assume here, that a cast of the return value was meant. Also I think the What we can do is add two suggestions, one that suggests to cast the pointer to |
||
applicability, | ||
); | ||
} | ||
} else if is_ptr { | ||
if to_nbits < cx.tcx.data_layout.pointer_size.bits() { | ||
span_lint_and_sugg( | ||
cx, | ||
|
@@ -1591,8 +1657,7 @@ fn lint_fn_to_numeric_cast( | |
applicability, | ||
); | ||
} | ||
}, | ||
_ => {}, | ||
} | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unrelated?I wouldn't do this, since the extra cast to
fn() -> T
is code bloat. If people prefer these explicit casts, they should enable the new lint (which should bepedantic
).