rustc_lint/
function_cast_as_integer.rs

1use rustc_hir as hir;
2use rustc_middle::ty;
3use rustc_session::{declare_lint, declare_lint_pass};
4use rustc_span::BytePos;
5
6use crate::lints::{FunctionCastsAsIntegerDiag, FunctionCastsAsIntegerSugg};
7use crate::{LateContext, LateLintPass};
8
9declare_lint! {
10    /// The `function_casts_as_integer` lint detects cases where a function item is cast
11    /// to an integer.
12    ///
13    /// ### Example
14    ///
15    /// ```rust
16    /// fn foo() {}
17    /// let x = foo as usize;
18    /// ```
19    ///
20    /// {{produces}}
21    ///
22    /// ### Explanation
23    ///
24    /// When casting a function item to an integer, it implicitly creates a
25    /// function pointer that will in turn be cast to an integer. By making
26    /// it explicit, it improves readability of the code and prevents bugs.
27    pub FUNCTION_CASTS_AS_INTEGER,
28    Warn,
29    "casting a function into an integer",
30}
31
32declare_lint_pass!(
33    /// Lint for casts of functions into integers.
34    FunctionCastsAsInteger => [FUNCTION_CASTS_AS_INTEGER]
35);
36
37impl<'tcx> LateLintPass<'tcx> for FunctionCastsAsInteger {
38    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
39        let hir::ExprKind::Cast(cast_from_expr, cast_to_expr) = expr.kind else { return };
40        let cast_to_ty = cx.typeck_results().expr_ty(expr);
41        // Casting to a function (pointer?), so all good.
42        //
43        // Normally, only casts to integers is possible, but if it ever changed, this condition
44        // will likely need to be updated.
45        if matches!(cast_to_ty.kind(), ty::FnDef(..) | ty::FnPtr(..) | ty::RawPtr(..)) {
46            return;
47        }
48        let cast_from_ty = cx.typeck_results().expr_ty(cast_from_expr);
49        if matches!(cast_from_ty.kind(), ty::FnDef(..)) {
50            cx.tcx.emit_node_span_lint(
51                FUNCTION_CASTS_AS_INTEGER,
52                expr.hir_id,
53                cast_to_expr.span.with_lo(cast_from_expr.span.hi() + BytePos(1)),
54                FunctionCastsAsIntegerDiag {
55                    sugg: FunctionCastsAsIntegerSugg {
56                        suggestion: cast_from_expr.span.shrink_to_hi(),
57                        cast_to_ty,
58                    },
59                },
60            );
61        }
62    }
63}