Skip to content

Commit 37d338c

Browse files
committed
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`]
2 parents 60d1718 + 151395d commit 37d338c

8 files changed

+171
-28
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4251,6 +4251,7 @@ Released 2018-09-13
42514251
[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
42524252
[`suspicious_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned
42534253
[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
4254+
[`suspicious_xor_used_as_pow`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_xor_used_as_pow
42544255
[`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref
42554256
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
42564257
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment

clippy_lints/src/declared_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
544544
crate::suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS_INFO,
545545
crate::suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL_INFO,
546546
crate::suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL_INFO,
547+
crate::suspicious_xor_used_as_pow::SUSPICIOUS_XOR_USED_AS_POW_INFO,
547548
crate::swap::ALMOST_SWAPPED_INFO,
548549
crate::swap::MANUAL_SWAP_INFO,
549550
crate::swap_ptr_to_ref::SWAP_PTR_TO_REF_INFO,

clippy_lints/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ mod strings;
268268
mod strlen_on_c_strings;
269269
mod suspicious_operation_groupings;
270270
mod suspicious_trait_impl;
271+
mod suspicious_xor_used_as_pow;
271272
mod swap;
272273
mod swap_ptr_to_ref;
273274
mod tabs_in_doc_comments;
@@ -916,6 +917,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
916917
store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
917918
store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
918919
store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
920+
store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
919921
// add lints here, do not remove this comment, it's used in `new_lint`
920922
}
921923

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use clippy_utils::{numeric_literal::NumericLiteral, source::snippet_with_context};
2+
use rustc_errors::Applicability;
3+
use rustc_hir::{BinOpKind, Expr, ExprKind};
4+
use rustc_lint::{LateContext, LateLintPass, LintContext};
5+
use rustc_middle::lint::in_external_macro;
6+
use rustc_session::{declare_lint_pass, declare_tool_lint};
7+
8+
declare_clippy_lint! {
9+
/// ### What it does
10+
/// 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.
11+
/// ### Why is this bad?
12+
/// It's most probably a typo and may lead to unexpected behaviours.
13+
/// ### Example
14+
/// ```rust
15+
/// let x = 3_i32 ^ 4_i32;
16+
/// ```
17+
/// Use instead:
18+
/// ```rust
19+
/// let x = 3_i32.pow(4);
20+
/// ```
21+
#[clippy::version = "1.66.0"]
22+
pub SUSPICIOUS_XOR_USED_AS_POW,
23+
restriction,
24+
"XOR (`^`) operator possibly used as exponentiation operator"
25+
}
26+
declare_lint_pass!(ConfusingXorAndPow => [SUSPICIOUS_XOR_USED_AS_POW]);
27+
28+
impl LateLintPass<'_> for ConfusingXorAndPow {
29+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
30+
if !in_external_macro(cx.sess(), expr.span) &&
31+
let ExprKind::Binary(op, left, right) = &expr.kind &&
32+
op.node == BinOpKind::BitXor &&
33+
left.span.ctxt() == right.span.ctxt() &&
34+
let ExprKind::Lit(lit_left) = &left.kind &&
35+
let ExprKind::Lit(lit_right) = &right.kind &&
36+
let snip_left = snippet_with_context(cx, lit_left.span, lit_left.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
37+
let snip_right = snippet_with_context(cx, lit_right.span, lit_right.span.ctxt(), "..", &mut Applicability::MaybeIncorrect) &&
38+
let Some(left_val) = NumericLiteral::from_lit_kind(&snip_left.0, &lit_left.node) &&
39+
let Some(right_val) = NumericLiteral::from_lit_kind(&snip_right.0, &lit_right.node) &&
40+
left_val.is_decimal() &&
41+
right_val.is_decimal() {
42+
clippy_utils::diagnostics::span_lint_and_sugg(
43+
cx,
44+
SUSPICIOUS_XOR_USED_AS_POW,
45+
expr.span,
46+
"`^` is not the exponentiation operator",
47+
"did you mean to write",
48+
format!("{}.pow({})", left_val.format(), right_val.format()),
49+
Applicability::MaybeIncorrect,
50+
);
51+
}
52+
}
53+
}

tests/ui/eq_op.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#![warn(clippy::eq_op)]
44
#![allow(clippy::double_parens, clippy::identity_op, clippy::nonminimal_bool)]
5+
#![allow(clippy::suspicious_xor_used_as_pow)]
56

67
fn main() {
78
// simple values and comparisons

tests/ui/eq_op.stderr

+28-28
Original file line numberDiff line numberDiff line change
@@ -1,169 +1,169 @@
11
error: equal expressions as operands to `==`
2-
--> $DIR/eq_op.rs:8:13
2+
--> $DIR/eq_op.rs:9:13
33
|
44
LL | let _ = 1 == 1;
55
| ^^^^^^
66
|
77
= note: `-D clippy::eq-op` implied by `-D warnings`
88

99
error: equal expressions as operands to `==`
10-
--> $DIR/eq_op.rs:9:13
10+
--> $DIR/eq_op.rs:10:13
1111
|
1212
LL | let _ = "no" == "no";
1313
| ^^^^^^^^^^^^
1414

1515
error: equal expressions as operands to `!=`
16-
--> $DIR/eq_op.rs:11:13
16+
--> $DIR/eq_op.rs:12:13
1717
|
1818
LL | let _ = false != false;
1919
| ^^^^^^^^^^^^^^
2020

2121
error: equal expressions as operands to `<`
22-
--> $DIR/eq_op.rs:12:13
22+
--> $DIR/eq_op.rs:13:13
2323
|
2424
LL | let _ = 1.5 < 1.5;
2525
| ^^^^^^^^^
2626

2727
error: equal expressions as operands to `>=`
28-
--> $DIR/eq_op.rs:13:13
28+
--> $DIR/eq_op.rs:14:13
2929
|
3030
LL | let _ = 1u64 >= 1u64;
3131
| ^^^^^^^^^^^^
3232

3333
error: equal expressions as operands to `&`
34-
--> $DIR/eq_op.rs:16:13
34+
--> $DIR/eq_op.rs:17:13
3535
|
3636
LL | let _ = (1u32 as u64) & (1u32 as u64);
3737
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3838

3939
error: equal expressions as operands to `^`
40-
--> $DIR/eq_op.rs:19:17
40+
--> $DIR/eq_op.rs:20:17
4141
|
4242
LL | let _ = 1 ^ ((((((1))))));
4343
| ^^^^^^^^^^^^^^^^^
4444

4545
error: equal expressions as operands to `<`
46-
--> $DIR/eq_op.rs:23:13
46+
--> $DIR/eq_op.rs:24:13
4747
|
4848
LL | let _ = (-(2) < -(2));
4949
| ^^^^^^^^^^^^^
5050

5151
error: equal expressions as operands to `==`
52-
--> $DIR/eq_op.rs:24:13
52+
--> $DIR/eq_op.rs:25:13
5353
|
5454
LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
5555
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5656

5757
error: equal expressions as operands to `&`
58-
--> $DIR/eq_op.rs:24:14
58+
--> $DIR/eq_op.rs:25:14
5959
|
6060
LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
6161
| ^^^^^^^^^^^^^^^^^
6262

6363
error: equal expressions as operands to `&`
64-
--> $DIR/eq_op.rs:24:35
64+
--> $DIR/eq_op.rs:25:35
6565
|
6666
LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
6767
| ^^^^^^^^^^^^^^^^^
6868

6969
error: equal expressions as operands to `==`
70-
--> $DIR/eq_op.rs:25:13
70+
--> $DIR/eq_op.rs:26:13
7171
|
7272
LL | let _ = (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
7373
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7474

7575
error: equal expressions as operands to `!=`
76-
--> $DIR/eq_op.rs:28:13
76+
--> $DIR/eq_op.rs:29:13
7777
|
7878
LL | let _ = ([1] != [1]);
7979
| ^^^^^^^^^^^^
8080

8181
error: equal expressions as operands to `!=`
82-
--> $DIR/eq_op.rs:29:13
82+
--> $DIR/eq_op.rs:30:13
8383
|
8484
LL | let _ = ((1, 2) != (1, 2));
8585
| ^^^^^^^^^^^^^^^^^^
8686

8787
error: equal expressions as operands to `==`
88-
--> $DIR/eq_op.rs:33:13
88+
--> $DIR/eq_op.rs:34:13
8989
|
9090
LL | let _ = 1 + 1 == 2;
9191
| ^^^^^^^^^^
9292

9393
error: equal expressions as operands to `==`
94-
--> $DIR/eq_op.rs:34:13
94+
--> $DIR/eq_op.rs:35:13
9595
|
9696
LL | let _ = 1 - 1 == 0;
9797
| ^^^^^^^^^^
9898

9999
error: equal expressions as operands to `-`
100-
--> $DIR/eq_op.rs:34:13
100+
--> $DIR/eq_op.rs:35:13
101101
|
102102
LL | let _ = 1 - 1 == 0;
103103
| ^^^^^
104104

105105
error: equal expressions as operands to `-`
106-
--> $DIR/eq_op.rs:36:13
106+
--> $DIR/eq_op.rs:37:13
107107
|
108108
LL | let _ = 1 - 1;
109109
| ^^^^^
110110

111111
error: equal expressions as operands to `/`
112-
--> $DIR/eq_op.rs:37:13
112+
--> $DIR/eq_op.rs:38:13
113113
|
114114
LL | let _ = 1 / 1;
115115
| ^^^^^
116116

117117
error: equal expressions as operands to `&&`
118-
--> $DIR/eq_op.rs:38:13
118+
--> $DIR/eq_op.rs:39:13
119119
|
120120
LL | let _ = true && true;
121121
| ^^^^^^^^^^^^
122122

123123
error: equal expressions as operands to `||`
124-
--> $DIR/eq_op.rs:40:13
124+
--> $DIR/eq_op.rs:41:13
125125
|
126126
LL | let _ = true || true;
127127
| ^^^^^^^^^^^^
128128

129129
error: equal expressions as operands to `&&`
130-
--> $DIR/eq_op.rs:45:13
130+
--> $DIR/eq_op.rs:46:13
131131
|
132132
LL | let _ = a == b && b == a;
133133
| ^^^^^^^^^^^^^^^^
134134

135135
error: equal expressions as operands to `&&`
136-
--> $DIR/eq_op.rs:46:13
136+
--> $DIR/eq_op.rs:47:13
137137
|
138138
LL | let _ = a != b && b != a;
139139
| ^^^^^^^^^^^^^^^^
140140

141141
error: equal expressions as operands to `&&`
142-
--> $DIR/eq_op.rs:47:13
142+
--> $DIR/eq_op.rs:48:13
143143
|
144144
LL | let _ = a < b && b > a;
145145
| ^^^^^^^^^^^^^^
146146

147147
error: equal expressions as operands to `&&`
148-
--> $DIR/eq_op.rs:48:13
148+
--> $DIR/eq_op.rs:49:13
149149
|
150150
LL | let _ = a <= b && b >= a;
151151
| ^^^^^^^^^^^^^^^^
152152

153153
error: equal expressions as operands to `==`
154-
--> $DIR/eq_op.rs:51:13
154+
--> $DIR/eq_op.rs:52:13
155155
|
156156
LL | let _ = a == a;
157157
| ^^^^^^
158158

159159
error: equal expressions as operands to `/`
160-
--> $DIR/eq_op.rs:61:20
160+
--> $DIR/eq_op.rs:62:20
161161
|
162162
LL | const D: u32 = A / A;
163163
| ^^^^^
164164

165165
error: equal expressions as operands to `==`
166-
--> $DIR/eq_op.rs:92:5
166+
--> $DIR/eq_op.rs:93:5
167167
|
168168
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
169169
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![allow(unused)]
2+
#![warn(clippy::suspicious_xor_used_as_pow)]
3+
#![allow(clippy::eq_op)]
4+
5+
macro_rules! macro_test {
6+
() => {
7+
13
8+
};
9+
}
10+
11+
macro_rules! macro_test_inside {
12+
() => {
13+
1 ^ 2 // should warn even if inside macro
14+
};
15+
}
16+
17+
fn main() {
18+
// Should warn:
19+
let _ = 2 ^ 5;
20+
let _ = 2i32 ^ 9i32;
21+
let _ = 2i32 ^ 2i32;
22+
let _ = 50i32 ^ 3i32;
23+
let _ = 5i32 ^ 8i32;
24+
let _ = 2i32 ^ 32i32;
25+
macro_test_inside!();
26+
27+
// Should not warn:
28+
let x = 0x02;
29+
let _ = x ^ 2;
30+
let _ = 2 ^ x;
31+
let _ = x ^ 5;
32+
let _ = 10 ^ 0b0101;
33+
let _ = 2i32 ^ macro_test!();
34+
}
+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
error: `^` is not the exponentiation operator
2+
--> $DIR/suspicious_xor_used_as_pow.rs:19:13
3+
|
4+
LL | let _ = 2 ^ 5;
5+
| ^^^^^ help: did you mean to write: `2.pow(5)`
6+
|
7+
= note: `-D clippy::suspicious-xor-used-as-pow` implied by `-D warnings`
8+
9+
error: `^` is not the exponentiation operator
10+
--> $DIR/suspicious_xor_used_as_pow.rs:20:13
11+
|
12+
LL | let _ = 2i32 ^ 9i32;
13+
| ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(9_i32)`
14+
15+
error: `^` is not the exponentiation operator
16+
--> $DIR/suspicious_xor_used_as_pow.rs:21:13
17+
|
18+
LL | let _ = 2i32 ^ 2i32;
19+
| ^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(2_i32)`
20+
21+
error: `^` is not the exponentiation operator
22+
--> $DIR/suspicious_xor_used_as_pow.rs:22:13
23+
|
24+
LL | let _ = 50i32 ^ 3i32;
25+
| ^^^^^^^^^^^^ help: did you mean to write: `50_i32.pow(3_i32)`
26+
27+
error: `^` is not the exponentiation operator
28+
--> $DIR/suspicious_xor_used_as_pow.rs:23:13
29+
|
30+
LL | let _ = 5i32 ^ 8i32;
31+
| ^^^^^^^^^^^ help: did you mean to write: `5_i32.pow(8_i32)`
32+
33+
error: `^` is not the exponentiation operator
34+
--> $DIR/suspicious_xor_used_as_pow.rs:24:13
35+
|
36+
LL | let _ = 2i32 ^ 32i32;
37+
| ^^^^^^^^^^^^ help: did you mean to write: `2_i32.pow(32_i32)`
38+
39+
error: `^` is not the exponentiation operator
40+
--> $DIR/suspicious_xor_used_as_pow.rs:13:9
41+
|
42+
LL | 1 ^ 2 // should warn even if inside macro
43+
| ^^^^^ help: did you mean to write: `1.pow(2)`
44+
...
45+
LL | macro_test_inside!();
46+
| -------------------- in this macro invocation
47+
|
48+
= note: this error originates in the macro `macro_test_inside` (in Nightly builds, run with -Z macro-backtrace for more info)
49+
50+
error: aborting due to 7 previous errors
51+

0 commit comments

Comments
 (0)