summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
blob: 301aa5798bf556eeeb4bf2389fc671c25c08cbf0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
use clippy_utils::{numeric_literal::NumericLiteral, source::snippet_with_context};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// ### What it does
    /// Warns for a Bitwise XOR (`^`) operator being probably confused as a powering. It will not trigger if any of the numbers are not in decimal.
    /// ### Why is this bad?
    ///	It's most probably a typo and may lead to unexpected behaviours.
    /// ### Example
    /// ```rust
    /// let x = 3_i32 ^ 4_i32;
    /// ```
    /// Use instead:
    /// ```rust
    /// let x = 3_i32.pow(4);
    /// ```
    #[clippy::version = "1.66.0"]
    pub SUSPICIOUS_XOR_USED_AS_POW,
    restriction,
    "XOR (`^`) operator possibly used as exponentiation operator"
}
declare_lint_pass!(ConfusingXorAndPow => [SUSPICIOUS_XOR_USED_AS_POW]);

impl LateLintPass<'_> for ConfusingXorAndPow {
    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
        if !in_external_macro(cx.sess(), expr.span) &&
        	let ExprKind::Binary(op, left, right) = &expr.kind &&
            op.node == BinOpKind::BitXor &&
            left.span.ctxt() == right.span.ctxt() &&
            let ExprKind::Lit(lit_left) = &left.kind &&
            let ExprKind::Lit(lit_right) = &right.kind &&
            let snip_left = snippet_with_context(cx, lit_left.span, lit_left.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
            let snip_right = snippet_with_context(cx, lit_right.span, lit_right.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
            let Some(left_val) = NumericLiteral::from_lit_kind(&snip_left.0, &lit_left.node) &&
            let Some(right_val) = NumericLiteral::from_lit_kind(&snip_right.0, &lit_right.node) &&
			left_val.is_decimal() &&
			right_val.is_decimal() {
					clippy_utils::diagnostics::span_lint_and_sugg(
					        cx,
					        SUSPICIOUS_XOR_USED_AS_POW,
					        expr.span,
					        "`^` is not the exponentiation operator",
					        "did you mean to write",
					        format!("{}.pow({})", left_val.format(), right_val.format()),
					        Applicability::MaybeIncorrect,
					    );
		}
    }
}