Skip to content

Commit 4336396

Browse files
LunaBorowskacgm616
authored andcommitted
Add lint for use of ^ operator as exponentiation.
1 parent 9c9aa2d commit 4336396

File tree

6 files changed

+129
-0
lines changed

6 files changed

+129
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,6 +2047,7 @@ Released 2018-09-13
20472047
[`wrong_pub_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_pub_self_convention
20482048
[`wrong_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention
20492049
[`wrong_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_transmute
2050+
[`xor_used_as_pow`]: https://rust-lang.github.io/rust-clippy/master/index.html#xor_used_as_pow
20502051
[`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
20512052
[`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
20522053
[`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr

clippy_lints/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ mod verbose_file_reads;
335335
mod wildcard_dependencies;
336336
mod wildcard_imports;
337337
mod write;
338+
mod xor_used_as_pow;
338339
mod zero_div_zero;
339340
// end lints modules, do not remove this comment, it’s used in `update_lints`
340341

@@ -909,6 +910,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
909910
&write::WRITELN_EMPTY_STRING,
910911
&write::WRITE_LITERAL,
911912
&write::WRITE_WITH_NEWLINE,
913+
&xor_used_as_pow::XOR_USED_AS_POW,
912914
&zero_div_zero::ZERO_DIVIDED_BY_ZERO,
913915
]);
914916
// end register lints, do not remove this comment, it’s used in `update_lints`
@@ -1148,6 +1150,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11481150
store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
11491151
store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
11501152
store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
1153+
store.register_early_pass(|| box xor_used_as_pow::XorUsedAsPow);
11511154

11521155

11531156
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
@@ -1557,6 +1560,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15571560
LintId::of(&write::WRITELN_EMPTY_STRING),
15581561
LintId::of(&write::WRITE_LITERAL),
15591562
LintId::of(&write::WRITE_WITH_NEWLINE),
1563+
LintId::of(&xor_used_as_pow::XOR_USED_AS_POW),
15601564
LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
15611565
]);
15621566

@@ -1820,6 +1824,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
18201824
LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
18211825
LintId::of(&unwrap::PANICKING_UNWRAP),
18221826
LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
1827+
LintId::of(&xor_used_as_pow::XOR_USED_AS_POW),
18231828
]);
18241829

18251830
store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![

clippy_lints/src/xor_used_as_pow.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use crate::utils::{span_help_and_lint, span_lint_and_sugg};
2+
use if_chain::if_chain;
3+
use rustc::lint::{in_external_macro, EarlyContext, EarlyLintPass, LintArray, LintPass};
4+
use rustc::{declare_lint_pass, declare_tool_lint};
5+
use rustc_errors::Applicability;
6+
use syntax::ast::{BinOpKind, Expr, ExprKind, LitKind};
7+
8+
declare_clippy_lint! {
9+
/// **What it does:** Checks for use of `^` operator when exponentiation was intended.
10+
///
11+
/// **Why is this bad?** This is most probably a typo.
12+
///
13+
/// **Known problems:** None.
14+
///
15+
/// **Example:**
16+
///
17+
/// ```rust,ignore
18+
/// // Bad
19+
/// 2 ^ 16;
20+
///
21+
/// // Good
22+
/// 1 << 16;
23+
/// 2i32.pow(16);
24+
/// ```
25+
pub XOR_USED_AS_POW,
26+
correctness,
27+
"use of `^` operator when exponentiation was intended"
28+
}
29+
30+
declare_lint_pass!(XorUsedAsPow => [XOR_USED_AS_POW]);
31+
32+
impl EarlyLintPass for XorUsedAsPow {
33+
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
34+
if_chain! {
35+
if !in_external_macro(cx.sess, expr.span);
36+
if let ExprKind::Binary(op, left, right) = &expr.node;
37+
if BinOpKind::BitXor == op.node;
38+
if let ExprKind::Lit(lit) = &left.node;
39+
if let LitKind::Int(lhs, _) = lit.node;
40+
if let ExprKind::Lit(lit) = &right.node;
41+
if let LitKind::Int(rhs, _) = lit.node;
42+
then {
43+
if lhs == 2 {
44+
if rhs == 8 || rhs == 16 || rhs == 32 || rhs == 64 || rhs == 128 {
45+
span_lint_and_sugg(
46+
cx,
47+
XOR_USED_AS_POW,
48+
expr.span,
49+
"it appears you are trying to get the maximum value of an integer, but `^` is not an exponentiation operator",
50+
"try",
51+
format!("std::u{}::MAX", rhs),
52+
Applicability::MaybeIncorrect,
53+
)
54+
} else {
55+
span_lint_and_sugg(
56+
cx,
57+
XOR_USED_AS_POW,
58+
expr.span,
59+
"it appears you are trying to get a power of two, but `^` is not an exponentiation operator",
60+
"use a bitshift instead",
61+
format!("1 << {}", rhs),
62+
Applicability::MaybeIncorrect,
63+
)
64+
}
65+
} else {
66+
span_help_and_lint(
67+
cx,
68+
XOR_USED_AS_POW,
69+
expr.span,
70+
"`^` is not an exponentiation operator but appears to have been used as one",
71+
"did you mean to use .pow()?"
72+
)
73+
}
74+
}
75+
}
76+
}
77+
}

src/lintlist/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2853,6 +2853,13 @@ vec![
28532853
deprecation: None,
28542854
module: "transmute",
28552855
},
2856+
Lint {
2857+
name: "xor_used_as_pow",
2858+
group: "correctness",
2859+
desc: "use of `^` operator when exponentiation was intended",
2860+
deprecation: None,
2861+
module: "xor_used_as_pow",
2862+
},
28562863
Lint {
28572864
name: "zero_divided_by_zero",
28582865
group: "complexity",

tests/ui/xor_used_as_pow.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![warn(clippy::xor_used_as_pow)]
2+
3+
fn main() {
4+
// These should succeed
5+
// With variables, it's not as clear whether the intention was exponentiation or not
6+
let x = 15;
7+
println!("{}", 2 ^ x);
8+
let y = 2;
9+
println!("{}", y ^ 16);
10+
11+
// These should fail
12+
println!("{}", 2 ^ 16);
13+
println!("{}", 2 ^ 7);
14+
println!("{}", 9 ^ 3);
15+
}

tests/ui/xor_used_as_pow.stderr

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error: it appears you are trying to get the maximum value of an integer, but `^` is not an exponentiation operator
2+
--> $DIR/xor_used_as_pow.rs:12:20
3+
|
4+
LL | println!("{}", 2 ^ 16);
5+
| ^^^^^^ help: try: `std::u16::MAX`
6+
|
7+
= note: `-D clippy::xor-used-as-pow` implied by `-D warnings`
8+
9+
error: it appears you are trying to get a power of two, but `^` is not an exponentiation operator
10+
--> $DIR/xor_used_as_pow.rs:13:20
11+
|
12+
LL | println!("{}", 2 ^ 7);
13+
| ^^^^^ help: use a bitshift instead: `1 << 7`
14+
15+
error: `^` is not an exponentiation operator but appears to have been used as one
16+
--> $DIR/xor_used_as_pow.rs:14:20
17+
|
18+
LL | println!("{}", 9 ^ 3);
19+
| ^^^^^
20+
|
21+
= help: did you mean to use .pow()?
22+
23+
error: aborting due to 3 previous errors
24+

0 commit comments

Comments
 (0)