Skip to content

Commit

Permalink
Merge pull request rust-lang#1 from kraktus/pr-9506
Browse files Browse the repository at this point in the history
Suggestions for rust-lang#9506
  • Loading branch information
blyxyas authored Sep 26, 2022
2 parents 0a32643 + c349d8a commit 5cbd8df
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 70 deletions.
79 changes: 22 additions & 57 deletions clippy_lints/src/suspicious_xor.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use clippy_utils::{numeric_literal::NumericLiteral, source::snippet};
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, Lit};
use rustc_lint::{LateContext, LateLintPass};
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! {
Expand All @@ -27,61 +27,26 @@ declare_lint_pass!(ConfusingXorAndPow => [SUSPICIOUS_XOR]);

impl LateLintPass<'_> for ConfusingXorAndPow {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
if let ExprKind::Binary(op, left, right) = &expr.kind;
if op.node == BinOpKind::BitXor;
if let ExprKind::Lit(litr) = &right.kind;
if let ExprKind::Lit(litl) = &left.kind;
if let snip_left = snippet(cx, litl.span, "..");
if let snip_right = snippet(cx, litr.span, "..");
if get_numlit(litr, &snip_right)
.zip(get_numlit(litl, &snip_left))
.map_or(false, |(a,b)| a.is_decimal() && b.is_decimal());
if let left_val = unwrap_lit_to_dec(left).unwrap_or(0);
if let right_val = unwrap_lit_to_dec(right).unwrap_or(0);
if let suffix = get_numlit(litr, &snip_right).unwrap().suffix.unwrap_or("");
then {

if left_val == 2 &&
(right_val == 8 ||
right_val == 16 ||
right_val == 32 ||
right_val == 64 || right_val == 128)
{
clippy_utils::diagnostics::span_lint_and_sugg(
cx,
SUSPICIOUS_XOR,
expr.span,
"it appears that you are trying to get the maximum value of an integer, but '^' is not exponentiation operator",
"try with",
format!("u{right_val}::MAX"),
Applicability::MaybeIncorrect,
);
} else {
// Even then, warn always.
clippy_utils::diagnostics::span_lint_and_sugg(
cx,
SUSPICIOUS_XOR,
expr.span,
"'^' is not the exponentiation operator",
"did you mean to write",
format!("{left_val}{suffix}.pow({right_val})"),
Applicability::MaybeIncorrect,
);
}

}
}
}
}

fn unwrap_lit_to_dec(expr: &Expr<'_>) -> Option<u128> {
match &expr.kind {
ExprKind::Lit(lit) => match lit.node {
LitKind::Int(num, _) => Some(num),
_ => None,
},
_ => None,
if !in_external_macro(cx.sess(), expr.span) &&
let ExprKind::Binary(op, left, right) = &expr.kind &&
op.node == BinOpKind::BitXor &&
let ExprKind::Lit(lit_left) = &left.kind &&
let ExprKind::Lit(lit_right) = &right.kind &&
let snip_left = snippet(cx, lit_left.span, "..") &&
let snip_right = snippet(cx, lit_right.span, "..") &&
let Some(left_val) = get_numlit(lit_left, &snip_left) &&
let Some(right_val) = get_numlit(lit_right, &snip_right) &&
left_val.is_decimal() && right_val.is_decimal() {
clippy_utils::diagnostics::span_lint_and_sugg(
cx,
SUSPICIOUS_XOR,
expr.span,
"'^' is not the exponentiation operator",
"did you mean to write",
format!("{}.pow({})", left_val.format(), right_val.format()),
Applicability::MaybeIncorrect,
);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/ui/suspicious_xor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ macro_rules! macro_test {

fn main() {
// Should warn:
let _ = 2 ^ 5;
let _ = 2i32 ^ 9i32;
let _ = 2i32 ^ 2i32;
let _ = 50i32 ^ 3i32;
Expand Down
32 changes: 19 additions & 13 deletions tests/ui/suspicious_xor.stderr
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
error: '^' is not the exponentiation operator
--> $DIR/suspicious_xor.rs:13:13
|
LL | let _ = 2i32 ^ 9i32;
| ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(9)`
LL | let _ = 2 ^ 5;
| ^^^^^ help: did you mean to write: `2.pow(5)`
|
= note: `-D clippy::suspicious-xor` implied by `-D warnings`

error: '^' is not the exponentiation operator
--> $DIR/suspicious_xor.rs:14:13
|
LL | let _ = 2i32 ^ 2i32;
| ^^^^^^^^^^^ help: did you mean to write: `2i32.pow(2)`
LL | let _ = 2i32 ^ 9i32;
| ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(9_i32)`

error: '^' is not the exponentiation operator
--> $DIR/suspicious_xor.rs:15:13
|
LL | let _ = 50i32 ^ 3i32;
| ^^^^^^^^^^^^ help: did you mean to write: `50i32.pow(3)`
LL | let _ = 2i32 ^ 2i32;
| ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(2_i32)`

error: '^' is not the exponentiation operator
--> $DIR/suspicious_xor.rs:16:13
|
LL | let _ = 5i32 ^ 8i32;
| ^^^^^^^^^^^ help: did you mean to write: `5i32.pow(8)`
LL | let _ = 50i32 ^ 3i32;
| ^^^^^^^^^^^^ help: did you mean to write: `50_i32.pow(3_i32)`

error: it appears that you are trying to get the maximum value of an integer, but '^' is not exponentiation operator
error: '^' is not the exponentiation operator
--> $DIR/suspicious_xor.rs:17:13
|
LL | let _ = 2i32 ^ 32i32;
| ^^^^^^^^^^^^ help: try with: `u32::MAX`
LL | let _ = 5i32 ^ 8i32;
| ^^^^^^^^^^^ help: did you mean to write: `5_i32.pow(8_i32)`

error: '^' is not the exponentiation operator
--> $DIR/suspicious_xor.rs:18:13
|
LL | let _ = 2i32 ^ 32i32;
| ^^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(32_i32)`

error: '^' is not the exponentiation operator
--> $DIR/suspicious_xor.rs:19:13
|
LL | let _ = 2i32 ^ macro_test!();
| ^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `2.pow(13)`
| ^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(13)`

error: aborting due to 6 previous errors
error: aborting due to 7 previous errors

0 comments on commit 5cbd8df

Please sign in to comment.