Skip to content

Commit 45413ed

Browse files
LunaBorowskacgm616
authored andcommitted
Add lint for use of ^ operator as exponentiation.
1 parent 85959be commit 45413ed

File tree

6 files changed

+127
-0
lines changed

6 files changed

+127
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,6 +2041,7 @@ Released 2018-09-13
20412041
[`wrong_pub_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_pub_self_convention
20422042
[`wrong_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention
20432043
[`wrong_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_transmute
2044+
[`xor_used_as_pow`]: https://rust-lang.github.io/rust-clippy/master/index.html#xor_used_as_pow
20442045
[`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
20452046
[`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
20462047
[`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr

clippy_lints/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ mod verbose_file_reads;
333333
mod wildcard_dependencies;
334334
mod wildcard_imports;
335335
mod write;
336+
mod xor_used_as_pow;
336337
mod zero_div_zero;
337338
// end lints modules, do not remove this comment, it’s used in `update_lints`
338339

@@ -1137,6 +1138,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11371138
store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
11381139
store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
11391140
store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
1141+
store.register_early_pass(|| box xor_used_as_pow::XorUsedAsPow);
11401142

11411143

11421144
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
@@ -1540,6 +1542,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15401542
LintId::of(&write::WRITELN_EMPTY_STRING),
15411543
LintId::of(&write::WRITE_LITERAL),
15421544
LintId::of(&write::WRITE_WITH_NEWLINE),
1545+
LintId::of(&xor_used_as_pow::XOR_USED_AS_POW),
15431546
LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
15441547
]);
15451548

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
@@ -2811,6 +2811,13 @@ vec![
28112811
deprecation: None,
28122812
module: "transmute",
28132813
},
2814+
Lint {
2815+
name: "xor_used_as_pow",
2816+
group: "correctness",
2817+
desc: "use of `^` operator when exponentiation was intended",
2818+
deprecation: None,
2819+
module: "xor_used_as_pow",
2820+
},
28142821
Lint {
28152822
name: "zero_divided_by_zero",
28162823
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)