mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-14 17:07:17 +00:00
Auto merge of #9506 - blyxyas:master, r=giraffate
Add lint for confusing use of `^` instead of `.pow` fixes #4205 Adds a lint named [`confusing_xor_and_pow`], it warns the user when `a ^ b` is used as the `.pow()` function, it doesn't warn for Hex, Binary... etc. --- changelog: New lint: [`confusing_xor_and_pow`]
This commit is contained in:
commit
37d338c1ef
8 changed files with 171 additions and 28 deletions
|
@ -4251,6 +4251,7 @@ Released 2018-09-13
|
|||
[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
|
||||
[`suspicious_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned
|
||||
[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
|
||||
[`suspicious_xor_used_as_pow`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_xor_used_as_pow
|
||||
[`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref
|
||||
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
|
||||
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
|
||||
|
|
|
@ -544,6 +544,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO,
|
||||
crate::suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL_INFO,
|
||||
crate::suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL_INFO,
|
||||
crate::suspicious_xor_used_as_pow::SUSPICIOUS_XOR_USED_AS_POW_INFO,
|
||||
crate::swap::ALMOST_SWAPPED_INFO,
|
||||
crate::swap::MANUAL_SWAP_INFO,
|
||||
crate::swap_ptr_to_ref::SWAP_PTR_TO_REF_INFO,
|
||||
|
|
|
@ -268,6 +268,7 @@ mod strings;
|
|||
mod strlen_on_c_strings;
|
||||
mod suspicious_operation_groupings;
|
||||
mod suspicious_trait_impl;
|
||||
mod suspicious_xor_used_as_pow;
|
||||
mod swap;
|
||||
mod swap_ptr_to_ref;
|
||||
mod tabs_in_doc_comments;
|
||||
|
@ -916,6 +917,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
|
||||
store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
|
||||
store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
|
||||
store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
53
clippy_lints/src/suspicious_xor_used_as_pow.rs
Normal file
53
clippy_lints/src/suspicious_xor_used_as_pow.rs
Normal file
|
@ -0,0 +1,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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#![warn(clippy::eq_op)]
|
||||
#![allow(clippy::double_parens, clippy::identity_op, clippy::nonminimal_bool)]
|
||||
#![allow(clippy::suspicious_xor_used_as_pow)]
|
||||
|
||||
fn main() {
|
||||
// simple values and comparisons
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: equal expressions as operands to `==`
|
||||
--> $DIR/eq_op.rs:8:13
|
||||
--> $DIR/eq_op.rs:9:13
|
||||
|
|
||||
LL | let _ = 1 == 1;
|
||||
| ^^^^^^
|
||||
|
@ -7,163 +7,163 @@ LL | let _ = 1 == 1;
|
|||
= note: `-D clippy::eq-op` implied by `-D warnings`
|
||||
|
||||
error: equal expressions as operands to `==`
|
||||
--> $DIR/eq_op.rs:9:13
|
||||
--> $DIR/eq_op.rs:10:13
|
||||
|
|
||||
LL | let _ = "no" == "no";
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `!=`
|
||||
--> $DIR/eq_op.rs:11:13
|
||||
--> $DIR/eq_op.rs:12:13
|
||||
|
|
||||
LL | let _ = false != false;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `<`
|
||||
--> $DIR/eq_op.rs:12:13
|
||||
--> $DIR/eq_op.rs:13:13
|
||||
|
|
||||
LL | let _ = 1.5 < 1.5;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `>=`
|
||||
--> $DIR/eq_op.rs:13:13
|
||||
--> $DIR/eq_op.rs:14:13
|
||||
|
|
||||
LL | let _ = 1u64 >= 1u64;
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `&`
|
||||
--> $DIR/eq_op.rs:16:13
|
||||
--> $DIR/eq_op.rs:17:13
|
||||
|
|
||||
LL | let _ = (1u32 as u64) & (1u32 as u64);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `^`
|
||||
--> $DIR/eq_op.rs:19:17
|
||||
--> $DIR/eq_op.rs:20:17
|
||||
|
|
||||
LL | let _ = 1 ^ ((((((1))))));
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `<`
|
||||
--> $DIR/eq_op.rs:23:13
|
||||
--> $DIR/eq_op.rs:24:13
|
||||
|
|
||||
LL | let _ = (-(2) < -(2));
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `==`
|
||||
--> $DIR/eq_op.rs:24:13
|
||||
--> $DIR/eq_op.rs:25:13
|
||||
|
|
||||
LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `&`
|
||||
--> $DIR/eq_op.rs:24:14
|
||||
--> $DIR/eq_op.rs:25:14
|
||||
|
|
||||
LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `&`
|
||||
--> $DIR/eq_op.rs:24:35
|
||||
--> $DIR/eq_op.rs:25:35
|
||||
|
|
||||
LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `==`
|
||||
--> $DIR/eq_op.rs:25:13
|
||||
--> $DIR/eq_op.rs:26:13
|
||||
|
|
||||
LL | let _ = (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `!=`
|
||||
--> $DIR/eq_op.rs:28:13
|
||||
--> $DIR/eq_op.rs:29:13
|
||||
|
|
||||
LL | let _ = ([1] != [1]);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `!=`
|
||||
--> $DIR/eq_op.rs:29:13
|
||||
--> $DIR/eq_op.rs:30:13
|
||||
|
|
||||
LL | let _ = ((1, 2) != (1, 2));
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `==`
|
||||
--> $DIR/eq_op.rs:33:13
|
||||
--> $DIR/eq_op.rs:34:13
|
||||
|
|
||||
LL | let _ = 1 + 1 == 2;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `==`
|
||||
--> $DIR/eq_op.rs:34:13
|
||||
--> $DIR/eq_op.rs:35:13
|
||||
|
|
||||
LL | let _ = 1 - 1 == 0;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `-`
|
||||
--> $DIR/eq_op.rs:34:13
|
||||
--> $DIR/eq_op.rs:35:13
|
||||
|
|
||||
LL | let _ = 1 - 1 == 0;
|
||||
| ^^^^^
|
||||
|
||||
error: equal expressions as operands to `-`
|
||||
--> $DIR/eq_op.rs:36:13
|
||||
--> $DIR/eq_op.rs:37:13
|
||||
|
|
||||
LL | let _ = 1 - 1;
|
||||
| ^^^^^
|
||||
|
||||
error: equal expressions as operands to `/`
|
||||
--> $DIR/eq_op.rs:37:13
|
||||
--> $DIR/eq_op.rs:38:13
|
||||
|
|
||||
LL | let _ = 1 / 1;
|
||||
| ^^^^^
|
||||
|
||||
error: equal expressions as operands to `&&`
|
||||
--> $DIR/eq_op.rs:38:13
|
||||
--> $DIR/eq_op.rs:39:13
|
||||
|
|
||||
LL | let _ = true && true;
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `||`
|
||||
--> $DIR/eq_op.rs:40:13
|
||||
--> $DIR/eq_op.rs:41:13
|
||||
|
|
||||
LL | let _ = true || true;
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `&&`
|
||||
--> $DIR/eq_op.rs:45:13
|
||||
--> $DIR/eq_op.rs:46:13
|
||||
|
|
||||
LL | let _ = a == b && b == a;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `&&`
|
||||
--> $DIR/eq_op.rs:46:13
|
||||
--> $DIR/eq_op.rs:47:13
|
||||
|
|
||||
LL | let _ = a != b && b != a;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `&&`
|
||||
--> $DIR/eq_op.rs:47:13
|
||||
--> $DIR/eq_op.rs:48:13
|
||||
|
|
||||
LL | let _ = a < b && b > a;
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `&&`
|
||||
--> $DIR/eq_op.rs:48:13
|
||||
--> $DIR/eq_op.rs:49:13
|
||||
|
|
||||
LL | let _ = a <= b && b >= a;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: equal expressions as operands to `==`
|
||||
--> $DIR/eq_op.rs:51:13
|
||||
--> $DIR/eq_op.rs:52:13
|
||||
|
|
||||
LL | let _ = a == a;
|
||||
| ^^^^^^
|
||||
|
||||
error: equal expressions as operands to `/`
|
||||
--> $DIR/eq_op.rs:61:20
|
||||
--> $DIR/eq_op.rs:62:20
|
||||
|
|
||||
LL | const D: u32 = A / A;
|
||||
| ^^^^^
|
||||
|
||||
error: equal expressions as operands to `==`
|
||||
--> $DIR/eq_op.rs:92:5
|
||||
--> $DIR/eq_op.rs:93:5
|
||||
|
|
||||
LL | (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
34
tests/ui/suspicious_xor_used_as_pow.rs
Normal file
34
tests/ui/suspicious_xor_used_as_pow.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
#![allow(unused)]
|
||||
#![warn(clippy::suspicious_xor_used_as_pow)]
|
||||
#![allow(clippy::eq_op)]
|
||||
|
||||
macro_rules! macro_test {
|
||||
() => {
|
||||
13
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! macro_test_inside {
|
||||
() => {
|
||||
1 ^ 2 // should warn even if inside macro
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Should warn:
|
||||
let _ = 2 ^ 5;
|
||||
let _ = 2i32 ^ 9i32;
|
||||
let _ = 2i32 ^ 2i32;
|
||||
let _ = 50i32 ^ 3i32;
|
||||
let _ = 5i32 ^ 8i32;
|
||||
let _ = 2i32 ^ 32i32;
|
||||
macro_test_inside!();
|
||||
|
||||
// Should not warn:
|
||||
let x = 0x02;
|
||||
let _ = x ^ 2;
|
||||
let _ = 2 ^ x;
|
||||
let _ = x ^ 5;
|
||||
let _ = 10 ^ 0b0101;
|
||||
let _ = 2i32 ^ macro_test!();
|
||||
}
|
51
tests/ui/suspicious_xor_used_as_pow.stderr
Normal file
51
tests/ui/suspicious_xor_used_as_pow.stderr
Normal file
|
@ -0,0 +1,51 @@
|
|||
error: `^` is not the exponentiation operator
|
||||
--> $DIR/suspicious_xor_used_as_pow.rs:19:13
|
||||
|
|
||||
LL | let _ = 2 ^ 5;
|
||||
| ^^^^^ help: did you mean to write: `2.pow(5)`
|
||||
|
|
||||
= note: `-D clippy::suspicious-xor-used-as-pow` implied by `-D warnings`
|
||||
|
||||
error: `^` is not the exponentiation operator
|
||||
--> $DIR/suspicious_xor_used_as_pow.rs:20:13
|
||||
|
|
||||
LL | let _ = 2i32 ^ 9i32;
|
||||
| ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(9_i32)`
|
||||
|
||||
error: `^` is not the exponentiation operator
|
||||
--> $DIR/suspicious_xor_used_as_pow.rs:21:13
|
||||
|
|
||||
LL | let _ = 2i32 ^ 2i32;
|
||||
| ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(2_i32)`
|
||||
|
||||
error: `^` is not the exponentiation operator
|
||||
--> $DIR/suspicious_xor_used_as_pow.rs:22:13
|
||||
|
|
||||
LL | let _ = 50i32 ^ 3i32;
|
||||
| ^^^^^^^^^^^^ help: did you mean to write: `50_i32.pow(3_i32)`
|
||||
|
||||
error: `^` is not the exponentiation operator
|
||||
--> $DIR/suspicious_xor_used_as_pow.rs:23:13
|
||||
|
|
||||
LL | let _ = 5i32 ^ 8i32;
|
||||
| ^^^^^^^^^^^ help: did you mean to write: `5_i32.pow(8_i32)`
|
||||
|
||||
error: `^` is not the exponentiation operator
|
||||
--> $DIR/suspicious_xor_used_as_pow.rs:24: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_used_as_pow.rs:13:9
|
||||
|
|
||||
LL | 1 ^ 2 // should warn even if inside macro
|
||||
| ^^^^^ help: did you mean to write: `1.pow(2)`
|
||||
...
|
||||
LL | macro_test_inside!();
|
||||
| -------------------- in this macro invocation
|
||||
|
|
||||
= note: this error originates in the macro `macro_test_inside` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
Loading…
Reference in a new issue