Skip to content

Commit ad9b9a8

Browse files
KamilaBorowskacgm616
authored andcommitted
Add lint for use of ^ operator as exponentiation.
1 parent 81890c5 commit ad9b9a8

File tree

6 files changed

+127
-0
lines changed

6 files changed

+127
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -2040,6 +2040,7 @@ Released 2018-09-13
20402040
[`wrong_pub_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_pub_self_convention
20412041
[`wrong_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention
20422042
[`wrong_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_transmute
2043+
[`xor_used_as_pow`]: https://rust-lang.github.io/rust-clippy/master/index.html#xor_used_as_pow
20432044
[`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
20442045
[`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
20452046
[`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr

clippy_lints/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ mod verbose_file_reads;
332332
mod wildcard_dependencies;
333333
mod wildcard_imports;
334334
mod write;
335+
mod xor_used_as_pow;
335336
mod zero_div_zero;
336337
// end lints modules, do not remove this comment, it’s used in `update_lints`
337338

@@ -1134,6 +1135,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11341135
store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
11351136
store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
11361137
store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
1138+
store.register_early_pass(|| box xor_used_as_pow::XorUsedAsPow);
11371139

11381140

11391141
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
@@ -1536,6 +1538,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15361538
LintId::of(&write::WRITELN_EMPTY_STRING),
15371539
LintId::of(&write::WRITE_LITERAL),
15381540
LintId::of(&write::WRITE_WITH_NEWLINE),
1541+
LintId::of(&xor_used_as_pow::XOR_USED_AS_POW),
15391542
LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
15401543
]);
15411544

clippy_lints/src/xor_used_as_pow.rs

+77
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 {
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

+7
Original file line numberDiff line numberDiff line change
@@ -2804,6 +2804,13 @@ vec![
28042804
deprecation: None,
28052805
module: "transmute",
28062806
},
2807+
Lint {
2808+
name: "xor_used_as_pow",
2809+
group: "correctness",
2810+
desc: "use of `^` operator when exponentiation was intended",
2811+
deprecation: None,
2812+
module: "xor_used_as_pow",
2813+
},
28072814
Lint {
28082815
name: "zero_divided_by_zero",
28092816
group: "complexity",

tests/ui/xor_used_as_pow.rs

+15
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

+24
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)