about summary refs log tree commit diff
path: root/clippy_lints/src
diff options
context:
space:
mode:
Diffstat (limited to 'clippy_lints/src')
-rw-r--r--clippy_lints/src/casts/fn_to_numeric_cast_any.rs34
-rw-r--r--clippy_lints/src/casts/mod.rs39
-rw-r--r--clippy_lints/src/lib.register_lints.rs1
-rw-r--r--clippy_lints/src/lib.register_restriction.rs1
4 files changed, 75 insertions, 0 deletions
diff --git a/clippy_lints/src/casts/fn_to_numeric_cast_any.rs b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
new file mode 100644
index 00000000000..03621887a34
--- /dev/null
+++ b/clippy_lints/src/casts/fn_to_numeric_cast_any.rs
@@ -0,0 +1,34 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+
+use super::FN_TO_NUMERIC_CAST_ANY;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+    // We allow casts from any function type to any function type.
+    match cast_to.kind() {
+        ty::FnDef(..) | ty::FnPtr(..) => return,
+        _ => { /* continue to checks */ },
+    }
+
+    match cast_from.kind() {
+        ty::FnDef(..) | ty::FnPtr(_) => {
+            let mut applicability = Applicability::MaybeIncorrect;
+            let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
+
+            span_lint_and_sugg(
+                cx,
+                FN_TO_NUMERIC_CAST_ANY,
+                expr.span,
+                &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
+                "did you mean to invoke the function?",
+                format!("{}() as {}", from_snippet, cast_to),
+                applicability,
+            );
+        },
+        _ => {},
+    }
+}
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index 27e1bea7993..f0800c6a6f1 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -7,6 +7,7 @@ mod cast_ref_to_mut;
 mod cast_sign_loss;
 mod char_lit_as_u8;
 mod fn_to_numeric_cast;
+mod fn_to_numeric_cast_any;
 mod fn_to_numeric_cast_with_truncation;
 mod ptr_as_ptr;
 mod unnecessary_cast;
@@ -253,6 +254,42 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for casts of a function pointer to any integer type.
+    ///
+    /// ### Why is this bad?
+    /// Casting a function pointer to an integer can have surprising results and can occur
+    /// accidentally if parantheses are omitted from a function call. If you aren't doing anything
+    /// low-level with function pointers then you can opt-out of casting functions to integers in
+    /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
+    /// pointer casts in your code.
+    ///
+    /// ### Example
+    /// ```rust
+    /// // Bad: fn1 is cast as `usize`
+    /// fn fn1() -> u16 {
+    ///     1
+    /// };
+    /// let _ = fn1 as usize;
+    ///
+    /// // Good: maybe you intended to call the function?
+    /// fn fn2() -> u16 {
+    ///     1
+    /// };
+    /// let _ = fn2() as usize;
+    ///
+    /// // Good: maybe you intended to cast it to a function type?
+    /// fn fn3() -> u16 {
+    ///     1
+    /// }
+    /// let _ = fn3 as fn() -> u16;
+    /// ```
+    pub FN_TO_NUMERIC_CAST_ANY,
+    restriction,
+    "casting a function pointer to any integer type"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for casts of `&T` to `&mut T` anywhere in the code.
     ///
     /// ### Why is this bad?
@@ -360,6 +397,7 @@ impl_lint_pass!(Casts => [
     CAST_REF_TO_MUT,
     CAST_PTR_ALIGNMENT,
     UNNECESSARY_CAST,
+    FN_TO_NUMERIC_CAST_ANY,
     FN_TO_NUMERIC_CAST,
     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
     CHAR_LIT_AS_U8,
@@ -385,6 +423,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
                 return;
             }
 
+            fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
             fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
             fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
             if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index 2ba2b3da55c..3c6d8103b6d 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -67,6 +67,7 @@ store.register_lints(&[
     casts::CAST_SIGN_LOSS,
     casts::CHAR_LIT_AS_U8,
     casts::FN_TO_NUMERIC_CAST,
+    casts::FN_TO_NUMERIC_CAST_ANY,
     casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
     casts::PTR_AS_PTR,
     casts::UNNECESSARY_CAST,
diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs
index 4463dea5fcb..503f4f64a0e 100644
--- a/clippy_lints/src/lib.register_restriction.rs
+++ b/clippy_lints/src/lib.register_restriction.rs
@@ -8,6 +8,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(as_conversions::AS_CONVERSIONS),
     LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
     LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
+    LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
     LintId::of(create_dir::CREATE_DIR),
     LintId::of(dbg_macro::DBG_MACRO),
     LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),