diff --git a/CHANGELOG.md b/CHANGELOG.md index d40eb9513f4d..aca6d82bcac3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1157,6 +1157,7 @@ All notable changes to this project will be documented in this file. [`wrong_pub_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_pub_self_convention [`wrong_self_convention`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_self_convention [`wrong_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#wrong_transmute +[`xor_used_as_pow`]: https://rust-lang.github.io/rust-clippy/master/index.html#xor_used_as_pow [`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero [`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal [`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr diff --git a/README.md b/README.md index 4c2e65300a67..cb28113f5e6d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 305 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 306 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index cfd6070356d1..ccc92ff4e01b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -273,6 +273,7 @@ pub mod use_self; pub mod vec; pub mod wildcard_dependencies; pub mod write; +pub mod xor_used_as_pow; pub mod zero_div_zero; // end lints modules, do not remove this comment, it’s used in `update_lints` @@ -582,6 +583,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { reg.register_late_lint_pass(box path_buf_push_overwrite::PathBufPushOverwrite); reg.register_late_lint_pass(box checked_conversions::CheckedConversions); reg.register_late_lint_pass(box integer_division::IntegerDivision); + reg.register_early_lint_pass(box xor_used_as_pow::XorUsedAsPow); reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![ arithmetic::FLOAT_ARITHMETIC, @@ -889,6 +891,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { write::WRITELN_EMPTY_STRING, write::WRITE_LITERAL, write::WRITE_WITH_NEWLINE, + xor_used_as_pow::XOR_USED_AS_POW, zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); @@ -1105,6 +1108,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { types::UNIT_CMP, unicode::ZERO_WIDTH_SPACE, unused_io_amount::UNUSED_IO_AMOUNT, + xor_used_as_pow::XOR_USED_AS_POW, ]); reg.register_lint_group("clippy::perf", Some("clippy_perf"), vec![ diff --git a/clippy_lints/src/xor_used_as_pow.rs b/clippy_lints/src/xor_used_as_pow.rs new file mode 100644 index 000000000000..06b069b41eb9 --- /dev/null +++ b/clippy_lints/src/xor_used_as_pow.rs @@ -0,0 +1,54 @@ +use crate::utils::span_lint_and_sugg; +use if_chain::if_chain; +use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass}; +use rustc::{declare_lint_pass, declare_tool_lint}; +use rustc_errors::Applicability; +use syntax::ast::{BinOpKind, Expr, ExprKind, LitKind}; + +declare_clippy_lint! { + /// **What it does:** Checks for use of `^` operator when exponentiation was intended. + /// + /// **Why is this bad?** This is most probably a typo. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust,ignore + /// // Bad + /// 2 ^ 16; + /// + /// // Good + /// 1 << 16; + /// 2i32.pow(16); + /// ``` + pub XOR_USED_AS_POW, + correctness, + "use of `^` operator when exponentiation was intended" +} + +declare_lint_pass!(XorUsedAsPow => [XOR_USED_AS_POW]); + +impl EarlyLintPass for XorUsedAsPow { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if_chain! { + if let ExprKind::Binary(op, left, right) = &expr.node; + if BinOpKind::BitXor == op.node; + if let ExprKind::Lit(lit) = &left.node; + if let LitKind::Int(2, _) = lit.node; + if let ExprKind::Lit(lit) = &right.node; + if let LitKind::Int(right, _) = lit.node; + then { + span_lint_and_sugg( + cx, + XOR_USED_AS_POW, + expr.span, + "`^` is not an exponentiation operator but was used as one", + "did you mean to write", + format!("1 << {}", right), + Applicability::MaybeIncorrect, + ) + } + } + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index f28bbf31539d..845b12f1c549 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -6,7 +6,7 @@ pub use lint::Lint; pub use lint::LINT_LEVELS; // begin lint list, do not remove this comment, it’s used in `update_lints` -pub const ALL_LINTS: [Lint; 305] = [ +pub const ALL_LINTS: [Lint; 306] = [ Lint { name: "absurd_extreme_comparisons", group: "correctness", @@ -2114,6 +2114,13 @@ pub const ALL_LINTS: [Lint; 305] = [ deprecation: None, module: "transmute", }, + Lint { + name: "xor_used_as_pow", + group: "correctness", + desc: "use of `^` operator when exponentiation was intended", + deprecation: None, + module: "xor_used_as_pow", + }, Lint { name: "zero_divided_by_zero", group: "complexity", diff --git a/tests/ui/xor_used_as_pow.rs b/tests/ui/xor_used_as_pow.rs new file mode 100644 index 000000000000..08a9d76705aa --- /dev/null +++ b/tests/ui/xor_used_as_pow.rs @@ -0,0 +1,10 @@ +#![warn(clippy::xor_used_as_pow)] + +fn main() { + println!("{}", 2 ^ 16); + // Should be allowed + let x = 16; + println!("{}", 2 ^ x); + let y = 2; + println!("{}", y ^ 16); +} diff --git a/tests/ui/xor_used_as_pow.stderr b/tests/ui/xor_used_as_pow.stderr new file mode 100644 index 000000000000..c3338d788e7d --- /dev/null +++ b/tests/ui/xor_used_as_pow.stderr @@ -0,0 +1,10 @@ +error: `^` is not an exponentiation operator but was used as one + --> $DIR/xor_used_as_pow.rs:4:20 + | +LL | println!("{}", 2 ^ 16); + | ^^^^^^ help: did you mean to write: `1 << 16` + | + = note: `-D clippy::xor-used-as-pow` implied by `-D warnings` + +error: aborting due to previous error +