From d7ea6addf06f0db99f4d21b229c7bfea223d827d Mon Sep 17 00:00:00 2001 From: Michael Recachinas Date: Sun, 17 Sep 2017 17:18:12 +0100 Subject: [PATCH 01/60] (#1955): Suggests `x > y` over `x >= y + 1` for ints This module handles the following cases: - `... >= ... + 1` and `... >= 1 + ...` - `... - 1 >= ...` and `-1 + ... >= ...` - `... + 1 <= ...` and `... + 1 <= ...` - `... <= ... - 1` and `... <= -1 + ...` Note: this only goes 1 level deep (i.e., does not constant-fold) and does not currently simplify expressions. Examples of these cases include: ```rust let x = 1; y >= y + x; // won't catch this case or any permutation x + 1 >= y + 2; // won't catch this case x + 1 - 1 >= y - 1 + 1; // WILL catch this case when it likely shouldn't ``` --- clippy_lints/src/int_plus_one.rs | 115 +++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 clippy_lints/src/int_plus_one.rs diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs new file mode 100644 index 000000000000..75538e7946e1 --- /dev/null +++ b/clippy_lints/src/int_plus_one.rs @@ -0,0 +1,115 @@ +//! lint on blocks unnecessarily using >= with a + 1 or - 1 + +use rustc::lint::*; +use syntax::ast::*; + +use utils::span_help_and_lint; + +/// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block +/// +/// +/// **Why is this bad?** Readability -- better to use `> y` instead of `>= y + 1`. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// x >= y + 1 +/// ``` +/// +/// Could be written: +/// +/// ```rust +/// x > y +/// ``` +declare_lint! { + pub INT_PLUS_ONE, + Allow, + "instead of using x >= y + 1, use x > y" +} + +pub struct IntPlusOne; + +impl LintPass for IntPlusOne { + fn get_lints(&self) -> LintArray { + lint_array!(INT_PLUS_ONE) + } +} + +// cases: +// BinOpKind::Ge +// x >= y + 1 +// x - 1 >= y +// +// BinOpKind::Le +// x + 1 <= y +// x <= y - 1 + +impl IntPlusOne { + #[allow(cast_sign_loss)] + fn check_lit(&self, lit: &Lit, target_value: i128) -> bool { + if let LitKind::Int(value, ..) = lit.node { + return value == (target_value as u128) + } + false + } + + fn check_binop(&self, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> bool { + match (binop, &lhs.node, &rhs.node) { + // case where `x - 1 >= ...` or `-1 + x >= ...` + (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => { + match (lhskind.node, &lhslhs.node, &lhsrhs.node) { + // `-1 + x` + (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => self.check_lit(lit, -1), + // `x - 1` + (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => self.check_lit(lit, 1), + _ => false + } + }, + // case where `... >= y + 1` or `... >= 1 + y` + (BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) if rhskind.node == BinOpKind::Add => { + match (&rhslhs.node, &rhsrhs.node) { + // `y + 1` and `1 + y` + (&ExprKind::Lit(ref lit), _)|(_, &ExprKind::Lit(ref lit)) => self.check_lit(lit, 1), + _ => false + } + }, + // case where `x + 1 <= ...` or `1 + x <= ...` + (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => { + match (&lhslhs.node, &lhsrhs.node) { + // `1 + x` and `x + 1` + (&ExprKind::Lit(ref lit), _)|(_, &ExprKind::Lit(ref lit)) => self.check_lit(lit, 1), + _ => false + } + }, + // case where `... >= y - 1` or `... >= -1 + y` + (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => { + match (rhskind.node, &rhslhs.node, &rhsrhs.node) { + // `-1 + y` + (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => self.check_lit(lit, -1), + // `y - 1` + (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => self.check_lit(lit, 1), + _ => false + } + }, + _ => false + } + } + +} + +impl EarlyLintPass for IntPlusOne { + fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) { + if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.node { + if self.check_binop(kind.node, lhs, rhs) { + span_help_and_lint( + cx, + INT_PLUS_ONE, + item.span, + "Unnecessary `>= y + 1` or `x - 1 >=`", + "Consider reducing `x >= y + 1` or `x - 1 >= y` to `x > y`", + ); + } + } + } +} From 535302efda3b36b850f74019adc3f0e9823efeba Mon Sep 17 00:00:00 2001 From: Michael Recachinas Date: Sun, 17 Sep 2017 17:27:16 +0100 Subject: [PATCH 02/60] Register 'int_plus_one' lint case in clippy_lints --- clippy_lints/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 520f9362c0fd..e8b468e13f6d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -96,6 +96,7 @@ pub mod identity_op; pub mod if_let_redundant_pattern_matching; pub mod if_not_else; pub mod infinite_iter; +pub mod int_plus_one; pub mod is_unit_expr; pub mod items_after_statements; pub mod large_enum_variant; @@ -299,6 +300,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_early_lint_pass(box formatting::Formatting); reg.register_late_lint_pass(box swap::Swap); reg.register_early_lint_pass(box if_not_else::IfNotElse); + reg.register_early_lint_pass(box int_plus_one::IntPlusOne); reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional); reg.register_late_lint_pass(box unused_label::UnusedLabel); reg.register_late_lint_pass(box new_without_default::NewWithoutDefault); @@ -341,6 +343,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { enum_variants::PUB_ENUM_VARIANT_NAMES, enum_variants::STUTTER, if_not_else::IF_NOT_ELSE, + int_plus_one::INT_PLUS_ONE, infinite_iter::MAYBE_INFINITE_ITER, items_after_statements::ITEMS_AFTER_STATEMENTS, matches::SINGLE_MATCH_ELSE, From bb40bd68a460b024a6141db290dccd51bdc7f747 Mon Sep 17 00:00:00 2001 From: Michael Recachinas Date: Sun, 17 Sep 2017 17:27:40 +0100 Subject: [PATCH 03/60] Add tests for 'int_plus_one' --- tests/ui/int_plus_one.rs | 18 ++++++++++++++++++ tests/ui/int_plus_one.stderr | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 tests/ui/int_plus_one.rs create mode 100644 tests/ui/int_plus_one.stderr diff --git a/tests/ui/int_plus_one.rs b/tests/ui/int_plus_one.rs new file mode 100644 index 000000000000..90375dad555f --- /dev/null +++ b/tests/ui/int_plus_one.rs @@ -0,0 +1,18 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#[allow(no_effect, unnecessary_operation)] +#[warn(int_plus_one)] +fn main() { + let x = 1i32; + let y = 0i32; + + x >= y + 1; + y + 1 <= x; + + x - 1 >= y; + y <= x - 1; + + x > y; // should be ok + y < x; // should be ok +} diff --git a/tests/ui/int_plus_one.stderr b/tests/ui/int_plus_one.stderr new file mode 100644 index 000000000000..fd39e038e014 --- /dev/null +++ b/tests/ui/int_plus_one.stderr @@ -0,0 +1,35 @@ +error: Unnecessary `>= y + 1` or `x - 1 >=` + --> $DIR/int_plus_one.rs:10:5 + | +10 | x >= y + 1; + | ^^^^^^^^^^ + | + = note: `-D int-plus-one` implied by `-D warnings` + = help: Consider reducing `x >= y + 1` or `x - 1 >= y` to `x > y` + +error: Unnecessary `>= y + 1` or `x - 1 >=` + --> $DIR/int_plus_one.rs:11:5 + | +11 | y + 1 <= x; + | ^^^^^^^^^^ + | + = help: Consider reducing `x >= y + 1` or `x - 1 >= y` to `x > y` + +error: Unnecessary `>= y + 1` or `x - 1 >=` + --> $DIR/int_plus_one.rs:13:5 + | +13 | x - 1 >= y; + | ^^^^^^^^^^ + | + = help: Consider reducing `x >= y + 1` or `x - 1 >= y` to `x > y` + +error: Unnecessary `>= y + 1` or `x - 1 >=` + --> $DIR/int_plus_one.rs:14:5 + | +14 | y <= x - 1; + | ^^^^^^^^^^ + | + = help: Consider reducing `x >= y + 1` or `x - 1 >= y` to `x > y` + +error: aborting due to 4 previous errors + From 62ae6d225185843a5b0d9d543e2f710d1a3306cc Mon Sep 17 00:00:00 2001 From: Luca Bruno Date: Mon, 18 Sep 2017 14:44:28 +0000 Subject: [PATCH 04/60] lints/doc_markdown: add two more entries --- clippy_lints/src/utils/conf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 7251538c09aa..3c05fca316f0 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -154,7 +154,7 @@ define_Conf! { "JavaScript", "NaN", "OAuth", - "OpenGL", + "OpenGL", "OpenSSH", "OpenSSL", "TrueType", "iOS", "macOS", "TeX", "LaTeX", "BibTex", "BibLaTex", From 0b64222a68abb56798ddb57dbbd1fb3ddf2e4b9e Mon Sep 17 00:00:00 2001 From: Martin Carton Date: Mon, 18 Sep 2017 22:40:00 +0200 Subject: [PATCH 05/60] Fix case in doc_valid_idents BibTeX and BibLaTeX use the usual capitalization of TeX tools: - https://www.ctan.org/pkg/bibtex - https://www.ctan.org/pkg/biblatex --- clippy_lints/src/utils/conf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 3c05fca316f0..f88294763dc3 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -157,7 +157,7 @@ define_Conf! { "OpenGL", "OpenSSH", "OpenSSL", "TrueType", "iOS", "macOS", - "TeX", "LaTeX", "BibTex", "BibLaTex", + "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", ] => Vec), /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have From 35fa4429e3889cc87c2087d5faa351b5861d408c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 18 Sep 2017 20:23:08 -0700 Subject: [PATCH 06/60] Rust upgrade to rustc 1.22.0-nightly (0701b37d9 2017-09-18) --- clippy_lints/src/bit_mask.rs | 2 +- clippy_lints/src/consts.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index db57864cb2f0..9b64a42d4f7f 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -307,7 +307,7 @@ fn fetch_int_literal(cx: &LateContext, lit: &Expr) -> Option { cx.tcx.mir_const_qualif(def_id); cx.tcx.hir.body(cx.tcx.hir.body_owned_by(id)) } else { - cx.tcx.extern_const_body(def_id) + cx.tcx.extern_const_body(def_id).body }; fetch_int_literal(cx, &body.value) }) diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 2611ba1adf2d..7e6f3c2acf11 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -298,7 +298,7 @@ impl<'c, 'cc> ConstEvalLateContext<'c, 'cc> { self.tcx.mir_const_qualif(def_id); self.tcx.hir.body(self.tcx.hir.body_owned_by(id)) } else { - self.tcx.extern_const_body(def_id) + self.tcx.extern_const_body(def_id).body }; let ret = cx.expr(&body.value); if ret.is_some() { From 31489d75a3492f3e6e0d2394d54caa9ea69df084 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 18 Sep 2017 20:26:36 -0700 Subject: [PATCH 07/60] Bump to 0.0.162 --- CHANGELOG.md | 6 ++++++ Cargo.lock | 6 +++--- Cargo.toml | 4 ++-- clippy_lints/Cargo.toml | 2 +- clippy_lints/src/lib.rs | 1 + 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 989f9f2da787..d000f2dd9994 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Change Log All notable changes to this project will be documented in this file. +## 0.0.162 +* Update to *rustc 1.22.0-nightly (0701b37d9 2017-09-18)* +* New lint: [`chars_last_cmp`] +* Improved suggestions for [`needless_borrow`], [`ptr_arg`], + ## 0.0.161 * Update to *rustc 1.22.0-nightly (539f2083d 2017-09-13)* @@ -457,6 +462,7 @@ All notable changes to this project will be documented in this file. [`cast_precision_loss`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cast_precision_loss [`cast_sign_loss`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#cast_sign_loss [`char_lit_as_u8`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#char_lit_as_u8 +[`chars_last_cmp`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#chars_last_cmp [`chars_next_cmp`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#chars_next_cmp [`clone_double_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#clone_double_ref [`clone_on_copy`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#clone_on_copy diff --git a/Cargo.lock b/Cargo.lock index ffc84a488eb9..88f1a8a7f3ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "clippy_lints" -version = "0.0.161" +version = "0.0.162" dependencies = [ "itertools 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -73,11 +73,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clippy" -version = "0.0.161" +version = "0.0.162" dependencies = [ "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.1.0", - "clippy_lints 0.0.161", + "clippy_lints 0.0.162", "compiletest_rs 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 41ea684f327f..46780712ad94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.161" +version = "0.0.162" authors = [ "Manish Goregaokar ", "Andre Bogus ", @@ -31,7 +31,7 @@ path = "src/main.rs" [dependencies] # begin automatic update -clippy_lints = { version = "0.0.161", path = "clippy_lints" } +clippy_lints = { version = "0.0.162", path = "clippy_lints" } # end automatic update cargo_metadata = "0.2" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index fee0391dacd6..ef527dbf0399 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin automatic update -version = "0.0.161" +version = "0.0.162" # end automatic update authors = [ "Manish Goregaokar ", diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 520f9362c0fd..5cb7034c7bfc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -458,6 +458,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { matches::MATCH_REF_PATS, matches::MATCH_WILD_ERR_ARM, matches::SINGLE_MATCH, + methods::CHARS_LAST_CMP, methods::CHARS_NEXT_CMP, methods::CLONE_DOUBLE_REF, methods::CLONE_ON_COPY, From 1e0268fda85abecd3b9f6d2f6d401c51ca09acc1 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 20 Sep 2017 23:59:23 +0200 Subject: [PATCH 08/60] avoid linting `ptr_arg` if `.capacity()` is called. Also suggest removing `.as_str()` where applicable. THis fixes #2070. Also fixes a few formatting mishaps --- Cargo.lock | 64 ++++++------ clippy_lints/src/literal_digit_grouping.rs | 16 ++- clippy_lints/src/missing_doc.rs | 11 +- clippy_lints/src/print.rs | 3 +- clippy_lints/src/ptr.rs | 111 ++++++++++++--------- clippy_lints/src/utils/conf.rs | 9 +- tests/ui/ptr_arg.rs | 12 +++ tests/ui/ptr_arg.stderr | 31 ++++-- 8 files changed, 154 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 88f1a8a7f3ad..53e3cc9ff6a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,8 +9,8 @@ dependencies = [ "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -28,22 +28,22 @@ name = "backtrace" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -61,11 +61,16 @@ name = "cargo_metadata" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.2" @@ -82,8 +87,8 @@ dependencies = [ "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -137,11 +142,6 @@ dependencies = [ "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "gcc" -version = "0.3.53" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "getopts" version = "0.2.15" @@ -157,7 +157,7 @@ dependencies = [ [[package]] name = "itoa" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -181,7 +181,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.30" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -199,7 +199,7 @@ name = "memchr" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -209,7 +209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -289,12 +289,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -317,9 +317,9 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -328,7 +328,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -364,7 +364,7 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -408,10 +408,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" -"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c" +"checksum backtrace-sys 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "c63ea141ef8fdb10409d0f5daf30ac51f84ef43bff66f16627773d2a292cd189" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" +"checksum cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum compiletest_rs 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2741d378feb7a434dba54228c89a70b4e427fee521de67cdda3750b8a0265f5a" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" @@ -419,14 +420,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e45aa15fe0a8a8f511e6d834626afd55e49b62e5c8802e18328a87e8a8f6065c" "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" "checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46" -"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" "checksum itertools 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22c285d60139cf413244894189ca52debcfd70b57966feed060da76802e415a0" -"checksum itoa 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ac17257442c2ed77dbc9fd555cf83c58b0c7f7d0e8f2ae08c0ac05c72842e1f6" +"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" "checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b" -"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" +"checksum libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d1419b2939a0bc44b77feb34661583c7546b532b192feab36249ab584b86856c" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" @@ -442,8 +442,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb6a7637a47663ee073391a139ed07851f27ed2532c2abc88c6bf27a16cdf34" -"checksum serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "812ff66056fd9a9a5b7c119714243b0862cf98340e7d4b5ee05a932c40d5ea6c" +"checksum serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7046c9d4c6c522d10b2d098f9bebe2bef227e0e74044d8c1bfcf6b476af799" +"checksum serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1afcaae083fd1c46952a315062326bc9957f182358eb7da03b57ef1c688f7aa9" "checksum serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd381f6d01a6616cdba8530492d453b7761b456ba974e98768a18cad2cd76f58" "checksum serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d243424e06f9f9c39e3cd36147470fd340db785825e367625f79298a6ac6b7ac" "checksum shared_child 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "099b38928dbe4a0a01fcd8c233183072f14a7d126a34bed05880869be66e14cc" diff --git a/clippy_lints/src/literal_digit_grouping.rs b/clippy_lints/src/literal_digit_grouping.rs index 1cd539eac398..b656fed1cfbc 100644 --- a/clippy_lints/src/literal_digit_grouping.rs +++ b/clippy_lints/src/literal_digit_grouping.rs @@ -279,12 +279,19 @@ impl LiteralDigitGrouping { let fractional_part = &parts[1].chars().rev().collect::(); let _ = Self::do_lint(fractional_part) .map(|fractional_group_size| { - let consistent = Self::parts_consistent(integral_group_size, fractional_group_size, parts[0].len(), parts[1].len()); + let consistent = Self::parts_consistent(integral_group_size, + fractional_group_size, + parts[0].len(), + parts[1].len()); if !consistent { - WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(), cx, &lit.span); + WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(), + cx, + &lit.span); } }) - .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), cx, &lit.span)); + .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), + cx, + &lit.span)); } }) .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), cx, &lit.span)); @@ -332,7 +339,8 @@ impl LiteralDigitGrouping { .windows(2) .all(|ps| ps[1] - ps[0] == group_size + 1) // number of digits to the left of the last group cannot be bigger than group size. - && (digits.len() - underscore_positions.last().expect("there's at least one element") <= group_size + 1); + && (digits.len() - underscore_positions.last() + .expect("there's at least one element") <= group_size + 1); if !consistent { return Err(WarningType::InconsistentDigitGrouping); diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 81a8b4ffb2e4..2ad6c36ab5f0 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -15,16 +15,7 @@ // *rustc*'s // [`missing_doc`]. // -// [`missing_doc`]: -// https://github. -// com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin. -// -// -// -// -// -// -// rs#L246 +// [`missing_doc`]: https://github.com/rust-lang/rust/blob/d6d05904697d89099b55da3331155392f1db9c00/src/librustc_lint/builtin.rs#L246 // use rustc::hir; diff --git a/clippy_lints/src/print.rs b/clippy_lints/src/print.rs index 1f24a7af0526..078e208467aa 100644 --- a/clippy_lints/src/print.rs +++ b/clippy_lints/src/print.rs @@ -124,7 +124,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { else if args.len() == 2 && match_def_path(cx.tcx, fun_id, &paths::FMT_ARGUMENTV1_NEW) { if let ExprPath(ref qpath) = args[1].node { if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, args[1].hir_id)) { - if match_def_path(cx.tcx, def_id, &paths::DEBUG_FMT_METHOD) && !is_in_debug_impl(cx, expr) && is_expn_of(expr.span, "panic").is_none() { + if match_def_path(cx.tcx, def_id, &paths::DEBUG_FMT_METHOD) + && !is_in_debug_impl(cx, expr) && is_expn_of(expr.span, "panic").is_none() { span_lint(cx, USE_DEBUG, args[0].span, "use of `Debug`-based formatting"); } } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index cbba4ad26108..69ba0d8bccf4 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -1,5 +1,6 @@ //! Checks for usage of `&Vec[_]` and `&String`. +use std::borrow::Cow; use rustc::hir::*; use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc::hir::map::NodeItem; @@ -163,44 +164,48 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option< ], { ty_snippet = snippet_opt(cx, parameters.types[0].span); }); - let spans = get_spans(cx, opt_body_id, idx, "to_owned"); - span_lint_and_then( - cx, - PTR_ARG, - arg.span, - "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ - with non-Vec-based slices.", - |db| { - if let Some(ref snippet) = ty_snippet { + if let Ok(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) { + span_lint_and_then( + cx, + PTR_ARG, + arg.span, + "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \ + with non-Vec-based slices.", + |db| { + if let Some(ref snippet) = ty_snippet { + db.span_suggestion(arg.span, + "change this to", + format!("&[{}]", snippet)); + } + for (clonespan, suggestion) in spans { + db.span_suggestion(clonespan, + &snippet_opt(cx, clonespan).map_or("change the call to".into(), + |x| Cow::Owned(format!("change `{}` to", x))), + suggestion.into()); + } + } + ); + } + } else if match_type(cx, ty, &paths::STRING) { + if let Ok(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) { + span_lint_and_then( + cx, + PTR_ARG, + arg.span, + "writing `&String` instead of `&str` involves a new object where a slice will do.", + |db| { db.span_suggestion(arg.span, "change this to", - format!("&[{}]", snippet)); + "&str".into()); + for (clonespan, suggestion) in spans { + db.span_suggestion_short(clonespan, + &snippet_opt(cx, clonespan).map_or("change the call to".into(), + |x| Cow::Owned(format!("change `{}` to", x))), + suggestion.into()); + } } - for (clonespan, suggestion) in spans { - db.span_suggestion(clonespan, - "change the `.clone()` to", - suggestion); - } - } - ); - } else if match_type(cx, ty, &paths::STRING) { - let spans = get_spans(cx, opt_body_id, idx, "to_string"); - span_lint_and_then( - cx, - PTR_ARG, - arg.span, - "writing `&String` instead of `&str` involves a new object where a slice will do.", - |db| { - db.span_suggestion(arg.span, - "change this to", - "&str".into()); - for (clonespan, suggestion) in spans { - db.span_suggestion_short(clonespan, - "change the `.clone` to ", - suggestion); - } - } - ); + ); + } } } } @@ -229,38 +234,50 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option< } } -fn get_spans(cx: &LateContext, opt_body_id: Option, idx: usize, fn_name: &'static str) -> Vec<(Span, String)> { +fn get_spans(cx: &LateContext, opt_body_id: Option, idx: usize, replacements: &'static [(&'static str, &'static str)]) -> Result)>, ()> { if let Some(body) = opt_body_id.map(|id| cx.tcx.hir.body(id)) { - get_binding_name(&body.arguments[idx]).map_or_else(Vec::new, - |name| extract_clone_suggestions(cx, name, fn_name, body)) + get_binding_name(&body.arguments[idx]).map_or_else(|| Ok(vec![]), + |name| extract_clone_suggestions(cx, name, replacements, body)) } else { - vec![] + Ok(vec![]) } } -fn extract_clone_suggestions<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, fn_name: &'static str, body: &'tcx Body) -> Vec<(Span, String)> { +fn extract_clone_suggestions<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, name: Name, replace: &'static [(&'static str, &'static str)], body: &'tcx Body) -> Result)>, ()> { let mut visitor = PtrCloneVisitor { cx, name, - fn_name, - spans: vec![] + replace, + spans: vec![], + abort: false, }; visitor.visit_body(body); - visitor.spans + if visitor.abort { Err(()) } else { Ok(visitor.spans) } } struct PtrCloneVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, name: Name, - fn_name: &'static str, - spans: Vec<(Span, String)>, + replace: &'static [(&'static str, &'static str)], + spans: Vec<(Span, Cow<'static, str>)>, + abort: bool, } impl<'a, 'tcx: 'a> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr) { + if self.abort { return; } if let ExprMethodCall(ref seg, _, ref args) = expr.node { - if args.len() == 1 && match_var(&args[0], self.name) && seg.name == "clone" { - self.spans.push((expr.span, format!("{}.{}()", snippet(self.cx, args[0].span, "_"), self.fn_name))); + if args.len() == 1 && match_var(&args[0], self.name) { + if seg.name == "capacity" { + self.abort = true; + return; + } + for &(fn_name, suffix) in self.replace { + if seg.name == fn_name { + self.spans.push((expr.span, snippet(self.cx, args[0].span, "_") + suffix)); + return; + } + } } return; } diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index f88294763dc3..4145f74e9368 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -82,7 +82,8 @@ macro_rules! define_Conf { #[serde(rename_all="kebab-case")] #[serde(deny_unknown_fields)] pub struct Conf { - $(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)] pub $rust_name: define_Conf!(TY $($ty)+),)+ + $(#[$doc] #[serde(default=$rust_name_str)] #[serde(with=$rust_name_str)] + pub $rust_name: define_Conf!(TY $($ty)+),)+ #[allow(dead_code)] #[serde(default)] third_party: Option<::toml::Value>, @@ -91,10 +92,12 @@ macro_rules! define_Conf { mod $rust_name { use serde; use serde::Deserialize; - pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result { + pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) + -> Result { type T = define_Conf!(TY $($ty)+); Ok(T::deserialize(deserializer).unwrap_or_else(|e| { - ::utils::conf::ERRORS.lock().expect("no threading here").push(::utils::conf::Error::Toml(e.to_string())); + ::utils::conf::ERRORS.lock().expect("no threading here") + .push(::utils::conf::Error::Toml(e.to_string())); super::$rust_name() })) } diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index a386fcf82df7..127ae7037021 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -55,3 +55,15 @@ fn str_cloned(x: &String) -> String { .clone(); x.clone() } + +fn false_positive_capacity(x: &Vec, y: &String) { + let a = x.capacity(); + let b = y.clone(); + let c = y.as_str(); +} + +fn false_positive_capacity_too(x: &String) -> String { + if x.capacity() > 1024 { panic!("Too large!"); } + x.clone() +} + diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index 46d7cbdb0310..e9ada9f8aaa8 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -28,11 +28,11 @@ help: change this to | 40 | fn cloned(x: &[u8]) -> Vec { | ^^^^^ -help: change the `.clone()` to +help: change `x.clone()` to | 41 | let e = x.to_owned(); | ^^^^^^^^^^^^ -help: change the `.clone()` to +help: change `x.clone()` to | 46 | x.to_owned() | ^^^^^^^^^^^^ @@ -47,18 +47,37 @@ help: change this to | 49 | fn str_cloned(x: &str) -> String { | ^^^^ -help: change the `.clone` to +help: change `x.clone()` to | 50 | let a = x.to_string(); | ^^^^^^^^^^^^^ -help: change the `.clone` to +help: change `x.clone()` to | 51 | let b = x.to_string(); | ^^^^^^^^^^^^^ -help: change the `.clone` to +help: change `x.clone()` to | 56 | x.to_string() | ^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: writing `&String` instead of `&str` involves a new object where a slice will do. + --> $DIR/ptr_arg.rs:59:44 + | +59 | fn false_positive_capacity(x: &Vec, y: &String) { + | ^^^^^^^ + | +help: change this to + | +59 | fn false_positive_capacity(x: &Vec, y: &str) { + | ^^^^ +help: change `y.clone()` to + | +61 | let b = y.to_string(); + | ^^^^^^^^^^^^^ +help: change `y.as_str()` to + | +62 | let c = y; + | ^ + +error: aborting due to 6 previous errors From 21e9a1285de20f2aaad9b644655fb24f146f3a76 Mon Sep 17 00:00:00 2001 From: Michael Recachinas Date: Sat, 23 Sep 2017 19:32:11 +0100 Subject: [PATCH 09/60] Use span_lint_and_then as per feedback --- clippy_lints/src/int_plus_one.rs | 112 +++++++++++++++++++++++++------ tests/ui/int_plus_one.stderr | 20 ++++-- 2 files changed, 106 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 75538e7946e1..d8b056fc29a5 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -3,7 +3,7 @@ use rustc::lint::*; use syntax::ast::*; -use utils::span_help_and_lint; +use utils::{span_lint_and_then, snippet_opt}; /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block /// @@ -45,6 +45,11 @@ impl LintPass for IntPlusOne { // x + 1 <= y // x <= y - 1 +enum Side { + LHS, + RHS, +} + impl IntPlusOne { #[allow(cast_sign_loss)] fn check_lit(&self, lit: &Lit, target_value: i128) -> bool { @@ -54,62 +59,125 @@ impl IntPlusOne { false } - fn check_binop(&self, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> bool { + fn check_binop(&self, cx: &EarlyContext, block: &Expr, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<(bool, Option)> { match (binop, &lhs.node, &rhs.node) { // case where `x - 1 >= ...` or `-1 + x >= ...` (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => { match (lhskind.node, &lhslhs.node, &lhsrhs.node) { // `-1 + x` - (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => self.check_lit(lit, -1), + (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => { + let recommendation = self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS); + if self.check_lit(lit, -1) { + self.emit_warning(cx, block, recommendation) + } + }, // `x - 1` - (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => self.check_lit(lit, 1), - _ => false + (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => { + let recommendation = self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS); + if self.check_lit(lit, 1) { + self.emit_warning(cx, block, recommendation) + } + } + _ => () } }, // case where `... >= y + 1` or `... >= 1 + y` (BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) if rhskind.node == BinOpKind::Add => { match (&rhslhs.node, &rhsrhs.node) { // `y + 1` and `1 + y` - (&ExprKind::Lit(ref lit), _)|(_, &ExprKind::Lit(ref lit)) => self.check_lit(lit, 1), - _ => false + (&ExprKind::Lit(ref lit), _) => { + let recommendation = self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS); + if self.check_lit(lit, 1) { + self.emit_warning(cx, block, recommendation) + } + }, + (_, &ExprKind::Lit(ref lit)) => { + let recommendation = self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS); + if self.check_lit(lit, 1) { + self.emit_warning(cx, block, recommendation) + } + }, + _ => () } }, // case where `x + 1 <= ...` or `1 + x <= ...` (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => { match (&lhslhs.node, &lhsrhs.node) { // `1 + x` and `x + 1` - (&ExprKind::Lit(ref lit), _)|(_, &ExprKind::Lit(ref lit)) => self.check_lit(lit, 1), - _ => false + (&ExprKind::Lit(ref lit), _) => { + let recommendation = self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS); + if self.check_lit(lit, 1) { + self.emit_warning(cx, block, recommendation) + } + }, + (_, &ExprKind::Lit(ref lit)) => { + let recommendation = self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS); + if self.check_lit(lit, 1) { + self.emit_warning(cx, block, recommendation) + } + }, + _ => () } }, // case where `... >= y - 1` or `... >= -1 + y` (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => { match (rhskind.node, &rhslhs.node, &rhsrhs.node) { // `-1 + y` - (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => self.check_lit(lit, -1), + (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => { + let recommendation = self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS); + if self.check_lit(lit, -1) { + self.emit_warning(cx, block, recommendation) + } + }, // `y - 1` - (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => self.check_lit(lit, 1), - _ => false + (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => { + let recommendation = self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS); + if self.check_lit(lit, 1) { + self.emit_warning(cx, block, recommendation) + } + }, + _ => () } }, - _ => false + _ => () } } + fn generate_recommendation(&self, cx: &EarlyContext, binop: BinOpKind, node: &Expr, other_side: &Expr, side: Side) -> Option { + let binop_string = match binop { + BinOpKind::Ge => ">", + BinOpKind::Le => "<", + _ => return None + }; + if let Some(snippet) = snippet_opt(cx, node.span) { + if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) { + let rec = match side { + Side::LHS => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)), + Side::RHS => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)), + }; + return rec; + } + } + None + } + + fn emit_warning(&self, cx: &EarlyContext, block: &Expr, recommendation: Option) { + if let Some(rec) = recommendation { + span_lint_and_then(cx, + INT_PLUS_ONE, + block.span, + "Unnecessary `>= y + 1` or `x - 1 >=`", + |db| { + db.span_suggestion(block.span, "change `>= y + 1` to `> y` as shown", rec); + }); + } + } } impl EarlyLintPass for IntPlusOne { fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) { if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.node { - if self.check_binop(kind.node, lhs, rhs) { - span_help_and_lint( - cx, - INT_PLUS_ONE, - item.span, - "Unnecessary `>= y + 1` or `x - 1 >=`", - "Consider reducing `x >= y + 1` or `x - 1 >= y` to `x > y`", - ); - } + self.check_binop(cx, item, kind.node, lhs, rhs); } } } diff --git a/tests/ui/int_plus_one.stderr b/tests/ui/int_plus_one.stderr index fd39e038e014..6f69ba9d7146 100644 --- a/tests/ui/int_plus_one.stderr +++ b/tests/ui/int_plus_one.stderr @@ -5,7 +5,10 @@ error: Unnecessary `>= y + 1` or `x - 1 >=` | ^^^^^^^^^^ | = note: `-D int-plus-one` implied by `-D warnings` - = help: Consider reducing `x >= y + 1` or `x - 1 >= y` to `x > y` +help: change `>= y + 1` to `> y` as shown + | +10 | x > y; + | ^^^^^ error: Unnecessary `>= y + 1` or `x - 1 >=` --> $DIR/int_plus_one.rs:11:5 @@ -13,7 +16,10 @@ error: Unnecessary `>= y + 1` or `x - 1 >=` 11 | y + 1 <= x; | ^^^^^^^^^^ | - = help: Consider reducing `x >= y + 1` or `x - 1 >= y` to `x > y` +help: change `>= y + 1` to `> y` as shown + | +11 | y < x; + | ^^^^^ error: Unnecessary `>= y + 1` or `x - 1 >=` --> $DIR/int_plus_one.rs:13:5 @@ -21,7 +27,10 @@ error: Unnecessary `>= y + 1` or `x - 1 >=` 13 | x - 1 >= y; | ^^^^^^^^^^ | - = help: Consider reducing `x >= y + 1` or `x - 1 >= y` to `x > y` +help: change `>= y + 1` to `> y` as shown + | +13 | x > y; + | ^^^^^ error: Unnecessary `>= y + 1` or `x - 1 >=` --> $DIR/int_plus_one.rs:14:5 @@ -29,7 +38,10 @@ error: Unnecessary `>= y + 1` or `x - 1 >=` 14 | y <= x - 1; | ^^^^^^^^^^ | - = help: Consider reducing `x >= y + 1` or `x - 1 >= y` to `x > y` +help: change `>= y + 1` to `> y` as shown + | +14 | y < x; + | ^^^^^ error: aborting due to 4 previous errors From e3c4ec74d7f0661fdcab30566c2065ecafb66ecb Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 23 Sep 2017 13:30:29 -0700 Subject: [PATCH 10/60] Rust upgrade to rustc 1.22.0-nightly (14039a42a 2017-09-22) --- clippy_lints/src/lifetimes.rs | 18 +++++++++--------- clippy_lints/src/types.rs | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 9e7e19a8df5a..5cbb854be923 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -113,7 +113,7 @@ fn check_fn_inner<'a, 'tcx>( .parameters .lifetimes; for bound in bounds { - if bound.name != "'static" && !bound.is_elided() { + if bound.name.name() != "'static" && !bound.is_elided() { return; } bounds_lts.push(bound); @@ -225,7 +225,7 @@ fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet { let mut allowed_lts = HashSet::new(); for lt in named_lts { if lt.bounds.is_empty() { - allowed_lts.insert(RefLt::Named(lt.lifetime.name)); + allowed_lts.insert(RefLt::Named(lt.lifetime.name.name())); } } allowed_lts.insert(RefLt::Unnamed); @@ -235,8 +235,8 @@ fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet { fn lts_from_bounds<'a, T: Iterator>(mut vec: Vec, bounds_lts: T) -> Vec { for lt in bounds_lts { - if lt.name != "'static" { - vec.push(RefLt::Named(lt.name)); + if lt.name.name() != "'static" { + vec.push(RefLt::Named(lt.name.name())); } } @@ -266,12 +266,12 @@ impl<'v, 't> RefVisitor<'v, 't> { fn record(&mut self, lifetime: &Option) { if let Some(ref lt) = *lifetime { - if lt.name == "'static" { + if lt.name.name() == "'static" { self.lts.push(RefLt::Static); } else if lt.is_elided() { self.lts.push(RefLt::Unnamed); } else { - self.lts.push(RefLt::Named(lt.name)); + self.lts.push(RefLt::Named(lt.name.name())); } } else { self.lts.push(RefLt::Unnamed); @@ -396,7 +396,7 @@ struct LifetimeChecker { impl<'tcx> Visitor<'tcx> for LifetimeChecker { // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { - self.map.remove(&lifetime.name); + self.map.remove(&lifetime.name.name()); } fn visit_lifetime_def(&mut self, _: &'tcx LifetimeDef) { @@ -415,7 +415,7 @@ fn report_extra_lifetimes<'a, 'tcx: 'a>(cx: &LateContext<'a, 'tcx>, func: &'tcx let hs = generics .lifetimes .iter() - .map(|lt| (lt.lifetime.name, lt.lifetime.span)) + .map(|lt| (lt.lifetime.name.name(), lt.lifetime.span)) .collect(); let mut checker = LifetimeChecker { map: hs }; @@ -434,7 +434,7 @@ struct BodyLifetimeChecker { impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker { // for lifetimes as parameters of generics fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) { - if lifetime.name != keywords::Invalid.name() && lifetime.name != "'static" { + if lifetime.name.name() != keywords::Invalid.name() && lifetime.name.name() != "'static" { self.lifetimes_used_in_body = true; } } diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 567e8b5423e1..90f1e87796d3 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -223,7 +223,7 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { let ltopt = if lt.is_elided() { "".to_owned() } else { - format!("{} ", lt.name.as_str()) + format!("{} ", lt.name.name().as_str()) }; let mutopt = if *mutbl == Mutability::MutMutable { "mut " From 50e410e7968540cfd55b43720c599f653d7d1162 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 23 Sep 2017 13:35:06 -0700 Subject: [PATCH 11/60] Update test expectations --- tests/ui/mut_mut.stderr | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index dd3a85c97760..7a7bb840ba98 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -27,12 +27,6 @@ error: this expression mutably borrows a mutable reference. Consider reborrowing 26 | let mut y = &mut x; | ^^^^^^ -error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:30:17 - | -30 | let y : &mut &mut u32 = &mut &mut 2; - | ^^^^^^^^^^^^^ - error: generally you want to avoid `&mut &mut _` if possible --> $DIR/mut_mut.rs:30:33 | @@ -45,6 +39,18 @@ error: generally you want to avoid `&mut &mut _` if possible 30 | let y : &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ +error: generally you want to avoid `&mut &mut _` if possible + --> $DIR/mut_mut.rs:30:17 + | +30 | let y : &mut &mut u32 = &mut &mut 2; + | ^^^^^^^^^^^^^ + +error: generally you want to avoid `&mut &mut _` if possible + --> $DIR/mut_mut.rs:35:38 + | +35 | let y : &mut &mut &mut u32 = &mut &mut &mut 2; + | ^^^^^^^^^^^^^^^^ + error: generally you want to avoid `&mut &mut _` if possible --> $DIR/mut_mut.rs:35:17 | @@ -57,12 +63,6 @@ error: generally you want to avoid `&mut &mut _` if possible 35 | let y : &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ -error: generally you want to avoid `&mut &mut _` if possible - --> $DIR/mut_mut.rs:35:38 - | -35 | let y : &mut &mut &mut u32 = &mut &mut &mut 2; - | ^^^^^^^^^^^^^^^^ - error: generally you want to avoid `&mut &mut _` if possible --> $DIR/mut_mut.rs:35:17 | From 287e997b1e2a92a0e887c1918ad6f1c9ed5e7a4f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 23 Sep 2017 13:36:18 -0700 Subject: [PATCH 12/60] Bump to 0.0.163 --- CHANGELOG.md | 3 +++ Cargo.toml | 4 ++-- clippy_lints/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d000f2dd9994..15a0ee74e6b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Change Log All notable changes to this project will be documented in this file. +## 0.0.163 +* Update to *rustc 1.22.0-nightly (14039a42a 2017-09-22)* + ## 0.0.162 * Update to *rustc 1.22.0-nightly (0701b37d9 2017-09-18)* * New lint: [`chars_last_cmp`] diff --git a/Cargo.toml b/Cargo.toml index 46780712ad94..16aaf148c60a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.162" +version = "0.0.163" authors = [ "Manish Goregaokar ", "Andre Bogus ", @@ -31,7 +31,7 @@ path = "src/main.rs" [dependencies] # begin automatic update -clippy_lints = { version = "0.0.162", path = "clippy_lints" } +clippy_lints = { version = "0.0.163", path = "clippy_lints" } # end automatic update cargo_metadata = "0.2" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index ef527dbf0399..96bd05162dca 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin automatic update -version = "0.0.162" +version = "0.0.163" # end automatic update authors = [ "Manish Goregaokar ", From a822cab01f7f7c0db3fb55182e38a30b4fcbd3e4 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 23 Sep 2017 13:36:40 -0700 Subject: [PATCH 13/60] fix docs --- PUBLISH.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PUBLISH.md b/PUBLISH.md index 1ff3f2b4b731..a9496d5b414d 100644 --- a/PUBLISH.md +++ b/PUBLISH.md @@ -7,7 +7,7 @@ Steps to publish a new clippy version - `git push` - Wait for Travis's approval. - Merge. -- `cargo publish` in `./clippy_clints`. +- `cargo publish` in `./clippy_lints`. - `cargo publish` in the root directory. - `git pull`. - `git tag -s v0.0.X -m "v0.0.X"`. From fff35736e4d91f62e0ee3a6d4350c76ab578c38f Mon Sep 17 00:00:00 2001 From: Michael Recachinas Date: Sun, 24 Sep 2017 09:58:58 +0100 Subject: [PATCH 14/60] Remove old return-value --- clippy_lints/src/int_plus_one.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index d8b056fc29a5..eeb0c7edb7af 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -59,7 +59,7 @@ impl IntPlusOne { false } - fn check_binop(&self, cx: &EarlyContext, block: &Expr, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<(bool, Option)> { + fn check_binop(&self, cx: &EarlyContext, block: &Expr, binop: BinOpKind, lhs: &Expr, rhs: &Expr) { match (binop, &lhs.node, &rhs.node) { // case where `x - 1 >= ...` or `-1 + x >= ...` (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => { From 9437d2909c601525a7313cf8a4d72ef3b9810127 Mon Sep 17 00:00:00 2001 From: Michael Recachinas Date: Sun, 24 Sep 2017 10:30:29 +0100 Subject: [PATCH 15/60] Change to returning Option<(bool, Option)> --- clippy_lints/src/int_plus_one.rs | 75 +++++++++++--------------------- 1 file changed, 26 insertions(+), 49 deletions(-) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index eeb0c7edb7af..54142b924ae0 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -59,26 +59,20 @@ impl IntPlusOne { false } - fn check_binop(&self, cx: &EarlyContext, block: &Expr, binop: BinOpKind, lhs: &Expr, rhs: &Expr) { + fn check_binop(&self, cx: &EarlyContext, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<(bool, Option)> { match (binop, &lhs.node, &rhs.node) { // case where `x - 1 >= ...` or `-1 + x >= ...` (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => { match (lhskind.node, &lhslhs.node, &lhsrhs.node) { // `-1 + x` (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => { - let recommendation = self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS); - if self.check_lit(lit, -1) { - self.emit_warning(cx, block, recommendation) - } + Some((self.check_lit(lit, -1), self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS))) }, // `x - 1` (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => { - let recommendation = self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS); - if self.check_lit(lit, 1) { - self.emit_warning(cx, block, recommendation) - } + Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS))) } - _ => () + _ => None } }, // case where `... >= y + 1` or `... >= 1 + y` @@ -86,18 +80,12 @@ impl IntPlusOne { match (&rhslhs.node, &rhsrhs.node) { // `y + 1` and `1 + y` (&ExprKind::Lit(ref lit), _) => { - let recommendation = self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS); - if self.check_lit(lit, 1) { - self.emit_warning(cx, block, recommendation) - } + Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS))) }, (_, &ExprKind::Lit(ref lit)) => { - let recommendation = self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS); - if self.check_lit(lit, 1) { - self.emit_warning(cx, block, recommendation) - } + Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS))) }, - _ => () + _ => None } }, // case where `x + 1 <= ...` or `1 + x <= ...` @@ -105,18 +93,12 @@ impl IntPlusOne { match (&lhslhs.node, &lhsrhs.node) { // `1 + x` and `x + 1` (&ExprKind::Lit(ref lit), _) => { - let recommendation = self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS); - if self.check_lit(lit, 1) { - self.emit_warning(cx, block, recommendation) - } + Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS))) }, (_, &ExprKind::Lit(ref lit)) => { - let recommendation = self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS); - if self.check_lit(lit, 1) { - self.emit_warning(cx, block, recommendation) - } + Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS))) }, - _ => () + _ => None } }, // case where `... >= y - 1` or `... >= -1 + y` @@ -124,22 +106,16 @@ impl IntPlusOne { match (rhskind.node, &rhslhs.node, &rhsrhs.node) { // `-1 + y` (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => { - let recommendation = self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS); - if self.check_lit(lit, -1) { - self.emit_warning(cx, block, recommendation) - } + Some((self.check_lit(lit, -1), self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS))) }, // `y - 1` (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => { - let recommendation = self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS); - if self.check_lit(lit, 1) { - self.emit_warning(cx, block, recommendation) - } + Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS))) }, - _ => () + _ => None } }, - _ => () + _ => None } } @@ -161,23 +137,24 @@ impl IntPlusOne { None } - fn emit_warning(&self, cx: &EarlyContext, block: &Expr, recommendation: Option) { - if let Some(rec) = recommendation { - span_lint_and_then(cx, - INT_PLUS_ONE, - block.span, - "Unnecessary `>= y + 1` or `x - 1 >=`", - |db| { - db.span_suggestion(block.span, "change `>= y + 1` to `> y` as shown", rec); - }); - } + fn emit_warning(&self, cx: &EarlyContext, block: &Expr, recommendation: String) { + span_lint_and_then(cx, + INT_PLUS_ONE, + block.span, + "Unnecessary `>= y + 1` or `x - 1 >=`", + |db| { + db.span_suggestion(block.span, "change `>= y + 1` to `> y` as shown", recommendation); + }); } } impl EarlyLintPass for IntPlusOne { fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) { if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.node { - self.check_binop(cx, item, kind.node, lhs, rhs); + match self.check_binop(cx, kind.node, lhs, rhs) { + Some((should_emit, Some(ref rec))) if should_emit => self.emit_warning(cx, item, rec.clone()), + _ => () + } } } } From f571cf0b5e56ff2f7651fdd809410d35edba09bd Mon Sep 17 00:00:00 2001 From: Michael Recachinas Date: Sun, 24 Sep 2017 12:31:12 +0100 Subject: [PATCH 16/60] Change rtype of int_plus_one detection to Option --- clippy_lints/src/int_plus_one.rs | 39 +++++++++----------------------- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/int_plus_one.rs b/clippy_lints/src/int_plus_one.rs index 54142b924ae0..420427e7d0ab 100644 --- a/clippy_lints/src/int_plus_one.rs +++ b/clippy_lints/src/int_plus_one.rs @@ -59,19 +59,15 @@ impl IntPlusOne { false } - fn check_binop(&self, cx: &EarlyContext, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option<(bool, Option)> { + fn check_binop(&self, cx: &EarlyContext, binop: BinOpKind, lhs: &Expr, rhs: &Expr) -> Option { match (binop, &lhs.node, &rhs.node) { // case where `x - 1 >= ...` or `-1 + x >= ...` (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => { match (lhskind.node, &lhslhs.node, &lhsrhs.node) { // `-1 + x` - (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => { - Some((self.check_lit(lit, -1), self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS))) - }, + (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS), // `x - 1` - (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => { - Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS))) - } + (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS), _ => None } }, @@ -79,12 +75,8 @@ impl IntPlusOne { (BinOpKind::Ge, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) if rhskind.node == BinOpKind::Add => { match (&rhslhs.node, &rhsrhs.node) { // `y + 1` and `1 + y` - (&ExprKind::Lit(ref lit), _) => { - Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS))) - }, - (_, &ExprKind::Lit(ref lit)) => { - Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS))) - }, + (&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS), + (_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS), _ => None } }, @@ -92,12 +84,8 @@ impl IntPlusOne { (BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) if lhskind.node == BinOpKind::Add => { match (&lhslhs.node, &lhsrhs.node) { // `1 + x` and `x + 1` - (&ExprKind::Lit(ref lit), _) => { - Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS))) - }, - (_, &ExprKind::Lit(ref lit)) => { - Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS))) - }, + (&ExprKind::Lit(ref lit), _) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS), + (_, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS), _ => None } }, @@ -105,13 +93,9 @@ impl IntPlusOne { (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => { match (rhskind.node, &rhslhs.node, &rhsrhs.node) { // `-1 + y` - (BinOpKind::Add, &ExprKind::Lit(ref lit), _) => { - Some((self.check_lit(lit, -1), self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS))) - }, + (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if self.check_lit(lit, -1) => self.generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS), // `y - 1` - (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) => { - Some((self.check_lit(lit, 1), self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS))) - }, + (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if self.check_lit(lit, 1) => self.generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS), _ => None } }, @@ -151,9 +135,8 @@ impl IntPlusOne { impl EarlyLintPass for IntPlusOne { fn check_expr(&mut self, cx: &EarlyContext, item: &Expr) { if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.node { - match self.check_binop(cx, kind.node, lhs, rhs) { - Some((should_emit, Some(ref rec))) if should_emit => self.emit_warning(cx, item, rec.clone()), - _ => () + if let Some(ref rec) = self.check_binop(cx, kind.node, lhs, rhs) { + self.emit_warning(cx, item, rec.clone()); } } } From b091fb9b2464907a34279ab99aeffd0552827192 Mon Sep 17 00:00:00 2001 From: Laura Peskin Date: Fri, 11 Aug 2017 02:21:43 +0300 Subject: [PATCH 17/60] add lint declaration and example that should trigger the lint --- clippy_lints/src/loops.rs | 11 ++++++++++- mut_range_bound | Bin 0 -> 422840 bytes tests/run-pass/mut_range_bound.rs | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100755 mut_range_bound create mode 100644 tests/run-pass/mut_range_bound.rs diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 42b31f8eaaaf..e994b88fdcfc 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -328,6 +328,14 @@ declare_lint! { "any loop that will always `break` or `return`" } +/// TODO: add documentation + +declare_lint! { + pub MUT_RANGE_BOUND, + Warn, + "for loop over a range where one of the bounds is a mutable variable" +} + #[derive(Copy, Clone)] pub struct Pass; @@ -348,7 +356,8 @@ impl LintPass for Pass { EMPTY_LOOP, WHILE_LET_ON_ITERATOR, FOR_KV_MAP, - NEVER_LOOP + NEVER_LOOP, + MUT_RANGE_BOUND ) } } diff --git a/mut_range_bound b/mut_range_bound new file mode 100755 index 0000000000000000000000000000000000000000..fdf917d51588cf1dc8e1b99aab86370de80e8355 GIT binary patch literal 422840 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 z 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 literal 0 HcmV?d00001 diff --git a/tests/run-pass/mut_range_bound.rs b/tests/run-pass/mut_range_bound.rs new file mode 100644 index 000000000000..e08babe3137f --- /dev/null +++ b/tests/run-pass/mut_range_bound.rs @@ -0,0 +1,15 @@ +#![feature(plugin)] +#![plugin(clippy)] + +// cause the build to fail if this warning is invoked +#![deny(check_for_loop_mut_bound)] + +// an example +fn mut_range_bound() { + let mut m = 4; + for i in 0..m { continue; } // ERROR One of the range bounds is mutable +} + +fn main(){ + mut_range_bound(); +} From 319f12a4c4d290b12a6d7396e8592391d4fcb1a9 Mon Sep 17 00:00:00 2001 From: Laura Peskin Date: Tue, 15 Aug 2017 19:41:59 +0300 Subject: [PATCH 18/60] implement lint for mutable range bound --- clippy_lints/src/loops.rs | 39 +++++++++++++++++++++++++++ tests/run-pass/mut_range_bound_tmp.rs | 30 +++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 tests/run-pass/mut_range_bound_tmp.rs diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index e994b88fdcfc..31b8b04ecf6f 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -614,6 +614,7 @@ fn check_for_loop<'a, 'tcx>( check_for_loop_arg(cx, pat, arg, expr); check_for_loop_explicit_counter(cx, arg, body, expr); check_for_loop_over_map_kv(cx, pat, arg, body, expr); + check_for_mut_range_bound(cx, arg, expr); detect_manual_memcpy(cx, pat, arg, body, expr); } @@ -1303,6 +1304,44 @@ fn check_for_loop_over_map_kv<'a, 'tcx>( } } +fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, expr: &Expr) { + if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(arg) { + let bounds = vec![start, end]; + for bound in &bounds { + if check_for_mutability(cx, bound) { + span_lint(cx, MUT_RANGE_BOUND, expr.span, "you are looping over a range where at least one bound was defined as a mutable variable. keep in mind that mutating this variable inside the loop will not affect the range"); + return; + } + } + } +} + +fn check_for_mutability(cx: &LateContext, bound: &Expr) -> bool { + if_let_chain! {[ + let ExprPath(ref qpath) = bound.node, + let QPath::Resolved(None, ref path) = *qpath, + path.segments.len() == 1, + ], { + let def = cx.tables.qpath_def(qpath, bound.id); + match def { + Def::Local(..) | Def::Upvar(..) => { + let def_id = def.def_id(); + let node_id = cx.tcx.hir.as_local_node_id(def_id).expect("local/upvar are local nodes"); + let node_str = cx.tcx.hir.get(node_id); + if_let_chain! {[ + let map::Node::NodeLocal(pat) = node_str, + let PatKind::Binding(bind_ann, _, _, _) = pat.node, + let BindingAnnotation::Mutable = bind_ann, + ], { + return true; + }} + }, + _ => (), + }} + } + return false; +} + /// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`. fn pat_is_wild<'tcx>(pat: &'tcx PatKind, body: &'tcx Expr) -> bool { match *pat { diff --git a/tests/run-pass/mut_range_bound_tmp.rs b/tests/run-pass/mut_range_bound_tmp.rs new file mode 100644 index 000000000000..af5cb8f8035a --- /dev/null +++ b/tests/run-pass/mut_range_bound_tmp.rs @@ -0,0 +1,30 @@ +#![feature(plugin)] +#![plugin(clippy)] + +fn main() { + mut_range_bound_upper(); + mut_range_bound_lower(); + mut_range_bound_both(); + immut_range_bound(); +} + +fn mut_range_bound_upper() { + let mut m = 4; + for i in 0..m { continue; } // WARNING the range upper bound is mutable +} + +fn mut_range_bound_lower() { + let mut m = 4; + for i in m..10 { continue; } // WARNING the range lower bound is mutable +} + +fn mut_range_bound_both() { + let mut m = 4; + let mut n = 6; + for i in m..n { continue; } // WARNING both bounds are mutable (should get just one warning for this) +} + +fn immut_range_bound() { + let m = 4; + for i in 0..m { continue; } // no warning +} From 74f4fd32e98f59414758f3b156e417742ef59e29 Mon Sep 17 00:00:00 2001 From: Laura Peskin Date: Wed, 30 Aug 2017 17:38:13 +0300 Subject: [PATCH 19/60] attempt to add check for mutation of range bound within loop; compiles but doesn't work as intended. pushed for feedback --- clippy_lints/src/loops.rs | 62 ++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 31b8b04ecf6f..a40278982ab4 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -7,11 +7,15 @@ use rustc::hir::map::Node::{NodeBlock, NodeExpr, NodeStmt}; use rustc::lint::*; use rustc::middle::const_val::ConstVal; use rustc::middle::region; +use rustc::middle::region::CodeExtent; +use rustc::middle::expr_use_visitor::*; +use rustc::middle::mem_categorization::cmt; use rustc::ty::{self, Ty}; use rustc::ty::subst::{Subst, Substs}; use rustc_const_eval::ConstContext; use std::collections::{HashMap, HashSet}; use syntax::ast; +use syntax::codemap::Span; use utils::sugg; use utils::const_to_u64; @@ -614,7 +618,7 @@ fn check_for_loop<'a, 'tcx>( check_for_loop_arg(cx, pat, arg, expr); check_for_loop_explicit_counter(cx, arg, body, expr); check_for_loop_over_map_kv(cx, pat, arg, body, expr); - check_for_mut_range_bound(cx, arg, expr); + check_for_mut_range_bound(cx, arg, body, expr); detect_manual_memcpy(cx, pat, arg, body, expr); } @@ -1304,11 +1308,49 @@ fn check_for_loop_over_map_kv<'a, 'tcx>( } } -fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, expr: &Expr) { +// TODO: clippy builds, but the `mutate` method of `Delegate` is never called when compiling `tests/run-pass/mut_range_bound_tmp.rs`. what's wrong? + +struct MutateDelegate<'a, 'tcx: 'a> { + cx: &'a LateContext<'a, 'tcx>, + node_id: NodeId, + was_mutated: bool +} + +impl<'a, 'tcx> Delegate<'tcx> for MutateDelegate<'a, 'tcx> { + fn consume(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, mode: ConsumeMode) { + } + + fn matched_pat(&mut self, matched_pat: &Pat, cmt: cmt<'tcx>, mode: MatchMode) { + } + + fn consume_pat(&mut self, consume_pat: &Pat, cmt: cmt<'tcx>, mode: ConsumeMode) { + } + + fn borrow(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, _: LoanCause) { + } + + fn mutate(&mut self, assignment_id: NodeId, _: Span, _: cmt<'tcx>, _: MutateMode) { + println!("something was mutated"); // tmp: see if this function is ever called at all (no) + if assignment_id == self.node_id { + self.was_mutated = true; + } + } + + fn decl_without_init(&mut self, _: NodeId, _: Span) { + } +} + +impl<'a, 'tcx> MutateDelegate<'a, 'tcx> { + fn bound_was_mutated(&self) -> bool { + self.was_mutated + } +} + +fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr, expr: &Expr) { if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(arg) { let bounds = vec![start, end]; for bound in &bounds { - if check_for_mutability(cx, bound) { + if check_for_mutation(cx, body, bound) { span_lint(cx, MUT_RANGE_BOUND, expr.span, "you are looping over a range where at least one bound was defined as a mutable variable. keep in mind that mutating this variable inside the loop will not affect the range"); return; } @@ -1316,11 +1358,10 @@ fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, expr: &Expr) { } } -fn check_for_mutability(cx: &LateContext, bound: &Expr) -> bool { +fn check_for_mutation(cx: &LateContext, body: &Expr, bound: &Expr) -> bool { if_let_chain! {[ let ExprPath(ref qpath) = bound.node, let QPath::Resolved(None, ref path) = *qpath, - path.segments.len() == 1, ], { let def = cx.tables.qpath_def(qpath, bound.id); match def { @@ -1328,13 +1369,18 @@ fn check_for_mutability(cx: &LateContext, bound: &Expr) -> bool { let def_id = def.def_id(); let node_id = cx.tcx.hir.as_local_node_id(def_id).expect("local/upvar are local nodes"); let node_str = cx.tcx.hir.get(node_id); - if_let_chain! {[ + if_let_chain! {[ // prob redundant now, remove let map::Node::NodeLocal(pat) = node_str, let PatKind::Binding(bind_ann, _, _, _) = pat.node, let BindingAnnotation::Mutable = bind_ann, + ], { - return true; - }} + println!("bound was mutable"); // tmp: make sure the full if-let chain executes when it should (yes) + let mut delegate = MutateDelegate { cx: cx, node_id: node_id, was_mutated: false }; + let region_maps = &cx.tcx.region_maps(def_id); // is this the correct argument? + ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_maps, cx.tables).walk_expr(body); + return delegate.bound_was_mutated(); + }} }, _ => (), }} From 27d5ff6c9cafe87411b067b9ef21c50e7590171a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 30 Aug 2017 09:47:28 -0700 Subject: [PATCH 20/60] Rustup --- clippy_lints/src/loops.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index a40278982ab4..bcae2868db27 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1363,15 +1363,15 @@ fn check_for_mutation(cx: &LateContext, body: &Expr, bound: &Expr) -> bool { let ExprPath(ref qpath) = bound.node, let QPath::Resolved(None, ref path) = *qpath, ], { - let def = cx.tables.qpath_def(qpath, bound.id); + let def = cx.tables.qpath_def(qpath, bound.hir_id); match def { Def::Local(..) | Def::Upvar(..) => { let def_id = def.def_id(); let node_id = cx.tcx.hir.as_local_node_id(def_id).expect("local/upvar are local nodes"); let node_str = cx.tcx.hir.get(node_id); if_let_chain! {[ // prob redundant now, remove - let map::Node::NodeLocal(pat) = node_str, - let PatKind::Binding(bind_ann, _, _, _) = pat.node, + let map::Node::NodeLocal(local) = node_str, + let PatKind::Binding(bind_ann, _, _, _) = local.pat.node, let BindingAnnotation::Mutable = bind_ann, ], { From d0eff10a7c3837e447f73864fd61478c7bfbd591 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 30 Aug 2017 10:07:25 -0700 Subject: [PATCH 21/60] Update test, fix lint --- clippy_lints/src/loops.rs | 13 +++++++------ tests/run-pass/mut_range_bound_tmp.rs | 7 ++++++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index bcae2868db27..e1db9447d394 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1329,8 +1329,8 @@ impl<'a, 'tcx> Delegate<'tcx> for MutateDelegate<'a, 'tcx> { fn borrow(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, _: LoanCause) { } - fn mutate(&mut self, assignment_id: NodeId, _: Span, _: cmt<'tcx>, _: MutateMode) { - println!("something was mutated"); // tmp: see if this function is ever called at all (no) + fn mutate(&mut self, assignment_id: NodeId, sp: Span, _: cmt<'tcx>, _: MutateMode) { + self.cx.sess().span_note_without_error(sp, "mutates!"); if assignment_id == self.node_id { self.was_mutated = true; } @@ -1364,18 +1364,19 @@ fn check_for_mutation(cx: &LateContext, body: &Expr, bound: &Expr) -> bool { let QPath::Resolved(None, ref path) = *qpath, ], { let def = cx.tables.qpath_def(qpath, bound.hir_id); + + cx.sess().span_note_without_error(body.span, "loop"); match def { Def::Local(..) | Def::Upvar(..) => { let def_id = def.def_id(); let node_id = cx.tcx.hir.as_local_node_id(def_id).expect("local/upvar are local nodes"); let node_str = cx.tcx.hir.get(node_id); - if_let_chain! {[ // prob redundant now, remove - let map::Node::NodeLocal(local) = node_str, - let PatKind::Binding(bind_ann, _, _, _) = local.pat.node, + if_let_chain! {[ + let map::Node::NodeBinding(pat) = node_str, + let PatKind::Binding(bind_ann, _, _, _) = pat.node, let BindingAnnotation::Mutable = bind_ann, ], { - println!("bound was mutable"); // tmp: make sure the full if-let chain executes when it should (yes) let mut delegate = MutateDelegate { cx: cx, node_id: node_id, was_mutated: false }; let region_maps = &cx.tcx.region_maps(def_id); // is this the correct argument? ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_maps, cx.tables).walk_expr(body); diff --git a/tests/run-pass/mut_range_bound_tmp.rs b/tests/run-pass/mut_range_bound_tmp.rs index af5cb8f8035a..ff164438f3fa 100644 --- a/tests/run-pass/mut_range_bound_tmp.rs +++ b/tests/run-pass/mut_range_bound_tmp.rs @@ -1,6 +1,8 @@ #![feature(plugin)] #![plugin(clippy)] +#![allow(unused)] + fn main() { mut_range_bound_upper(); mut_range_bound_lower(); @@ -10,7 +12,10 @@ fn main() { fn mut_range_bound_upper() { let mut m = 4; - for i in 0..m { continue; } // WARNING the range upper bound is mutable + for i in 0..m { + + m = 5; + continue; } // WARNING the range upper bound is mutable } fn mut_range_bound_lower() { From 9a17150a0683129e6f781958fb55836994ed6ce4 Mon Sep 17 00:00:00 2001 From: Laura Peskin Date: Mon, 18 Sep 2017 17:10:33 -0700 Subject: [PATCH 22/60] refactor, add spans to warnings, add tests --- clippy_lints/src/loops.rs | 91 +++++++++++++++++---------- tests/run-pass/mut_range_bound_tmp.rs | 24 +++++-- 2 files changed, 76 insertions(+), 39 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index e1db9447d394..522e0ae79c02 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -7,8 +7,9 @@ use rustc::hir::map::Node::{NodeBlock, NodeExpr, NodeStmt}; use rustc::lint::*; use rustc::middle::const_val::ConstVal; use rustc::middle::region; -use rustc::middle::region::CodeExtent; +// use rustc::middle::region::CodeExtent; use rustc::middle::expr_use_visitor::*; +use rustc::middle::mem_categorization::Categorization; use rustc::middle::mem_categorization::cmt; use rustc::ty::{self, Ty}; use rustc::ty::subst::{Subst, Substs}; @@ -1308,31 +1309,35 @@ fn check_for_loop_over_map_kv<'a, 'tcx>( } } -// TODO: clippy builds, but the `mutate` method of `Delegate` is never called when compiling `tests/run-pass/mut_range_bound_tmp.rs`. what's wrong? - struct MutateDelegate<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, - node_id: NodeId, - was_mutated: bool + node_id_low: Option, + node_id_high: Option, + span_low: Option, + span_high: Option, } impl<'a, 'tcx> Delegate<'tcx> for MutateDelegate<'a, 'tcx> { - fn consume(&mut self, _: NodeId, _: Span, cmt: cmt<'tcx>, mode: ConsumeMode) { + fn consume(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ConsumeMode) { } - fn matched_pat(&mut self, matched_pat: &Pat, cmt: cmt<'tcx>, mode: MatchMode) { + fn matched_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: MatchMode) { } - fn consume_pat(&mut self, consume_pat: &Pat, cmt: cmt<'tcx>, mode: ConsumeMode) { + fn consume_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: ConsumeMode) { } fn borrow(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, _: LoanCause) { } - fn mutate(&mut self, assignment_id: NodeId, sp: Span, _: cmt<'tcx>, _: MutateMode) { - self.cx.sess().span_note_without_error(sp, "mutates!"); - if assignment_id == self.node_id { - self.was_mutated = true; + fn mutate(&mut self, _: NodeId, sp: Span, cmt: cmt<'tcx>, _: MutateMode) { + if let Categorization::Local(id) = cmt.cat { + if Some(id) == self.node_id_low { + self.span_low = Some(sp) + } + if Some(id) == self.node_id_high { + self.span_high = Some(sp) + } } } @@ -1341,31 +1346,34 @@ impl<'a, 'tcx> Delegate<'tcx> for MutateDelegate<'a, 'tcx> { } impl<'a, 'tcx> MutateDelegate<'a, 'tcx> { - fn bound_was_mutated(&self) -> bool { - self.was_mutated + fn mutation_span(&self) -> (Option, Option) { + (self.span_low, self.span_high) } } fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr, expr: &Expr) { if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(arg) { - let bounds = vec![start, end]; - for bound in &bounds { - if check_for_mutation(cx, body, bound) { - span_lint(cx, MUT_RANGE_BOUND, expr.span, "you are looping over a range where at least one bound was defined as a mutable variable. keep in mind that mutating this variable inside the loop will not affect the range"); - return; - } + let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)]; + if mut_ids[0].is_some() || mut_ids[1].is_some() { + let (span_low, span_high) = check_for_mutation(cx, body, mut_ids); + mut_warn_with_span(cx, span_low); + mut_warn_with_span(cx, span_high); } } } -fn check_for_mutation(cx: &LateContext, body: &Expr, bound: &Expr) -> bool { +fn mut_warn_with_span(cx: &LateContext, span: Option) { + if let Some(sp) = span { + span_lint(cx, MUT_RANGE_BOUND, sp, "attempt to mutate range bound within loop; note that the range of the loop is unchanged"); + } +} + +fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option { if_let_chain! {[ let ExprPath(ref qpath) = bound.node, let QPath::Resolved(None, ref path) = *qpath, ], { let def = cx.tables.qpath_def(qpath, bound.hir_id); - - cx.sess().span_note_without_error(body.span, "loop"); match def { Def::Local(..) | Def::Upvar(..) => { let def_id = def.def_id(); @@ -1375,18 +1383,35 @@ fn check_for_mutation(cx: &LateContext, body: &Expr, bound: &Expr) -> bool { let map::Node::NodeBinding(pat) = node_str, let PatKind::Binding(bind_ann, _, _, _) = pat.node, let BindingAnnotation::Mutable = bind_ann, - - ], { - let mut delegate = MutateDelegate { cx: cx, node_id: node_id, was_mutated: false }; - let region_maps = &cx.tcx.region_maps(def_id); // is this the correct argument? - ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_maps, cx.tables).walk_expr(body); - return delegate.bound_was_mutated(); + ], { + return Some(node_id); }} - }, - _ => (), - }} + } + _ => () + } + }} + return None; +} + +fn check_for_mutation(cx: &LateContext, body: &Expr, bound_ids: Vec>) -> (Option, Option) { + let mut delegate = MutateDelegate { cx: cx, node_id_low: bound_ids[0], node_id_high: bound_ids[1], span_low: None, span_high: None }; + if let Some(id) = get_id_if_some(&bound_ids) { + let def_id = cx.tcx.hir.local_def_id(id); + let region_scope_tree = &cx.tcx.region_scope_tree(def_id); + ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables).walk_expr(body); + return delegate.mutation_span(); + } else { + return (None, None); } - return false; +} + +fn get_id_if_some(bound_ids: &Vec>) -> Option { + for id in bound_ids.into_iter() { + if id.is_some() { + return *id; + } + } + return None; } /// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`. diff --git a/tests/run-pass/mut_range_bound_tmp.rs b/tests/run-pass/mut_range_bound_tmp.rs index ff164438f3fa..c13c0c0ae853 100644 --- a/tests/run-pass/mut_range_bound_tmp.rs +++ b/tests/run-pass/mut_range_bound_tmp.rs @@ -7,28 +7,40 @@ fn main() { mut_range_bound_upper(); mut_range_bound_lower(); mut_range_bound_both(); + mut_range_bound_no_mutation(); immut_range_bound(); } fn mut_range_bound_upper() { let mut m = 4; - for i in 0..m { - - m = 5; - continue; } // WARNING the range upper bound is mutable + for i in 0..m { m = 5; } // warning } fn mut_range_bound_lower() { let mut m = 4; - for i in m..10 { continue; } // WARNING the range lower bound is mutable + for i in m..10 { m *= 2; } // warning } fn mut_range_bound_both() { let mut m = 4; let mut n = 6; - for i in m..n { continue; } // WARNING both bounds are mutable (should get just one warning for this) + for i in m..n { m = 5; n = 7; } // warning (1 for each mutated bound) } +fn mut_range_bound_no_mutation() { + let mut m = 4; + for i in 0..m { continue; } // no warning +} + +fn mut_borrow_range_bound() { + let mut m = 4; + for i in 0..m { + let n = &mut m; + *n += 1; + } +} + + fn immut_range_bound() { let m = 4; for i in 0..m { continue; } // no warning From c326a779dd5edf1bdeec207723da928cc2d4aec8 Mon Sep 17 00:00:00 2001 From: Laura Peskin Date: Sun, 24 Sep 2017 15:40:10 -0400 Subject: [PATCH 23/60] use def_id of function in check_for_mutation --- clippy_lints/src/loops.rs | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 522e0ae79c02..f8c3e7b4cbdf 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -2,6 +2,7 @@ use itertools::Itertools; use reexport::*; use rustc::hir::*; use rustc::hir::def::Def; +use rustc::hir::def_id; use rustc::hir::intravisit::{walk_block, walk_decl, walk_expr, walk_pat, walk_stmt, NestedVisitorMap, Visitor}; use rustc::hir::map::Node::{NodeBlock, NodeExpr, NodeStmt}; use rustc::lint::*; @@ -619,7 +620,7 @@ fn check_for_loop<'a, 'tcx>( check_for_loop_arg(cx, pat, arg, expr); check_for_loop_explicit_counter(cx, arg, body, expr); check_for_loop_over_map_kv(cx, pat, arg, body, expr); - check_for_mut_range_bound(cx, arg, body, expr); + check_for_mut_range_bound(cx, arg, body); detect_manual_memcpy(cx, pat, arg, body, expr); } @@ -1309,15 +1310,14 @@ fn check_for_loop_over_map_kv<'a, 'tcx>( } } -struct MutateDelegate<'a, 'tcx: 'a> { - cx: &'a LateContext<'a, 'tcx>, +struct MutateDelegate { node_id_low: Option, node_id_high: Option, span_low: Option, span_high: Option, } -impl<'a, 'tcx> Delegate<'tcx> for MutateDelegate<'a, 'tcx> { +impl<'tcx> Delegate<'tcx> for MutateDelegate { fn consume(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ConsumeMode) { } @@ -1345,14 +1345,14 @@ impl<'a, 'tcx> Delegate<'tcx> for MutateDelegate<'a, 'tcx> { } } -impl<'a, 'tcx> MutateDelegate<'a, 'tcx> { +impl<'tcx> MutateDelegate { fn mutation_span(&self) -> (Option, Option) { (self.span_low, self.span_high) } } -fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr, expr: &Expr) { - if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(arg) { +fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) { + if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(arg) { let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)]; if mut_ids[0].is_some() || mut_ids[1].is_some() { let (span_low, span_high) = check_for_mutation(cx, body, mut_ids); @@ -1371,7 +1371,7 @@ fn mut_warn_with_span(cx: &LateContext, span: Option) { fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option { if_let_chain! {[ let ExprPath(ref qpath) = bound.node, - let QPath::Resolved(None, ref path) = *qpath, + let QPath::Resolved(None, _) = *qpath, ], { let def = cx.tables.qpath_def(qpath, bound.hir_id); match def { @@ -1394,24 +1394,11 @@ fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option { } fn check_for_mutation(cx: &LateContext, body: &Expr, bound_ids: Vec>) -> (Option, Option) { - let mut delegate = MutateDelegate { cx: cx, node_id_low: bound_ids[0], node_id_high: bound_ids[1], span_low: None, span_high: None }; - if let Some(id) = get_id_if_some(&bound_ids) { - let def_id = cx.tcx.hir.local_def_id(id); - let region_scope_tree = &cx.tcx.region_scope_tree(def_id); - ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables).walk_expr(body); - return delegate.mutation_span(); - } else { - return (None, None); - } -} - -fn get_id_if_some(bound_ids: &Vec>) -> Option { - for id in bound_ids.into_iter() { - if id.is_some() { - return *id; - } - } - return None; + let mut delegate = MutateDelegate { node_id_low: bound_ids[0], node_id_high: bound_ids[1], span_low: None, span_high: None }; + let def_id = def_id::DefId::local(body.hir_id.owner); + let region_scope_tree = &cx.tcx.region_scope_tree(def_id); + ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables).walk_expr(body); + return delegate.mutation_span(); } /// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`. From 2fe968774abcaa806fc7227f70bd2416d2a4a71f Mon Sep 17 00:00:00 2001 From: Laura Peskin Date: Mon, 25 Sep 2017 01:44:47 -0400 Subject: [PATCH 24/60] replace defids with nodeids for local variables --- Cargo.lock | 6 +++--- clippy_lints/src/loops.rs | 27 +++++++++++---------------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 88f1a8a7f3ad..21f2b4332c12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "clippy_lints" -version = "0.0.162" +version = "0.0.163" dependencies = [ "itertools 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -73,11 +73,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clippy" -version = "0.0.162" +version = "0.0.163" dependencies = [ "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.1.0", - "clippy_lints 0.0.162", + "clippy_lints 0.0.163", "compiletest_rs 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index f8c3e7b4cbdf..518b6e213478 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1374,20 +1374,15 @@ fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option { let QPath::Resolved(None, _) = *qpath, ], { let def = cx.tables.qpath_def(qpath, bound.hir_id); - match def { - Def::Local(..) | Def::Upvar(..) => { - let def_id = def.def_id(); - let node_id = cx.tcx.hir.as_local_node_id(def_id).expect("local/upvar are local nodes"); - let node_str = cx.tcx.hir.get(node_id); - if_let_chain! {[ - let map::Node::NodeBinding(pat) = node_str, - let PatKind::Binding(bind_ann, _, _, _) = pat.node, - let BindingAnnotation::Mutable = bind_ann, - ], { - return Some(node_id); - }} - } - _ => () + if let Def::Local(node_id) = def { + let node_str = cx.tcx.hir.get(node_id); + if_let_chain! {[ + let map::Node::NodeBinding(pat) = node_str, + let PatKind::Binding(bind_ann, _, _, _) = pat.node, + let BindingAnnotation::Mutable = bind_ann, + ], { + return Some(node_id); + }} } }} return None; @@ -1395,8 +1390,8 @@ fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option { fn check_for_mutation(cx: &LateContext, body: &Expr, bound_ids: Vec>) -> (Option, Option) { let mut delegate = MutateDelegate { node_id_low: bound_ids[0], node_id_high: bound_ids[1], span_low: None, span_high: None }; - let def_id = def_id::DefId::local(body.hir_id.owner); - let region_scope_tree = &cx.tcx.region_scope_tree(def_id); + let d = def_id::DefId::local(body.hir_id.owner); + let region_scope_tree = &cx.tcx.region_scope_tree(d); ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables).walk_expr(body); return delegate.mutation_span(); } From d7867ef8c15bfa199bac13ae919e9b93f9a34b57 Mon Sep 17 00:00:00 2001 From: Laura Peskin Date: Mon, 25 Sep 2017 02:00:21 -0400 Subject: [PATCH 25/60] add lint for mutable borrow; may have false positives. pushed for feedback --- clippy_lints/src/loops.rs | 19 ++++++++++++++++--- tests/run-pass/mut_range_bound_tmp.rs | 13 +++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 518b6e213478..c82ddb7383d3 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1327,7 +1327,20 @@ impl<'tcx> Delegate<'tcx> for MutateDelegate { fn consume_pat(&mut self, _: &Pat, _: cmt<'tcx>, _: ConsumeMode) { } - fn borrow(&mut self, _: NodeId, _: Span, _: cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, _: LoanCause) { + fn borrow(&mut self, _: NodeId, sp: Span, cmt: cmt<'tcx>, _: ty::Region, bk: ty::BorrowKind, _: LoanCause) { + match bk { + ty::BorrowKind::MutBorrow => { + if let Categorization::Local(id) = cmt.cat { + if Some(id) == self.node_id_low { + self.span_low = Some(sp) + } + if Some(id) == self.node_id_high { + self.span_high = Some(sp) + } + } + }, + _ => (), + } } fn mutate(&mut self, _: NodeId, sp: Span, cmt: cmt<'tcx>, _: MutateMode) { @@ -1390,8 +1403,8 @@ fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option { fn check_for_mutation(cx: &LateContext, body: &Expr, bound_ids: Vec>) -> (Option, Option) { let mut delegate = MutateDelegate { node_id_low: bound_ids[0], node_id_high: bound_ids[1], span_low: None, span_high: None }; - let d = def_id::DefId::local(body.hir_id.owner); - let region_scope_tree = &cx.tcx.region_scope_tree(d); + let def_id = def_id::DefId::local(body.hir_id.owner); + let region_scope_tree = &cx.tcx.region_scope_tree(def_id); ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables).walk_expr(body); return delegate.mutation_span(); } diff --git a/tests/run-pass/mut_range_bound_tmp.rs b/tests/run-pass/mut_range_bound_tmp.rs index c13c0c0ae853..1a7159c330e3 100644 --- a/tests/run-pass/mut_range_bound_tmp.rs +++ b/tests/run-pass/mut_range_bound_tmp.rs @@ -9,6 +9,8 @@ fn main() { mut_range_bound_both(); mut_range_bound_no_mutation(); immut_range_bound(); + mut_borrow_range_bound(); + immut_borrow_range_bound(); } fn mut_range_bound_upper() { @@ -35,8 +37,15 @@ fn mut_range_bound_no_mutation() { fn mut_borrow_range_bound() { let mut m = 4; for i in 0..m { - let n = &mut m; - *n += 1; + let n = &mut m; // warning here? + *n += 1; // or here? + } +} + +fn immut_borrow_range_bound() { + let mut m = 4; + for i in 0..m { + let n = &m; // should be no warning? } } From a3ad409341ceb557169479d9fce06ac1dadbec4d Mon Sep 17 00:00:00 2001 From: Yury Krivopalov Date: Mon, 25 Sep 2017 23:38:49 +0300 Subject: [PATCH 26/60] Configuration option for VERBOSE_BIT_MASK threshold By default is 1. u64, because I didn't figure out how to deserialize u128 option from config. --- clippy_lints/src/bit_mask.rs | 13 ++++++++++++- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/utils/conf.rs | 2 ++ tests/ui/bit_masks.stderr | 16 +--------------- tests/ui/conf_unknown_key.stderr | 2 +- tests/ui/trailing_zeros.rs | 1 + 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/bit_mask.rs b/clippy_lints/src/bit_mask.rs index 9b64a42d4f7f..6372221fd440 100644 --- a/clippy_lints/src/bit_mask.rs +++ b/clippy_lints/src/bit_mask.rs @@ -90,7 +90,17 @@ declare_lint! { } #[derive(Copy, Clone)] -pub struct BitMask; +pub struct BitMask { + verbose_bit_mask_threshold: u64, +} + +impl BitMask { + pub fn new(verbose_bit_mask_threshold: u64) -> Self { + Self { + verbose_bit_mask_threshold: verbose_bit_mask_threshold, + } + } +} impl LintPass for BitMask { fn get_lints(&self) -> LintArray { @@ -119,6 +129,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask { let Expr_::ExprLit(ref lit1) = right.node, let LitKind::Int(0, _) = lit1.node, n.leading_zeros() == n.count_zeros(), + n > u128::from(self.verbose_bit_mask_threshold), ], { span_lint_and_then(cx, VERBOSE_BIT_MASK, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5cb7034c7bfc..955bb883635b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -231,7 +231,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_early_lint_pass(box enum_variants::EnumVariantNames::new(conf.enum_variant_name_threshold)); reg.register_late_lint_pass(box enum_glob_use::EnumGlobUse); reg.register_late_lint_pass(box enum_clike::UnportableVariant); - reg.register_late_lint_pass(box bit_mask::BitMask); + reg.register_late_lint_pass(box bit_mask::BitMask::new(conf.verbose_bit_mask_threshold)); reg.register_late_lint_pass(box ptr::PointerPass); reg.register_late_lint_pass(box needless_bool::NeedlessBool); reg.register_late_lint_pass(box needless_bool::BoolComparison); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index f88294763dc3..5272e8a6ca64 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -172,6 +172,8 @@ define_Conf! { (enum_variant_name_threshold, "enum_variant_name_threshold", 3 => u64), /// Lint: LARGE_ENUM_VARIANT. The maximum size of a emum's variant to avoid box suggestion (enum_variant_size_threshold, "enum_variant_size_threshold", 200 => u64), + /// Lint: VERBOSE_BIT_MASK. The maximum size of a bit mask, that won't be checked on verbosity + (verbose_bit_mask_threshold, "verbose_bit_mask_threshold", 1 => u64), } /// Search for the configuration file. diff --git a/tests/ui/bit_masks.stderr b/tests/ui/bit_masks.stderr index 4b40fa086b84..40aa585d1243 100644 --- a/tests/ui/bit_masks.stderr +++ b/tests/ui/bit_masks.stderr @@ -6,20 +6,6 @@ error: &-masking with zero | = note: `-D bad-bit-mask` implied by `-D warnings` -error: bit mask could be simplified with a call to `trailing_zeros` - --> $DIR/bit_masks.rs:12:5 - | -12 | x & 0 == 0; - | ^^^^^^^^^^ help: try: `x.trailing_zeros() >= 0` - | - = note: `-D verbose-bit-mask` implied by `-D warnings` - -error: bit mask could be simplified with a call to `trailing_zeros` - --> $DIR/bit_masks.rs:14:5 - | -14 | x & 1 == 0; //ok, compared with zero - | ^^^^^^^^^^ help: try: `x.trailing_zeros() >= 1` - error: incompatible bit mask: `_ & 2` can never be equal to `1` --> $DIR/bit_masks.rs:15:5 | @@ -106,5 +92,5 @@ error: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared 55 | x | 1 >= 8; | ^^^^^^^^^^ -error: aborting due to 17 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/conf_unknown_key.stderr b/tests/ui/conf_unknown_key.stderr index bd16dfd47da9..8de3cd93370e 100644 --- a/tests/ui/conf_unknown_key.stderr +++ b/tests/ui/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file: unknown field `foobar`, expected one of `blacklisted-names`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `third-party` +error: error reading Clippy's configuration file: unknown field `foobar`, expected one of `blacklisted-names`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `third-party` error: aborting due to previous error diff --git a/tests/ui/trailing_zeros.rs b/tests/ui/trailing_zeros.rs index 40f588cecef2..9fc71506ffe4 100644 --- a/tests/ui/trailing_zeros.rs +++ b/tests/ui/trailing_zeros.rs @@ -7,4 +7,5 @@ fn main() { let _ = #[clippy(author)] (x & 0b1111 == 0); // suggest trailing_zeros let _ = x & 0b1_1111 == 0; // suggest trailing_zeros let _ = x & 0b1_1010 == 0; // do not lint + let _ = x & 1 == 0; // do not lint } From 44ecc19a3f25f8741736c05c477047386ff9f2fb Mon Sep 17 00:00:00 2001 From: Michal Budzynski Date: Thu, 14 Sep 2017 16:04:04 +0200 Subject: [PATCH 27/60] stabilizing feature iterator_for_each for rust 1.21.0 --- tests/ui/infinite_iter.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs index fd433edf98d2..deb5c5edd8c0 100644 --- a/tests/ui/infinite_iter.rs +++ b/tests/ui/infinite_iter.rs @@ -1,5 +1,4 @@ #![feature(plugin)] -#![feature(iterator_for_each)] #![plugin(clippy)] use std::iter::repeat; From 04c44fa3fe5960e924ce25fca43e80c097f24eab Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Sep 2017 13:52:17 -0700 Subject: [PATCH 28/60] Update line numbers --- tests/ui/infinite_iter.stderr | 90 +++++++++++++++++------------------ 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/tests/ui/infinite_iter.stderr b/tests/ui/infinite_iter.stderr index b3d2f08a8657..f79db7784884 100644 --- a/tests/ui/infinite_iter.stderr +++ b/tests/ui/infinite_iter.stderr @@ -1,99 +1,99 @@ error: you are collect()ing an iterator and throwing away the result. Consider using an explicit for loop to exhaust the iterator - --> $DIR/infinite_iter.rs:11:5 + --> $DIR/infinite_iter.rs:10:5 | -11 | repeat(0_u8).collect::>(); // infinite iter +10 | repeat(0_u8).collect::>(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D unused-collect` implied by `-D warnings` error: infinite iteration detected - --> $DIR/infinite_iter.rs:11:5 + --> $DIR/infinite_iter.rs:10:5 | -11 | repeat(0_u8).collect::>(); // infinite iter +10 | repeat(0_u8).collect::>(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/infinite_iter.rs:9:8 + --> $DIR/infinite_iter.rs:8:8 | -9 | #[deny(infinite_iter)] +8 | #[deny(infinite_iter)] | ^^^^^^^^^^^^^ +error: infinite iteration detected + --> $DIR/infinite_iter.rs:11:5 + | +11 | (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: infinite iteration detected --> $DIR/infinite_iter.rs:12:5 | -12 | (0..8_u32).take_while(square_is_lower_64).cycle().count(); // infinite iter - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: infinite iteration detected - --> $DIR/infinite_iter.rs:13:5 - | -13 | (0..8_u64).chain(0..).max(); // infinite iter +12 | (0..8_u64).chain(0..).max(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> $DIR/infinite_iter.rs:15:5 + --> $DIR/infinite_iter.rs:14:5 | -15 | (0..8_u32).rev().cycle().map(|x| x + 1_u32).for_each(|x| println!("{}", x)); // infinite iter +14 | (0..8_u32).rev().cycle().map(|x| x + 1_u32).for_each(|x| println!("{}", x)); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: infinite iteration detected + --> $DIR/infinite_iter.rs:16:5 + | +16 | (0_usize..).flat_map(|x| 0..x).product::(); // infinite iter + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: infinite iteration detected --> $DIR/infinite_iter.rs:17:5 | -17 | (0_usize..).flat_map(|x| 0..x).product::(); // infinite iter - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: infinite iteration detected - --> $DIR/infinite_iter.rs:18:5 - | -18 | (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter +17 | (0_u64..).filter(|x| x % 2 == 0).last(); // infinite iter | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: possible infinite iteration detected + --> $DIR/infinite_iter.rs:24:5 + | +24 | (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/infinite_iter.rs:22:8 + | +22 | #[deny(maybe_infinite_iter)] + | ^^^^^^^^^^^^^^^^^^^ + error: possible infinite iteration detected --> $DIR/infinite_iter.rs:25:5 | -25 | (0..).zip((0..).take_while(square_is_lower_64)).count(); // maybe infinite iter - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: lint level defined here - --> $DIR/infinite_iter.rs:23:8 - | -23 | #[deny(maybe_infinite_iter)] - | ^^^^^^^^^^^^^^^^^^^ +25 | repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected --> $DIR/infinite_iter.rs:26:5 | -26 | repeat(42).take_while(|x| *x == 42).chain(0..42).max(); // maybe infinite iter - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +26 | (1..).scan(0, |state, x| { *state += x; Some(*state) }).min(); // maybe infinite iter + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected --> $DIR/infinite_iter.rs:27:5 | -27 | (1..).scan(0, |state, x| { *state += x; Some(*state) }).min(); // maybe infinite iter - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +27 | (0..).find(|x| *x == 24); // maybe infinite iter + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected --> $DIR/infinite_iter.rs:28:5 | -28 | (0..).find(|x| *x == 24); // maybe infinite iter - | ^^^^^^^^^^^^^^^^^^^^^^^^ +28 | (0..).position(|x| x == 24); // maybe infinite iter + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected --> $DIR/infinite_iter.rs:29:5 | -29 | (0..).position(|x| x == 24); // maybe infinite iter - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +29 | (0..).any(|x| x == 24); // maybe infinite iter + | ^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected --> $DIR/infinite_iter.rs:30:5 | -30 | (0..).any(|x| x == 24); // maybe infinite iter - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: possible infinite iteration detected - --> $DIR/infinite_iter.rs:31:5 - | -31 | (0..).all(|x| x == 24); // maybe infinite iter +30 | (0..).all(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 14 previous errors From 8408d486585c9c8757d0e65ace1daabf3b0dfcd9 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Sep 2017 13:52:23 -0700 Subject: [PATCH 29/60] Update lockfile --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53e3cc9ff6a4..4d5f05f93bf1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "clippy_lints" -version = "0.0.162" +version = "0.0.163" dependencies = [ "itertools 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -78,11 +78,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clippy" -version = "0.0.162" +version = "0.0.163" dependencies = [ "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.1.0", - "clippy_lints 0.0.162", + "clippy_lints 0.0.163", "compiletest_rs 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", From bfc31536c74a30b49ba84c6539620a0aecc1504a Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Sep 2017 18:32:05 -0700 Subject: [PATCH 30/60] Make it a ui test, update --- tests/run-pass/mut_range_bound.rs | 15 -------- .../mut_range_bound.rs} | 6 ++-- tests/ui/mut_range_bound.stderr | 34 +++++++++++++++++++ 3 files changed, 37 insertions(+), 18 deletions(-) delete mode 100644 tests/run-pass/mut_range_bound.rs rename tests/{run-pass/mut_range_bound_tmp.rs => ui/mut_range_bound.rs} (88%) create mode 100644 tests/ui/mut_range_bound.stderr diff --git a/tests/run-pass/mut_range_bound.rs b/tests/run-pass/mut_range_bound.rs deleted file mode 100644 index e08babe3137f..000000000000 --- a/tests/run-pass/mut_range_bound.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(plugin)] -#![plugin(clippy)] - -// cause the build to fail if this warning is invoked -#![deny(check_for_loop_mut_bound)] - -// an example -fn mut_range_bound() { - let mut m = 4; - for i in 0..m { continue; } // ERROR One of the range bounds is mutable -} - -fn main(){ - mut_range_bound(); -} diff --git a/tests/run-pass/mut_range_bound_tmp.rs b/tests/ui/mut_range_bound.rs similarity index 88% rename from tests/run-pass/mut_range_bound_tmp.rs rename to tests/ui/mut_range_bound.rs index 1a7159c330e3..835ceeedc94d 100644 --- a/tests/run-pass/mut_range_bound_tmp.rs +++ b/tests/ui/mut_range_bound.rs @@ -15,7 +15,7 @@ fn main() { fn mut_range_bound_upper() { let mut m = 4; - for i in 0..m { m = 5; } // warning + for i in 0..m { m = 5; } // warning } fn mut_range_bound_lower() { @@ -37,8 +37,8 @@ fn mut_range_bound_no_mutation() { fn mut_borrow_range_bound() { let mut m = 4; for i in 0..m { - let n = &mut m; // warning here? - *n += 1; // or here? + let n = &mut m; // warning + *n += 1; } } diff --git a/tests/ui/mut_range_bound.stderr b/tests/ui/mut_range_bound.stderr new file mode 100644 index 000000000000..d7be7ae1e6fc --- /dev/null +++ b/tests/ui/mut_range_bound.stderr @@ -0,0 +1,34 @@ +error: attempt to mutate range bound within loop; note that the range of the loop is unchanged + --> $DIR/mut_range_bound.rs:18:21 + | +18 | for i in 0..m { m = 5; } // warning + | ^^^^^ + | + = note: `-D mut-range-bound` implied by `-D warnings` + +error: attempt to mutate range bound within loop; note that the range of the loop is unchanged + --> $DIR/mut_range_bound.rs:23:22 + | +23 | for i in m..10 { m *= 2; } // warning + | ^^^^^^ + +error: attempt to mutate range bound within loop; note that the range of the loop is unchanged + --> $DIR/mut_range_bound.rs:29:21 + | +29 | for i in m..n { m = 5; n = 7; } // warning (1 for each mutated bound) + | ^^^^^ + +error: attempt to mutate range bound within loop; note that the range of the loop is unchanged + --> $DIR/mut_range_bound.rs:29:28 + | +29 | for i in m..n { m = 5; n = 7; } // warning (1 for each mutated bound) + | ^^^^^ + +error: attempt to mutate range bound within loop; note that the range of the loop is unchanged + --> $DIR/mut_range_bound.rs:40:22 + | +40 | let n = &mut m; // warning + | ^ + +error: aborting due to 5 previous errors + From 94c6f4a868a56667d695db98beff5ec10f294ec9 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Sep 2017 18:39:50 -0700 Subject: [PATCH 31/60] Pass dogfood --- clippy_lints/src/loops.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index c82ddb7383d3..a0300530a59d 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1328,18 +1328,15 @@ impl<'tcx> Delegate<'tcx> for MutateDelegate { } fn borrow(&mut self, _: NodeId, sp: Span, cmt: cmt<'tcx>, _: ty::Region, bk: ty::BorrowKind, _: LoanCause) { - match bk { - ty::BorrowKind::MutBorrow => { - if let Categorization::Local(id) = cmt.cat { - if Some(id) == self.node_id_low { - self.span_low = Some(sp) - } - if Some(id) == self.node_id_high { - self.span_high = Some(sp) - } + if let ty::BorrowKind::MutBorrow = bk { + if let Categorization::Local(id) = cmt.cat { + if Some(id) == self.node_id_low { + self.span_low = Some(sp) } - }, - _ => (), + if Some(id) == self.node_id_high { + self.span_high = Some(sp) + } + } } } @@ -1368,7 +1365,7 @@ fn check_for_mut_range_bound(cx: &LateContext, arg: &Expr, body: &Expr) { if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(arg) { let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)]; if mut_ids[0].is_some() || mut_ids[1].is_some() { - let (span_low, span_high) = check_for_mutation(cx, body, mut_ids); + let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids); mut_warn_with_span(cx, span_low); mut_warn_with_span(cx, span_high); } @@ -1398,15 +1395,15 @@ fn check_for_mutability(cx: &LateContext, bound: &Expr) -> Option { }} } }} - return None; + None } -fn check_for_mutation(cx: &LateContext, body: &Expr, bound_ids: Vec>) -> (Option, Option) { +fn check_for_mutation(cx: &LateContext, body: &Expr, bound_ids: &[Option]) -> (Option, Option) { let mut delegate = MutateDelegate { node_id_low: bound_ids[0], node_id_high: bound_ids[1], span_low: None, span_high: None }; let def_id = def_id::DefId::local(body.hir_id.owner); let region_scope_tree = &cx.tcx.region_scope_tree(def_id); ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables).walk_expr(body); - return delegate.mutation_span(); + delegate.mutation_span() } /// Return true if the pattern is a `PatWild` or an ident prefixed with `'_'`. From d337c7f9270f6a414ff9c51b6e81e919222488f1 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Sep 2017 18:43:34 -0700 Subject: [PATCH 32/60] Update changelog --- CHANGELOG.md | 5 +++++ clippy_lints/src/lib.rs | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15a0ee74e6b0..2730ca6a181d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Change Log All notable changes to this project will be documented in this file. +## Trunk +* New lints: [`mut_range_bound`], [`int_plus_one`] + ## 0.0.163 * Update to *rustc 1.22.0-nightly (14039a42a 2017-09-22)* @@ -519,6 +522,7 @@ All notable changes to this project will be documented in this file. [`ineffective_bit_mask`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#ineffective_bit_mask [`infinite_iter`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#infinite_iter [`inline_always`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#inline_always +[`int_plus_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#int_plus_one [`integer_arithmetic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#integer_arithmetic [`invalid_regex`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_regex [`invalid_upcast_comparisons`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons @@ -556,6 +560,7 @@ All notable changes to this project will be documented in this file. [`modulo_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#modulo_one [`mut_from_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mut_from_ref [`mut_mut`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mut_mut +[`mut_range_bound`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mut_range_bound [`mutex_atomic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mutex_atomic [`mutex_integer`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#mutex_integer [`naive_bytecount`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#naive_bytecount diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f4c9aaf3b085..b840c3ddd02e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -343,8 +343,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { enum_variants::PUB_ENUM_VARIANT_NAMES, enum_variants::STUTTER, if_not_else::IF_NOT_ELSE, - int_plus_one::INT_PLUS_ONE, infinite_iter::MAYBE_INFINITE_ITER, + int_plus_one::INT_PLUS_ONE, items_after_statements::ITEMS_AFTER_STATEMENTS, matches::SINGLE_MATCH_ELSE, mem_forget::MEM_FORGET, @@ -449,6 +449,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { loops::FOR_LOOP_OVER_RESULT, loops::ITER_NEXT_LOOP, loops::MANUAL_MEMCPY, + loops::MUT_RANGE_BOUND, loops::NEEDLESS_RANGE_LOOP, loops::NEVER_LOOP, loops::REVERSE_RANGE_LOOP, From fabb6b6645ec9f804b17707fb1e69ff09c15cbed Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Sep 2017 19:04:55 -0700 Subject: [PATCH 33/60] Rustup to rustc 1.22.0-nightly (6c476ce46 2017-09-25) --- clippy_lints/src/lifetimes.rs | 50 +++++++++++----------- clippy_lints/src/map_clone.rs | 3 +- clippy_lints/src/methods.rs | 17 +++++--- clippy_lints/src/needless_pass_by_value.rs | 3 +- clippy_lints/src/ptr.rs | 2 +- clippy_lints/src/transmute.rs | 5 ++- clippy_lints/src/types.rs | 22 ++++++---- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/utils/hir_utils.rs | 9 +++- 9 files changed, 69 insertions(+), 44 deletions(-) diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index 5cbb854be923..16d636c68ab6 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -104,19 +104,20 @@ fn check_fn_inner<'a, 'tcx>( for typ in &generics.ty_params { for bound in &typ.bounds { if let TraitTyParamBound(ref trait_ref, _) = *bound { - let bounds = &trait_ref + let params = &trait_ref .trait_ref .path .segments .last() .expect("a path must have at least one segment") - .parameters - .lifetimes; - for bound in bounds { - if bound.name.name() != "'static" && !bound.is_elided() { - return; + .parameters; + if let Some(ref params) = *params { + for bound in ¶ms.lifetimes { + if bound.name.name() != "'static" && !bound.is_elided() { + return; + } + bounds_lts.push(bound); } - bounds_lts.push(bound); } } } @@ -287,23 +288,24 @@ impl<'v, 't> RefVisitor<'v, 't> { } fn collect_anonymous_lifetimes(&mut self, qpath: &QPath, ty: &Ty) { - let last_path_segment = &last_path_segment(qpath).parameters; - if !last_path_segment.parenthesized && last_path_segment.lifetimes.is_empty() { - let hir_id = self.cx.tcx.hir.node_to_hir_id(ty.id); - match self.cx.tables.qpath_def(qpath, hir_id) { - Def::TyAlias(def_id) | Def::Struct(def_id) => { - let generics = self.cx.tcx.generics_of(def_id); - for _ in generics.regions.as_slice() { - self.record(&None); - } - }, - Def::Trait(def_id) => { - let trait_def = self.cx.tcx.trait_def(def_id); - for _ in &self.cx.tcx.generics_of(trait_def.def_id).regions { - self.record(&None); - } - }, - _ => (), + if let Some(ref last_path_segment) = last_path_segment(qpath).parameters { + if !last_path_segment.parenthesized && last_path_segment.lifetimes.is_empty() { + let hir_id = self.cx.tcx.hir.node_to_hir_id(ty.id); + match self.cx.tables.qpath_def(qpath, hir_id) { + Def::TyAlias(def_id) | Def::Struct(def_id) => { + let generics = self.cx.tcx.generics_of(def_id); + for _ in generics.regions.as_slice() { + self.record(&None); + } + }, + Def::Trait(def_id) => { + let trait_def = self.cx.tcx.trait_def(def_id); + for _ in &self.cx.tcx.generics_of(trait_def.def_id).regions { + self.record(&None); + } + }, + _ => (), + } } } } diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 733022f1703f..e35e1ab477c0 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -100,7 +100,8 @@ fn expr_eq_name(expr: &Expr, id: ast::Name) -> bool { let arg_segment = [ PathSegment { name: id, - parameters: PathParameters::none(), + parameters: None, + infer_types: true, }, ]; !path.is_global() && path.segments[..] == arg_segment diff --git a/clippy_lints/src/methods.rs b/clippy_lints/src/methods.rs index b36e1851d0de..6d3a3f39d1a2 100644 --- a/clippy_lints/src/methods.rs +++ b/clippy_lints/src/methods.rs @@ -1617,11 +1617,18 @@ fn is_as_ref_or_mut_trait(ty: &hir::Ty, self_ty: &hir::Ty, generics: &hir::Gener match_path(path, name) && path.segments .last() - .map_or(false, |s| if s.parameters.parenthesized { - false - } else { - s.parameters.types.len() == 1 && - (is_self_ty(&s.parameters.types[0]) || is_ty(&*s.parameters.types[0], self_ty)) + .map_or(false, |s| { + if let Some(ref params) = s.parameters { + if params.parenthesized { + false + } else { + params.types.len() == 1 && + (is_self_ty(¶ms.types[0]) + || is_ty(&*params.types[0], self_ty)) + } + } else { + false + } }) } else { false diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 4a7a042924a2..35cbd6ff3dbf 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -144,7 +144,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { let TyPath(QPath::Resolved(_, ref path)) = input.node, let Some(elem_ty) = path.segments.iter() .find(|seg| seg.name == "Vec") - .map(|ps| &ps.parameters.types[0]), + .and_then(|ref ps| ps.parameters.as_ref()) + .map(|params| ¶ms.types[0]), ], { let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_")); db.span_suggestion(input.span, diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 69ba0d8bccf4..03c94cbf3fbd 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -159,7 +159,7 @@ fn check_fn(cx: &LateContext, decl: &FnDecl, fn_id: NodeId, opt_body_id: Option< let mut ty_snippet = None; if_let_chain!([ let TyPath(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).node, - let Some(&PathSegment{ref parameters, ..}) = path.segments.last(), + let Some(&PathSegment{parameters: Some(ref parameters), ..}) = path.segments.last(), parameters.types.len() == 1, ], { ty_snippet = snippet_opt(cx, parameters.types[0].span); diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 18b80c76810c..76110ecb152b 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -194,8 +194,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { fn get_type_snippet(cx: &LateContext, path: &QPath, to_rty: Ty) -> String { let seg = last_path_segment(path); if_let_chain!{[ - !seg.parameters.parenthesized, - let Some(to_ty) = seg.parameters.types.get(1), + let Some(ref params) = seg.parameters, + !params.parenthesized, + let Some(to_ty) = params.types.get(1), let TyRptr(_, ref to_ty) = to_ty.node, ], { return snippet(cx, to_ty.ty.span, &to_rty.to_string()).to_string(); diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 90f1e87796d3..50683d1fb402 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -154,8 +154,9 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { if Some(def_id) == cx.tcx.lang_items().owned_box() { let last = last_path_segment(qpath); if_let_chain! {[ - !last.parameters.parenthesized, - let Some(vec) = last.parameters.types.get(0), + let Some(ref params) = last.parameters, + !params.parenthesized, + let Some(vec) = params.types.get(0), let TyPath(ref qpath) = vec.node, let Some(did) = opt_def_id(cx.tables.qpath_def(qpath, cx.tcx.hir.node_to_hir_id(vec.id))), match_def_path(cx.tcx, did, &paths::VEC), @@ -183,21 +184,25 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { check_ty(cx, ty, is_local); for ty in p.segments .iter() - .flat_map(|seg| seg.parameters.types.iter()) + .filter_map(|ref seg| seg.parameters.as_ref()) + .flat_map(|ref params| params.types.iter()) { check_ty(cx, ty, is_local); } }, QPath::Resolved(None, ref p) => for ty in p.segments .iter() - .flat_map(|seg| seg.parameters.types.iter()) + .filter_map(|ref seg| seg.parameters.as_ref()) + .flat_map(|ref params| params.types.iter()) { check_ty(cx, ty, is_local); }, QPath::TypeRelative(ref ty, ref seg) => { check_ty(cx, ty, is_local); - for ty in seg.parameters.types.iter() { - check_ty(cx, ty, is_local); + if let Some(ref params) = seg.parameters { + for ty in params.types.iter() { + check_ty(cx, ty, is_local); + } } }, } @@ -212,8 +217,9 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { Some(def_id) == cx.tcx.lang_items().owned_box(), let QPath::Resolved(None, ref path) = *qpath, let [ref bx] = *path.segments, - !bx.parameters.parenthesized, - let [ref inner] = *bx.parameters.types + let Some(ref params) = bx.parameters, + !params.parenthesized, + let [ref inner] = *params.types ], { if is_any_trait(inner) { // Ignore `Box` types, see #1884 for details. diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index bb5f6075d0da..d4166f6a2bda 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -59,7 +59,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf { let Ty_::TyPath(QPath::Resolved(_, ref item_path)) = item_type.node, ], { let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).parameters; - if !parameters.parenthesized && parameters.lifetimes.len() == 0 { + if parameters.is_none() { let visitor = &mut UseSelfVisitor { item_path: item_path, cx: cx, diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs index 2d3d5874d821..f7867dfd0bd4 100644 --- a/clippy_lints/src/utils/hir_utils.rs +++ b/clippy_lints/src/utils/hir_utils.rs @@ -214,7 +214,14 @@ impl<'a, 'tcx: 'a> SpanlessEq<'a, 'tcx> { fn eq_path_segment(&self, left: &PathSegment, right: &PathSegment) -> bool { // The == of idents doesn't work with different contexts, // we have to be explicit about hygiene - left.name.as_str() == right.name.as_str() && self.eq_path_parameters(&left.parameters, &right.parameters) + if left.name.as_str() != right.name.as_str() { + return false; + } + match (&left.parameters, &right.parameters) { + (&None, &None) => true, + (&Some(ref l), &Some(ref r)) => self.eq_path_parameters(l, r), + _ => false + } } fn eq_ty(&self, left: &Ty, right: &Ty) -> bool { From 2551bd8924e17b8d10f8331d11cf0e469558b5f1 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Sep 2017 19:44:50 -0700 Subject: [PATCH 34/60] Reduce cyclomatic complexity of types::check_ty --- clippy_lints/src/types.rs | 96 ++++++++++++++++++------------------ clippy_lints/src/use_self.rs | 7 ++- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 50683d1fb402..9d57527faee2 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -184,16 +184,16 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { check_ty(cx, ty, is_local); for ty in p.segments .iter() - .filter_map(|ref seg| seg.parameters.as_ref()) - .flat_map(|ref params| params.types.iter()) + .filter_map(|seg| seg.parameters.as_ref()) + .flat_map(|params| params.types.iter()) { check_ty(cx, ty, is_local); } }, QPath::Resolved(None, ref p) => for ty in p.segments .iter() - .filter_map(|ref seg| seg.parameters.as_ref()) - .flat_map(|ref params| params.types.iter()) + .filter_map(|seg| seg.parameters.as_ref()) + .flat_map(|params| params.types.iter()) { check_ty(cx, ty, is_local); }, @@ -207,49 +207,7 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { }, } }, - TyRptr(ref lt, MutTy { ref ty, ref mutbl }) => { - match ty.node { - TyPath(ref qpath) => { - let hir_id = cx.tcx.hir.node_to_hir_id(ty.id); - let def = cx.tables.qpath_def(qpath, hir_id); - if_let_chain! {[ - let Some(def_id) = opt_def_id(def), - Some(def_id) == cx.tcx.lang_items().owned_box(), - let QPath::Resolved(None, ref path) = *qpath, - let [ref bx] = *path.segments, - let Some(ref params) = bx.parameters, - !params.parenthesized, - let [ref inner] = *params.types - ], { - if is_any_trait(inner) { - // Ignore `Box` types, see #1884 for details. - return; - } - - let ltopt = if lt.is_elided() { - "".to_owned() - } else { - format!("{} ", lt.name.name().as_str()) - }; - let mutopt = if *mutbl == Mutability::MutMutable { - "mut " - } else { - "" - }; - span_lint_and_sugg(cx, - BORROWED_BOX, - ast_ty.span, - "you seem to be trying to use `&Box`. Consider using just `&T`", - "try", - format!("&{}{}{}", ltopt, mutopt, &snippet(cx, inner.span, "..")) - ); - return; // don't recurse into the type - }}; - check_ty(cx, ty, is_local); - }, - _ => check_ty(cx, ty, is_local), - } - }, + TyRptr(ref lt, ref mut_ty) => check_ty_rptr(cx, ast_ty, is_local, lt, mut_ty), // recurse TySlice(ref ty) | TyArray(ref ty, _) | TyPtr(MutTy { ref ty, .. }) => check_ty(cx, ty, is_local), TyTup(ref tys) => for ty in tys { @@ -259,6 +217,50 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { } } +fn check_ty_rptr(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool, lt: &Lifetime, mut_ty: &MutTy) { + match mut_ty.ty.node { + TyPath(ref qpath) => { + let hir_id = cx.tcx.hir.node_to_hir_id(mut_ty.ty.id); + let def = cx.tables.qpath_def(qpath, hir_id); + if_let_chain! {[ + let Some(def_id) = opt_def_id(def), + Some(def_id) == cx.tcx.lang_items().owned_box(), + let QPath::Resolved(None, ref path) = *qpath, + let [ref bx] = *path.segments, + let Some(ref params) = bx.parameters, + !params.parenthesized, + let [ref inner] = *params.types + ], { + if is_any_trait(inner) { + // Ignore `Box` types, see #1884 for details. + return; + } + + let ltopt = if lt.is_elided() { + "".to_owned() + } else { + format!("{} ", lt.name.name().as_str()) + }; + let mutopt = if mut_ty.mutbl == Mutability::MutMutable { + "mut " + } else { + "" + }; + span_lint_and_sugg(cx, + BORROWED_BOX, + ast_ty.span, + "you seem to be trying to use `&Box`. Consider using just `&T`", + "try", + format!("&{}{}{}", ltopt, mutopt, &snippet(cx, inner.span, "..")) + ); + return; // don't recurse into the type + }}; + check_ty(cx, &mut_ty.ty, is_local); + }, + _ => check_ty(cx, &mut_ty.ty, is_local), + } +} + // Returns true if given type is `Any` trait. fn is_any_trait(t: &hir::Ty) -> bool { if_let_chain! {[ diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index d4166f6a2bda..946df625cb61 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -59,7 +59,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UseSelf { let Ty_::TyPath(QPath::Resolved(_, ref item_path)) = item_type.node, ], { let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).parameters; - if parameters.is_none() { + let should_check = if let Some(ref params) = *parameters { + !params.parenthesized && params.lifetimes.len() == 0 + } else { + true + }; + if should_check { let visitor = &mut UseSelfVisitor { item_path: item_path, cx: cx, From 1b4aba47b7978cd1b1af11c2d406a4160f8a0fcb Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Sep 2017 19:52:13 -0700 Subject: [PATCH 35/60] Fix dogfood filter-map --- clippy_lints/src/types.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 9d57527faee2..acea709123bd 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -184,16 +184,18 @@ fn check_ty(cx: &LateContext, ast_ty: &hir::Ty, is_local: bool) { check_ty(cx, ty, is_local); for ty in p.segments .iter() - .filter_map(|seg| seg.parameters.as_ref()) - .flat_map(|params| params.types.iter()) + .flat_map(|seg| seg.parameters.as_ref() + .map_or_else(|| [].iter(), + |params| params.types.iter())) { check_ty(cx, ty, is_local); } }, QPath::Resolved(None, ref p) => for ty in p.segments .iter() - .filter_map(|seg| seg.parameters.as_ref()) - .flat_map(|params| params.types.iter()) + .flat_map(|seg| seg.parameters.as_ref() + .map_or_else(|| [].iter(), + |params| params.types.iter())) { check_ty(cx, ty, is_local); }, From 66eea5e662db32dcdd233c48b3cddd691c2cb8fa Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Sep 2017 19:52:20 -0700 Subject: [PATCH 36/60] Fix dogfood needless-borrow --- clippy_lints/src/needless_pass_by_value.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 35cbd6ff3dbf..ccdb3c179cc1 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue { let TyPath(QPath::Resolved(_, ref path)) = input.node, let Some(elem_ty) = path.segments.iter() .find(|seg| seg.name == "Vec") - .and_then(|ref ps| ps.parameters.as_ref()) + .and_then(|ps| ps.parameters.as_ref()) .map(|params| ¶ms.types[0]), ], { let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_")); From bebc99d893cf2aebec87f925c80209971eba10da Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Sep 2017 19:54:24 -0700 Subject: [PATCH 37/60] Run prepublish script --- clippy_lints/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f4c9aaf3b085..2d600277e834 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -343,8 +343,8 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { enum_variants::PUB_ENUM_VARIANT_NAMES, enum_variants::STUTTER, if_not_else::IF_NOT_ELSE, - int_plus_one::INT_PLUS_ONE, infinite_iter::MAYBE_INFINITE_ITER, + int_plus_one::INT_PLUS_ONE, items_after_statements::ITEMS_AFTER_STATEMENTS, matches::SINGLE_MATCH_ELSE, mem_forget::MEM_FORGET, From 15a2d1a473596e6c6e9b05681556ca72d6506f67 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 25 Sep 2017 19:56:48 -0700 Subject: [PATCH 38/60] Bump to 0.0.164 --- CHANGELOG.md | 5 +++++ Cargo.lock | 6 +++--- Cargo.toml | 4 ++-- clippy_lints/Cargo.toml | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15a0ee74e6b0..d3c8071f3698 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Change Log All notable changes to this project will be documented in this file. +## 0.0.164 +* Update to *rustc 1.22.0-nightly (6c476ce46 2017-09-25)* +* New lint: [`int_plus_one`] + ## 0.0.163 * Update to *rustc 1.22.0-nightly (14039a42a 2017-09-22)* @@ -519,6 +523,7 @@ All notable changes to this project will be documented in this file. [`ineffective_bit_mask`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#ineffective_bit_mask [`infinite_iter`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#infinite_iter [`inline_always`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#inline_always +[`int_plus_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#int_plus_one [`integer_arithmetic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#integer_arithmetic [`invalid_regex`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_regex [`invalid_upcast_comparisons`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons diff --git a/Cargo.lock b/Cargo.lock index 4d5f05f93bf1..2a0b20d5891a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "clippy_lints" -version = "0.0.163" +version = "0.0.164" dependencies = [ "itertools 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -78,11 +78,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clippy" -version = "0.0.163" +version = "0.0.164" dependencies = [ "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.1.0", - "clippy_lints 0.0.163", + "clippy_lints 0.0.164", "compiletest_rs 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 16aaf148c60a..80ea4188c3a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.163" +version = "0.0.164" authors = [ "Manish Goregaokar ", "Andre Bogus ", @@ -31,7 +31,7 @@ path = "src/main.rs" [dependencies] # begin automatic update -clippy_lints = { version = "0.0.163", path = "clippy_lints" } +clippy_lints = { version = "0.0.164", path = "clippy_lints" } # end automatic update cargo_metadata = "0.2" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 96bd05162dca..ef1dcb23818f 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin automatic update -version = "0.0.163" +version = "0.0.164" # end automatic update authors = [ "Manish Goregaokar ", From 5c56c924fc587b0343f1a878f04895e2e20bae73 Mon Sep 17 00:00:00 2001 From: Yury Krivopalov Date: Tue, 26 Sep 2017 18:54:08 +0300 Subject: [PATCH 39/60] Clarify verbose_bit_mask_threshold description --- clippy_lints/src/utils/conf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 5272e8a6ca64..ff2832186bf5 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -172,7 +172,7 @@ define_Conf! { (enum_variant_name_threshold, "enum_variant_name_threshold", 3 => u64), /// Lint: LARGE_ENUM_VARIANT. The maximum size of a emum's variant to avoid box suggestion (enum_variant_size_threshold, "enum_variant_size_threshold", 200 => u64), - /// Lint: VERBOSE_BIT_MASK. The maximum size of a bit mask, that won't be checked on verbosity + /// Lint: VERBOSE_BIT_MASK. The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros' (verbose_bit_mask_threshold, "verbose_bit_mask_threshold", 1 => u64), } From 0ca166277cb663465430d79e5311bd1ea97a27d5 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 28 Sep 2017 07:11:34 -0700 Subject: [PATCH 40/60] Rust upgrade to rustc 1.22.0-nightly (0e6f4cf51 2017-09-27) --- clippy_lints/src/loops.rs | 2 +- clippy_lints/src/utils/sugg.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index a0300530a59d..76f1a603f242 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1604,7 +1604,7 @@ fn is_ref_iterable_type(cx: &LateContext, e: &Expr) -> bool { fn is_iterable_array(ty: Ty) -> bool { // IntoIterator is currently only implemented for array sizes <= 32 in rustc match ty.sty { - ty::TyArray(_, n) => (0...32).contains(const_to_u64(n)), + ty::TyArray(_, n) => (0..=32).contains(const_to_u64(n)), _ => false, } } diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index ec0a351b8b09..d376a62912d0 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -126,7 +126,7 @@ impl<'a> Sugg<'a> { ast::ExprKind::While(..) | ast::ExprKind::WhileLet(..) => Sugg::NonParen(snippet), ast::ExprKind::Range(.., RangeLimits::HalfOpen) => Sugg::BinOp(AssocOp::DotDot, snippet), - ast::ExprKind::Range(.., RangeLimits::Closed) => Sugg::BinOp(AssocOp::DotDotDot, snippet), + ast::ExprKind::Range(.., RangeLimits::Closed) => Sugg::BinOp(AssocOp::DotDotEq, snippet), ast::ExprKind::Assign(..) => Sugg::BinOp(AssocOp::Assign, snippet), ast::ExprKind::AssignOp(op, ..) => Sugg::BinOp(astbinop2assignop(op), snippet), ast::ExprKind::Binary(op, ..) => Sugg::BinOp(AssocOp::from_ast_binop(op.node), snippet), @@ -165,7 +165,7 @@ impl<'a> Sugg<'a> { pub fn range(self, end: Self, limit: ast::RangeLimits) -> Sugg<'static> { match limit { ast::RangeLimits::HalfOpen => make_assoc(AssocOp::DotDot, &self, &end), - ast::RangeLimits::Closed => make_assoc(AssocOp::DotDotDot, &self, &end), + ast::RangeLimits::Closed => make_assoc(AssocOp::DotDotEq, &self, &end), } } @@ -312,7 +312,7 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { AssocOp::AssignOp(op) => format!("{} {}= {}", lhs, token_to_string(&token::BinOp(op)), rhs), AssocOp::As => format!("{} as {}", lhs, rhs), AssocOp::DotDot => format!("{}..{}", lhs, rhs), - AssocOp::DotDotDot => format!("{}...{}", lhs, rhs), + AssocOp::DotDotEq => format!("{}...{}", lhs, rhs), AssocOp::Colon => format!("{}: {}", lhs, rhs), }; @@ -362,7 +362,7 @@ fn associativity(op: &AssocOp) -> Associativity { ShiftLeft | ShiftRight | Subtract => Associativity::Left, - DotDot | DotDotDot => Associativity::None, + DotDot | DotDotEq => Associativity::None, } } From 201b5c2f2444e242c9f96e732a3e4cc5e5cc4e8d Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 28 Sep 2017 10:35:14 -0700 Subject: [PATCH 41/60] Use ..= in the suggestion --- Cargo.lock | 6 +++--- clippy_lints/src/utils/sugg.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a0b20d5891a..34be0d11a52b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "clippy_lints" -version = "0.0.164" +version = "0.0.165" dependencies = [ "itertools 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -78,11 +78,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clippy" -version = "0.0.164" +version = "0.0.165" dependencies = [ "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.1.0", - "clippy_lints 0.0.164", + "clippy_lints 0.0.165", "compiletest_rs 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index d376a62912d0..d811de59844f 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -312,7 +312,7 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg, rhs: &Sugg) -> Sugg<'static> { AssocOp::AssignOp(op) => format!("{} {}= {}", lhs, token_to_string(&token::BinOp(op)), rhs), AssocOp::As => format!("{} as {}", lhs, rhs), AssocOp::DotDot => format!("{}..{}", lhs, rhs), - AssocOp::DotDotEq => format!("{}...{}", lhs, rhs), + AssocOp::DotDotEq => format!("{}..={}", lhs, rhs), AssocOp::Colon => format!("{}: {}", lhs, rhs), }; From 3159a7f2a12c8e1b753598544c71be8ae8eae628 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 28 Sep 2017 10:40:19 -0700 Subject: [PATCH 42/60] Update ... -> ..= in tests --- tests/ui/array_indexing.rs | 16 ++++++++-------- tests/ui/array_indexing.stderr | 16 ++++++++-------- tests/ui/copies.rs | 12 ++++++------ tests/ui/for_loop.rs | 8 ++++---- tests/ui/for_loop.stderr | 6 +++--- tests/ui/no_effect.rs | 2 +- tests/ui/no_effect.stderr | 2 +- tests/ui/range.rs | 2 +- tests/ui/range.stderr | 2 +- 9 files changed, 33 insertions(+), 33 deletions(-) diff --git a/tests/ui/array_indexing.rs b/tests/ui/array_indexing.rs index 34b422db6e96..c38342daf689 100644 --- a/tests/ui/array_indexing.rs +++ b/tests/ui/array_indexing.rs @@ -13,8 +13,8 @@ fn main() { x[1 << 3]; &x[1..5]; &x[0..3]; - &x[0...4]; - &x[...4]; + &x[0..=4]; + &x[..=4]; &x[..]; &x[1..]; &x[4..]; @@ -26,19 +26,19 @@ fn main() { y[0]; &y[1..2]; &y[..]; - &y[0...4]; - &y[...4]; + &y[0..=4]; + &y[..=4]; let empty: [i8; 0] = []; empty[0]; &empty[1..5]; - &empty[0...4]; - &empty[...4]; + &empty[0..=4]; + &empty[..=4]; &empty[..]; &empty[0..]; &empty[0..0]; - &empty[0...0]; - &empty[...0]; + &empty[0..=0]; + &empty[..=0]; &empty[..0]; &empty[1..]; &empty[..4]; diff --git a/tests/ui/array_indexing.stderr b/tests/ui/array_indexing.stderr index ea95c3254606..d730b012932a 100644 --- a/tests/ui/array_indexing.stderr +++ b/tests/ui/array_indexing.stderr @@ -21,13 +21,13 @@ error: range is out of bounds error: range is out of bounds --> $DIR/array_indexing.rs:16:6 | -16 | &x[0...4]; +16 | &x[0..=4]; | ^^^^^^^^ error: range is out of bounds --> $DIR/array_indexing.rs:17:6 | -17 | &x[...4]; +17 | &x[..=4]; | ^^^^^^^ error: range is out of bounds @@ -59,13 +59,13 @@ error: slicing may panic error: slicing may panic --> $DIR/array_indexing.rs:29:6 | -29 | &y[0...4]; +29 | &y[0..=4]; | ^^^^^^^^ error: slicing may panic --> $DIR/array_indexing.rs:30:6 | -30 | &y[...4]; +30 | &y[..=4]; | ^^^^^^^ error: const index is out of bounds @@ -83,25 +83,25 @@ error: range is out of bounds error: range is out of bounds --> $DIR/array_indexing.rs:35:6 | -35 | &empty[0...4]; +35 | &empty[0..=4]; | ^^^^^^^^^^^^ error: range is out of bounds --> $DIR/array_indexing.rs:36:6 | -36 | &empty[...4]; +36 | &empty[..=4]; | ^^^^^^^^^^^ error: range is out of bounds --> $DIR/array_indexing.rs:40:6 | -40 | &empty[0...0]; +40 | &empty[0..=0]; | ^^^^^^^^^^^^ error: range is out of bounds --> $DIR/array_indexing.rs:41:6 | -41 | &empty[...0]; +41 | &empty[..=0]; | ^^^^^^^^^^^ error: range is out of bounds diff --git a/tests/ui/copies.rs b/tests/ui/copies.rs index a7b992527359..652afac6c685 100644 --- a/tests/ui/copies.rs +++ b/tests/ui/copies.rs @@ -1,4 +1,4 @@ -#![feature(plugin, inclusive_range_syntax)] +#![feature(plugin, dotdoteq_in_patterns, inclusive_range_syntax)] #![plugin(clippy)] #![allow(dead_code, no_effect, unnecessary_operation)] @@ -33,7 +33,7 @@ fn if_same_then_else() -> Result<&'static str, ()> { ..; 0..; ..10; - 0...10; + 0..=10; foo(); } else { @@ -42,7 +42,7 @@ fn if_same_then_else() -> Result<&'static str, ()> { ..; 0..; ..10; - 0...10; + 0..=10; foo(); } @@ -64,7 +64,7 @@ fn if_same_then_else() -> Result<&'static str, ()> { 0..10; } else { - 0...10; + 0..=10; } if true { @@ -161,7 +161,7 @@ fn if_same_then_else() -> Result<&'static str, ()> { let _ = match 42 { 42 => 1, a if a > 0 => 2, - 10...15 => 3, + 10..=15 => 3, _ => 4, }; } @@ -172,7 +172,7 @@ fn if_same_then_else() -> Result<&'static str, ()> { let _ = match 42 { 42 => 1, a if a > 0 => 2, - 10...15 => 3, + 10..=15 => 3, _ => 4, }; } diff --git a/tests/ui/for_loop.rs b/tests/ui/for_loop.rs index aa8b96322930..95d15776a36a 100644 --- a/tests/ui/for_loop.rs +++ b/tests/ui/for_loop.rs @@ -125,7 +125,7 @@ fn main() { println!("{}", vec[i]); } - for i in 0...MAX_LEN { + for i in 0..=MAX_LEN { println!("{}", vec[i]); } @@ -133,7 +133,7 @@ fn main() { println!("{}", vec[i]); } - for i in 5...10 { + for i in 5..=10 { println!("{}", vec[i]); } @@ -149,7 +149,7 @@ fn main() { println!("{}", i); } - for i in 10...0 { + for i in 10..=0 { println!("{}", i); } @@ -161,7 +161,7 @@ fn main() { println!("{}", i); } - for i in 5...5 { + for i in 5..=5 { // not an error, this is the range with only one element “5” println!("{}", i); } diff --git a/tests/ui/for_loop.stderr b/tests/ui/for_loop.stderr index 79c6c781a7a5..09c4deb492a9 100644 --- a/tests/ui/for_loop.stderr +++ b/tests/ui/for_loop.stderr @@ -178,7 +178,7 @@ help: consider using an iterator error: the loop variable `i` is only used to index `vec`. --> $DIR/for_loop.rs:128:5 | -128 | / for i in 0...MAX_LEN { +128 | / for i in 0..=MAX_LEN { 129 | | println!("{}", vec[i]); 130 | | } | |_____^ @@ -204,7 +204,7 @@ help: consider using an iterator error: the loop variable `i` is only used to index `vec`. --> $DIR/for_loop.rs:136:5 | -136 | / for i in 5...10 { +136 | / for i in 5..=10 { 137 | | println!("{}", vec[i]); 138 | | } | |_____^ @@ -257,7 +257,7 @@ help: consider using the following if you are attempting to iterate over this ra error: this range is empty so this for loop will never run --> $DIR/for_loop.rs:152:5 | -152 | / for i in 10...0 { +152 | / for i in 10..=0 { 153 | | println!("{}", i); 154 | | } | |_____^ diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index bef1fad4f69f..5c3a1a041c20 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -49,7 +49,7 @@ fn main() { 5..; ..5; 5..6; - 5...6; + 5..=6; [42, 55]; [42, 55][1]; (42, 55).1; diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index 590b1eab4977..b6db8e7498e4 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -111,7 +111,7 @@ error: statement with no effect error: statement with no effect --> $DIR/no_effect.rs:52:5 | -52 | 5...6; +52 | 5..=6; | ^^^^^^ error: statement with no effect diff --git a/tests/ui/range.rs b/tests/ui/range.rs index 4f4573d9e602..bb1a04cfcf3f 100644 --- a/tests/ui/range.rs +++ b/tests/ui/range.rs @@ -15,7 +15,7 @@ fn main() { let _ = (0..1).step_by(1); let _ = (1..).step_by(0); - let _ = (1...2).step_by(0); + let _ = (1..=2).step_by(0); let x = 0..1; let _ = x.step_by(0); diff --git a/tests/ui/range.stderr b/tests/ui/range.stderr index 772375c179b0..fc51f1a07f07 100644 --- a/tests/ui/range.stderr +++ b/tests/ui/range.stderr @@ -15,7 +15,7 @@ error: Iterator::step_by(0) will panic at runtime error: Iterator::step_by(0) will panic at runtime --> $DIR/range.rs:18:13 | -18 | let _ = (1...2).step_by(0); +18 | let _ = (1..=2).step_by(0); | ^^^^^^^^^^^^^^^^^^ error: Iterator::step_by(0) will panic at runtime From b1c62e12958170326e973c910d559bccea0f70ff Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 28 Sep 2017 10:44:26 -0700 Subject: [PATCH 43/60] Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c95d96c2c3f4..0e3fb8be43de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Change Log All notable changes to this project will be documented in this file. -## Trunk +## 0.0.165 +* Rust upgrade to rustc 1.22.0-nightly (0e6f4cf51 2017-09-27) * New lint: [`mut_range_bound`] ## 0.0.164 From 02e7fada5cdcf4c8573ca5ab81037fd80fa6ca49 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 28 Sep 2017 10:44:29 -0700 Subject: [PATCH 44/60] Bump to 0.0.165 --- Cargo.toml | 4 ++-- clippy_lints/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 80ea4188c3a1..f9c3fd0fd67c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.0.164" +version = "0.0.165" authors = [ "Manish Goregaokar ", "Andre Bogus ", @@ -31,7 +31,7 @@ path = "src/main.rs" [dependencies] # begin automatic update -clippy_lints = { version = "0.0.164", path = "clippy_lints" } +clippy_lints = { version = "0.0.165", path = "clippy_lints" } # end automatic update cargo_metadata = "0.2" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index ef1dcb23818f..85d65c791761 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin automatic update -version = "0.0.164" +version = "0.0.165" # end automatic update authors = [ "Manish Goregaokar ", From 4da0aeb40e2459a86bda60a1883b21690943d130 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 27 Sep 2017 14:17:08 -0400 Subject: [PATCH 45/60] Set RUSTC_WRAPPER instead of RUSTC when invoking Cargo Some build scripts rely on the RUSTC binary being the actual compiler (e.g. parsing the output of 'RUSTC --version'). To prevent clippy from breaking these build scripts, this commit sets RUSTC_WRAPPER instead. This will cause Cargo to leave RUSTC unchanged, making the use of clippy transparent to build scripts. --- src/main.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index f4945998fde5..f21cd7bd28ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -181,7 +181,7 @@ pub fn main() { return; } - if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { + if "clippy" == std::env::args().nth(1).as_ref().expect("cargo-clippy should be called with at least one argument!") { // this arm is executed on the initial call to `cargo clippy` let manifest_path_arg = std::env::args() @@ -285,7 +285,7 @@ pub fn main() { } } } else { - // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC` + // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC_WRAPPER` // env var set to itself let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); @@ -310,13 +310,17 @@ pub fn main() { }; rustc_driver::in_rustc_thread(|| { + // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. + // We're invoking the compiler programatically, so we ignore this/ + let orig_args: Vec = env::args().skip(1).collect(); + // this conditional check for the --sysroot flag is there so users can call // `cargo-clippy` directly // without having to pass --sysroot or anything - let mut args: Vec = if env::args().any(|s| s == "--sysroot") { - env::args().collect() + let mut args: Vec = if orig_args.iter().any(|s| s == "--sysroot") { + orig_args.clone() } else { - env::args() + orig_args.clone().into_iter() .chain(Some("--sysroot".to_owned())) .chain(Some(sys_root)) .collect() @@ -325,7 +329,7 @@ pub fn main() { // this check ensures that dependencies are built but not linted and the final // crate is // linted but not built - let clippy_enabled = env::args().any(|s| s == "--emit=metadata"); + let clippy_enabled = orig_args.iter().any(|s| s == "--emit=metadata"); if clippy_enabled { args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); @@ -361,7 +365,7 @@ where let path = std::env::current_exe().expect("current executable path invalid"); let exit_status = std::process::Command::new("cargo") .args(&args) - .env("RUSTC", path) + .env("RUSTC_WRAPPER", path) .spawn() .expect("could not run cargo") .wait() From cae9cedeb5acc9b4edc23b376e15fba339254c31 Mon Sep 17 00:00:00 2001 From: mcarton Date: Fri, 29 Sep 2017 18:36:03 +0200 Subject: [PATCH 46/60] Fix regression with `format!` --- clippy_lints/src/format.rs | 27 +++++++++++++++------------ tests/ui/format.stderr | 14 +++++++++++++- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index f1a450e58df3..26b500d55463 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -50,8 +50,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { let Some(fun_def_id) = opt_def_id(resolve_node(cx, qpath, fun.hir_id)), match_def_path(cx.tcx, fun_def_id, &paths::FMT_ARGUMENTS_NEWV1), // ensure the format string is `"{..}"` with only one argument and no text - check_static_str(cx, &args[0]), + check_static_str(&args[0]), // ensure the format argument is `{}` ie. Display with no fancy option + // and that the argument is a string check_arg_is_display(cx, &args[1]) ], { span_lint(cx, USELESS_FORMAT, span, "useless use of `format!`"); @@ -96,17 +97,19 @@ pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Exp None } -/// Checks if the expressions matches -/// ```rust, ignore -/// { static __STATIC_FMTSTR: &'static[&'static str] = &["a", "b", c]; -/// __STATIC_FMTSTR } -/// ``` -fn check_static_str(cx: &LateContext, expr: &Expr) -> bool { - if let Some(expr) = get_argument_fmtstr_parts(cx, expr) { - expr.len() == 1 && expr[0].is_empty() - } else { - false - } +/// Checks if the expressions matches `&[""]` +fn check_static_str(expr: &Expr) -> bool { + if_let_chain! {[ + let ExprAddrOf(_, ref expr) = expr.node, // &[""] + let ExprArray(ref exprs) = expr.node, // [""] + exprs.len() == 1, + let ExprLit(ref lit) = exprs[0].node, + let LitKind::Str(ref lit, _) = lit.node, + ], { + return lit.as_str().is_empty(); + }} + + false } /// Checks if the expressions matches diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index 5f5bdc02a592..d2c9f3938312 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -6,5 +6,17 @@ error: useless use of `format!` | = note: `-D useless-format` implied by `-D warnings` -error: aborting due to previous error +error: useless use of `format!` + --> $DIR/format.rs:8:5 + | +8 | format!("{}", "foo"); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: useless use of `format!` + --> $DIR/format.rs:15:5 + | +15 | format!("{}", arg); + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors From 7e956ac7c4a38c862e344e5e60243b3995bc5831 Mon Sep 17 00:00:00 2001 From: mcarton Date: Fri, 29 Sep 2017 19:13:21 +0200 Subject: [PATCH 47/60] Fix regression with `print!` --- clippy_lints/src/format.rs | 29 ----------------------------- clippy_lints/src/print.rs | 26 ++++++++++++++++++++------ tests/ui/print_with_newline.stderr | 28 ++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 35 deletions(-) diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 26b500d55463..6a6cbadb6fa3 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,9 +1,7 @@ use rustc::hir::*; -use rustc::hir::map::Node::NodeItem; use rustc::lint::*; use rustc::ty; use syntax::ast::LitKind; -use syntax::symbol::InternedString; use utils::paths; use utils::{is_expn_of, match_def_path, match_type, resolve_node, span_lint, walk_ptrs_ty, opt_def_id}; @@ -70,33 +68,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } -/// Returns the slice of format string parts in an `Arguments::new_v1` call. -/// Public because it's shared with a lint in print.rs. -pub fn get_argument_fmtstr_parts<'a, 'b>(cx: &LateContext<'a, 'b>, expr: &'a Expr) -> Option> { - if_let_chain! {[ - let ExprBlock(ref block) = expr.node, - block.stmts.len() == 1, - let StmtDecl(ref decl, _) = block.stmts[0].node, - let DeclItem(ref decl) = decl.node, - let Some(NodeItem(decl)) = cx.tcx.hir.find(decl.id), - decl.name == "__STATIC_FMTSTR", - let ItemStatic(_, _, ref expr) = decl.node, - let ExprAddrOf(_, ref expr) = cx.tcx.hir.body(*expr).value.node, // &["…", "…", …] - let ExprArray(ref exprs) = expr.node, - ], { - let mut result = Vec::new(); - for expr in exprs { - if let ExprLit(ref lit) = expr.node { - if let LitKind::Str(ref lit, _) = lit.node { - result.push(lit.as_str()); - } - } - } - return Some(result); - }} - None -} - /// Checks if the expressions matches `&[""]` fn check_static_str(expr: &Expr) -> bool { if_let_chain! {[ diff --git a/clippy_lints/src/print.rs b/clippy_lints/src/print.rs index 078e208467aa..96557b8b0cb4 100644 --- a/clippy_lints/src/print.rs +++ b/clippy_lints/src/print.rs @@ -1,9 +1,10 @@ use rustc::hir::*; use rustc::hir::map::Node::{NodeImplItem, NodeItem}; use rustc::lint::*; -use utils::{paths, opt_def_id}; +use syntax::ast::LitKind; +use syntax::symbol::InternedString; use utils::{is_expn_of, match_def_path, match_path, resolve_node, span_lint}; -use format::get_argument_fmtstr_parts; +use utils::{paths, opt_def_id}; /// **What it does:** This lint warns when you using `print!()` with a format /// string that @@ -103,15 +104,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { let ExprTup(ref args) = args.node, // collect the format string parts and check the last one - let Some(fmtstrs) = get_argument_fmtstr_parts(cx, &args_args[0]), - let Some(last_str) = fmtstrs.last(), - let Some('\n') = last_str.chars().last(), + let Some((fmtstr, fmtlen)) = get_argument_fmtstr_parts(&args_args[0]), + let Some('\n') = fmtstr.chars().last(), // "foo{}bar" is made into two strings + one argument, // if the format string starts with `{}` (eg. "{}foo"), // the string array is prepended an empty string "". // We only want to check the last string after any `{}`: - args.len() < fmtstrs.len(), + args.len() < fmtlen, ], { span_lint(cx, PRINT_WITH_NEWLINE, span, "using `print!()` with a format string that ends in a \ @@ -150,3 +150,17 @@ fn is_in_debug_impl(cx: &LateContext, expr: &Expr) -> bool { false } + +/// Returns the slice of format string parts in an `Arguments::new_v1` call. +fn get_argument_fmtstr_parts(expr: &Expr) -> Option<(InternedString, usize)> { + if_let_chain! {[ + let ExprAddrOf(_, ref expr) = expr.node, // &["…", "…", …] + let ExprArray(ref exprs) = expr.node, + let Some(expr) = exprs.last(), + let ExprLit(ref lit) = expr.node, + let LitKind::Str(ref lit, _) = lit.node, + ], { + return Some((lit.as_str(), exprs.len())); + }} + None +} diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr index e69de29bb2d1..1bacc40bfb4f 100644 --- a/tests/ui/print_with_newline.stderr +++ b/tests/ui/print_with_newline.stderr @@ -0,0 +1,28 @@ +error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead + --> $DIR/print_with_newline.rs:6:5 + | +6 | print!("Hello/n"); + | ^^^^^^^^^^^^^^^^^^ + | + = note: `-D print-with-newline` implied by `-D warnings` + +error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead + --> $DIR/print_with_newline.rs:7:5 + | +7 | print!("Hello {}/n", "world"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead + --> $DIR/print_with_newline.rs:8:5 + | +8 | print!("Hello {} {}/n/n", "world", "#2"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: using `print!()` with a format string that ends in a newline, consider using `println!()` instead + --> $DIR/print_with_newline.rs:9:5 + | +9 | print!("{}/n", 1265); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + From f3e51d8d65e7188ae10506807591aca621f8ad96 Mon Sep 17 00:00:00 2001 From: Laura Peskin Date: Thu, 28 Sep 2017 22:24:31 -0400 Subject: [PATCH 48/60] add lint for creation of invalid references --- clippy_lints/src/invalid_ref.rs | 59 +++++++++++++++++++++++++++++++++ clippy_lints/src/lib.rs | 3 ++ clippy_lints/src/utils/paths.rs | 4 +++ tests/ui/invalid_ref.rs | 45 +++++++++++++++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 clippy_lints/src/invalid_ref.rs create mode 100644 tests/ui/invalid_ref.rs diff --git a/clippy_lints/src/invalid_ref.rs b/clippy_lints/src/invalid_ref.rs new file mode 100644 index 000000000000..440e3055bb10 --- /dev/null +++ b/clippy_lints/src/invalid_ref.rs @@ -0,0 +1,59 @@ +use rustc::lint::*; +use rustc::ty; +use rustc::hir::*; +use utils::{match_def_path, paths, span_help_and_lint, opt_def_id}; + +/// **What it does:** Checks for creation of references to zeroed or uninitialized memory. +/// +/// **Why is this bad?** Creation of null references is undefined behavior. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// let bad_ref: &usize = std::mem::zeroed(); +/// ``` + +declare_lint! { + pub INVALID_REF, + Warn, + "creation of invalid reference" +} + +const ZERO_REF_SUMMARY: &str = "reference to zeroed memory"; +const UNINIT_REF_SUMMARY: &str = "reference to uninitialized memory"; + +pub struct InvalidRef; + +impl LintPass for InvalidRef { + fn get_lints(&self) -> LintArray { + lint_array!(INVALID_REF) + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { + if_let_chain!{[ + let ty::TyRef(..) = cx.tables.expr_ty(expr).sty, + let ExprCall(ref path, ref args) = expr.node, + let ExprPath(ref qpath) = path.node, + args.len() == 0, + let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id)), + ], { + let help = "Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html"; + if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) | match_def_path(cx.tcx, def_id, &paths::INIT) { + let lint = INVALID_REF; + let msg = ZERO_REF_SUMMARY; + span_help_and_lint(cx, lint, expr.span, &msg, &help); + } else if match_def_path(cx.tcx, def_id, &paths::MEM_UNINIT) | match_def_path(cx.tcx, def_id, &paths::UNINIT) { + let lint = INVALID_REF; + let msg = UNINIT_REF_SUMMARY; + span_help_and_lint(cx, lint, expr.span, &msg, &help); + } else { + return; + } + }} + return; + } +} + diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index bca15f693265..759a66eaae5b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -97,6 +97,7 @@ pub mod if_let_redundant_pattern_matching; pub mod if_not_else; pub mod infinite_iter; pub mod int_plus_one; +pub mod invalid_ref; pub mod is_unit_expr; pub mod items_after_statements; pub mod large_enum_variant; @@ -328,6 +329,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_late_lint_pass(box use_self::UseSelf); reg.register_late_lint_pass(box bytecount::ByteCount); reg.register_late_lint_pass(box infinite_iter::Pass); + reg.register_late_lint_pass(box invalid_ref::InvalidRef); reg.register_lint_group("clippy_restrictions", vec![ arithmetic::FLOAT_ARITHMETIC, @@ -345,6 +347,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { if_not_else::IF_NOT_ELSE, infinite_iter::MAYBE_INFINITE_ITER, int_plus_one::INT_PLUS_ONE, + invalid_ref::INVALID_REF, items_after_statements::ITEMS_AFTER_STATEMENTS, matches::SINGLE_MATCH_ELSE, mem_forget::MEM_FORGET, diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index d18a5af59e3b..89bc84f4a50b 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -30,6 +30,7 @@ pub const HASH: [&'static str; 2] = ["hash", "Hash"]; pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHSET: [&'static str; 5] = ["std", "collections", "hash", "set", "HashSet"]; +pub const INIT: [&'static str; 4] = ["core", "intrinsics", "", "init"]; pub const INTO_ITERATOR: [&'static str; 4] = ["core", "iter", "traits", "IntoIterator"]; pub const IO_PRINT: [&'static str; 4] = ["std", "io", "stdio", "_print"]; pub const IO_READ: [&'static str; 3] = ["std", "io", "Read"]; @@ -39,6 +40,8 @@ pub const LINKED_LIST: [&'static str; 3] = ["alloc", "linked_list", "LinkedList" pub const LINT: [&'static str; 3] = ["rustc", "lint", "Lint"]; pub const LINT_ARRAY: [&'static str; 3] = ["rustc", "lint", "LintArray"]; pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"]; +pub const MEM_ZEROED: [&'static str; 3] = ["core", "mem", "zeroed"]; +pub const MEM_UNINIT: [&'static str; 3] = ["core", "mem", "uninitialized"]; pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const OPS_MODULE: [&'static str; 2] = ["core", "ops"]; @@ -80,6 +83,7 @@ pub const TO_OWNED: [&'static str; 3] = ["alloc", "borrow", "ToOwned"]; pub const TO_STRING: [&'static str; 3] = ["alloc", "string", "ToString"]; pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"]; pub const TRY_INTO_RESULT: [&'static str; 4] = ["std", "ops", "Try", "into_result"]; +pub const UNINIT: [&'static str; 4] = ["core", "intrinsics", "", "uninit"]; pub const VEC: [&'static str; 3] = ["alloc", "vec", "Vec"]; pub const VEC_DEQUE: [&'static str; 3] = ["alloc", "vec_deque", "VecDeque"]; pub const VEC_FROM_ELEM: [&'static str; 3] = ["alloc", "vec", "from_elem"]; diff --git a/tests/ui/invalid_ref.rs b/tests/ui/invalid_ref.rs new file mode 100644 index 000000000000..d7341575e95d --- /dev/null +++ b/tests/ui/invalid_ref.rs @@ -0,0 +1,45 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![allow(unused)] +#![feature(core_intrinsics)] + +extern crate core; +use std::intrinsics::{init, uninit}; + +fn main() { + let x = 1; + unsafe { + ref_to_zeroed_std(&x); + ref_to_zeroed_core(&x); + ref_to_zeroed_intr(&x); + ref_to_uninit_std(&x); + ref_to_uninit_core(&x); + ref_to_uninit_intr(&x); + } +} + +unsafe fn ref_to_zeroed_std(t: &T) { + let ref_zero: &T = std::mem::zeroed(); // warning +} + +unsafe fn ref_to_zeroed_core(t: &T) { + let ref_zero: &T = core::mem::zeroed(); // warning +} + +unsafe fn ref_to_zeroed_intr(t: &T) { + let ref_zero: &T = std::intrinsics::init(); // warning +} + +unsafe fn ref_to_uninit_std(t: &T) { + let ref_uninit: &T = std::mem::uninitialized(); // warning +} + +unsafe fn ref_to_uninit_core(t: &T) { + let ref_uninit: &T = core::mem::uninitialized(); // warning +} + +unsafe fn ref_to_uninit_intr(t: &T) { + let ref_uninit: &T = std::intrinsics::uninit(); // warning +} + From 7fd11d23b04d6117e1e90c74b4091509c8aff249 Mon Sep 17 00:00:00 2001 From: Laura Peskin Date: Thu, 28 Sep 2017 22:52:10 -0400 Subject: [PATCH 49/60] add ui test for invalid_ref --- tests/ui/invalid_ref.stderr | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 tests/ui/invalid_ref.stderr diff --git a/tests/ui/invalid_ref.stderr b/tests/ui/invalid_ref.stderr new file mode 100644 index 000000000000..7cdc31a0ffa1 --- /dev/null +++ b/tests/ui/invalid_ref.stderr @@ -0,0 +1,51 @@ +error: reference to zeroed memory + --> $DIR/invalid_ref.rs:23:24 + | +23 | let ref_zero: &T = std::mem::zeroed(); // warning + | ^^^^^^^^^^^^^^^^^^ + | + = note: `-D invalid-ref` implied by `-D warnings` + = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html + +error: reference to zeroed memory + --> $DIR/invalid_ref.rs:27:24 + | +27 | let ref_zero: &T = core::mem::zeroed(); // warning + | ^^^^^^^^^^^^^^^^^^^ + | + = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html + +error: reference to zeroed memory + --> $DIR/invalid_ref.rs:31:24 + | +31 | let ref_zero: &T = std::intrinsics::init(); // warning + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html + +error: reference to uninitialized memory + --> $DIR/invalid_ref.rs:35:26 + | +35 | let ref_uninit: &T = std::mem::uninitialized(); // warning + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html + +error: reference to uninitialized memory + --> $DIR/invalid_ref.rs:39:26 + | +39 | let ref_uninit: &T = core::mem::uninitialized(); // warning + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html + +error: reference to uninitialized memory + --> $DIR/invalid_ref.rs:43:26 + | +43 | let ref_uninit: &T = std::intrinsics::uninit(); // warning + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html + +error: aborting due to 6 previous errors + From ddad5e0f86176e7bd2edaa95ec5272911791669f Mon Sep 17 00:00:00 2001 From: Laura Peskin Date: Fri, 29 Sep 2017 21:01:02 -0400 Subject: [PATCH 50/60] add tests for false positives --- clippy_lints/src/invalid_ref.rs | 20 ++++++++----------- tests/ui/invalid_ref.rs | 21 ++++++++++++++++++++ tests/ui/invalid_ref.stderr | 34 ++++++++++++++++----------------- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/clippy_lints/src/invalid_ref.rs b/clippy_lints/src/invalid_ref.rs index 440e3055bb10..ad3398cb0782 100644 --- a/clippy_lints/src/invalid_ref.rs +++ b/clippy_lints/src/invalid_ref.rs @@ -22,6 +22,7 @@ declare_lint! { const ZERO_REF_SUMMARY: &str = "reference to zeroed memory"; const UNINIT_REF_SUMMARY: &str = "reference to uninitialized memory"; +const HELP: &str = "Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html"; pub struct InvalidRef; @@ -34,26 +35,21 @@ impl LintPass for InvalidRef { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) { if_let_chain!{[ - let ty::TyRef(..) = cx.tables.expr_ty(expr).sty, let ExprCall(ref path, ref args) = expr.node, let ExprPath(ref qpath) = path.node, args.len() == 0, + let ty::TyRef(..) = cx.tables.expr_ty(expr).sty, let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id)), ], { - let help = "Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html"; - if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) | match_def_path(cx.tcx, def_id, &paths::INIT) { - let lint = INVALID_REF; - let msg = ZERO_REF_SUMMARY; - span_help_and_lint(cx, lint, expr.span, &msg, &help); + let msg = if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) | match_def_path(cx.tcx, def_id, &paths::INIT) { + ZERO_REF_SUMMARY } else if match_def_path(cx.tcx, def_id, &paths::MEM_UNINIT) | match_def_path(cx.tcx, def_id, &paths::UNINIT) { - let lint = INVALID_REF; - let msg = UNINIT_REF_SUMMARY; - span_help_and_lint(cx, lint, expr.span, &msg, &help); + UNINIT_REF_SUMMARY } else { return; - } - }} + }; + span_help_and_lint(cx, INVALID_REF, expr.span, msg, HELP); + }} return; } } - diff --git a/tests/ui/invalid_ref.rs b/tests/ui/invalid_ref.rs index d7341575e95d..2b8f04c9781c 100644 --- a/tests/ui/invalid_ref.rs +++ b/tests/ui/invalid_ref.rs @@ -16,6 +16,10 @@ fn main() { ref_to_uninit_std(&x); ref_to_uninit_core(&x); ref_to_uninit_intr(&x); + some_ref(); + std_zeroed_no_ref(); + core_zeroed_no_ref(); + intr_init_no_ref(); } } @@ -43,3 +47,20 @@ unsafe fn ref_to_uninit_intr(t: &T) { let ref_uninit: &T = std::intrinsics::uninit(); // warning } +fn some_ref() { + let some_ref = &1; +} + +unsafe fn std_zeroed_no_ref() { + let mem_zero: usize = std::mem::zeroed(); // no warning +} + +unsafe fn core_zeroed_no_ref() { + let mem_zero: usize = core::mem::zeroed(); // no warning +} + +unsafe fn intr_init_no_ref() { + let mem_zero: usize = std::intrinsics::init(); // no warning +} + + diff --git a/tests/ui/invalid_ref.stderr b/tests/ui/invalid_ref.stderr index 7cdc31a0ffa1..420fed017444 100644 --- a/tests/ui/invalid_ref.stderr +++ b/tests/ui/invalid_ref.stderr @@ -1,48 +1,48 @@ error: reference to zeroed memory - --> $DIR/invalid_ref.rs:23:24 + --> $DIR/invalid_ref.rs:27:24 | -23 | let ref_zero: &T = std::mem::zeroed(); // warning +27 | let ref_zero: &T = std::mem::zeroed(); // warning | ^^^^^^^^^^^^^^^^^^ | = note: `-D invalid-ref` implied by `-D warnings` = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to zeroed memory - --> $DIR/invalid_ref.rs:27:24 + --> $DIR/invalid_ref.rs:31:24 | -27 | let ref_zero: &T = core::mem::zeroed(); // warning +31 | let ref_zero: &T = core::mem::zeroed(); // warning | ^^^^^^^^^^^^^^^^^^^ | = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to zeroed memory - --> $DIR/invalid_ref.rs:31:24 + --> $DIR/invalid_ref.rs:35:24 | -31 | let ref_zero: &T = std::intrinsics::init(); // warning +35 | let ref_zero: &T = std::intrinsics::init(); // warning | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html -error: reference to uninitialized memory - --> $DIR/invalid_ref.rs:35:26 - | -35 | let ref_uninit: &T = std::mem::uninitialized(); // warning - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html - error: reference to uninitialized memory --> $DIR/invalid_ref.rs:39:26 | -39 | let ref_uninit: &T = core::mem::uninitialized(); // warning - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +39 | let ref_uninit: &T = std::mem::uninitialized(); // warning + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html error: reference to uninitialized memory --> $DIR/invalid_ref.rs:43:26 | -43 | let ref_uninit: &T = std::intrinsics::uninit(); // warning +43 | let ref_uninit: &T = core::mem::uninitialized(); // warning + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html + +error: reference to uninitialized memory + --> $DIR/invalid_ref.rs:47:26 + | +47 | let ref_uninit: &T = std::intrinsics::uninit(); // warning | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html From 8e6abc6fd761b8a1c607d9d1f626db99f146aee7 Mon Sep 17 00:00:00 2001 From: Laura Peskin Date: Fri, 29 Sep 2017 21:48:10 -0400 Subject: [PATCH 51/60] alphabetize paths to pass dogfood --- clippy_lints/src/utils/paths.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 89bc84f4a50b..2a2eabcca1f8 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -40,8 +40,8 @@ pub const LINKED_LIST: [&'static str; 3] = ["alloc", "linked_list", "LinkedList" pub const LINT: [&'static str; 3] = ["rustc", "lint", "Lint"]; pub const LINT_ARRAY: [&'static str; 3] = ["rustc", "lint", "LintArray"]; pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"]; -pub const MEM_ZEROED: [&'static str; 3] = ["core", "mem", "zeroed"]; pub const MEM_UNINIT: [&'static str; 3] = ["core", "mem", "uninitialized"]; +pub const MEM_ZEROED: [&'static str; 3] = ["core", "mem", "zeroed"]; pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"]; pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"]; pub const OPS_MODULE: [&'static str; 2] = ["core", "ops"]; From e40c270d4f37662b7263ab40914105978da2dbb3 Mon Sep 17 00:00:00 2001 From: mcarton Date: Sun, 18 Jun 2017 23:00:14 +0200 Subject: [PATCH 52/60] Don't lint autolinks in `doc_markdown` --- clippy_lints/src/doc.rs | 12 +++++++++++- tests/ui/doc.rs | 5 +++++ tests/ui/doc.stderr | 8 +++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 170ca5cf0079..0c4a2a88ae0e 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -195,16 +195,26 @@ fn check_doc<'a, Events: Iterator)>>( use pulldown_cmark::Tag::*; let mut in_code = false; + let mut in_link = None; for (offset, event) in docs { match event { Start(CodeBlock(_)) | Start(Code) => in_code = true, End(CodeBlock(_)) | End(Code) => in_code = false, - Start(_tag) | End(_tag) => (), // We don't care about other tags + Start(Link(link, _)) => in_link = Some(link), + End(Link(_, _)) => in_link = None, + Start(_tag) | End(_tag) => (), // We don't care about other tags Html(_html) | InlineHtml(_html) => (), // HTML is weird, just ignore it SoftBreak => (), HardBreak => (), FootnoteReference(text) | Text(text) => { + if Some(&text) == in_link.as_ref() { + // Probably a link of the form `` + // Which are represented as a link to "http://example.com" with + // text "http://example.com" by pulldown-cmark + continue; + } + if !in_code { let index = match spans.binary_search_by(|c| c.0.cmp(&offset)) { Ok(o) => o, diff --git a/tests/ui/doc.rs b/tests/ui/doc.rs index 9e7b34e3ea50..21449e526af1 100644 --- a/tests/ui/doc.rs +++ b/tests/ui/doc.rs @@ -159,3 +159,8 @@ fn issue_1469() {} *This would also be an error under a strict common mark interpretation */ fn issue_1920() {} + +/// Ok: +/// +/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels +fn issue_1832() {} diff --git a/tests/ui/doc.stderr b/tests/ui/doc.stderr index c3146f17d088..fb0d724172d1 100644 --- a/tests/ui/doc.stderr +++ b/tests/ui/doc.stderr @@ -156,5 +156,11 @@ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the doc 138 | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 26 previous errors +error: you should put `http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels` between ticks in the documentation + --> $DIR/doc.rs:165:13 + | +165 | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 27 previous errors From b10610cdebc4d86349985c8dbca5a523a92b9aec Mon Sep 17 00:00:00 2001 From: mcarton Date: Mon, 19 Jun 2017 19:49:29 +0200 Subject: [PATCH 53/60] Add the `url` crate as a dependency --- Cargo.lock | 38 ++++++++++++++++++++++++++++++++++++++ clippy_lints/Cargo.toml | 1 + clippy_lints/src/lib.rs | 1 + 3 files changed, 40 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 34be0d11a52b..1eed9fa4e954 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,7 @@ dependencies = [ "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -147,6 +148,16 @@ name = "getopts" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "idna" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itertools" version = "0.6.2" @@ -228,6 +239,11 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "percent-encoding" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pulldown-cmark" version = "0.0.15" @@ -367,6 +383,14 @@ dependencies = [ "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-normalization" version = "0.1.5" @@ -385,6 +409,16 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "url" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "utf8-ranges" version = "1.0.0" @@ -421,6 +455,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" "checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" +"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum itertools 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22c285d60139cf413244894189ca52debcfd70b57966feed060da76802e415a0" "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" @@ -433,6 +468,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum nix 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47e49f6982987135c5e9620ab317623e723bd06738fd85377e8d55f57c8b6487" "checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" "checksum os_pipe 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "998bfbb3042e715190fe2a41abfa047d7e8cb81374d2977d7f100eacd8619cb1" +"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" "checksum pulldown-cmark 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "378e941dbd392c101f2cb88097fa4d7167bc421d4b88de3ff7dbee503bc3233b" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" @@ -451,9 +487,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 85d65c791761..9c78514285d4 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -28,6 +28,7 @@ serde_derive = "1.0" toml = "0.4" unicode-normalization = "0.1" pulldown-cmark = "0.0.15" +url = "1.5.0" [features] debugging = [] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index bca15f693265..c61d78c6410f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -51,6 +51,7 @@ extern crate lazy_static; extern crate itertools; extern crate pulldown_cmark; +extern crate url; macro_rules! declare_restriction_lint { { pub $name:tt, $description:tt } => { From aca6c1e06576b41f75da5b5faa682cdd3f17531e Mon Sep 17 00:00:00 2001 From: mcarton Date: Mon, 19 Jun 2017 21:23:50 +0200 Subject: [PATCH 54/60] Have a separate message for raw URLs in doc --- clippy_lints/src/doc.rs | 13 +++++++++++++ tests/ui/doc.rs | 3 +++ tests/ui/doc.stderr | 24 +++++++++++++++++++++--- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 0c4a2a88ae0e..3162dbc422bd 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -5,6 +5,7 @@ use syntax::ast; use syntax::codemap::{BytePos, Span}; use syntax_pos::Pos; use utils::span_lint; +use url::Url; /// **What it does:** Checks for the presence of `_`, `::` or camel-case words /// outside ticks in documentation. @@ -280,6 +281,18 @@ fn check_word(cx: &EarlyContext, word: &str, span: Span) { s != "_" && !s.contains("\\_") && s.contains('_') } + if let Ok(url) = Url::parse(word) { + // try to get around the fact that `foo::bar` parses as a valid URL + if !url.cannot_be_a_base() { + span_lint(cx, + DOC_MARKDOWN, + span, + "you should put bare URLs between `<`/`>` or make a proper Markdown link"); + + return; + } + } + if has_underscore(word) || word.contains("::") || is_camel_case(word) { span_lint( cx, diff --git a/tests/ui/doc.rs b/tests/ui/doc.rs index 21449e526af1..70009d76f5d9 100644 --- a/tests/ui/doc.rs +++ b/tests/ui/doc.rs @@ -162,5 +162,8 @@ fn issue_1920() {} /// Ok: /// +/// Not ok: http://www.unicode.org +/// Not ok: https://www.unicode.org +/// Not ok: http://www.unicode.org/ /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels fn issue_1832() {} diff --git a/tests/ui/doc.stderr b/tests/ui/doc.stderr index fb0d724172d1..f38678e89aac 100644 --- a/tests/ui/doc.stderr +++ b/tests/ui/doc.stderr @@ -156,11 +156,29 @@ error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the doc 138 | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: you should put `http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels` between ticks in the documentation +error: you should put bare URLs between `<`/`>` or make a proper Markdown link --> $DIR/doc.rs:165:13 | -165 | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels +165 | /// Not ok: http://www.unicode.org + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: you should put bare URLs between `<`/`>` or make a proper Markdown link + --> $DIR/doc.rs:166:13 + | +166 | /// Not ok: https://www.unicode.org + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: you should put bare URLs between `<`/`>` or make a proper Markdown link + --> $DIR/doc.rs:167:13 + | +167 | /// Not ok: http://www.unicode.org/ + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: you should put bare URLs between `<`/`>` or make a proper Markdown link + --> $DIR/doc.rs:168:13 + | +168 | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 27 previous errors +error: aborting due to 30 previous errors From 50ffaca4c9686af96ab86a8ec201f5b31dd62a32 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 18 Sep 2017 12:47:33 +0200 Subject: [PATCH 55/60] Reduce the hackiness of cargo-clippy --- .travis.yml | 1 + Cargo.toml | 6 + build.rs | 8 + src/driver.rs | 198 ++++++++++ src/main.rs | 349 +++++------------- tests/compile-test.rs | 15 +- tests/{run-pass => }/conf_whitelisted.rs | 1 - tests/run-pass/associated-constant-ice.rs | 4 +- tests/run-pass/enum-glob-import-crate.rs | 4 +- tests/run-pass/ice-1588.rs | 4 +- tests/run-pass/ice-1969.rs | 4 +- tests/run-pass/ice-700.rs | 4 +- tests/run-pass/mut_mut_macro.rs | 4 +- .../run-pass/needless_lifetimes_impl_trait.rs | 4 +- tests/run-pass/procedural_macro.rs | 2 +- tests/run-pass/regressions.rs | 4 +- tests/run-pass/single-match-else.rs | 4 +- tests/ui-posix/conf_non_existant.rs | 6 - tests/ui-posix/conf_non_existant.stderr | 4 - tests/ui-posix/update-all-references.sh | 28 -- tests/ui-posix/update-references.sh | 50 --- tests/ui-windows/conf_non_existant.rs | 6 - tests/ui-windows/conf_non_existant.stderr | 4 - tests/ui-windows/update-all-references.sh | 28 -- tests/ui-windows/update-references.sh | 50 --- tests/ui/absurd-extreme-comparisons.rs | 4 +- tests/ui/absurd-extreme-comparisons.stderr | 2 - tests/ui/approx_const.rs | 4 +- tests/ui/approx_const.stderr | 2 - tests/ui/arithmetic.rs | 4 +- tests/ui/arithmetic.stderr | 2 - tests/ui/array_indexing.rs | 2 +- tests/ui/array_indexing.stderr | 2 - tests/ui/assign_ops.rs | 4 +- tests/ui/assign_ops.stderr | 2 - tests/ui/assign_ops2.rs | 4 +- tests/ui/assign_ops2.stderr | 2 - tests/ui/attrs.rs | 4 +- tests/ui/attrs.stderr | 2 - tests/ui/bit_masks.rs | 4 +- tests/ui/bit_masks.stderr | 2 - tests/ui/blacklisted_name.rs | 4 +- tests/ui/blacklisted_name.stderr | 2 - tests/ui/block_in_if_condition.rs | 4 +- tests/ui/block_in_if_condition.stderr | 2 - tests/ui/bool_comparison.rs | 4 +- tests/ui/bool_comparison.stderr | 2 - tests/ui/booleans.rs | 4 +- tests/ui/booleans.stderr | 2 - tests/ui/borrow_box.rs | 4 +- tests/ui/borrow_box.stderr | 2 - tests/ui/box_vec.rs | 4 +- tests/ui/box_vec.stderr | 2 - tests/ui/builtin-type-shadow.rs | 4 +- tests/ui/builtin-type-shadow.stderr | 2 - tests/ui/bytecount.rs | 4 +- tests/ui/bytecount.stderr | 2 - tests/ui/cast.rs | 4 +- tests/ui/cast.stderr | 2 - tests/ui/char_lit_as_u8.rs | 4 +- tests/ui/char_lit_as_u8.stderr | 2 - tests/ui/cmp_nan.rs | 4 +- tests/ui/cmp_nan.stderr | 2 - tests/ui/cmp_null.rs | 4 +- tests/ui/cmp_null.stderr | 2 - tests/ui/cmp_owned.rs | 4 +- tests/ui/cmp_owned.stderr | 2 - tests/ui/collapsible_if.rs | 4 +- tests/ui/collapsible_if.stderr | 2 - tests/ui/complex_types.rs | 4 +- tests/ui/complex_types.stderr | 2 - tests/ui/conf_bad_arg.rs | 2 +- tests/ui/conf_bad_arg.stderr | 14 +- tests/ui/conf_bad_toml.rs | 2 +- tests/ui/conf_bad_toml.stderr | 10 +- tests/ui/conf_bad_type.rs | 2 +- tests/ui/conf_bad_type.stderr | 10 +- tests/ui/conf_french_blacklisted_name.rs | 2 +- tests/ui/conf_french_blacklisted_name.stderr | 48 +-- tests/ui/conf_path_non_string.rs | 2 +- tests/ui/conf_path_non_string.stderr | 14 +- tests/ui/conf_unknown_key.rs | 2 +- tests/ui/conf_unknown_key.stderr | 10 +- tests/ui/copies.rs | 3 +- tests/ui/copies.stderr | 18 +- tests/ui/cyclomatic_complexity.rs | 2 +- tests/ui/cyclomatic_complexity.stderr | 2 - tests/ui/cyclomatic_complexity_attr_used.rs | 2 +- .../ui/cyclomatic_complexity_attr_used.stderr | 2 - tests/ui/deprecated.rs | 4 +- tests/ui/deprecated.stderr | 2 - tests/ui/derive.rs | 4 +- tests/ui/derive.stderr | 2 - tests/ui/diverging_sub_expression.rs | 2 +- tests/ui/diverging_sub_expression.stderr | 2 - tests/ui/dlist.rs | 2 +- tests/ui/dlist.stderr | 2 - tests/ui/doc.rs | 4 +- tests/ui/doc.stderr | 2 - tests/ui/double_neg.rs | 4 +- tests/ui/double_neg.stderr | 2 - tests/ui/double_parens.rs | 4 +- tests/ui/double_parens.stderr | 2 - tests/ui/drop_forget_copy.rs | 4 +- tests/ui/drop_forget_copy.stderr | 2 - tests/ui/drop_forget_ref.rs | 4 +- tests/ui/drop_forget_ref.stderr | 2 - tests/ui/duplicate_underscore_argument.rs | 4 +- tests/ui/duplicate_underscore_argument.stderr | 2 - tests/ui/empty_enum.rs | 4 +- tests/ui/empty_enum.stderr | 2 - tests/ui/entry.rs | 4 +- tests/ui/entry.stderr | 2 - tests/ui/enum_glob_use.rs | 4 +- tests/ui/enum_glob_use.stderr | 2 - tests/ui/enum_variants.rs | 2 +- tests/ui/enum_variants.stderr | 2 - tests/ui/enums_clike.rs | 4 +- tests/ui/enums_clike.stderr | 2 - tests/ui/eq_op.rs | 4 +- tests/ui/eq_op.stderr | 2 - tests/ui/escape_analysis.rs | 2 +- tests/ui/eta.rs | 4 +- tests/ui/eta.stderr | 2 - tests/ui/eval_order_dependence.rs | 4 +- tests/ui/eval_order_dependence.stderr | 2 - tests/ui/filter_methods.rs | 4 +- tests/ui/filter_methods.stderr | 2 - tests/ui/float_cmp.rs | 4 +- tests/ui/float_cmp.stderr | 2 - tests/ui/for_loop.rs | 2 +- tests/ui/for_loop.stderr | 2 - tests/ui/format.rs | 4 +- tests/ui/format.stderr | 2 - tests/ui/formatting.rs | 4 +- tests/ui/formatting.stderr | 2 - tests/ui/functions.rs | 4 +- tests/ui/functions.stderr | 2 - tests/ui/ices.rs | 5 - tests/ui/ices.stderr | 8 - tests/ui/identity_op.rs | 4 +- tests/ui/identity_op.stderr | 2 - tests/ui/if_let_redundant_pattern_matching.rs | 4 +- .../if_let_redundant_pattern_matching.stderr | 2 - tests/ui/if_not_else.rs | 4 +- tests/ui/if_not_else.stderr | 2 - tests/ui/inconsistent_digit_grouping.rs | 4 +- tests/ui/inconsistent_digit_grouping.stderr | 2 - tests/ui/infinite_iter.rs | 4 +- tests/ui/infinite_iter.stderr | 2 - tests/ui/int_plus_one.stderr | 4 +- tests/ui/invalid_ref.stderr | 4 +- tests/ui/invalid_upcast_comparisons.rs | 4 +- tests/ui/invalid_upcast_comparisons.stderr | 2 - tests/ui/is_unit_expr.rs | 4 +- tests/ui/is_unit_expr.stderr | 2 - tests/ui/item_after_statement.rs | 4 +- tests/ui/item_after_statement.stderr | 2 - tests/ui/large_digit_groups.rs | 4 +- tests/ui/large_digit_groups.stderr | 2 - tests/ui/large_enum_variant.rs | 4 +- tests/ui/large_enum_variant.stderr | 2 - tests/ui/len_zero.rs | 4 +- tests/ui/len_zero.stderr | 2 - tests/ui/let_if_seq.rs | 4 +- tests/ui/let_if_seq.stderr | 2 - tests/ui/let_return.rs | 4 +- tests/ui/let_return.stderr | 2 - tests/ui/let_unit.rs | 4 +- tests/ui/let_unit.stderr | 2 - tests/ui/lifetimes.rs | 4 +- tests/ui/lifetimes.stderr | 2 - tests/ui/lint_pass.rs | 4 +- tests/ui/lint_pass.stderr | 2 - tests/ui/literals.rs | 4 +- tests/ui/literals.stderr | 2 - tests/ui/map_clone.rs | 4 +- tests/ui/map_clone.stderr | 2 - tests/ui/matches.rs | 4 +- tests/ui/matches.stderr | 2 - tests/ui/mem_forget.rs | 4 +- tests/ui/mem_forget.stderr | 2 - tests/ui/methods.rs | 4 +- tests/ui/methods.stderr | 2 - tests/ui/min_max.rs | 4 +- tests/ui/min_max.stderr | 2 - tests/ui/missing-doc.rs | 4 +- tests/ui/missing-doc.stderr | 2 - tests/ui/module_inception.rs | 4 +- tests/ui/module_inception.stderr | 2 - tests/ui/modulo_one.rs | 4 +- tests/ui/modulo_one.stderr | 2 - tests/ui/mut_from_ref.rs | 4 +- tests/ui/mut_from_ref.stderr | 2 - tests/ui/mut_mut.rs | 4 +- tests/ui/mut_mut.stderr | 2 - tests/ui/mut_range_bound.stderr | 4 +- tests/ui/mut_reference.rs | 4 +- tests/ui/mut_reference.stderr | 2 - tests/ui/mutex_atomic.rs | 4 +- tests/ui/mutex_atomic.stderr | 2 - tests/ui/needless_bool.rs | 4 +- tests/ui/needless_bool.stderr | 2 - tests/ui/needless_borrow.rs | 4 +- tests/ui/needless_borrow.stderr | 2 - tests/ui/needless_borrowed_ref.rs | 4 +- tests/ui/needless_borrowed_ref.stderr | 2 - tests/ui/needless_continue.rs | 4 +- tests/ui/needless_continue.stderr | 2 - tests/ui/needless_pass_by_value.rs | 4 +- tests/ui/needless_pass_by_value.stderr | 2 - tests/ui/needless_pass_by_value_proc_macro.rs | 4 +- tests/ui/needless_return.rs | 4 +- tests/ui/needless_return.stderr | 2 - tests/ui/needless_update.rs | 4 +- tests/ui/needless_update.stderr | 2 - tests/ui/neg_multiply.rs | 4 +- tests/ui/neg_multiply.stderr | 2 - tests/ui/never_loop.rs | 4 +- tests/ui/never_loop.stderr | 2 - tests/ui/new_without_default.rs | 2 +- tests/ui/new_without_default.stderr | 2 - tests/ui/no_effect.rs | 2 +- tests/ui/no_effect.stderr | 2 - tests/ui/non_expressive_names.rs | 4 +- tests/ui/non_expressive_names.stderr | 2 - tests/ui/ok_if_let.rs | 4 +- tests/ui/ok_if_let.stderr | 2 - tests/ui/op_ref.rs | 6 +- tests/ui/op_ref.stderr | 2 - tests/ui/open_options.rs | 4 +- tests/ui/open_options.stderr | 2 - tests/ui/overflow_check_conditional.rs | 4 +- tests/ui/overflow_check_conditional.stderr | 2 - tests/ui/panic.rs | 4 +- tests/ui/panic.stderr | 2 - tests/ui/partialeq_ne_impl.rs | 4 +- tests/ui/partialeq_ne_impl.stderr | 2 - tests/ui/patterns.rs | 4 +- tests/ui/patterns.stderr | 2 - tests/ui/precedence.rs | 4 +- tests/ui/precedence.stderr | 2 - tests/ui/print.rs | 4 +- tests/ui/print.stderr | 2 - tests/ui/print_with_newline.rs | 4 +- tests/ui/print_with_newline.stderr | 2 - tests/ui/ptr_arg.rs | 4 +- tests/ui/ptr_arg.stderr | 2 - tests/ui/range.rs | 4 +- tests/ui/range.stderr | 2 - tests/ui/redundant_closure_call.rs | 4 +- tests/ui/redundant_closure_call.stderr | 2 - tests/ui/reference.rs | 4 +- tests/ui/reference.stderr | 2 - tests/ui/regex.rs | 4 +- tests/ui/regex.stderr | 2 - tests/ui/serde.rs | 4 +- tests/ui/serde.stderr | 2 - tests/ui/shadow.rs | 4 +- tests/ui/shadow.stderr | 2 - tests/ui/short_circuit_statement.rs | 4 +- tests/ui/short_circuit_statement.stderr | 2 - tests/ui/should_assert_eq.rs | 4 +- tests/ui/should_assert_eq.stderr | 2 - tests/ui/strings.rs | 4 +- tests/ui/strings.stderr | 2 - tests/ui/stutter.rs | 4 +- tests/ui/stutter.stderr | 2 - tests/ui/swap.rs | 4 +- tests/ui/swap.stderr | 2 - tests/ui/temporary_assignment.rs | 4 +- tests/ui/temporary_assignment.stderr | 2 - tests/ui/toplevel_ref_arg.rs | 4 +- tests/ui/toplevel_ref_arg.stderr | 2 - tests/ui/trailing_zeros.rs | 2 +- tests/ui/trailing_zeros.stderr | 2 - tests/ui/transmute.rs | 4 +- tests/ui/transmute.stderr | 2 - tests/ui/transmute_32bit.rs | 4 +- tests/ui/transmute_64bit.rs | 4 +- tests/ui/transmute_64bit.stderr | 2 - tests/ui/unicode.rs | 4 +- tests/ui/unicode.stderr | 2 - tests/ui/unit_cmp.rs | 4 +- tests/ui/unit_cmp.stderr | 2 - tests/ui/unneeded_field_pattern.rs | 4 +- tests/ui/unneeded_field_pattern.stderr | 2 - tests/ui/unreadable_literal.rs | 4 +- tests/ui/unreadable_literal.stderr | 2 - tests/ui/unsafe_removed_from_name.rs | 4 +- tests/ui/unsafe_removed_from_name.stderr | 2 - tests/ui/unused_io_amount.rs | 4 +- tests/ui/unused_io_amount.stderr | 2 - tests/ui/unused_labels.rs | 4 +- tests/ui/unused_labels.stderr | 2 - tests/ui/unused_lt.rs | 4 +- tests/ui/unused_lt.stderr | 2 - tests/ui/use_self.rs | 4 +- tests/ui/use_self.stderr | 2 - tests/ui/used_underscore_binding.rs | 4 +- tests/ui/used_underscore_binding.stderr | 2 - tests/ui/useless_attribute.rs | 4 +- tests/ui/useless_attribute.stderr | 2 - tests/ui/vec.rs | 4 +- tests/ui/vec.stderr | 2 - tests/ui/while_loop.rs | 4 +- tests/ui/while_loop.stderr | 2 - tests/ui/wrong_self_convention.rs | 4 +- tests/ui/wrong_self_convention.stderr | 2 - tests/ui/zero_div_zero.rs | 4 +- tests/ui/zero_div_zero.stderr | 2 - tests/ui/zero_ptr.rs | 4 +- tests/ui/zero_ptr.stderr | 2 - 313 files changed, 647 insertions(+), 1099 deletions(-) create mode 100644 build.rs create mode 100644 src/driver.rs rename tests/{run-pass => }/conf_whitelisted.rs (87%) delete mode 100644 tests/ui-posix/conf_non_existant.rs delete mode 100644 tests/ui-posix/conf_non_existant.stderr delete mode 100755 tests/ui-posix/update-all-references.sh delete mode 100755 tests/ui-posix/update-references.sh delete mode 100644 tests/ui-windows/conf_non_existant.rs delete mode 100644 tests/ui-windows/conf_non_existant.stderr delete mode 100755 tests/ui-windows/update-all-references.sh delete mode 100755 tests/ui-windows/update-references.sh delete mode 100644 tests/ui/ices.rs delete mode 100644 tests/ui/ices.stderr diff --git a/.travis.yml b/.travis.yml index 2664a01ea476..8fe1be2ddfaf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,7 @@ script: - cargo test --features debugging - mkdir -p ~/rust/cargo/bin - cp target/debug/cargo-clippy ~/rust/cargo/bin/cargo-clippy + - cp target/debug/clippy-driver ~/rust/cargo/bin/clippy-driver - PATH=$PATH:~/rust/cargo/bin cargo clippy --all -- -D clippy - cd clippy_workspace_tests && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd .. - cd clippy_workspace_tests/src && PATH=$PATH:~/rust/cargo/bin cargo clippy -- -D clippy && cd ../.. diff --git a/Cargo.toml b/Cargo.toml index f9c3fd0fd67c..3d3b8abaa769 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ readme = "README.md" license = "MPL-2.0" keywords = ["clippy", "lint", "plugin"] categories = ["development-tools", "development-tools::cargo-plugins"] +build = "build.rs" [badges] travis-ci = { repository = "rust-lang-nursery/rust-clippy" } @@ -29,6 +30,11 @@ name = "cargo-clippy" test = false path = "src/main.rs" +[[bin]] +name = "clippy-driver" +test = false +path = "src/driver.rs" + [dependencies] # begin automatic update clippy_lints = { version = "0.0.165", path = "clippy_lints" } diff --git a/build.rs b/build.rs new file mode 100644 index 000000000000..1c930c1b2c95 --- /dev/null +++ b/build.rs @@ -0,0 +1,8 @@ +use std::env; + +fn main() { + // Forward the profile to the main compilation + println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap()); + // Don't rebuild even if nothing changed + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/src/driver.rs b/src/driver.rs new file mode 100644 index 000000000000..ab5e90141a9a --- /dev/null +++ b/src/driver.rs @@ -0,0 +1,198 @@ +// error-pattern:yummy +#![feature(box_syntax)] +#![feature(rustc_private)] +#![allow(unknown_lints, missing_docs_in_private_items)] + +extern crate clippy_lints; +extern crate getopts; +extern crate rustc; +extern crate rustc_driver; +extern crate rustc_errors; +extern crate rustc_plugin; +extern crate syntax; + +use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; +use rustc::session::{config, CompileIncomplete, Session}; +use rustc::session::config::{ErrorOutputType, Input}; +use std::path::PathBuf; +use std::process::Command; +use syntax::ast; + +struct ClippyCompilerCalls { + default: RustcDefaultCalls, + run_lints: bool, +} + +impl ClippyCompilerCalls { + fn new(run_lints: bool) -> Self { + Self { + default: RustcDefaultCalls, + run_lints: run_lints, + } + } +} + +impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { + fn early_callback( + &mut self, + matches: &getopts::Matches, + sopts: &config::Options, + cfg: &ast::CrateConfig, + descriptions: &rustc_errors::registry::Registry, + output: ErrorOutputType, + ) -> Compilation { + self.default + .early_callback(matches, sopts, cfg, descriptions, output) + } + fn no_input( + &mut self, + matches: &getopts::Matches, + sopts: &config::Options, + cfg: &ast::CrateConfig, + odir: &Option, + ofile: &Option, + descriptions: &rustc_errors::registry::Registry, + ) -> Option<(Input, Option)> { + self.default + .no_input(matches, sopts, cfg, odir, ofile, descriptions) + } + fn late_callback( + &mut self, + matches: &getopts::Matches, + sess: &Session, + crate_stores: &rustc::middle::cstore::CrateStore, + input: &Input, + odir: &Option, + ofile: &Option, + ) -> Compilation { + self.default + .late_callback(matches, sess, crate_stores, input, odir, ofile) + } + fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { + let mut control = self.default.build_controller(sess, matches); + + if self.run_lints { + let old = std::mem::replace(&mut control.after_parse.callback, box |_| {}); + control.after_parse.callback = Box::new(move |state| { + { + let mut registry = rustc_plugin::registry::Registry::new( + state.session, + state + .krate + .as_ref() + .expect( + "at this compilation stage \ + the krate must be parsed", + ) + .span, + ); + registry.args_hidden = Some(Vec::new()); + clippy_lints::register_plugins(&mut registry); + + let rustc_plugin::registry::Registry { + early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + .. + } = registry; + let sess = &state.session; + let mut ls = sess.lint_store.borrow_mut(); + for pass in early_lint_passes { + ls.register_early_pass(Some(sess), true, pass); + } + for pass in late_lint_passes { + ls.register_late_pass(Some(sess), true, pass); + } + + for (name, to) in lint_groups { + ls.register_group(Some(sess), true, name, to); + } + + sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); + sess.plugin_attributes.borrow_mut().extend(attributes); + } + old(state); + }); + } + + control + } +} + +#[allow(print_stdout)] +fn show_version() { + println!("{}", env!("CARGO_PKG_VERSION")); +} + +pub fn main() { + use std::env; + + if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) { + panic!("yummy"); + } + + if std::env::args().any(|a| a == "--version" || a == "-V") { + show_version(); + return; + } + + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) { + format!("{}/toolchains/{}", home, toolchain) + } else { + option_env!("SYSROOT") + .map(|s| s.to_owned()) + .or_else(|| { + Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned()) + }) + .expect( + "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust", + ) + }; + + rustc_driver::in_rustc_thread(|| { + // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. + // We're invoking the compiler programatically, so we ignore this/ + let mut orig_args: Vec = env::args().collect(); + if orig_args[1] == "rustc" { + // we still want to be able to invoke it normally though + orig_args.remove(1); + } + // this conditional check for the --sysroot flag is there so users can call + // `clippy_driver` directly + // without having to pass --sysroot or anything + let mut args: Vec = if orig_args.iter().any(|s| s == "--sysroot") { + orig_args.clone() + } else { + orig_args.clone().into_iter() + .chain(Some("--sysroot".to_owned())) + .chain(Some(sys_root)) + .collect() + }; + + // this check ensures that dependencies are built but not linted and the final + // crate is + // linted but not built + let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") || + orig_args.iter().any(|s| s == "--emit=metadata"); + + if clippy_enabled { + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); + } + + let mut ccc = ClippyCompilerCalls::new(clippy_enabled); + let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); + if let Err(CompileIncomplete::Errored(_)) = result { + std::process::exit(1); + } + }).expect("rustc_thread failed"); +} diff --git a/src/main.rs b/src/main.rs index f21cd7bd28ca..69f416e20925 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,128 +3,12 @@ #![feature(rustc_private)] #![allow(unknown_lints, missing_docs_in_private_items)] -extern crate clippy_lints; -extern crate getopts; -extern crate rustc; -extern crate rustc_driver; -extern crate rustc_errors; -extern crate rustc_plugin; -extern crate syntax; - -use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls}; -use rustc::session::{config, CompileIncomplete, Session}; -use rustc::session::config::{ErrorOutputType, Input}; use std::collections::HashMap; -use std::path::PathBuf; -use std::process::{self, Command}; -use syntax::ast; +use std::process; use std::io::{self, Write}; extern crate cargo_metadata; -struct ClippyCompilerCalls { - default: RustcDefaultCalls, - run_lints: bool, -} - -impl ClippyCompilerCalls { - fn new(run_lints: bool) -> Self { - Self { - default: RustcDefaultCalls, - run_lints: run_lints, - } - } -} - -impl<'a> CompilerCalls<'a> for ClippyCompilerCalls { - fn early_callback( - &mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - descriptions: &rustc_errors::registry::Registry, - output: ErrorOutputType, - ) -> Compilation { - self.default - .early_callback(matches, sopts, cfg, descriptions, output) - } - fn no_input( - &mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - odir: &Option, - ofile: &Option, - descriptions: &rustc_errors::registry::Registry, - ) -> Option<(Input, Option)> { - self.default - .no_input(matches, sopts, cfg, odir, ofile, descriptions) - } - fn late_callback( - &mut self, - matches: &getopts::Matches, - sess: &Session, - crate_stores: &rustc::middle::cstore::CrateStore, - input: &Input, - odir: &Option, - ofile: &Option, - ) -> Compilation { - self.default - .late_callback(matches, sess, crate_stores, input, odir, ofile) - } - fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> { - let mut control = self.default.build_controller(sess, matches); - - if self.run_lints { - let old = std::mem::replace(&mut control.after_parse.callback, box |_| {}); - control.after_parse.callback = Box::new(move |state| { - { - let mut registry = rustc_plugin::registry::Registry::new( - state.session, - state - .krate - .as_ref() - .expect( - "at this compilation stage \ - the krate must be parsed", - ) - .span, - ); - registry.args_hidden = Some(Vec::new()); - clippy_lints::register_plugins(&mut registry); - - let rustc_plugin::registry::Registry { - early_lint_passes, - late_lint_passes, - lint_groups, - llvm_passes, - attributes, - .. - } = registry; - let sess = &state.session; - let mut ls = sess.lint_store.borrow_mut(); - for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, pass); - } - for pass in late_lint_passes { - ls.register_late_pass(Some(sess), true, pass); - } - - for (name, to) in lint_groups { - ls.register_group(Some(sess), true, name, to); - } - - sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes); - sess.plugin_attributes.borrow_mut().extend(attributes); - } - old(state); - }); - } - - control - } -} - use std::path::Path; const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. @@ -181,166 +65,105 @@ pub fn main() { return; } - if "clippy" == std::env::args().nth(1).as_ref().expect("cargo-clippy should be called with at least one argument!") { - // this arm is executed on the initial call to `cargo clippy` + let manifest_path_arg = std::env::args() + .skip(2) + .find(|val| val.starts_with("--manifest-path=")); - let manifest_path_arg = std::env::args() - .skip(2) - .find(|val| val.starts_with("--manifest-path=")); + let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) + { + metadata + } else { + let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); + process::exit(101); + }; - let mut metadata = if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) - { - metadata - } else { - let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n")); - process::exit(101); - }; + let manifest_path = manifest_path_arg.map(|arg| { + Path::new(&arg["--manifest-path=".len()..]) + .canonicalize() + .expect("manifest path could not be canonicalized") + }); - let manifest_path = manifest_path_arg.map(|arg| { - Path::new(&arg["--manifest-path=".len()..]) - .canonicalize() - .expect("manifest path could not be canonicalized") - }); - - let packages = if std::env::args().any(|a| a == "--all") { - metadata.packages - } else { - let package_index = { - if let Some(manifest_path) = manifest_path { - metadata.packages.iter().position(|package| { - let package_manifest_path = Path::new(&package.manifest_path) - .canonicalize() - .expect("package manifest path could not be canonicalized"); - package_manifest_path == manifest_path - }) - } else { - let package_manifest_paths: HashMap<_, _> = metadata - .packages - .iter() - .enumerate() - .map(|(i, package)| { - let package_manifest_path = Path::new(&package.manifest_path) - .parent() - .expect("could not find parent directory of package manifest") - .canonicalize() - .expect("package directory cannot be canonicalized"); - (package_manifest_path, i) - }) - .collect(); - - let current_dir = std::env::current_dir() - .expect("could not read current directory") + let packages = if std::env::args().any(|a| a == "--all") { + metadata.packages + } else { + let package_index = { + if let Some(manifest_path) = manifest_path { + metadata.packages.iter().position(|package| { + let package_manifest_path = Path::new(&package.manifest_path) .canonicalize() - .expect("current directory cannot be canonicalized"); + .expect("package manifest path could not be canonicalized"); + package_manifest_path == manifest_path + }) + } else { + let package_manifest_paths: HashMap<_, _> = metadata + .packages + .iter() + .enumerate() + .map(|(i, package)| { + let package_manifest_path = Path::new(&package.manifest_path) + .parent() + .expect("could not find parent directory of package manifest") + .canonicalize() + .expect("package directory cannot be canonicalized"); + (package_manifest_path, i) + }) + .collect(); - let mut current_path: &Path = ¤t_dir; + let current_dir = std::env::current_dir() + .expect("could not read current directory") + .canonicalize() + .expect("current directory cannot be canonicalized"); - // This gets the most-recent parent (the one that takes the fewest `cd ..`s to - // reach). - loop { - if let Some(&package_index) = package_manifest_paths.get(current_path) { - break Some(package_index); - } else { - // We'll never reach the filesystem root, because to get to this point in the - // code - // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to - // unwrap the current path's parent. - current_path = current_path - .parent() - .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display())); - } + let mut current_path: &Path = ¤t_dir; + + // This gets the most-recent parent (the one that takes the fewest `cd ..`s to + // reach). + loop { + if let Some(&package_index) = package_manifest_paths.get(current_path) { + break Some(package_index); + } else { + // We'll never reach the filesystem root, because to get to this point in the + // code + // the call to `cargo_metadata::metadata` must have succeeded. So it's okay to + // unwrap the current path's parent. + current_path = current_path + .parent() + .unwrap_or_else(|| panic!("could not find parent of path {}", current_path.display())); } } - }.expect("could not find matching package"); + } + }.expect("could not find matching package"); - vec![metadata.packages.remove(package_index)] - }; + vec![metadata.packages.remove(package_index)] + }; - for package in packages { - let manifest_path = package.manifest_path; + for package in packages { + let manifest_path = package.manifest_path; - for target in package.targets { - let args = std::env::args() - .skip(2) - .filter(|a| a != "--all" && !a.starts_with("--manifest-path=")); + for target in package.targets { + let args = std::env::args() + .skip(2) + .filter(|a| a != "--all" && !a.starts_with("--manifest-path=")); - let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args); - if let Some(first) = target.kind.get(0) { - if target.kind.len() > 1 || first.ends_with("lib") { - if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) { - std::process::exit(code); - } - } else if ["bin", "example", "test", "bench"].contains(&&**first) { - if let Err(code) = process( - vec![format!("--{}", first), target.name] - .into_iter() - .chain(args), - ) { - std::process::exit(code); - } + let args = std::iter::once(format!("--manifest-path={}", manifest_path)).chain(args); + if let Some(first) = target.kind.get(0) { + if target.kind.len() > 1 || first.ends_with("lib") { + if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) { + std::process::exit(code); + } + } else if ["bin", "example", "test", "bench"].contains(&&**first) { + if let Err(code) = process( + vec![format!("--{}", first), target.name] + .into_iter() + .chain(args), + ) { + std::process::exit(code); } - } else { - panic!("badly formatted cargo metadata: target::kind is an empty array"); } + } else { + panic!("badly formatted cargo metadata: target::kind is an empty array"); } } - } else { - // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC_WRAPPER` - // env var set to itself - - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) { - format!("{}/toolchains/{}", home, toolchain) - } else { - option_env!("SYSROOT") - .map(|s| s.to_owned()) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect( - "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust", - ) - }; - - rustc_driver::in_rustc_thread(|| { - // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument. - // We're invoking the compiler programatically, so we ignore this/ - let orig_args: Vec = env::args().skip(1).collect(); - - // this conditional check for the --sysroot flag is there so users can call - // `cargo-clippy` directly - // without having to pass --sysroot or anything - let mut args: Vec = if orig_args.iter().any(|s| s == "--sysroot") { - orig_args.clone() - } else { - orig_args.clone().into_iter() - .chain(Some("--sysroot".to_owned())) - .chain(Some(sys_root)) - .collect() - }; - - // this check ensures that dependencies are built but not linted and the final - // crate is - // linted but not built - let clippy_enabled = orig_args.iter().any(|s| s == "--emit=metadata"); - - if clippy_enabled { - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]); - } - - let mut ccc = ClippyCompilerCalls::new(clippy_enabled); - let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None); - if let Err(CompileIncomplete::Errored(_)) = result { - std::process::exit(1); - } - }).expect("rustc_thread failed"); } } @@ -362,7 +185,9 @@ where args.push("--cfg".to_owned()); args.push(r#"feature="cargo-clippy""#.to_owned()); - let path = std::env::current_exe().expect("current executable path invalid"); + let path = std::env::current_exe() + .expect("current executable path invalid") + .with_file_name("clippy-driver"); let exit_status = std::process::Command::new("cargo") .args(&args) .env("RUSTC_WRAPPER", path) diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 8fa0d440ee7b..be8793215dc2 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -3,6 +3,14 @@ extern crate compiletest_rs as compiletest; use std::path::PathBuf; use std::env::{set_var, var}; +fn clippy_driver_path() -> PathBuf { + if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") { + PathBuf::from(path) + } else { + PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver")) + } +} + fn run_mode(dir: &'static str, mode: &'static str) { let mut config = compiletest::Config::default(); @@ -16,12 +24,15 @@ fn run_mode(dir: &'static str, mode: &'static str) { config.mode = cfg_mode; config.build_base = PathBuf::from("target/debug/test_build_base"); config.src_base = PathBuf::from(format!("tests/{}", dir)); + config.rustc_path = clippy_driver_path(); compiletest::run_tests(&config); } fn prepare_env() { set_var("CLIPPY_DISABLE_DOCS_LINKS", "true"); + set_var("CLIPPY_TESTS", "true"); + set_var("RUST_BACKTRACE", "0"); } #[test] @@ -29,8 +40,4 @@ fn compile_test() { prepare_env(); run_mode("run-pass", "run-pass"); run_mode("ui", "ui"); - #[cfg(target_os = "windows")] - run_mode("ui-windows", "ui"); - #[cfg(not(target_os = "windows"))] - run_mode("ui-posix", "ui"); } diff --git a/tests/run-pass/conf_whitelisted.rs b/tests/conf_whitelisted.rs similarity index 87% rename from tests/run-pass/conf_whitelisted.rs rename to tests/conf_whitelisted.rs index 1c82a010b3d4..198bf465bd57 100644 --- a/tests/run-pass/conf_whitelisted.rs +++ b/tests/conf_whitelisted.rs @@ -1,4 +1,3 @@ #![feature(plugin)] #![plugin(clippy(conf_file="./tests/auxiliary/conf_whitelisted.toml"))] -fn main() {} diff --git a/tests/run-pass/associated-constant-ice.rs b/tests/run-pass/associated-constant-ice.rs index 8fb55fa2272a..744de9bcf384 100644 --- a/tests/run-pass/associated-constant-ice.rs +++ b/tests/run-pass/associated-constant-ice.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + pub trait Trait { const CONSTANT: u8; diff --git a/tests/run-pass/enum-glob-import-crate.rs b/tests/run-pass/enum-glob-import-crate.rs index e08a00d26e2f..21ed2dbf9910 100644 --- a/tests/run-pass/enum-glob-import-crate.rs +++ b/tests/run-pass/enum-glob-import-crate.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![deny(clippy)] #![allow(unused_imports)] diff --git a/tests/run-pass/ice-1588.rs b/tests/run-pass/ice-1588.rs index d53d3a1cc758..780df5235115 100644 --- a/tests/run-pass/ice-1588.rs +++ b/tests/run-pass/ice-1588.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(clippy)] fn main() { diff --git a/tests/run-pass/ice-1969.rs b/tests/run-pass/ice-1969.rs index 23a002a5cdee..296339828480 100644 --- a/tests/run-pass/ice-1969.rs +++ b/tests/run-pass/ice-1969.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(clippy)] fn main() { } diff --git a/tests/run-pass/ice-700.rs b/tests/run-pass/ice-700.rs index a7ff78eac146..a1e3a6756e9e 100644 --- a/tests/run-pass/ice-700.rs +++ b/tests/run-pass/ice-700.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![deny(clippy)] fn core() {} diff --git a/tests/run-pass/mut_mut_macro.rs b/tests/run-pass/mut_mut_macro.rs index a6473b0f909e..adc308626b1b 100644 --- a/tests/run-pass/mut_mut_macro.rs +++ b/tests/run-pass/mut_mut_macro.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![deny(mut_mut, zero_ptr, cmp_nan)] #![allow(dead_code)] diff --git a/tests/run-pass/needless_lifetimes_impl_trait.rs b/tests/run-pass/needless_lifetimes_impl_trait.rs index 8edb444f936c..0ebc1bf3c6c1 100644 --- a/tests/run-pass/needless_lifetimes_impl_trait.rs +++ b/tests/run-pass/needless_lifetimes_impl_trait.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![feature(conservative_impl_trait)] #![deny(needless_lifetimes)] #![allow(dead_code)] diff --git a/tests/run-pass/procedural_macro.rs b/tests/run-pass/procedural_macro.rs index 91269726172d..b185f6dc4277 100644 --- a/tests/run-pass/procedural_macro.rs +++ b/tests/run-pass/procedural_macro.rs @@ -1,5 +1,5 @@ #![feature(plugin)] -#![plugin(clippy, clippy_mini_macro_test)] +#![plugin(clippy_mini_macro_test)] #[deny(warnings)] fn main() { diff --git a/tests/run-pass/regressions.rs b/tests/run-pass/regressions.rs index 442b01d35f80..d5e343c56c20 100644 --- a/tests/run-pass/regressions.rs +++ b/tests/run-pass/regressions.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(blacklisted_name)] pub fn foo(bar: *const u8) { diff --git a/tests/run-pass/single-match-else.rs b/tests/run-pass/single-match-else.rs index fe3cf1ce71f0..b8fa7294dcde 100644 --- a/tests/run-pass/single-match-else.rs +++ b/tests/run-pass/single-match-else.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(single_match_else)] fn main() { diff --git a/tests/ui-posix/conf_non_existant.rs b/tests/ui-posix/conf_non_existant.rs deleted file mode 100644 index e287f7e02af9..000000000000 --- a/tests/ui-posix/conf_non_existant.rs +++ /dev/null @@ -1,6 +0,0 @@ -// error-pattern: error reading Clippy's configuration file - -#![feature(plugin)] -#![plugin(clippy(conf_file="./tests/auxiliary/non_existant_conf.toml"))] - -fn main() {} diff --git a/tests/ui-posix/conf_non_existant.stderr b/tests/ui-posix/conf_non_existant.stderr deleted file mode 100644 index 7920bd35589d..000000000000 --- a/tests/ui-posix/conf_non_existant.stderr +++ /dev/null @@ -1,4 +0,0 @@ -error: error reading Clippy's configuration file: No such file or directory (os error 2) - -error: aborting due to previous error - diff --git a/tests/ui-posix/update-all-references.sh b/tests/ui-posix/update-all-references.sh deleted file mode 100755 index d6aa69c7e8d3..000000000000 --- a/tests/ui-posix/update-all-references.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# A script to update the references for all tests. The idea is that -# you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. You then -# run this script, which will copy those files over. If you find -# yourself manually editing a foo.stderr file, you're doing it wrong. -# -# See all `update-references.sh`, if you just want to update a single test. - -if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" ]]; then - echo "usage: $0" -fi - -BUILD_DIR=$PWD/target/debug/test_build_base -MY_DIR=$(dirname $0) -cd $MY_DIR -find . -name '*.rs' | xargs ./update-references.sh $BUILD_DIR diff --git a/tests/ui-posix/update-references.sh b/tests/ui-posix/update-references.sh deleted file mode 100755 index aa99d35f7aa7..000000000000 --- a/tests/ui-posix/update-references.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# A script to update the references for particular tests. The idea is -# that you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. This -# script will then copy that output and replace the "expected output" -# files. You can then commit the changes. -# -# If you find yourself manually editing a foo.stderr file, you're -# doing it wrong. - -if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then - echo "usage: $0 " - echo "" - echo "For example:" - echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" -fi - -MYDIR=$(dirname $0) - -BUILD_DIR="$1" -shift - -while [[ "$1" != "" ]]; do - STDERR_NAME="${1/%.rs/.stderr}" - STDOUT_NAME="${1/%.rs/.stdout}" - shift - if [ -f $BUILD_DIR/$STDOUT_NAME ] && \ - ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then - echo updating $MYDIR/$STDOUT_NAME - cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME - fi - if [ -f $BUILD_DIR/$STDERR_NAME ] && \ - ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then - echo updating $MYDIR/$STDERR_NAME - cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME - fi -done - - diff --git a/tests/ui-windows/conf_non_existant.rs b/tests/ui-windows/conf_non_existant.rs deleted file mode 100644 index e287f7e02af9..000000000000 --- a/tests/ui-windows/conf_non_existant.rs +++ /dev/null @@ -1,6 +0,0 @@ -// error-pattern: error reading Clippy's configuration file - -#![feature(plugin)] -#![plugin(clippy(conf_file="./tests/auxiliary/non_existant_conf.toml"))] - -fn main() {} diff --git a/tests/ui-windows/conf_non_existant.stderr b/tests/ui-windows/conf_non_existant.stderr deleted file mode 100644 index f21ae524f5ea..000000000000 --- a/tests/ui-windows/conf_non_existant.stderr +++ /dev/null @@ -1,4 +0,0 @@ -error: error reading Clippy's configuration file: The system cannot find the file specified. (os error 2) - -error: aborting due to previous error - diff --git a/tests/ui-windows/update-all-references.sh b/tests/ui-windows/update-all-references.sh deleted file mode 100755 index d6aa69c7e8d3..000000000000 --- a/tests/ui-windows/update-all-references.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# A script to update the references for all tests. The idea is that -# you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. You then -# run this script, which will copy those files over. If you find -# yourself manually editing a foo.stderr file, you're doing it wrong. -# -# See all `update-references.sh`, if you just want to update a single test. - -if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" ]]; then - echo "usage: $0" -fi - -BUILD_DIR=$PWD/target/debug/test_build_base -MY_DIR=$(dirname $0) -cd $MY_DIR -find . -name '*.rs' | xargs ./update-references.sh $BUILD_DIR diff --git a/tests/ui-windows/update-references.sh b/tests/ui-windows/update-references.sh deleted file mode 100755 index aa99d35f7aa7..000000000000 --- a/tests/ui-windows/update-references.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# A script to update the references for particular tests. The idea is -# that you do a run, which will generate files in the build directory -# containing the (normalized) actual output of the compiler. This -# script will then copy that output and replace the "expected output" -# files. You can then commit the changes. -# -# If you find yourself manually editing a foo.stderr file, you're -# doing it wrong. - -if [[ "$1" == "--help" || "$1" == "-h" || "$1" == "" || "$2" == "" ]]; then - echo "usage: $0 " - echo "" - echo "For example:" - echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs" -fi - -MYDIR=$(dirname $0) - -BUILD_DIR="$1" -shift - -while [[ "$1" != "" ]]; do - STDERR_NAME="${1/%.rs/.stderr}" - STDOUT_NAME="${1/%.rs/.stdout}" - shift - if [ -f $BUILD_DIR/$STDOUT_NAME ] && \ - ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then - echo updating $MYDIR/$STDOUT_NAME - cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME - fi - if [ -f $BUILD_DIR/$STDERR_NAME ] && \ - ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then - echo updating $MYDIR/$STDERR_NAME - cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME - fi -done - - diff --git a/tests/ui/absurd-extreme-comparisons.rs b/tests/ui/absurd-extreme-comparisons.rs index ad381c6cd491..1f88d94bd2ba 100644 --- a/tests/ui/absurd-extreme-comparisons.rs +++ b/tests/ui/absurd-extreme-comparisons.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(absurd_extreme_comparisons)] #![allow(unused, eq_op, no_effect, unnecessary_operation, needless_pass_by_value)] diff --git a/tests/ui/absurd-extreme-comparisons.stderr b/tests/ui/absurd-extreme-comparisons.stderr index 2b1e9ad66feb..a4b8839797c3 100644 --- a/tests/ui/absurd-extreme-comparisons.stderr +++ b/tests/ui/absurd-extreme-comparisons.stderr @@ -143,5 +143,3 @@ error: <-comparison of unit values detected. This will always be false | = note: `-D unit-cmp` implied by `-D warnings` -error: aborting due to 18 previous errors - diff --git a/tests/ui/approx_const.rs b/tests/ui/approx_const.rs index eb66a633f9e1..f2239ecb467c 100644 --- a/tests/ui/approx_const.rs +++ b/tests/ui/approx_const.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(approx_constant)] #[allow(unused, shadow_unrelated, similar_names)] diff --git a/tests/ui/approx_const.stderr b/tests/ui/approx_const.stderr index dda28433d7a9..f102dc5b5dca 100644 --- a/tests/ui/approx_const.stderr +++ b/tests/ui/approx_const.stderr @@ -114,5 +114,3 @@ error: approximate value of `f{32, 64}::consts::SQRT_2` found. Consider using it 55 | let my_sq2 = 1.4142; | ^^^^^^ -error: aborting due to 19 previous errors - diff --git a/tests/ui/arithmetic.rs b/tests/ui/arithmetic.rs index b281c239f36d..7ed71b597074 100644 --- a/tests/ui/arithmetic.rs +++ b/tests/ui/arithmetic.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(integer_arithmetic, float_arithmetic)] #![allow(unused, shadow_reuse, shadow_unrelated, no_effect, unnecessary_operation)] diff --git a/tests/ui/arithmetic.stderr b/tests/ui/arithmetic.stderr index ad4a02e21901..ea32a0052190 100644 --- a/tests/ui/arithmetic.stderr +++ b/tests/ui/arithmetic.stderr @@ -69,5 +69,3 @@ error: floating-point arithmetic detected 29 | -f; | ^^ -error: aborting due to 11 previous errors - diff --git a/tests/ui/array_indexing.rs b/tests/ui/array_indexing.rs index c38342daf689..faafa9a7a0d2 100644 --- a/tests/ui/array_indexing.rs +++ b/tests/ui/array_indexing.rs @@ -1,5 +1,5 @@ #![feature(inclusive_range_syntax, plugin)] -#![plugin(clippy)] + #![warn(indexing_slicing)] #![warn(out_of_bounds_indexing)] diff --git a/tests/ui/array_indexing.stderr b/tests/ui/array_indexing.stderr index d730b012932a..dd11247243c2 100644 --- a/tests/ui/array_indexing.stderr +++ b/tests/ui/array_indexing.stderr @@ -116,5 +116,3 @@ error: range is out of bounds 44 | &empty[..4]; | ^^^^^^^^^^ -error: aborting due to 19 previous errors - diff --git a/tests/ui/assign_ops.rs b/tests/ui/assign_ops.rs index f92f2252114f..2b49f2146ba4 100644 --- a/tests/ui/assign_ops.rs +++ b/tests/ui/assign_ops.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(assign_ops)] #[allow(unused_assignments)] diff --git a/tests/ui/assign_ops.stderr b/tests/ui/assign_ops.stderr index 2123507e2ef6..c1cc5d24426c 100644 --- a/tests/ui/assign_ops.stderr +++ b/tests/ui/assign_ops.stderr @@ -134,5 +134,3 @@ error: manual implementation of an assign operation 40 | s = s + "bla"; | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` -error: aborting due to 22 previous errors - diff --git a/tests/ui/assign_ops2.rs b/tests/ui/assign_ops2.rs index b5de5b712ff1..8d6ef827f52d 100644 --- a/tests/ui/assign_ops2.rs +++ b/tests/ui/assign_ops2.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[allow(unused_assignments)] #[warn(misrefactored_assign_op)] diff --git a/tests/ui/assign_ops2.stderr b/tests/ui/assign_ops2.stderr index 0ff211259c03..47528c315d43 100644 --- a/tests/ui/assign_ops2.stderr +++ b/tests/ui/assign_ops2.stderr @@ -48,5 +48,3 @@ error: variable appears on both sides of an assignment operation 15 | a &= a & 1; | ^^^^^^^^^^ help: replace it with: `a &= 1` -error: aborting due to 8 previous errors - diff --git a/tests/ui/attrs.rs b/tests/ui/attrs.rs index 1ff5edcd6307..eb27b833aded 100644 --- a/tests/ui/attrs.rs +++ b/tests/ui/attrs.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(inline_always, deprecated_semver)] diff --git a/tests/ui/attrs.stderr b/tests/ui/attrs.stderr index f743399a6069..9e4ac3d12834 100644 --- a/tests/ui/attrs.stderr +++ b/tests/ui/attrs.stderr @@ -20,5 +20,3 @@ error: the since field must contain a semver-compliant version 30 | #[deprecated(since = "1")] | ^^^^^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/bit_masks.rs b/tests/ui/bit_masks.rs index c211b85d7e27..4843b4eba0d4 100644 --- a/tests/ui/bit_masks.rs +++ b/tests/ui/bit_masks.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + const THREE_BITS : i64 = 7; const EVEN_MORE_REDIRECTION : i64 = THREE_BITS; diff --git a/tests/ui/bit_masks.stderr b/tests/ui/bit_masks.stderr index 40aa585d1243..9f2c2d0a2c4a 100644 --- a/tests/ui/bit_masks.stderr +++ b/tests/ui/bit_masks.stderr @@ -92,5 +92,3 @@ error: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared 55 | x | 1 >= 8; | ^^^^^^^^^^ -error: aborting due to 15 previous errors - diff --git a/tests/ui/blacklisted_name.rs b/tests/ui/blacklisted_name.rs index dabce55883b8..7baeb7bb75cb 100644 --- a/tests/ui/blacklisted_name.rs +++ b/tests/ui/blacklisted_name.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code, similar_names, single_match, toplevel_ref_arg, unused_mut, unused_variables)] #![warn(blacklisted_name)] diff --git a/tests/ui/blacklisted_name.stderr b/tests/ui/blacklisted_name.stderr index 68fbe27a01ee..a08a53268943 100644 --- a/tests/ui/blacklisted_name.stderr +++ b/tests/ui/blacklisted_name.stderr @@ -84,5 +84,3 @@ error: use of a blacklisted/placeholder name `baz` 35 | if let Some(ref mut baz) = Some(42) {} | ^^^ -error: aborting due to 14 previous errors - diff --git a/tests/ui/block_in_if_condition.rs b/tests/ui/block_in_if_condition.rs index 08e510317d92..9e65a127af28 100644 --- a/tests/ui/block_in_if_condition.rs +++ b/tests/ui/block_in_if_condition.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(block_in_if_condition_expr)] #![warn(block_in_if_condition_stmt)] diff --git a/tests/ui/block_in_if_condition.stderr b/tests/ui/block_in_if_condition.stderr index 4b7d12598ecf..86a289c19a84 100644 --- a/tests/ui/block_in_if_condition.stderr +++ b/tests/ui/block_in_if_condition.stderr @@ -50,5 +50,3 @@ error: this boolean expression can be simplified | = note: `-D nonminimal-bool` implied by `-D warnings` -error: aborting due to 5 previous errors - diff --git a/tests/ui/bool_comparison.rs b/tests/ui/bool_comparison.rs index 9b32ed7304bb..f05b9894fea0 100644 --- a/tests/ui/bool_comparison.rs +++ b/tests/ui/bool_comparison.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(bool_comparison)] fn main() { diff --git a/tests/ui/bool_comparison.stderr b/tests/ui/bool_comparison.stderr index 4436980bc117..e5e062e0246d 100644 --- a/tests/ui/bool_comparison.stderr +++ b/tests/ui/bool_comparison.stderr @@ -24,5 +24,3 @@ error: equality checks against false can be replaced by a negation 10 | if false == x { "yes" } else { "no" }; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` -error: aborting due to 4 previous errors - diff --git a/tests/ui/booleans.rs b/tests/ui/booleans.rs index ac60bf5e3458..0434285a5238 100644 --- a/tests/ui/booleans.rs +++ b/tests/ui/booleans.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(nonminimal_bool, logic_bug)] #[allow(unused, many_single_char_names)] diff --git a/tests/ui/booleans.stderr b/tests/ui/booleans.stderr index a76eb7a5cc04..0311e95a4f11 100644 --- a/tests/ui/booleans.stderr +++ b/tests/ui/booleans.stderr @@ -130,5 +130,3 @@ help: try 39 | let _ = !(a == b && c == d); | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors - diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index b5543da6e35c..394b810ed866 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![deny(borrowed_box)] #![allow(blacklisted_name)] diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index 2cf0ea79626c..74134f4f2b18 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -28,5 +28,3 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` 22 | fn test4(a: &Box); | ^^^^^^^^^^ help: try: `&bool` -error: aborting due to 4 previous errors - diff --git a/tests/ui/box_vec.rs b/tests/ui/box_vec.rs index f8c5a80c59de..75b3b62643e8 100644 --- a/tests/ui/box_vec.rs +++ b/tests/ui/box_vec.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(boxed_local, needless_pass_by_value)] diff --git a/tests/ui/box_vec.stderr b/tests/ui/box_vec.stderr index 254d07713862..c1badd0dc9b4 100644 --- a/tests/ui/box_vec.stderr +++ b/tests/ui/box_vec.stderr @@ -7,5 +7,3 @@ error: you seem to be trying to use `Box>`. Consider using just `Vec` = note: `-D box-vec` implied by `-D warnings` = help: `Vec` is already on the heap, `Box>` makes an extra allocation. -error: aborting due to previous error - diff --git a/tests/ui/builtin-type-shadow.rs b/tests/ui/builtin-type-shadow.rs index a3609cfe1046..4c4f5cbd3fe7 100644 --- a/tests/ui/builtin-type-shadow.rs +++ b/tests/ui/builtin-type-shadow.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(builtin_type_shadow)] fn foo(a: u32) -> u32 { diff --git a/tests/ui/builtin-type-shadow.stderr b/tests/ui/builtin-type-shadow.stderr index eb4c73b65c69..058813356cd0 100644 --- a/tests/ui/builtin-type-shadow.stderr +++ b/tests/ui/builtin-type-shadow.stderr @@ -17,5 +17,3 @@ error[E0308]: mismatched types = note: expected type `u32` found type `{integer}` -error: aborting due to 2 previous errors - diff --git a/tests/ui/bytecount.rs b/tests/ui/bytecount.rs index 8fc27c49f34b..fc94667d968f 100644 --- a/tests/ui/bytecount.rs +++ b/tests/ui/bytecount.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[deny(naive_bytecount)] fn main() { diff --git a/tests/ui/bytecount.stderr b/tests/ui/bytecount.stderr index 307edecfde1a..c4f6b65a21ea 100644 --- a/tests/ui/bytecount.stderr +++ b/tests/ui/bytecount.stderr @@ -22,5 +22,3 @@ error: You appear to be counting bytes the naive way 22 | let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Consider using the bytecount crate: `bytecount::count(x, b + 1)` -error: aborting due to 3 previous errors - diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 82427c128e4f..1ad4630989dd 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(cast_precision_loss, cast_possible_truncation, cast_sign_loss, cast_possible_wrap, cast_lossless)] #[allow(no_effect, unnecessary_operation)] diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 8787083b4298..5e7ed6fae99c 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -460,5 +460,3 @@ error: casting to the same type is unnecessary (`bool` -> `bool`) 88 | false as bool; | ^^^^^^^^^^^^^ -error: aborting due to 75 previous errors - diff --git a/tests/ui/char_lit_as_u8.rs b/tests/ui/char_lit_as_u8.rs index 6f07b60fb101..c69181c76493 100644 --- a/tests/ui/char_lit_as_u8.rs +++ b/tests/ui/char_lit_as_u8.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(char_lit_as_u8)] #![allow(unused_variables)] diff --git a/tests/ui/char_lit_as_u8.stderr b/tests/ui/char_lit_as_u8.stderr index fcf038fe002d..4e7c1866a9af 100644 --- a/tests/ui/char_lit_as_u8.stderr +++ b/tests/ui/char_lit_as_u8.stderr @@ -8,5 +8,3 @@ error: casting character literal to u8. `char`s are 4 bytes wide in rust, so cas = help: Consider using a byte literal instead: b'a' -error: aborting due to previous error - diff --git a/tests/ui/cmp_nan.rs b/tests/ui/cmp_nan.rs index e8639273485c..71dfdd43da7c 100644 --- a/tests/ui/cmp_nan.rs +++ b/tests/ui/cmp_nan.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(cmp_nan)] #[allow(float_cmp, no_effect, unnecessary_operation)] diff --git a/tests/ui/cmp_nan.stderr b/tests/ui/cmp_nan.stderr index 46f3d3d57e0c..9ea1a29d29da 100644 --- a/tests/ui/cmp_nan.stderr +++ b/tests/ui/cmp_nan.stderr @@ -72,5 +72,3 @@ error: doomed comparison with NAN, use `std::{f32,f64}::is_nan()` instead 21 | y >= std::f64::NAN; | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors - diff --git a/tests/ui/cmp_null.rs b/tests/ui/cmp_null.rs index 47ecacd5558b..0f463bcfc30d 100644 --- a/tests/ui/cmp_null.rs +++ b/tests/ui/cmp_null.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(cmp_null)] #![allow(unused_mut)] diff --git a/tests/ui/cmp_null.stderr b/tests/ui/cmp_null.stderr index 481a4d0f9420..51c0ceea4b14 100644 --- a/tests/ui/cmp_null.stderr +++ b/tests/ui/cmp_null.stderr @@ -12,5 +12,3 @@ error: Comparing with null is better expressed by the .is_null() method 16 | if m == ptr::null_mut() { | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/cmp_owned.rs b/tests/ui/cmp_owned.rs index 4b9b6434ebca..36d3140d246f 100644 --- a/tests/ui/cmp_owned.rs +++ b/tests/ui/cmp_owned.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(cmp_owned)] #[allow(unnecessary_operation)] diff --git a/tests/ui/cmp_owned.stderr b/tests/ui/cmp_owned.stderr index d40fb4b8add8..e69962446642 100644 --- a/tests/ui/cmp_owned.stderr +++ b/tests/ui/cmp_owned.stderr @@ -36,5 +36,3 @@ error: this creates an owned instance just for comparison 30 | self.to_owned() == *other | ^^^^^^^^^^^^^^^ try calling implementing the comparison without allocating -error: aborting due to 6 previous errors - diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index d03a1ee19801..3c5c38525fe7 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(collapsible_if)] fn main() { diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index 940749d3f407..e726a36282b5 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -252,5 +252,3 @@ help: try 112 | } | -error: aborting due to 13 previous errors - diff --git a/tests/ui/complex_types.rs b/tests/ui/complex_types.rs index 481a6a82cf55..7719a7a86322 100644 --- a/tests/ui/complex_types.rs +++ b/tests/ui/complex_types.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(unused, needless_pass_by_value)] #![feature(associated_type_defaults)] diff --git a/tests/ui/complex_types.stderr b/tests/ui/complex_types.stderr index 829a22c233f0..8ce63652f0b6 100644 --- a/tests/ui/complex_types.stderr +++ b/tests/ui/complex_types.stderr @@ -90,5 +90,3 @@ error: very complex type used. Consider factoring parts into `type` definitions 40 | let _y: Vec>> = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 15 previous errors - diff --git a/tests/ui/conf_bad_arg.rs b/tests/ui/conf_bad_arg.rs index 68b902719f6e..b988fdb13853 100644 --- a/tests/ui/conf_bad_arg.rs +++ b/tests/ui/conf_bad_arg.rs @@ -1,6 +1,6 @@ // error-pattern: `conf_file` must be a named value -#![feature(plugin)] + #![plugin(clippy(conf_file))] fn main() {} diff --git a/tests/ui/conf_bad_arg.stderr b/tests/ui/conf_bad_arg.stderr index 92b3c82d4583..d91729039b19 100644 --- a/tests/ui/conf_bad_arg.stderr +++ b/tests/ui/conf_bad_arg.stderr @@ -1,14 +1,8 @@ -error: `conf_file` must be a named value - --> $DIR/conf_bad_arg.rs:4:18 +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_bad_arg.rs:4:1 | 4 | #![plugin(clippy(conf_file))] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: Clippy will use default configuration - --> $DIR/conf_bad_arg.rs:4:18 - | -4 | #![plugin(clippy(conf_file))] - | ^^^^^^^^^ - -error: aborting due to previous error + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_bad_toml.rs b/tests/ui/conf_bad_toml.rs index 22cbfca759e9..4de2cf6ae73c 100644 --- a/tests/ui/conf_bad_toml.rs +++ b/tests/ui/conf_bad_toml.rs @@ -1,6 +1,6 @@ // error-pattern: error reading Clippy's configuration file -#![feature(plugin)] + #![plugin(clippy(conf_file="./tests/ui/conf_bad_toml.toml"))] fn main() {} diff --git a/tests/ui/conf_bad_toml.stderr b/tests/ui/conf_bad_toml.stderr index 8ee392f89248..5ddf8c14f70f 100644 --- a/tests/ui/conf_bad_toml.stderr +++ b/tests/ui/conf_bad_toml.stderr @@ -1,4 +1,8 @@ -error: error reading Clippy's configuration file: expected an equals, found an identifier at line 1 - -error: aborting due to previous error +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_bad_toml.rs:4:1 + | +4 | #![plugin(clippy(conf_file="./$DIR/conf_bad_toml.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_bad_type.rs b/tests/ui/conf_bad_type.rs index d5cca60a3013..4cb21b91582e 100644 --- a/tests/ui/conf_bad_type.rs +++ b/tests/ui/conf_bad_type.rs @@ -1,6 +1,6 @@ // error-pattern: error reading Clippy's configuration file: `blacklisted-names` is expected to be a `Vec < String >` but is a `integer` -#![feature(plugin)] + #![plugin(clippy(conf_file="./tests/ui/conf_bad_type.toml"))] fn main() {} diff --git a/tests/ui/conf_bad_type.stderr b/tests/ui/conf_bad_type.stderr index 5cb4d05afef2..961df381c991 100644 --- a/tests/ui/conf_bad_type.stderr +++ b/tests/ui/conf_bad_type.stderr @@ -1,4 +1,8 @@ -error: error reading Clippy's configuration file: invalid type: integer `42`, expected a sequence - -error: aborting due to previous error +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_bad_type.rs:4:1 + | +4 | #![plugin(clippy(conf_file="./$DIR/conf_bad_type.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_french_blacklisted_name.rs b/tests/ui/conf_french_blacklisted_name.rs index 5bf1e896f5d1..9f22ff659f23 100644 --- a/tests/ui/conf_french_blacklisted_name.rs +++ b/tests/ui/conf_french_blacklisted_name.rs @@ -1,4 +1,4 @@ -#![feature(plugin)] + #![plugin(clippy(conf_file="./tests/auxiliary/conf_french_blacklisted_name.toml"))] #![allow(dead_code)] diff --git a/tests/ui/conf_french_blacklisted_name.stderr b/tests/ui/conf_french_blacklisted_name.stderr index b2b0f26b1405..c98adb6029fa 100644 --- a/tests/ui/conf_french_blacklisted_name.stderr +++ b/tests/ui/conf_french_blacklisted_name.stderr @@ -1,46 +1,8 @@ -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:9:9 +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_french_blacklisted_name.rs:2:1 | -9 | fn test(toto: ()) {} - | ^^^^ +2 | #![plugin(clippy(conf_file="./tests/auxiliary/conf_french_blacklisted_name.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `-D blacklisted-name` implied by `-D warnings` - -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:12:9 - | -12 | let toto = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:13:9 - | -13 | let tata = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:14:9 - | -14 | let titi = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:20:10 - | -20 | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:20:21 - | -20 | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:20:28 - | -20 | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: aborting due to 7 previous errors + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_path_non_string.rs b/tests/ui/conf_path_non_string.rs index f6f40513be8a..8d1f01358fc8 100644 --- a/tests/ui/conf_path_non_string.rs +++ b/tests/ui/conf_path_non_string.rs @@ -1,5 +1,5 @@ #![feature(attr_literals)] -#![feature(plugin)] + #![plugin(clippy(conf_file=42))] fn main() {} diff --git a/tests/ui/conf_path_non_string.stderr b/tests/ui/conf_path_non_string.stderr index 3bf53f10cce4..4b15b5d0e170 100644 --- a/tests/ui/conf_path_non_string.stderr +++ b/tests/ui/conf_path_non_string.stderr @@ -1,14 +1,8 @@ -error: `conf_file` value must be a string - --> $DIR/conf_path_non_string.rs:3:28 +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_path_non_string.rs:3:1 | 3 | #![plugin(clippy(conf_file=42))] - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: Clippy will use default configuration - --> $DIR/conf_path_non_string.rs:3:28 - | -3 | #![plugin(clippy(conf_file=42))] - | ^^ - -error: aborting due to previous error + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/conf_unknown_key.rs b/tests/ui/conf_unknown_key.rs index b5c1b240e4d1..aec2c883367c 100644 --- a/tests/ui/conf_unknown_key.rs +++ b/tests/ui/conf_unknown_key.rs @@ -1,6 +1,6 @@ // error-pattern: error reading Clippy's configuration file: unknown key `foobar` -#![feature(plugin)] + #![plugin(clippy(conf_file="./tests/auxiliary/conf_unknown_key.toml"))] fn main() {} diff --git a/tests/ui/conf_unknown_key.stderr b/tests/ui/conf_unknown_key.stderr index 8de3cd93370e..9fc7dbea5634 100644 --- a/tests/ui/conf_unknown_key.stderr +++ b/tests/ui/conf_unknown_key.stderr @@ -1,4 +1,8 @@ -error: error reading Clippy's configuration file: unknown field `foobar`, expected one of `blacklisted-names`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `third-party` - -error: aborting due to previous error +error: compiler plugins are experimental and possibly buggy (see issue #29597) + --> $DIR/conf_unknown_key.rs:4:1 + | +4 | #![plugin(clippy(conf_file="./tests/auxiliary/conf_unknown_key.toml"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(plugin)] to the crate attributes to enable diff --git a/tests/ui/copies.rs b/tests/ui/copies.rs index 652afac6c685..4c4050c014fd 100644 --- a/tests/ui/copies.rs +++ b/tests/ui/copies.rs @@ -1,5 +1,4 @@ -#![feature(plugin, dotdoteq_in_patterns, inclusive_range_syntax)] -#![plugin(clippy)] +#![feature(dotdoteq_in_patterns, inclusive_range_syntax)] #![allow(dead_code, no_effect, unnecessary_operation)] #![allow(let_and_return)] diff --git a/tests/ui/copies.stderr b/tests/ui/copies.stderr index bf9e8ed577d0..4457e2b7d731 100644 --- a/tests/ui/copies.stderr +++ b/tests/ui/copies.stderr @@ -1,11 +1,11 @@ error: This else block is redundant. - --> $DIR/copies.rs:121:20 + --> $DIR/copies.rs:120:20 | -121 | } else { +120 | } else { | ____________________^ -122 | | continue; -123 | | } +121 | | continue; +122 | | } | |_____________^ | = note: `-D needless-continue` implied by `-D warnings` @@ -18,12 +18,12 @@ error: This else block is redundant. error: This else block is redundant. - --> $DIR/copies.rs:131:20 + --> $DIR/copies.rs:130:20 | -131 | } else { +130 | } else { | ____________________^ -132 | | continue; -133 | | } +131 | | continue; +132 | | } | |_____________^ | = help: Consider dropping the else clause and merging the code that follows (in the loop) with the if block, like so: @@ -33,5 +33,3 @@ error: This else block is redundant. } -error: aborting due to 2 previous errors - diff --git a/tests/ui/cyclomatic_complexity.rs b/tests/ui/cyclomatic_complexity.rs index a236d6e869f3..0f5726e1ad73 100644 --- a/tests/ui/cyclomatic_complexity.rs +++ b/tests/ui/cyclomatic_complexity.rs @@ -1,5 +1,5 @@ #![feature(plugin, custom_attribute)] -#![plugin(clippy)] + #![allow(clippy)] #![warn(cyclomatic_complexity)] #![allow(unused)] diff --git a/tests/ui/cyclomatic_complexity.stderr b/tests/ui/cyclomatic_complexity.stderr index 43676762d6c0..62fd5313ccb6 100644 --- a/tests/ui/cyclomatic_complexity.stderr +++ b/tests/ui/cyclomatic_complexity.stderr @@ -269,5 +269,3 @@ error: the function has a cyclomatic complexity of 8 | = help: you could split it up into multiple smaller functions -error: aborting due to 20 previous errors - diff --git a/tests/ui/cyclomatic_complexity_attr_used.rs b/tests/ui/cyclomatic_complexity_attr_used.rs index 48ae12bc2d8c..5284d60a5245 100644 --- a/tests/ui/cyclomatic_complexity_attr_used.rs +++ b/tests/ui/cyclomatic_complexity_attr_used.rs @@ -1,5 +1,5 @@ #![feature(plugin, custom_attribute)] -#![plugin(clippy)] + #![warn(cyclomatic_complexity)] #![warn(unused)] diff --git a/tests/ui/cyclomatic_complexity_attr_used.stderr b/tests/ui/cyclomatic_complexity_attr_used.stderr index e671b34393b5..a9cefe93e329 100644 --- a/tests/ui/cyclomatic_complexity_attr_used.stderr +++ b/tests/ui/cyclomatic_complexity_attr_used.stderr @@ -13,5 +13,3 @@ error: the function has a cyclomatic complexity of 3 = note: `-D cyclomatic-complexity` implied by `-D warnings` = help: you could split it up into multiple smaller functions -error: aborting due to previous error - diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index e0c856e3d7cc..0598e174e50a 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(str_to_string)] diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 7d5d594cfa1c..4255959675a9 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -24,5 +24,3 @@ error: lint unstable_as_mut_slice has been removed: `Vec::as_mut_slice` has been 10 | #[warn(unstable_as_mut_slice)] | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/derive.rs b/tests/ui/derive.rs index 11cade0dc8e5..6440f73f31bd 100644 --- a/tests/ui/derive.rs +++ b/tests/ui/derive.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![feature(untagged_unions)] diff --git a/tests/ui/derive.stderr b/tests/ui/derive.stderr index ffeed948ba55..f336dc3a8e13 100644 --- a/tests/ui/derive.stderr +++ b/tests/ui/derive.stderr @@ -106,5 +106,3 @@ note: consider deriving `Clone` or removing `Copy` 87 | | } | |_^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index 7ae531cc6f27..d2aea93a77d8 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -1,5 +1,5 @@ #![feature(plugin, never_type)] -#![plugin(clippy)] + #![warn(diverging_sub_expression)] #![allow(match_same_arms, logic_bug)] diff --git a/tests/ui/diverging_sub_expression.stderr b/tests/ui/diverging_sub_expression.stderr index 0d7b1ca6fd66..b39d1ae07e5e 100644 --- a/tests/ui/diverging_sub_expression.stderr +++ b/tests/ui/diverging_sub_expression.stderr @@ -36,5 +36,3 @@ error: sub-expression diverges 37 | _ => true || break, | ^^^^^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/dlist.rs b/tests/ui/dlist.rs index 5e4e1cb2a64f..217a564742cf 100644 --- a/tests/ui/dlist.rs +++ b/tests/ui/dlist.rs @@ -1,7 +1,7 @@ #![feature(plugin, alloc)] #![feature(associated_type_defaults)] -#![plugin(clippy)] + #![warn(clippy)] #![allow(dead_code, needless_pass_by_value)] diff --git a/tests/ui/dlist.stderr b/tests/ui/dlist.stderr index de0422e17edd..95872c02994f 100644 --- a/tests/ui/dlist.stderr +++ b/tests/ui/dlist.stderr @@ -47,5 +47,3 @@ error: I see you're using a LinkedList! Perhaps you meant some other data struct | = help: a VecDeque might work -error: aborting due to 6 previous errors - diff --git a/tests/ui/doc.rs b/tests/ui/doc.rs index 70009d76f5d9..45e25409b128 100644 --- a/tests/ui/doc.rs +++ b/tests/ui/doc.rs @@ -1,7 +1,7 @@ //! This file tests for the DOC_MARKDOWN lint -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] #![warn(doc_markdown)] diff --git a/tests/ui/doc.stderr b/tests/ui/doc.stderr index f38678e89aac..fc036d01b866 100644 --- a/tests/ui/doc.stderr +++ b/tests/ui/doc.stderr @@ -180,5 +180,3 @@ error: you should put bare URLs between `<`/`>` or make a proper Markdown link 168 | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 30 previous errors - diff --git a/tests/ui/double_neg.rs b/tests/ui/double_neg.rs index d462e6f4ab6b..641e334fd165 100644 --- a/tests/ui/double_neg.rs +++ b/tests/ui/double_neg.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(double_neg)] fn main() { diff --git a/tests/ui/double_neg.stderr b/tests/ui/double_neg.stderr index fd4da8820a24..8c64eb37e154 100644 --- a/tests/ui/double_neg.stderr +++ b/tests/ui/double_neg.stderr @@ -6,5 +6,3 @@ error: `--x` could be misinterpreted as pre-decrement by C programmers, is usual | = note: `-D double-neg` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/double_parens.rs b/tests/ui/double_parens.rs index 8b57619edb0d..19d177328675 100644 --- a/tests/ui/double_parens.rs +++ b/tests/ui/double_parens.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(double_parens)] #![allow(dead_code)] diff --git a/tests/ui/double_parens.stderr b/tests/ui/double_parens.stderr index a77b08528c49..ab3e844d7a7f 100644 --- a/tests/ui/double_parens.stderr +++ b/tests/ui/double_parens.stderr @@ -30,5 +30,3 @@ error: Consider removing unnecessary double parentheses 32 | (()) | ^^^^ -error: aborting due to 5 previous errors - diff --git a/tests/ui/drop_forget_copy.rs b/tests/ui/drop_forget_copy.rs index 4e48a89b6598..9fef06b0edef 100644 --- a/tests/ui/drop_forget_copy.rs +++ b/tests/ui/drop_forget_copy.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(drop_copy, forget_copy)] #![allow(toplevel_ref_arg, drop_ref, forget_ref, unused_mut)] diff --git a/tests/ui/drop_forget_copy.stderr b/tests/ui/drop_forget_copy.stderr index 3ea7bf9735af..f399c5a125f8 100644 --- a/tests/ui/drop_forget_copy.stderr +++ b/tests/ui/drop_forget_copy.stderr @@ -72,5 +72,3 @@ note: argument has type SomeStruct 42 | forget(s4); | ^^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/drop_forget_ref.rs b/tests/ui/drop_forget_ref.rs index 48811f03b6f2..e8ab6a0d5d13 100644 --- a/tests/ui/drop_forget_ref.rs +++ b/tests/ui/drop_forget_ref.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(drop_ref, forget_ref)] #![allow(toplevel_ref_arg, similar_names, needless_pass_by_value)] diff --git a/tests/ui/drop_forget_ref.stderr b/tests/ui/drop_forget_ref.stderr index 1654fdd2861a..6058b89c70f3 100644 --- a/tests/ui/drop_forget_ref.stderr +++ b/tests/ui/drop_forget_ref.stderr @@ -216,5 +216,3 @@ note: argument has type &SomeStruct 59 | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^ -error: aborting due to 18 previous errors - diff --git a/tests/ui/duplicate_underscore_argument.rs b/tests/ui/duplicate_underscore_argument.rs index 893cc43f3646..df00f56aa621 100644 --- a/tests/ui/duplicate_underscore_argument.rs +++ b/tests/ui/duplicate_underscore_argument.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(duplicate_underscore_argument)] #[allow(dead_code, unused)] diff --git a/tests/ui/duplicate_underscore_argument.stderr b/tests/ui/duplicate_underscore_argument.stderr index c926f57f154f..de9e6f1e056c 100644 --- a/tests/ui/duplicate_underscore_argument.stderr +++ b/tests/ui/duplicate_underscore_argument.stderr @@ -6,5 +6,3 @@ error: `darth` already exists, having another argument having almost the same na | = note: `-D duplicate-underscore-argument` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/empty_enum.rs b/tests/ui/empty_enum.rs index 98138add0de3..c6e6946de866 100644 --- a/tests/ui/empty_enum.rs +++ b/tests/ui/empty_enum.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] #![warn(empty_enum)] diff --git a/tests/ui/empty_enum.stderr b/tests/ui/empty_enum.stderr index ca377cee8221..a0d491b6f968 100644 --- a/tests/ui/empty_enum.stderr +++ b/tests/ui/empty_enum.stderr @@ -11,5 +11,3 @@ help: consider using the uninhabited type `!` or a wrapper around it 7 | enum Empty {} | ^^^^^^^^^^^^^ -error: aborting due to previous error - diff --git a/tests/ui/entry.rs b/tests/ui/entry.rs index 1ae39689d8be..ccbc7038f136 100644 --- a/tests/ui/entry.rs +++ b/tests/ui/entry.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused, needless_pass_by_value)] #![warn(map_entry)] diff --git a/tests/ui/entry.stderr b/tests/ui/entry.stderr index 09c4a8822802..e60c158d7c06 100644 --- a/tests/ui/entry.stderr +++ b/tests/ui/entry.stderr @@ -42,5 +42,3 @@ error: usage of `contains_key` followed by `insert` on a `BTreeMap` 37 | if !m.contains_key(&k) { foo(); m.insert(k, v) } else { None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `m.entry(k)` -error: aborting due to 7 previous errors - diff --git a/tests/ui/enum_glob_use.rs b/tests/ui/enum_glob_use.rs index 514ef47c566d..76d0d29bb539 100644 --- a/tests/ui/enum_glob_use.rs +++ b/tests/ui/enum_glob_use.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy, clippy_pedantic)] #![allow(unused_imports, dead_code, missing_docs_in_private_items)] diff --git a/tests/ui/enum_glob_use.stderr b/tests/ui/enum_glob_use.stderr index 2d53618c1b18..1e0fffb9ac44 100644 --- a/tests/ui/enum_glob_use.stderr +++ b/tests/ui/enum_glob_use.stderr @@ -12,5 +12,3 @@ error: don't use glob imports for enum variants 12 | use self::Enum::*; | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/enum_variants.rs b/tests/ui/enum_variants.rs index a12eb3fd3447..9901baf9e128 100644 --- a/tests/ui/enum_variants.rs +++ b/tests/ui/enum_variants.rs @@ -1,5 +1,5 @@ #![feature(plugin, non_ascii_idents)] -#![plugin(clippy)] + #![warn(clippy, pub_enum_variant_names)] enum FakeCallType { diff --git a/tests/ui/enum_variants.stderr b/tests/ui/enum_variants.stderr index e33e29ec78e1..7e2716b8ea20 100644 --- a/tests/ui/enum_variants.stderr +++ b/tests/ui/enum_variants.stderr @@ -97,5 +97,3 @@ error: All variants have the same prefix: `With` = note: `-D pub-enum-variant-names` implied by `-D warnings` = help: remove the prefixes and use full paths to the variants instead of glob imports -error: aborting due to 10 previous errors - diff --git a/tests/ui/enums_clike.rs b/tests/ui/enums_clike.rs index fd2240353dd4..618603683e83 100644 --- a/tests/ui/enums_clike.rs +++ b/tests/ui/enums_clike.rs @@ -1,6 +1,6 @@ // ignore-x86 -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(unused)] diff --git a/tests/ui/enums_clike.stderr b/tests/ui/enums_clike.stderr index d6a137c6fe4d..e0555bb02398 100644 --- a/tests/ui/enums_clike.stderr +++ b/tests/ui/enums_clike.stderr @@ -48,5 +48,3 @@ error: Clike enum variant discriminant is not portable to 32-bit targets 37 | A = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors - diff --git a/tests/ui/eq_op.rs b/tests/ui/eq_op.rs index 12d62042dca8..89d85d1b3e9d 100644 --- a/tests/ui/eq_op.rs +++ b/tests/ui/eq_op.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(eq_op)] #[allow(identity_op, double_parens, many_single_char_names)] diff --git a/tests/ui/eq_op.stderr b/tests/ui/eq_op.stderr index 46c0ac108cda..914a85719d0f 100644 --- a/tests/ui/eq_op.stderr +++ b/tests/ui/eq_op.stderr @@ -204,5 +204,3 @@ error: taken reference of right operand | = note: `-D op-ref` implied by `-D warnings` -error: aborting due to 33 previous errors - diff --git a/tests/ui/escape_analysis.rs b/tests/ui/escape_analysis.rs index b4793198b7a1..b99534d05e17 100644 --- a/tests/ui/escape_analysis.rs +++ b/tests/ui/escape_analysis.rs @@ -1,5 +1,5 @@ #![feature(plugin, box_syntax)] -#![plugin(clippy)] + #![allow(warnings, clippy)] #![warn(boxed_local)] diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs index 46ac0ec8c736..0ff02a0b2ccc 100644 --- a/tests/ui/eta.rs +++ b/tests/ui/eta.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unknown_lints, unused, no_effect, redundant_closure_call, many_single_char_names, needless_pass_by_value)] #![warn(redundant_closure)] diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index 5dca265c2a40..34a6217cd709 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -32,5 +32,3 @@ error: redundant closure found 18 | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `generic` -error: aborting due to 5 previous errors - diff --git a/tests/ui/eval_order_dependence.rs b/tests/ui/eval_order_dependence.rs index 853c61af2f25..e7ccb190d2c7 100644 --- a/tests/ui/eval_order_dependence.rs +++ b/tests/ui/eval_order_dependence.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(eval_order_dependence)] #[allow(unused_assignments, unused_variables, many_single_char_names, no_effect, dead_code, blacklisted_name)] diff --git a/tests/ui/eval_order_dependence.stderr b/tests/ui/eval_order_dependence.stderr index 2e01a167c01b..e9bdc3b51d9d 100644 --- a/tests/ui/eval_order_dependence.stderr +++ b/tests/ui/eval_order_dependence.stderr @@ -47,5 +47,3 @@ note: whether read occurs before this write depends on evaluation order 21 | x += { x = 20; 2 }; | ^^^^^^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/filter_methods.rs b/tests/ui/filter_methods.rs index 77ebe9d12ddf..29230c48ea3e 100644 --- a/tests/ui/filter_methods.rs +++ b/tests/ui/filter_methods.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy, clippy_pedantic)] #![allow(missing_docs_in_private_items)] diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr index cec03a47bfde..8f1853c3952b 100644 --- a/tests/ui/filter_methods.stderr +++ b/tests/ui/filter_methods.stderr @@ -36,5 +36,3 @@ error: called `filter_map(p).map(q)` on an `Iterator`. This is more succinctly e 25 | | .map(|x| x.checked_mul(2)) | |__________________________________________________________^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/float_cmp.rs b/tests/ui/float_cmp.rs index f3f66f3c9c5e..9dd9ea9b04d5 100644 --- a/tests/ui/float_cmp.rs +++ b/tests/ui/float_cmp.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(float_cmp)] #![allow(unused, no_effect, unnecessary_operation, cast_lossless)] diff --git a/tests/ui/float_cmp.stderr b/tests/ui/float_cmp.stderr index a764403d0397..d2903f501f5f 100644 --- a/tests/ui/float_cmp.stderr +++ b/tests/ui/float_cmp.stderr @@ -95,5 +95,3 @@ note: std::f32::EPSILON and std::f64::EPSILON are available. 57 | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors - diff --git a/tests/ui/for_loop.rs b/tests/ui/for_loop.rs index 95d15776a36a..083e6f9a6e5a 100644 --- a/tests/ui/for_loop.rs +++ b/tests/ui/for_loop.rs @@ -1,5 +1,5 @@ #![feature(plugin, inclusive_range_syntax)] -#![plugin(clippy)] + use std::collections::*; use std::rc::Rc; diff --git a/tests/ui/for_loop.stderr b/tests/ui/for_loop.stderr index 09c4deb492a9..620c32b6ab50 100644 --- a/tests/ui/for_loop.stderr +++ b/tests/ui/for_loop.stderr @@ -586,5 +586,3 @@ error: it looks like you're manually copying between slices 549 | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])` -error: aborting due to 59 previous errors - diff --git a/tests/ui/format.rs b/tests/ui/format.rs index 377bcc7ca8d3..e9379d0a05bd 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(useless_format)] fn main() { diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index d2c9f3938312..67d97f295d81 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -18,5 +18,3 @@ error: useless use of `format!` 15 | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/formatting.rs b/tests/ui/formatting.rs index 7e2691776bf7..20b1c1655a72 100644 --- a/tests/ui/formatting.rs +++ b/tests/ui/formatting.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(unused_variables)] diff --git a/tests/ui/formatting.stderr b/tests/ui/formatting.stderr index 266de262ea0a..d121929d0c2d 100644 --- a/tests/ui/formatting.stderr +++ b/tests/ui/formatting.stderr @@ -86,5 +86,3 @@ error: possibly missing a comma here | = note: to remove this lint, add a comma or write the expr in a single line -error: aborting due to 10 previous errors - diff --git a/tests/ui/functions.rs b/tests/ui/functions.rs index 13d116542ac2..5688c471d86b 100644 --- a/tests/ui/functions.rs +++ b/tests/ui/functions.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(dead_code)] diff --git a/tests/ui/functions.stderr b/tests/ui/functions.stderr index 0a97748954f3..c8b4db352457 100644 --- a/tests/ui/functions.stderr +++ b/tests/ui/functions.stderr @@ -75,5 +75,3 @@ error: this public function dereferences a raw pointer but is not marked `unsafe 63 | unsafe { std::ptr::read(p) }; | ^ -error: aborting due to 12 previous errors - diff --git a/tests/ui/ices.rs b/tests/ui/ices.rs deleted file mode 100644 index 9c5129654e41..000000000000 --- a/tests/ui/ices.rs +++ /dev/null @@ -1,5 +0,0 @@ - -// this used to ICE -fubar!(); - -fn main() {} diff --git a/tests/ui/ices.stderr b/tests/ui/ices.stderr deleted file mode 100644 index cadd7cd417d4..000000000000 --- a/tests/ui/ices.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: cannot find macro `fubar!` in this scope - --> $DIR/ices.rs:3:1 - | -3 | fubar!(); - | ^^^^^ - -error: aborting due to previous error - diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index e6ebb9726432..b474344977c8 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + const ONE : i64 = 1; const NEG_ONE : i64 = -1; diff --git a/tests/ui/identity_op.stderr b/tests/ui/identity_op.stderr index 94b9b727a510..30367c989ec8 100644 --- a/tests/ui/identity_op.stderr +++ b/tests/ui/identity_op.stderr @@ -42,5 +42,3 @@ error: the operation is ineffective. Consider reducing it to `x` 29 | -1 & x; | ^^^^^^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/if_let_redundant_pattern_matching.rs b/tests/ui/if_let_redundant_pattern_matching.rs index 6444bd8ef685..0963caa62e28 100644 --- a/tests/ui/if_let_redundant_pattern_matching.rs +++ b/tests/ui/if_let_redundant_pattern_matching.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![warn(if_let_redundant_pattern_matching)] diff --git a/tests/ui/if_let_redundant_pattern_matching.stderr b/tests/ui/if_let_redundant_pattern_matching.stderr index e7bfd0275d8e..b15d17e372e0 100644 --- a/tests/ui/if_let_redundant_pattern_matching.stderr +++ b/tests/ui/if_let_redundant_pattern_matching.stderr @@ -24,5 +24,3 @@ error: redundant pattern matching, consider using `is_some()` 17 | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` -error: aborting due to 4 previous errors - diff --git a/tests/ui/if_not_else.rs b/tests/ui/if_not_else.rs index 7b838560ed10..9436af70cb8f 100644 --- a/tests/ui/if_not_else.rs +++ b/tests/ui/if_not_else.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![warn(if_not_else)] diff --git a/tests/ui/if_not_else.stderr b/tests/ui/if_not_else.stderr index b920ef3b6250..f9462f422ea7 100644 --- a/tests/ui/if_not_else.stderr +++ b/tests/ui/if_not_else.stderr @@ -23,5 +23,3 @@ error: Unnecessary `!=` operation | = help: change to `==` and swap the blocks of the if/else -error: aborting due to 2 previous errors - diff --git a/tests/ui/inconsistent_digit_grouping.rs b/tests/ui/inconsistent_digit_grouping.rs index 06e8996deb7b..ed6dc06edb17 100644 --- a/tests/ui/inconsistent_digit_grouping.rs +++ b/tests/ui/inconsistent_digit_grouping.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(inconsistent_digit_grouping)] #[allow(unused_variables)] fn main() { diff --git a/tests/ui/inconsistent_digit_grouping.stderr b/tests/ui/inconsistent_digit_grouping.stderr index 12d9e3cf0fd7..2725d5f4ef7f 100644 --- a/tests/ui/inconsistent_digit_grouping.stderr +++ b/tests/ui/inconsistent_digit_grouping.stderr @@ -39,5 +39,3 @@ error: digits grouped inconsistently by underscores | = help: consider: 1.234_567_8_f32 -error: aborting due to 5 previous errors - diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs index deb5c5edd8c0..08596ff20169 100644 --- a/tests/ui/infinite_iter.rs +++ b/tests/ui/infinite_iter.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] +#![feature(iterator_for_each)] + use std::iter::repeat; fn square_is_lower_64(x: &u32) -> bool { x * x < 64 } diff --git a/tests/ui/infinite_iter.stderr b/tests/ui/infinite_iter.stderr index f79db7784884..87b7ca493222 100644 --- a/tests/ui/infinite_iter.stderr +++ b/tests/ui/infinite_iter.stderr @@ -96,5 +96,3 @@ error: possible infinite iteration detected 30 | (0..).all(|x| x == 24); // maybe infinite iter | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors - diff --git a/tests/ui/int_plus_one.stderr b/tests/ui/int_plus_one.stderr index 6f69ba9d7146..92b012bd104f 100644 --- a/tests/ui/int_plus_one.stderr +++ b/tests/ui/int_plus_one.stderr @@ -1,3 +1,5 @@ +warning: running cargo clippy on a crate that also imports the clippy plugin + error: Unnecessary `>= y + 1` or `x - 1 >=` --> $DIR/int_plus_one.rs:10:5 | @@ -43,5 +45,3 @@ help: change `>= y + 1` to `> y` as shown 14 | y < x; | ^^^^^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/invalid_ref.stderr b/tests/ui/invalid_ref.stderr index 420fed017444..18064c91a017 100644 --- a/tests/ui/invalid_ref.stderr +++ b/tests/ui/invalid_ref.stderr @@ -1,3 +1,5 @@ +warning: running cargo clippy on a crate that also imports the clippy plugin + error: reference to zeroed memory --> $DIR/invalid_ref.rs:27:24 | @@ -47,5 +49,3 @@ error: reference to uninitialized memory | = help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html -error: aborting due to 6 previous errors - diff --git a/tests/ui/invalid_upcast_comparisons.rs b/tests/ui/invalid_upcast_comparisons.rs index 8d8e7bd8de11..5bf0bfdcb983 100644 --- a/tests/ui/invalid_upcast_comparisons.rs +++ b/tests/ui/invalid_upcast_comparisons.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(invalid_upcast_comparisons)] #![allow(unused, eq_op, no_effect, unnecessary_operation, cast_lossless)] diff --git a/tests/ui/invalid_upcast_comparisons.stderr b/tests/ui/invalid_upcast_comparisons.stderr index eb46802899e7..3f11c3730745 100644 --- a/tests/ui/invalid_upcast_comparisons.stderr +++ b/tests/ui/invalid_upcast_comparisons.stderr @@ -162,5 +162,3 @@ error: because of the numeric bounds on `u8` prior to casting, this expression i 78 | -5 >= (u8 as i32); | ^^^^^^^^^^^^^^^^^ -error: aborting due to 27 previous errors - diff --git a/tests/ui/is_unit_expr.rs b/tests/ui/is_unit_expr.rs index 164e391ff242..24a2587dc534 100644 --- a/tests/ui/is_unit_expr.rs +++ b/tests/ui/is_unit_expr.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(unit_expr)] #[allow(unused_variables)] diff --git a/tests/ui/is_unit_expr.stderr b/tests/ui/is_unit_expr.stderr index 2d9fcfff74f8..5524f866488c 100644 --- a/tests/ui/is_unit_expr.stderr +++ b/tests/ui/is_unit_expr.stderr @@ -51,5 +51,3 @@ note: Consider removing the trailing semicolon 42 | x; | ^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/item_after_statement.rs b/tests/ui/item_after_statement.rs index e3e4a4c75783..710a1adca565 100644 --- a/tests/ui/item_after_statement.rs +++ b/tests/ui/item_after_statement.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(items_after_statements)] fn ok() { diff --git a/tests/ui/item_after_statement.stderr b/tests/ui/item_after_statement.stderr index ec1296caf83e..e98e7ee129d8 100644 --- a/tests/ui/item_after_statement.stderr +++ b/tests/ui/item_after_statement.stderr @@ -12,5 +12,3 @@ error: adding items after statements is confusing, since items exist from the st 17 | fn foo() { println!("foo"); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/large_digit_groups.rs b/tests/ui/large_digit_groups.rs index 65bcdc7435e8..5d0fb11dbea5 100644 --- a/tests/ui/large_digit_groups.rs +++ b/tests/ui/large_digit_groups.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(large_digit_groups)] #[allow(unused_variables)] fn main() { diff --git a/tests/ui/large_digit_groups.stderr b/tests/ui/large_digit_groups.stderr index 6fc285274a0b..db49ded1d8a0 100644 --- a/tests/ui/large_digit_groups.stderr +++ b/tests/ui/large_digit_groups.stderr @@ -47,5 +47,3 @@ error: digit groups should be smaller | = help: consider: 123_456.123_456_f32 -error: aborting due to 6 previous errors - diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index 31a7760aa19c..aaf3e2924b31 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr index bb889087095b..899a84edeaad 100644 --- a/tests/ui/large_enum_variant.stderr +++ b/tests/ui/large_enum_variant.stderr @@ -68,5 +68,3 @@ help: consider boxing the large fields to reduce the total size of the enum 49 | StructLikeLarge2 { x: Box<[i32; 8000]> }, | ^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs index 9c66d5a8148a..aba1dd3055af 100644 --- a/tests/ui/len_zero.rs +++ b/tests/ui/len_zero.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(len_without_is_empty, len_zero)] #![allow(dead_code, unused)] diff --git a/tests/ui/len_zero.stderr b/tests/ui/len_zero.stderr index 6e3cf1b3ca1d..d23a972dddcb 100644 --- a/tests/ui/len_zero.stderr +++ b/tests/ui/len_zero.stderr @@ -94,5 +94,3 @@ error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_e 191 | | } | |_^ -error: aborting due to 12 previous errors - diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs index 2d3ab7da9964..564a67d2c8ef 100644 --- a/tests/ui/let_if_seq.rs +++ b/tests/ui/let_if_seq.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused_variables, unused_assignments, similar_names, blacklisted_name)] #![warn(useless_let_if_seq)] diff --git a/tests/ui/let_if_seq.stderr b/tests/ui/let_if_seq.stderr index b912373f95c6..39686a9dd07f 100644 --- a/tests/ui/let_if_seq.stderr +++ b/tests/ui/let_if_seq.stderr @@ -46,5 +46,3 @@ error: `if _ { .. } else { .. }` is an expression | = note: you might not need `mut` at all -error: aborting due to 4 previous errors - diff --git a/tests/ui/let_return.rs b/tests/ui/let_return.rs index 6aab70dbd8a4..1083603b2d63 100644 --- a/tests/ui/let_return.rs +++ b/tests/ui/let_return.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused)] #![warn(let_and_return)] diff --git a/tests/ui/let_return.stderr b/tests/ui/let_return.stderr index 459b2eafa26f..b38c9ab2e913 100644 --- a/tests/ui/let_return.stderr +++ b/tests/ui/let_return.stderr @@ -23,5 +23,3 @@ note: this expression can be directly returned 15 | let x = 5; | ^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/let_unit.rs b/tests/ui/let_unit.rs index d07cf8ede2f4..032dc85f2cd5 100644 --- a/tests/ui/let_unit.rs +++ b/tests/ui/let_unit.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(let_unit_value)] #![allow(unused_variables)] diff --git a/tests/ui/let_unit.stderr b/tests/ui/let_unit.stderr index da579ec80f31..196afc0570cd 100644 --- a/tests/ui/let_unit.stderr +++ b/tests/ui/let_unit.stderr @@ -12,5 +12,3 @@ error: this let-binding has unit value. Consider omitting `let _a =` 18 | let _a = (); | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/lifetimes.rs b/tests/ui/lifetimes.rs index 5f3c3604d809..dce9c23da686 100644 --- a/tests/ui/lifetimes.rs +++ b/tests/ui/lifetimes.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(needless_lifetimes, unused_lifetimes)] #![allow(dead_code, needless_pass_by_value)] diff --git a/tests/ui/lifetimes.stderr b/tests/ui/lifetimes.stderr index 23b353d13d2e..744e1ce21ec3 100644 --- a/tests/ui/lifetimes.stderr +++ b/tests/ui/lifetimes.stderr @@ -86,5 +86,3 @@ error: explicit lifetimes given in parameter types where they could be elided 120 | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { unimplemented!() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors - diff --git a/tests/ui/lint_pass.rs b/tests/ui/lint_pass.rs index 5ecbeb7f11a6..1990e137e678 100644 --- a/tests/ui/lint_pass.rs +++ b/tests/ui/lint_pass.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] + #![feature(rustc_private)] -#![plugin(clippy)] + #![warn(lint_without_lint_pass)] diff --git a/tests/ui/lint_pass.stderr b/tests/ui/lint_pass.stderr index 2f9a6813b96d..66f2d62ed24a 100644 --- a/tests/ui/lint_pass.stderr +++ b/tests/ui/lint_pass.stderr @@ -6,5 +6,3 @@ error: the lint `MISSING_LINT` is not added to any `LintPass` | = note: `-D lint-without-lint-pass` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/literals.rs b/tests/ui/literals.rs index e8105a74b5cf..c11adc0b0904 100644 --- a/tests/ui/literals.rs +++ b/tests/ui/literals.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(mixed_case_hex_literals)] #![warn(unseparated_literal_suffix)] #![warn(zero_prefixed_literal)] diff --git a/tests/ui/literals.stderr b/tests/ui/literals.stderr index 17210b6b275a..82c651e62902 100644 --- a/tests/ui/literals.stderr +++ b/tests/ui/literals.stderr @@ -87,5 +87,3 @@ help: if you mean to use an octal constant, use `0o` 30 | let fail8 = 0o123; | ^^^^^ -error: aborting due to 11 previous errors - diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index 81e298390f57..f11d21d2dfaf 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(map_clone)] #![allow(clone_on_copy, unused)] diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr index c29f37918517..272b868a278a 100644 --- a/tests/ui/map_clone.stderr +++ b/tests/ui/map_clone.stderr @@ -98,5 +98,3 @@ error: you seem to be using .map() to clone the contents of an Option, consider = help: try x.as_ref().cloned() -error: aborting due to 11 previous errors - diff --git a/tests/ui/matches.rs b/tests/ui/matches.rs index be1ca72aece6..f97038ca1f04 100644 --- a/tests/ui/matches.rs +++ b/tests/ui/matches.rs @@ -1,7 +1,7 @@ -#![feature(plugin)] + #![feature(exclusive_range_pattern)] -#![plugin(clippy)] + #![warn(clippy)] #![allow(unused, if_let_redundant_pattern_matching)] #![warn(single_match_else)] diff --git a/tests/ui/matches.stderr b/tests/ui/matches.stderr index 2f55428cca7c..1c2452c46ce6 100644 --- a/tests/ui/matches.stderr +++ b/tests/ui/matches.stderr @@ -392,5 +392,3 @@ note: consider refactoring into `Ok(3) | Ok(_)` | ^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate -error: aborting due to 33 previous errors - diff --git a/tests/ui/mem_forget.rs b/tests/ui/mem_forget.rs index 7854a3739680..991a402e2076 100644 --- a/tests/ui/mem_forget.rs +++ b/tests/ui/mem_forget.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + use std::sync::Arc; diff --git a/tests/ui/mem_forget.stderr b/tests/ui/mem_forget.stderr index 6e7a44694e14..c79afa829fe5 100644 --- a/tests/ui/mem_forget.stderr +++ b/tests/ui/mem_forget.stderr @@ -18,5 +18,3 @@ error: usage of mem::forget on Drop type 24 | forgetSomething(eight); | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 48132cc662cc..08ff47714205 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] + #![feature(const_fn)] -#![plugin(clippy)] + #![warn(clippy, clippy_pedantic)] #![allow(blacklisted_name, unused, print_stdout, non_ascii_literal, new_without_default, new_without_default_derive, missing_docs_in_private_items)] diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 7f3d505a3cd2..c5fab711fe1f 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -836,5 +836,3 @@ error: you should use the `ends_with` method 578 | Some(' ') != "".chars().next_back(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')` -error: aborting due to 123 previous errors - diff --git a/tests/ui/min_max.rs b/tests/ui/min_max.rs index 9a077eae4d92..1199206e42c3 100644 --- a/tests/ui/min_max.rs +++ b/tests/ui/min_max.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] use std::cmp::{min, max}; diff --git a/tests/ui/min_max.stderr b/tests/ui/min_max.stderr index de4c4e16fa03..e9225f93b5e5 100644 --- a/tests/ui/min_max.stderr +++ b/tests/ui/min_max.stderr @@ -42,5 +42,3 @@ error: this min/max combination leads to constant result 30 | max(min(s, "Apple"), "Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/missing-doc.rs b/tests/ui/missing-doc.rs index 596cec886f4e..cbd6439d47e8 100644 --- a/tests/ui/missing-doc.rs +++ b/tests/ui/missing-doc.rs @@ -11,8 +11,8 @@ * except according to those terms. */ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the diff --git a/tests/ui/missing-doc.stderr b/tests/ui/missing-doc.stderr index e25edb64181e..55eab4f5d692 100644 --- a/tests/ui/missing-doc.stderr +++ b/tests/ui/missing-doc.stderr @@ -270,5 +270,3 @@ error: missing documentation for a function 202 | fn main() {} | ^^^^^^^^^^^^ -error: aborting due to 40 previous errors - diff --git a/tests/ui/module_inception.rs b/tests/ui/module_inception.rs index e934c64023b4..77bd446c569c 100644 --- a/tests/ui/module_inception.rs +++ b/tests/ui/module_inception.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(module_inception)] mod foo { diff --git a/tests/ui/module_inception.stderr b/tests/ui/module_inception.stderr index c9d3319db1b6..cb6ea951a171 100644 --- a/tests/ui/module_inception.stderr +++ b/tests/ui/module_inception.stderr @@ -16,5 +16,3 @@ error: module has the same name as its containing module 14 | | } | |_____^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/modulo_one.rs b/tests/ui/modulo_one.rs index cda3f190f1e6..847ea1d9ab64 100644 --- a/tests/ui/modulo_one.rs +++ b/tests/ui/modulo_one.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(modulo_one)] #![allow(no_effect, unnecessary_operation)] diff --git a/tests/ui/modulo_one.stderr b/tests/ui/modulo_one.stderr index ccfca7154e04..48cfe6c38cc2 100644 --- a/tests/ui/modulo_one.stderr +++ b/tests/ui/modulo_one.stderr @@ -6,5 +6,3 @@ error: any number modulo 1 will be 0 | = note: `-D modulo-one` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/mut_from_ref.rs b/tests/ui/mut_from_ref.rs index 55498bad7597..9e757155260c 100644 --- a/tests/ui/mut_from_ref.rs +++ b/tests/ui/mut_from_ref.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused)] #![warn(mut_from_ref)] diff --git a/tests/ui/mut_from_ref.stderr b/tests/ui/mut_from_ref.stderr index a7cbc0b7a096..eacda70ce074 100644 --- a/tests/ui/mut_from_ref.stderr +++ b/tests/ui/mut_from_ref.stderr @@ -59,5 +59,3 @@ note: immutable borrow here 32 | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^ ^^^^^^^ -error: aborting due to 5 previous errors - diff --git a/tests/ui/mut_mut.rs b/tests/ui/mut_mut.rs index 766276bc4173..54176cd6d553 100644 --- a/tests/ui/mut_mut.rs +++ b/tests/ui/mut_mut.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused, no_effect, unnecessary_operation)] #![warn(mut_mut)] diff --git a/tests/ui/mut_mut.stderr b/tests/ui/mut_mut.stderr index 7a7bb840ba98..31f9178aa272 100644 --- a/tests/ui/mut_mut.stderr +++ b/tests/ui/mut_mut.stderr @@ -81,5 +81,3 @@ error: generally you want to avoid `&mut &mut _` if possible 35 | let y : &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ -error: aborting due to 13 previous errors - diff --git a/tests/ui/mut_range_bound.stderr b/tests/ui/mut_range_bound.stderr index d7be7ae1e6fc..f516ec9d95e3 100644 --- a/tests/ui/mut_range_bound.stderr +++ b/tests/ui/mut_range_bound.stderr @@ -1,3 +1,5 @@ +warning: running cargo clippy on a crate that also imports the clippy plugin + error: attempt to mutate range bound within loop; note that the range of the loop is unchanged --> $DIR/mut_range_bound.rs:18:21 | @@ -30,5 +32,3 @@ error: attempt to mutate range bound within loop; note that the range of the loo 40 | let n = &mut m; // warning | ^ -error: aborting due to 5 previous errors - diff --git a/tests/ui/mut_reference.rs b/tests/ui/mut_reference.rs index d746fc5e529c..ac40bf2a1867 100644 --- a/tests/ui/mut_reference.rs +++ b/tests/ui/mut_reference.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused_variables)] diff --git a/tests/ui/mut_reference.stderr b/tests/ui/mut_reference.stderr index 73df19bf1583..6708bca8b2ee 100644 --- a/tests/ui/mut_reference.stderr +++ b/tests/ui/mut_reference.stderr @@ -18,5 +18,3 @@ error: The function/method `takes_an_immutable_reference` doesn't need a mutable 28 | my_struct.takes_an_immutable_reference(&mut 42); | ^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/mutex_atomic.rs b/tests/ui/mutex_atomic.rs index b84ece497eb6..96502738456c 100644 --- a/tests/ui/mutex_atomic.rs +++ b/tests/ui/mutex_atomic.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![warn(mutex_integer)] diff --git a/tests/ui/mutex_atomic.stderr b/tests/ui/mutex_atomic.stderr index 354f9891c178..d46c713164ae 100644 --- a/tests/ui/mutex_atomic.stderr +++ b/tests/ui/mutex_atomic.stderr @@ -44,5 +44,3 @@ error: Consider using an AtomicIsize instead of a Mutex here. If you just want t 16 | Mutex::new(0i32); | ^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/needless_bool.rs b/tests/ui/needless_bool.rs index bd44332a1708..1213539c8276 100644 --- a/tests/ui/needless_bool.rs +++ b/tests/ui/needless_bool.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(needless_bool)] #[allow(if_same_then_else)] diff --git a/tests/ui/needless_bool.stderr b/tests/ui/needless_bool.stderr index 63e0632445f6..a25b34bfaafa 100644 --- a/tests/ui/needless_bool.stderr +++ b/tests/ui/needless_bool.stderr @@ -66,5 +66,3 @@ error: this if-then-else expression returns a bool literal 50 | if x && y { return false } else { return true }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `return !(x && y)` -error: aborting due to 11 previous errors - diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index 23d935e7df8c..78c1a125c94f 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + fn x(y: &i32) -> i32 { *y diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index fde38508b323..16962bb48f1c 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -38,5 +38,3 @@ error: this pattern creates a reference to a reference 50 | let _ = v.iter().filter(|&ref a| a.is_empty()); | ^^^^^ help: change this to: `a` -error: aborting due to 6 previous errors - diff --git a/tests/ui/needless_borrowed_ref.rs b/tests/ui/needless_borrowed_ref.rs index 4e9986561bc1..75ffa211180d 100644 --- a/tests/ui/needless_borrowed_ref.rs +++ b/tests/ui/needless_borrowed_ref.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(needless_borrowed_reference)] #[allow(unused_variables)] diff --git a/tests/ui/needless_borrowed_ref.stderr b/tests/ui/needless_borrowed_ref.stderr index 2a8cf4348d39..c85bf9f5a7c7 100644 --- a/tests/ui/needless_borrowed_ref.stderr +++ b/tests/ui/needless_borrowed_ref.stderr @@ -24,5 +24,3 @@ error: this pattern takes a reference on something that is being de-referenced 42 | (&Animal::Cat(v), &ref k) | (&ref k, &Animal::Cat(v)) => (), // lifetime mismatch error if there is no '&ref' | ^^^^^^ help: try removing the `&ref` part and just keep: `k` -error: aborting due to 4 previous errors - diff --git a/tests/ui/needless_continue.rs b/tests/ui/needless_continue.rs index 6710867077d2..3574b0fb3fdf 100644 --- a/tests/ui/needless_continue.rs +++ b/tests/ui/needless_continue.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + macro_rules! zero { ($x:expr) => ($x == 0); diff --git a/tests/ui/needless_continue.stderr b/tests/ui/needless_continue.stderr index 3e0368892a43..f63f120fcc7e 100644 --- a/tests/ui/needless_continue.stderr +++ b/tests/ui/needless_continue.stderr @@ -55,5 +55,3 @@ error: There is no need for an explicit `else` block for this `if` expression println!("Jabber"); ... -error: aborting due to 2 previous errors - diff --git a/tests/ui/needless_pass_by_value.rs b/tests/ui/needless_pass_by_value.rs index ea97e875ff73..6218bfb09206 100644 --- a/tests/ui/needless_pass_by_value.rs +++ b/tests/ui/needless_pass_by_value.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(needless_pass_by_value)] #![allow(dead_code, single_match, if_let_redundant_pattern_matching, many_single_char_names)] diff --git a/tests/ui/needless_pass_by_value.stderr b/tests/ui/needless_pass_by_value.stderr index 02293c9cb3cf..c081574127af 100644 --- a/tests/ui/needless_pass_by_value.stderr +++ b/tests/ui/needless_pass_by_value.stderr @@ -56,5 +56,3 @@ help: consider taking a reference instead 56 | let Wrapper(_) = *y; // still not moved | -error: aborting due to 7 previous errors - diff --git a/tests/ui/needless_pass_by_value_proc_macro.rs b/tests/ui/needless_pass_by_value_proc_macro.rs index 0d5bc4172d86..652e11fee9d6 100644 --- a/tests/ui/needless_pass_by_value_proc_macro.rs +++ b/tests/ui/needless_pass_by_value_proc_macro.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![crate_type = "proc-macro"] #![warn(needless_pass_by_value)] diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs index 403e5b8342e8..4739ded7b7ea 100644 --- a/tests/ui/needless_return.rs +++ b/tests/ui/needless_return.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(needless_return)] diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr index 42dc6e6594c5..68c2654c8635 100644 --- a/tests/ui/needless_return.stderr +++ b/tests/ui/needless_return.stderr @@ -48,5 +48,3 @@ error: unneeded return statement 39 | let _ = || return true; | ^^^^^^^^^^^ help: remove `return` as shown: `true` -error: aborting due to 8 previous errors - diff --git a/tests/ui/needless_update.rs b/tests/ui/needless_update.rs index 99876121ae77..35d5730dda1e 100644 --- a/tests/ui/needless_update.rs +++ b/tests/ui/needless_update.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(needless_update)] #![allow(no_effect)] diff --git a/tests/ui/needless_update.stderr b/tests/ui/needless_update.stderr index 3e509870d00f..978fd8e625ba 100644 --- a/tests/ui/needless_update.stderr +++ b/tests/ui/needless_update.stderr @@ -6,5 +6,3 @@ error: struct update has no effect, all the fields in the struct have already be | = note: `-D needless-update` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/neg_multiply.rs b/tests/ui/neg_multiply.rs index 75dc7c381fdb..367d2d5edfbd 100644 --- a/tests/ui/neg_multiply.rs +++ b/tests/ui/neg_multiply.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(neg_multiply)] #![allow(no_effect, unnecessary_operation)] diff --git a/tests/ui/neg_multiply.stderr b/tests/ui/neg_multiply.stderr index 1d52ba16eae8..6ed31d384a02 100644 --- a/tests/ui/neg_multiply.stderr +++ b/tests/ui/neg_multiply.stderr @@ -12,5 +12,3 @@ error: Negation by multiplying with -1 32 | -1 * x; | ^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index ff0126704b54..4866db1a5412 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(single_match, unused_assignments, unused_variables)] fn test1() { diff --git a/tests/ui/never_loop.stderr b/tests/ui/never_loop.stderr index dace2b7e261a..1ecdb5030f93 100644 --- a/tests/ui/never_loop.stderr +++ b/tests/ui/never_loop.stderr @@ -68,5 +68,3 @@ error: this loop never actually loops 103 | | } | |_____^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/new_without_default.rs b/tests/ui/new_without_default.rs index a10db135c5e4..9fd0fea137c8 100644 --- a/tests/ui/new_without_default.rs +++ b/tests/ui/new_without_default.rs @@ -1,5 +1,5 @@ #![feature(plugin, const_fn)] -#![plugin(clippy)] + #![allow(dead_code)] #![warn(new_without_default, new_without_default_derive)] diff --git a/tests/ui/new_without_default.stderr b/tests/ui/new_without_default.stderr index 91e437a6eb54..0ced183b1e07 100644 --- a/tests/ui/new_without_default.stderr +++ b/tests/ui/new_without_default.stderr @@ -38,5 +38,3 @@ help: try this 69 | ... -error: aborting due to 3 previous errors - diff --git a/tests/ui/no_effect.rs b/tests/ui/no_effect.rs index 5c3a1a041c20..ba7826d653ed 100644 --- a/tests/ui/no_effect.rs +++ b/tests/ui/no_effect.rs @@ -1,5 +1,5 @@ #![feature(plugin, box_syntax, inclusive_range_syntax)] -#![plugin(clippy)] + #![warn(no_effect, unnecessary_operation)] #![allow(dead_code)] diff --git a/tests/ui/no_effect.stderr b/tests/ui/no_effect.stderr index b6db8e7498e4..43e7fbb36098 100644 --- a/tests/ui/no_effect.stderr +++ b/tests/ui/no_effect.stderr @@ -266,5 +266,3 @@ error: statement can be reduced 83 | {get_number()}; | ^^^^^^^^^^^^^^^ help: replace it with: `get_number();` -error: aborting due to 44 previous errors - diff --git a/tests/ui/non_expressive_names.rs b/tests/ui/non_expressive_names.rs index f32dad2080fd..9eb3e5a82a7c 100644 --- a/tests/ui/non_expressive_names.rs +++ b/tests/ui/non_expressive_names.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy,similar_names)] #![allow(unused)] diff --git a/tests/ui/non_expressive_names.stderr b/tests/ui/non_expressive_names.stderr index 780d7d8aec90..014d45992712 100644 --- a/tests/ui/non_expressive_names.stderr +++ b/tests/ui/non_expressive_names.stderr @@ -129,5 +129,3 @@ error: 5th binding whose name is just one char 129 | e => panic!(), | ^ -error: aborting due to 11 previous errors - diff --git a/tests/ui/ok_if_let.rs b/tests/ui/ok_if_let.rs index dda38fec2873..fdc01bcc7bc0 100644 --- a/tests/ui/ok_if_let.rs +++ b/tests/ui/ok_if_let.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(if_let_some_result)] diff --git a/tests/ui/ok_if_let.stderr b/tests/ui/ok_if_let.stderr index e1371d924eb6..b696672d2fd0 100644 --- a/tests/ui/ok_if_let.stderr +++ b/tests/ui/ok_if_let.stderr @@ -11,5 +11,3 @@ error: Matching on `Some` with `ok()` is redundant = note: `-D if-let-some-result` implied by `-D warnings` = help: Consider matching on `Ok(y)` and removing the call to `ok` instead -error: aborting due to previous error - diff --git a/tests/ui/op_ref.rs b/tests/ui/op_ref.rs index 315e6535ef62..9eb697571b69 100644 --- a/tests/ui/op_ref.rs +++ b/tests/ui/op_ref.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused_variables, blacklisted_name)] @@ -21,4 +21,4 @@ fn main() { if b < &a { println!("OK"); } -} \ No newline at end of file +} diff --git a/tests/ui/op_ref.stderr b/tests/ui/op_ref.stderr index 715c7378e0cf..dbe53933fd5e 100644 --- a/tests/ui/op_ref.stderr +++ b/tests/ui/op_ref.stderr @@ -10,5 +10,3 @@ help: use the values directly 13 | let foo = 5 - 6; | ^ -error: aborting due to previous error - diff --git a/tests/ui/open_options.rs b/tests/ui/open_options.rs index c409aa564f8f..514808d41f1e 100644 --- a/tests/ui/open_options.rs +++ b/tests/ui/open_options.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + use std::fs::OpenOptions; #[allow(unused_must_use)] diff --git a/tests/ui/open_options.stderr b/tests/ui/open_options.stderr index f0d419041523..2f4070c2868f 100644 --- a/tests/ui/open_options.stderr +++ b/tests/ui/open_options.stderr @@ -42,5 +42,3 @@ error: the method "truncate" is called more than once 15 | OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors - diff --git a/tests/ui/overflow_check_conditional.rs b/tests/ui/overflow_check_conditional.rs index a669f741f290..889c339c8fda 100644 --- a/tests/ui/overflow_check_conditional.rs +++ b/tests/ui/overflow_check_conditional.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(many_single_char_names)] #![warn(overflow_check_conditional)] diff --git a/tests/ui/overflow_check_conditional.stderr b/tests/ui/overflow_check_conditional.stderr index 8a80dbedaeb4..9f23e96c0655 100644 --- a/tests/ui/overflow_check_conditional.stderr +++ b/tests/ui/overflow_check_conditional.stderr @@ -48,5 +48,3 @@ error: You are trying to use classic C underflow conditions that will fail in Ru 32 | if a < a - b { | ^^^^^^^^^ -error: aborting due to 8 previous errors - diff --git a/tests/ui/panic.rs b/tests/ui/panic.rs index 03d3c3dc2d94..f621a5f636df 100644 --- a/tests/ui/panic.rs +++ b/tests/ui/panic.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(panic_params)] diff --git a/tests/ui/panic.stderr b/tests/ui/panic.stderr index 25113ed80b6e..f2480dfea6ed 100644 --- a/tests/ui/panic.stderr +++ b/tests/ui/panic.stderr @@ -18,5 +18,3 @@ error: you probably are missing some parameter in your format string 12 | assert!(true, "here be missing values: {}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/partialeq_ne_impl.rs b/tests/ui/partialeq_ne_impl.rs index 41772700109e..36dd4df8a6ec 100644 --- a/tests/ui/partialeq_ne_impl.rs +++ b/tests/ui/partialeq_ne_impl.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] diff --git a/tests/ui/partialeq_ne_impl.stderr b/tests/ui/partialeq_ne_impl.stderr index 5e536cc51d28..c332ce53c1a4 100644 --- a/tests/ui/partialeq_ne_impl.stderr +++ b/tests/ui/partialeq_ne_impl.stderr @@ -6,5 +6,3 @@ error: re-implementing `PartialEq::ne` is unnecessary | = note: `-D partialeq-ne-impl` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/patterns.rs b/tests/ui/patterns.rs index 793b2b111d6d..65e319e2f881 100644 --- a/tests/ui/patterns.rs +++ b/tests/ui/patterns.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused)] #![warn(clippy)] diff --git a/tests/ui/patterns.stderr b/tests/ui/patterns.stderr index 59bce3a9a8f6..9a246c483b2b 100644 --- a/tests/ui/patterns.stderr +++ b/tests/ui/patterns.stderr @@ -6,5 +6,3 @@ error: the `y @ _` pattern can be written as just `y` | = note: `-D redundant-pattern` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/precedence.rs b/tests/ui/precedence.rs index c6865632cf72..720637c94b56 100644 --- a/tests/ui/precedence.rs +++ b/tests/ui/precedence.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(precedence)] #[allow(identity_op)] diff --git a/tests/ui/precedence.stderr b/tests/ui/precedence.stderr index 9f0e53ffca2b..26fbd75164d1 100644 --- a/tests/ui/precedence.stderr +++ b/tests/ui/precedence.stderr @@ -54,5 +54,3 @@ error: unary minus has lower precedence than method call 16 | -1f32.abs(); | ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())` -error: aborting due to 9 previous errors - diff --git a/tests/ui/print.rs b/tests/ui/print.rs index f1fb3cba8c1d..91304d961a7a 100644 --- a/tests/ui/print.rs +++ b/tests/ui/print.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(print_stdout, use_debug)] use std::fmt::{Debug, Display, Formatter, Result}; diff --git a/tests/ui/print.stderr b/tests/ui/print.stderr index 789e1218b780..fa547949bdb5 100644 --- a/tests/ui/print.stderr +++ b/tests/ui/print.stderr @@ -50,5 +50,3 @@ error: use of `Debug`-based formatting 31 | print!("Hello {:#?}", "#orld"); | ^^^^^^^ -error: aborting due to 8 previous errors - diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs index d852e375ded0..5cc50dea8104 100644 --- a/tests/ui/print_with_newline.rs +++ b/tests/ui/print_with_newline.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(print_with_newline)] fn main() { diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr index 1bacc40bfb4f..2ade3ae4ef59 100644 --- a/tests/ui/print_with_newline.stderr +++ b/tests/ui/print_with_newline.stderr @@ -24,5 +24,3 @@ error: using `print!()` with a format string that ends in a newline, consider us 9 | print!("{}/n", 1265); | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/ptr_arg.rs b/tests/ui/ptr_arg.rs index 127ae7037021..14b26e168474 100644 --- a/tests/ui/ptr_arg.rs +++ b/tests/ui/ptr_arg.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused, many_single_char_names)] #![warn(ptr_arg)] diff --git a/tests/ui/ptr_arg.stderr b/tests/ui/ptr_arg.stderr index e9ada9f8aaa8..13be68d4cd42 100644 --- a/tests/ui/ptr_arg.stderr +++ b/tests/ui/ptr_arg.stderr @@ -79,5 +79,3 @@ help: change `y.as_str()` to 62 | let c = y; | ^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/range.rs b/tests/ui/range.rs index bb1a04cfcf3f..71f2f2b219bd 100644 --- a/tests/ui/range.rs +++ b/tests/ui/range.rs @@ -1,7 +1,7 @@ #![feature(iterator_step_by)] #![feature(inclusive_range_syntax)] -#![feature(plugin)] -#![plugin(clippy)] + + struct NotARange; impl NotARange { diff --git a/tests/ui/range.stderr b/tests/ui/range.stderr index fc51f1a07f07..4098d32d08e3 100644 --- a/tests/ui/range.stderr +++ b/tests/ui/range.stderr @@ -38,5 +38,3 @@ error: Iterator::step_by(0) will panic at runtime 33 | let _ = v1.iter().step_by(2/3); | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/redundant_closure_call.rs b/tests/ui/redundant_closure_call.rs index 2c079273b7b5..ab3897bc3150 100644 --- a/tests/ui/redundant_closure_call.rs +++ b/tests/ui/redundant_closure_call.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(redundant_closure_call)] diff --git a/tests/ui/redundant_closure_call.stderr b/tests/ui/redundant_closure_call.stderr index e2865edc8705..d8ec72fda92a 100644 --- a/tests/ui/redundant_closure_call.stderr +++ b/tests/ui/redundant_closure_call.stderr @@ -30,5 +30,3 @@ error: Try not to call a closure in the expression where it is declared. 12 | k = (|a,b| a*b)(1,5); | ^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors - diff --git a/tests/ui/reference.rs b/tests/ui/reference.rs index 9451e19e3367..0bd000082e83 100644 --- a/tests/ui/reference.rs +++ b/tests/ui/reference.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + fn get_number() -> usize { 10 diff --git a/tests/ui/reference.stderr b/tests/ui/reference.stderr index 741c0cc10385..2e6b23f6dc0f 100644 --- a/tests/ui/reference.stderr +++ b/tests/ui/reference.stderr @@ -66,5 +66,3 @@ error: immediately dereferencing a reference 53 | let y = **&mut &mut x; | ^^^^^^^^^^^^ help: try this: `&mut x` -error: aborting due to 11 previous errors - diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index 56539c5468fc..3dd1f64202c7 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused)] #![warn(invalid_regex, trivial_regex, regex_macro)] diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr index 1c3a47b82be7..1c244c1df127 100644 --- a/tests/ui/regex.stderr +++ b/tests/ui/regex.stderr @@ -149,5 +149,3 @@ error: trivial regex | = help: consider using consider using `str::is_empty` -error: aborting due to 21 previous errors - diff --git a/tests/ui/serde.rs b/tests/ui/serde.rs index 61c691c01c1d..792ebc9b0ea1 100644 --- a/tests/ui/serde.rs +++ b/tests/ui/serde.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(serde_api_misuse)] #![allow(dead_code)] diff --git a/tests/ui/serde.stderr b/tests/ui/serde.stderr index 58667e0f820b..da0a96b2a3dc 100644 --- a/tests/ui/serde.stderr +++ b/tests/ui/serde.stderr @@ -10,5 +10,3 @@ error: you should not implement `visit_string` without also implementing `visit_ | = note: `-D serde-api-misuse` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs index e1f2ffacf496..fbe695a7657c 100644 --- a/tests/ui/shadow.rs +++ b/tests/ui/shadow.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy, clippy_pedantic)] #![allow(unused_parens, unused_variables, missing_docs_in_private_items)] diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr index 3fc2b7234f78..50f41627acbf 100644 --- a/tests/ui/shadow.stderr +++ b/tests/ui/shadow.stderr @@ -134,5 +134,3 @@ note: previous binding is here 21 | let x = y; | ^ -error: aborting due to 9 previous errors - diff --git a/tests/ui/short_circuit_statement.rs b/tests/ui/short_circuit_statement.rs index e783c6e5e690..0f5773623be3 100644 --- a/tests/ui/short_circuit_statement.rs +++ b/tests/ui/short_circuit_statement.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(short_circuit_statement)] diff --git a/tests/ui/short_circuit_statement.stderr b/tests/ui/short_circuit_statement.stderr index 7697cbd1c64c..d7a02d7b9c3c 100644 --- a/tests/ui/short_circuit_statement.stderr +++ b/tests/ui/short_circuit_statement.stderr @@ -18,5 +18,3 @@ error: boolean short circuit operator in statement may be clearer using an expli 9 | 1 == 2 || g(); | ^^^^^^^^^^^^^^ help: replace it with: `if !(1 == 2) { g(); }` -error: aborting due to 3 previous errors - diff --git a/tests/ui/should_assert_eq.rs b/tests/ui/should_assert_eq.rs index ac5fca8dd0b3..5814e9977530 100644 --- a/tests/ui/should_assert_eq.rs +++ b/tests/ui/should_assert_eq.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(needless_pass_by_value)] #![warn(should_assert_eq)] diff --git a/tests/ui/should_assert_eq.stderr b/tests/ui/should_assert_eq.stderr index 57abf8004988..5b393e1dbe87 100644 --- a/tests/ui/should_assert_eq.stderr +++ b/tests/ui/should_assert_eq.stderr @@ -55,5 +55,3 @@ error: use `assert_ne` for better reporting | = note: this error originates in a macro outside of the current crate -error: aborting due to 7 previous errors - diff --git a/tests/ui/strings.rs b/tests/ui/strings.rs index 1cb5619dd1da..66d24a3c0702 100644 --- a/tests/ui/strings.rs +++ b/tests/ui/strings.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(string_add)] #[allow(string_add_assign)] diff --git a/tests/ui/strings.stderr b/tests/ui/strings.stderr index d098ce9df5ea..a8fd59e12b27 100644 --- a/tests/ui/strings.stderr +++ b/tests/ui/strings.stderr @@ -72,5 +72,3 @@ error: manual implementation of an assign operation 65 | ; x = x + 1; | ^^^^^^^^^ help: replace it with: `x += 1` -error: aborting due to 11 previous errors - diff --git a/tests/ui/stutter.rs b/tests/ui/stutter.rs index 3fd410c08afd..24612fd3b3ef 100644 --- a/tests/ui/stutter.rs +++ b/tests/ui/stutter.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(stutter)] #![allow(dead_code)] diff --git a/tests/ui/stutter.stderr b/tests/ui/stutter.stderr index b68f561b483c..38cbcaa32f59 100644 --- a/tests/ui/stutter.stderr +++ b/tests/ui/stutter.stderr @@ -24,5 +24,3 @@ error: item name ends with its containing module's name 11 | pub enum CakeFoo {} | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors - diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index abcafac4b9db..d1d12641c46a 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(blacklisted_name, unused_assignments)] diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr index a01ec375e639..0bda9bc8d2b9 100644 --- a/tests/ui/swap.stderr +++ b/tests/ui/swap.stderr @@ -65,5 +65,3 @@ error: this looks like you are trying to swap `c.0` and `a` | = note: or maybe you should use `std::mem::replace`? -error: aborting due to 7 previous errors - diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs index 4a12d38285cf..8f25aad72bb5 100644 --- a/tests/ui/temporary_assignment.rs +++ b/tests/ui/temporary_assignment.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(temporary_assignment)] diff --git a/tests/ui/temporary_assignment.stderr b/tests/ui/temporary_assignment.stderr index 979720c914d1..73a4818ba160 100644 --- a/tests/ui/temporary_assignment.stderr +++ b/tests/ui/temporary_assignment.stderr @@ -12,5 +12,3 @@ error: assignment to temporary 30 | (0, 0).0 = 1; | ^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 7be52580c6f9..a0d6dd2dabd5 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -1,6 +1,6 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(unused)] diff --git a/tests/ui/toplevel_ref_arg.stderr b/tests/ui/toplevel_ref_arg.stderr index f360e85329f5..525b181bf91a 100644 --- a/tests/ui/toplevel_ref_arg.stderr +++ b/tests/ui/toplevel_ref_arg.stderr @@ -30,5 +30,3 @@ error: `ref` on an entire `let` pattern is discouraged, take a reference with `& 24 | let ref mut z = 1 + 2; | ----^^^^^^^^^--------- help: try: `let z = &mut (1 + 2);` -error: aborting due to 5 previous errors - diff --git a/tests/ui/trailing_zeros.rs b/tests/ui/trailing_zeros.rs index 9fc71506ffe4..6a7b6b05e701 100644 --- a/tests/ui/trailing_zeros.rs +++ b/tests/ui/trailing_zeros.rs @@ -1,5 +1,5 @@ #![feature(plugin, custom_attribute, stmt_expr_attributes)] -#![plugin(clippy)] + #![allow(unused_parens)] fn main() { diff --git a/tests/ui/trailing_zeros.stderr b/tests/ui/trailing_zeros.stderr index 91e4d59da986..0a4b5361d862 100644 --- a/tests/ui/trailing_zeros.stderr +++ b/tests/ui/trailing_zeros.stderr @@ -12,5 +12,3 @@ error: bit mask could be simplified with a call to `trailing_zeros` 8 | let _ = x & 0b1_1111 == 0; // suggest trailing_zeros | ^^^^^^^^^^^^^^^^^ help: try: `x.trailing_zeros() >= 5` -error: aborting due to 2 previous errors - diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index a83e5194736f..31cd8304eba7 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index a571fed24f05..0c5aff11b0ce 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -154,5 +154,3 @@ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) 117 | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 25 previous errors - diff --git a/tests/ui/transmute_32bit.rs b/tests/ui/transmute_32bit.rs index 4f9555297ff3..08866c63ec6f 100644 --- a/tests/ui/transmute_32bit.rs +++ b/tests/ui/transmute_32bit.rs @@ -1,6 +1,6 @@ //ignore-x86_64 -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(wrong_transmute)] fn main() { diff --git a/tests/ui/transmute_64bit.rs b/tests/ui/transmute_64bit.rs index 9be1e37b13e1..65240c80a480 100644 --- a/tests/ui/transmute_64bit.rs +++ b/tests/ui/transmute_64bit.rs @@ -1,7 +1,7 @@ //ignore-x86 //no-ignore-x86_64 -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(wrong_transmute)] fn main() { diff --git a/tests/ui/transmute_64bit.stderr b/tests/ui/transmute_64bit.stderr index 3a6a6e73f575..b679b9138771 100644 --- a/tests/ui/transmute_64bit.stderr +++ b/tests/ui/transmute_64bit.stderr @@ -12,5 +12,3 @@ error: transmute from a `f64` to a pointer 11 | let _: *mut usize = std::mem::transmute(6.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index 55dd0862700d..5bb0e7edfeda 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(zero_width_space)] fn zero() { diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr index 8a173daec9da..73599235ea81 100644 --- a/tests/ui/unicode.stderr +++ b/tests/ui/unicode.stderr @@ -28,5 +28,3 @@ error: literal non-ASCII character detected = help: Consider replacing the string with: ""/u{dc}ben!"" -error: aborting due to 3 previous errors - diff --git a/tests/ui/unit_cmp.rs b/tests/ui/unit_cmp.rs index ff57d2822cba..2b6d757845fe 100644 --- a/tests/ui/unit_cmp.rs +++ b/tests/ui/unit_cmp.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(unit_cmp)] #![allow(no_effect, unnecessary_operation)] diff --git a/tests/ui/unit_cmp.stderr b/tests/ui/unit_cmp.stderr index 51ad3fca9479..a85e4150a3eb 100644 --- a/tests/ui/unit_cmp.stderr +++ b/tests/ui/unit_cmp.stderr @@ -12,5 +12,3 @@ error: >-comparison of unit values detected. This will always be false 19 | if { true; } > { false; } { | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - diff --git a/tests/ui/unneeded_field_pattern.rs b/tests/ui/unneeded_field_pattern.rs index c2f5b11e24cd..8c9606022642 100644 --- a/tests/ui/unneeded_field_pattern.rs +++ b/tests/ui/unneeded_field_pattern.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(unneeded_field_pattern)] #[allow(dead_code, unused)] diff --git a/tests/ui/unneeded_field_pattern.stderr b/tests/ui/unneeded_field_pattern.stderr index 7e4c3a6cb9cb..ef1a8d75732e 100644 --- a/tests/ui/unneeded_field_pattern.stderr +++ b/tests/ui/unneeded_field_pattern.stderr @@ -15,5 +15,3 @@ error: All the struct fields are matched to a wildcard pattern, consider using ` | = help: Try with `Foo { .. }` instead -error: aborting due to 2 previous errors - diff --git a/tests/ui/unreadable_literal.rs b/tests/ui/unreadable_literal.rs index 45daf70b171a..327fea254a8c 100644 --- a/tests/ui/unreadable_literal.rs +++ b/tests/ui/unreadable_literal.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[warn(unreadable_literal)] #[allow(unused_variables)] fn main() { diff --git a/tests/ui/unreadable_literal.stderr b/tests/ui/unreadable_literal.stderr index 72cb160fafcb..81b69937a6da 100644 --- a/tests/ui/unreadable_literal.stderr +++ b/tests/ui/unreadable_literal.stderr @@ -31,5 +31,3 @@ error: long literal lacking separators | = help: consider: 1.234_56_f32 -error: aborting due to 4 previous errors - diff --git a/tests/ui/unsafe_removed_from_name.rs b/tests/ui/unsafe_removed_from_name.rs index 8e90964da8cc..29f34d31a8e9 100644 --- a/tests/ui/unsafe_removed_from_name.rs +++ b/tests/ui/unsafe_removed_from_name.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused_imports)] #![allow(dead_code)] #![warn(unsafe_removed_from_name)] diff --git a/tests/ui/unsafe_removed_from_name.stderr b/tests/ui/unsafe_removed_from_name.stderr index 93f2ddd533fe..7d455d31bcec 100644 --- a/tests/ui/unsafe_removed_from_name.stderr +++ b/tests/ui/unsafe_removed_from_name.stderr @@ -18,5 +18,3 @@ error: removed "unsafe" from the name of `Unsafe` in use as `LieAboutModSafety` 23 | use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/unused_io_amount.rs b/tests/ui/unused_io_amount.rs index 9beec63a6f01..ea72c1b1b704 100644 --- a/tests/ui/unused_io_amount.rs +++ b/tests/ui/unused_io_amount.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(dead_code)] #![warn(unused_io_amount)] diff --git a/tests/ui/unused_io_amount.stderr b/tests/ui/unused_io_amount.stderr index 0ce6887f5f20..8739ac245a79 100644 --- a/tests/ui/unused_io_amount.stderr +++ b/tests/ui/unused_io_amount.stderr @@ -39,5 +39,3 @@ error: handle read amount returned or use `Read::read_exact` instead 27 | s.read(&mut buf).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors - diff --git a/tests/ui/unused_labels.rs b/tests/ui/unused_labels.rs index 6d1e8c2a31c5..115121dc2757 100644 --- a/tests/ui/unused_labels.rs +++ b/tests/ui/unused_labels.rs @@ -1,5 +1,5 @@ -#![plugin(clippy)] -#![feature(plugin)] + + #![allow(dead_code, items_after_statements, never_loop)] #![warn(unused_label)] diff --git a/tests/ui/unused_labels.stderr b/tests/ui/unused_labels.stderr index 19c91e2a6a3c..338eb2f1551f 100644 --- a/tests/ui/unused_labels.stderr +++ b/tests/ui/unused_labels.stderr @@ -22,5 +22,3 @@ error: unused label `'same_label_in_two_fns` 34 | | } | |_____^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/unused_lt.rs b/tests/ui/unused_lt.rs index 722e19e6217c..91bca47eb12c 100644 --- a/tests/ui/unused_lt.rs +++ b/tests/ui/unused_lt.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![allow(unused, dead_code, needless_lifetimes, needless_pass_by_value)] #![warn(unused_lifetimes)] diff --git a/tests/ui/unused_lt.stderr b/tests/ui/unused_lt.stderr index b1fcebe6eed5..a4f01de18f7b 100644 --- a/tests/ui/unused_lt.stderr +++ b/tests/ui/unused_lt.stderr @@ -18,5 +18,3 @@ error: this lifetime isn't used in the function definition 50 | fn x<'a>(&self) {} | ^^ -error: aborting due to 3 previous errors - diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs index 14e31aae8ee5..b12900b7691a 100644 --- a/tests/ui/use_self.rs +++ b/tests/ui/use_self.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(use_self)] #![allow(dead_code)] #![allow(should_implement_trait)] diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr index bfd334335d88..9d316dd3e083 100644 --- a/tests/ui/use_self.stderr +++ b/tests/ui/use_self.stderr @@ -36,5 +36,3 @@ error: unnecessary structure name repetition 24 | Foo::new() | ^^^^^^^^ help: use the applicable keyword: `Self` -error: aborting due to 6 previous errors - diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index d8fc7c7cbca3..60a2c4e8b4c9 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(clippy)] #![allow(blacklisted_name)] diff --git a/tests/ui/used_underscore_binding.stderr b/tests/ui/used_underscore_binding.stderr index 712f81c1b6ff..388a3491477d 100644 --- a/tests/ui/used_underscore_binding.stderr +++ b/tests/ui/used_underscore_binding.stderr @@ -30,5 +30,3 @@ error: used binding `_underscore_field` which is prefixed with an underscore. A 36 | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors - diff --git a/tests/ui/useless_attribute.rs b/tests/ui/useless_attribute.rs index cd2636a5b6f9..4c2fb221af8e 100644 --- a/tests/ui/useless_attribute.rs +++ b/tests/ui/useless_attribute.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(useless_attribute)] #[allow(dead_code, unused_extern_crates)] diff --git a/tests/ui/useless_attribute.stderr b/tests/ui/useless_attribute.stderr index 707a11d55cc6..0bb87f8c5389 100644 --- a/tests/ui/useless_attribute.stderr +++ b/tests/ui/useless_attribute.stderr @@ -6,5 +6,3 @@ error: useless lint attribute | = note: `-D useless-attribute` implied by `-D warnings` -error: aborting due to previous error - diff --git a/tests/ui/vec.rs b/tests/ui/vec.rs index 1845b509af0d..23e438724540 100644 --- a/tests/ui/vec.rs +++ b/tests/ui/vec.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(useless_vec)] diff --git a/tests/ui/vec.stderr b/tests/ui/vec.stderr index 6a47eb5b064e..a1555bc79073 100644 --- a/tests/ui/vec.stderr +++ b/tests/ui/vec.stderr @@ -36,5 +36,3 @@ error: useless use of `vec!` 49 | for a in vec![1, 2, 3] { | ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]` -error: aborting due to 6 previous errors - diff --git a/tests/ui/while_loop.rs b/tests/ui/while_loop.rs index 9bae1bc48e6a..b7ef39da8175 100644 --- a/tests/ui/while_loop.rs +++ b/tests/ui/while_loop.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(while_let_loop, empty_loop, while_let_on_iterator)] #![allow(dead_code, never_loop, unused, cyclomatic_complexity)] diff --git a/tests/ui/while_loop.stderr b/tests/ui/while_loop.stderr index 689c92d6fb69..edc88405c40e 100644 --- a/tests/ui/while_loop.stderr +++ b/tests/ui/while_loop.stderr @@ -110,5 +110,3 @@ error: this loop could be written as a `for` loop 184 | | } | |_________^ help: try: `for v in y { .. }` -error: aborting due to 11 previous errors - diff --git a/tests/ui/wrong_self_convention.rs b/tests/ui/wrong_self_convention.rs index 91b60c8faaa2..bef87e2bb010 100644 --- a/tests/ui/wrong_self_convention.rs +++ b/tests/ui/wrong_self_convention.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #![warn(wrong_self_convention)] #![warn(wrong_pub_self_convention)] diff --git a/tests/ui/wrong_self_convention.stderr b/tests/ui/wrong_self_convention.stderr index 216fd0bb82b8..e57ffc3266b9 100644 --- a/tests/ui/wrong_self_convention.stderr +++ b/tests/ui/wrong_self_convention.stderr @@ -72,5 +72,3 @@ error: methods called `from_*` usually take no self; consider choosing a less am 54 | pub fn from_i64(self) {} | ^^^^ -error: aborting due to 12 previous errors - diff --git a/tests/ui/zero_div_zero.rs b/tests/ui/zero_div_zero.rs index af61e1c84299..65e1e2399803 100644 --- a/tests/ui/zero_div_zero.rs +++ b/tests/ui/zero_div_zero.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[allow(unused_variables)] #[warn(zero_divided_by_zero)] diff --git a/tests/ui/zero_div_zero.stderr b/tests/ui/zero_div_zero.stderr index b81e59c07f15..697432af4087 100644 --- a/tests/ui/zero_div_zero.stderr +++ b/tests/ui/zero_div_zero.stderr @@ -57,5 +57,3 @@ error: constant division of 0.0 with 0.0 will always result in NaN | = help: Consider using `std::f64::NAN` if you would like a constant representing NaN -error: aborting due to 8 previous errors - diff --git a/tests/ui/zero_ptr.rs b/tests/ui/zero_ptr.rs index a72223ef54c1..4a6010f4bd0b 100644 --- a/tests/ui/zero_ptr.rs +++ b/tests/ui/zero_ptr.rs @@ -1,5 +1,5 @@ -#![feature(plugin)] -#![plugin(clippy)] + + #[allow(unused_variables)] fn main() { diff --git a/tests/ui/zero_ptr.stderr b/tests/ui/zero_ptr.stderr index 5155dc401bd1..fb87a47536e0 100644 --- a/tests/ui/zero_ptr.stderr +++ b/tests/ui/zero_ptr.stderr @@ -12,5 +12,3 @@ error: `0 as *mut _` detected. Consider using `ptr::null_mut()` 7 | let y = 0 as *mut f64; | ^^^^^^^^^^^^^ -error: aborting due to 2 previous errors - From 47df71722923474014f26510d59968f063d8ecdd Mon Sep 17 00:00:00 2001 From: PizzaIter Date: Mon, 2 Oct 2017 17:23:24 +0200 Subject: [PATCH 56/60] Add lints `transmute_int_to_*` --- clippy_lints/src/lib.rs | 3 + clippy_lints/src/transmute.rs | 110 +++++++++++++++++++++++++++++++++- tests/ui/transmute.rs | 17 ++++++ tests/ui/transmute.stderr | 36 +++++++++++ 4 files changed, 165 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 38d7847f42b8..933ec1a8e70c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -544,6 +544,9 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { transmute::TRANSMUTE_PTR_TO_REF, transmute::USELESS_TRANSMUTE, transmute::WRONG_TRANSMUTE, + transmute::TRANSMUTE_INT_TO_CHAR, + transmute::TRANSMUTE_INT_TO_BOOL, + transmute::TRANSMUTE_INT_TO_FLOAT, types::ABSURD_EXTREME_COMPARISONS, types::BORROWED_BOX, types::BOX_VEC, diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 76110ecb152b..a97c24166b48 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -1,6 +1,8 @@ use rustc::lint::*; use rustc::ty::{self, Ty}; use rustc::hir::*; +use std::borrow::Cow; +use syntax::ast; use utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then}; use utils::{sugg, opt_def_id}; @@ -76,11 +78,73 @@ declare_lint! { "transmutes from a pointer to a reference type" } +/// **What it does:** Checks for transmutes from an integer to a `char`. +/// +/// **Why is this bad?** Not every integer is a unicode scalar value. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// let _: char = std::mem::transmute(x); // where x: u32 +/// // should be: +/// let _: Option = std::char::from_u32(x); +/// ``` +declare_lint! { + pub TRANSMUTE_INT_TO_CHAR, + Warn, + "transmutes from an integer to a `char`" +} + +/// **What it does:** Checks for transmutes from an integer to a `bool`. +/// +/// **Why is this bad?** This might result in an invalid in-memory representation of a `bool`. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// let _: bool = std::mem::transmute(x); // where x: u8 +/// // should be: +/// let _: bool = x != 0; +/// ``` +declare_lint! { + pub TRANSMUTE_INT_TO_BOOL, + Warn, + "transmutes from an integer to a `bool`" +} + +/// **What it does:** Checks for transmutes from an integer to a float. +/// +/// **Why is this bad?** This might result in an invalid in-memory representation of a float. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// let _: f32 = std::mem::transmute(x); // where x: u32 +/// // should be: +/// let _: f32 = f32::from_bits(x); +/// ``` +declare_lint! { + pub TRANSMUTE_INT_TO_FLOAT, + Warn, + "transmutes from an integer to a float" +} + pub struct Transmute; impl LintPass for Transmute { fn get_lints(&self) -> LintArray { - lint_array!(CROSSPOINTER_TRANSMUTE, TRANSMUTE_PTR_TO_REF, USELESS_TRANSMUTE, WRONG_TRANSMUTE) + lint_array!( + CROSSPOINTER_TRANSMUTE, + TRANSMUTE_PTR_TO_REF, + USELESS_TRANSMUTE, + WRONG_TRANSMUTE, + TRANSMUTE_INT_TO_CHAR, + TRANSMUTE_INT_TO_BOOL, + TRANSMUTE_INT_TO_FLOAT + ) } } @@ -177,6 +241,50 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute { db.span_suggestion(e.span, "try", sugg::make_unop(deref, arg).to_string()); }, ), + (&ty::TyInt(ast::IntTy::I32), &ty::TyChar) | + (&ty::TyUint(ast::UintTy::U32), &ty::TyChar) => span_lint_and_then( + cx, + TRANSMUTE_INT_TO_CHAR, + e.span, + &format!("transmute from a `{}` to a `char`", from_ty), + |db| { + let arg = sugg::Sugg::hir(cx, &args[0], ".."); + let arg = if let ty::TyInt(_) = from_ty.sty { + arg.as_ty(ty::TyUint(ast::UintTy::U32)) + } else { + arg + }; + db.span_suggestion(e.span, "consider using", format!("std::char::from_u32({})", arg.to_string())); + } + ), + (&ty::TyInt(ast::IntTy::I8), &ty::TyBool) | + (&ty::TyUint(ast::UintTy::U8), &ty::TyBool) => span_lint_and_then( + cx, + TRANSMUTE_INT_TO_BOOL, + e.span, + &format!("transmute from a `{}` to a `bool`", from_ty), + |db| { + let arg = sugg::Sugg::hir(cx, &args[0], ".."); + let zero = sugg::Sugg::NonParen(Cow::from("0")); + db.span_suggestion(e.span, "consider using", sugg::make_binop(ast::BinOpKind::Ne, &arg, &zero).to_string()); + } + ), + (&ty::TyInt(_), &ty::TyFloat(_)) | + (&ty::TyUint(_), &ty::TyFloat(_)) => span_lint_and_then( + cx, + TRANSMUTE_INT_TO_FLOAT, + e.span, + &format!("transmute from a `{}` to a `{}`", from_ty, to_ty), + |db| { + let arg = sugg::Sugg::hir(cx, &args[0], ".."); + let arg = if let ty::TyInt(int_ty) = from_ty.sty { + arg.as_ty(format!("u{}", int_ty.bit_width().map_or_else(|| "size".to_string(), |v| v.to_string()))) + } else { + arg + }; + db.span_suggestion(e.span, "consider using", format!("{}::from_bits({})", to_ty, arg.to_string())); + } + ), _ => return, }; } diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs index 31cd8304eba7..81582b5a15fa 100644 --- a/tests/ui/transmute.rs +++ b/tests/ui/transmute.rs @@ -118,4 +118,21 @@ fn crosspointer() { } } +#[warn(transmute_int_to_char)] +fn int_to_char() { + let _: char = unsafe { std::mem::transmute(0_u32) }; + let _: char = unsafe { std::mem::transmute(0_i32) }; +} + +#[warn(transmute_int_to_bool)] +fn int_to_bool() { + let _: bool = unsafe { std::mem::transmute(0_u8) }; +} + +#[warn(transmute_int_to_float)] +fn int_to_float() { + let _: f32 = unsafe { std::mem::transmute(0_u32) }; + let _: f32 = unsafe { std::mem::transmute(0_i32) }; +} + fn main() { } diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index 0c5aff11b0ce..c81ec5260be2 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -154,3 +154,39 @@ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) 117 | let _: *mut Usize = core::intrinsics::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: transmute from a `u32` to a `char` + --> $DIR/transmute.rs:123:28 + | +123 | let _: char = unsafe { std::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32)` + | + = note: `-D transmute-int-to-char` implied by `-D warnings` + +error: transmute from a `i32` to a `char` + --> $DIR/transmute.rs:124:28 + | +124 | let _: char = unsafe { std::mem::transmute(0_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32)` + +error: transmute from a `u8` to a `bool` + --> $DIR/transmute.rs:129:28 + | +129 | let _: bool = unsafe { std::mem::transmute(0_u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0` + | + = note: `-D transmute-int-to-bool` implied by `-D warnings` + +error: transmute from a `u32` to a `f32` + --> $DIR/transmute.rs:134:27 + | +134 | let _: f32 = unsafe { std::mem::transmute(0_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` + | + = note: `-D transmute-int-to-float` implied by `-D warnings` + +error: transmute from a `i32` to a `f32` + --> $DIR/transmute.rs:135:27 + | +135 | let _: f32 = unsafe { std::mem::transmute(0_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` + From 771d2220d28f458e59b2f12a571d2963bf7255f5 Mon Sep 17 00:00:00 2001 From: sinkuu Date: Sun, 5 Feb 2017 13:41:09 +0900 Subject: [PATCH 57/60] Add identity_conversion lint (fixes #1051) --- clippy_lints/src/identity_conversion.rs | 96 +++++++++++++++++++++++++ clippy_lints/src/lib.rs | 3 + clippy_lints/src/utils/paths.rs | 2 + clippy_lints/src/vec.rs | 4 +- tests/ui/identity_conversion.rs | 35 +++++++++ tests/ui/identity_conversion.stderr | 42 +++++++++++ 6 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 clippy_lints/src/identity_conversion.rs create mode 100644 tests/ui/identity_conversion.rs create mode 100644 tests/ui/identity_conversion.stderr diff --git a/clippy_lints/src/identity_conversion.rs b/clippy_lints/src/identity_conversion.rs new file mode 100644 index 000000000000..d64f352d7f16 --- /dev/null +++ b/clippy_lints/src/identity_conversion.rs @@ -0,0 +1,96 @@ +use rustc::lint::*; +use rustc::hir::*; +use syntax::ast::NodeId; +use utils::{in_macro, match_def_path, match_trait_method, same_tys, snippet, span_lint_and_then}; +use utils::{opt_def_id, paths, resolve_node}; + +/// **What it does:** Checks for always-identical `Into`/`From` conversions. +/// +/// **Why is this bad?** Redundant code. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// // format!() returns a `String` +/// let s: String = format!("hello").into(); +/// ``` +declare_lint! { + pub IDENTITY_CONVERSION, + Warn, + "using always-identical `Into`/`From` conversions" +} + +#[derive(Default)] +pub struct IdentityConversion { + try_desugar_arm: Vec, +} + +impl LintPass for IdentityConversion { + fn get_lints(&self) -> LintArray { + lint_array!(IDENTITY_CONVERSION) + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for IdentityConversion { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) { + if in_macro(e.span) { + return; + } + + if Some(&e.id) == self.try_desugar_arm.last() { + return; + } + + match e.node { + ExprMatch(_, ref arms, MatchSource::TryDesugar) => { + let e = match arms[0].body.node { + ExprRet(Some(ref e)) | ExprBreak(_, Some(ref e)) => e, + _ => return, + }; + if let ExprCall(_, ref args) = e.node { + self.try_desugar_arm.push(args[0].id); + } else { + return; + } + }, + + ExprMethodCall(ref name, .., ref args) => { + if match_trait_method(cx, e, &paths::INTO[..]) && &*name.name.as_str() == "into" { + let a = cx.tables.expr_ty(e); + let b = cx.tables.expr_ty(&args[0]); + if same_tys(cx, a, b) { + let sugg = snippet(cx, args[0].span, "").into_owned(); + span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| { + db.span_suggestion(e.span, "consider removing `.into()`", sugg); + }); + } + } + }, + + ExprCall(ref path, ref args) => if let ExprPath(ref qpath) = path.node { + if let Some(def_id) = opt_def_id(resolve_node(cx, qpath, path.hir_id)) { + if match_def_path(cx.tcx, def_id, &paths::FROM_FROM[..]) { + let a = cx.tables.expr_ty(e); + let b = cx.tables.expr_ty(&args[0]); + if same_tys(cx, a, b) { + let sugg = snippet(cx, args[0].span, "").into_owned(); + let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); + span_lint_and_then(cx, IDENTITY_CONVERSION, e.span, "identical conversion", |db| { + db.span_suggestion(e.span, &sugg_msg, sugg); + }); + } + } + } + }, + + _ => {}, + } + } + + fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, e: &'tcx Expr) { + if Some(&e.id) == self.try_desugar_arm.last() { + self.try_desugar_arm.pop(); + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 933ec1a8e70c..d4af88d5fede 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -93,6 +93,7 @@ pub mod eval_order_dependence; pub mod format; pub mod formatting; pub mod functions; +pub mod identity_conversion; pub mod identity_op; pub mod if_let_redundant_pattern_matching; pub mod if_not_else; @@ -331,6 +332,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { reg.register_late_lint_pass(box bytecount::ByteCount); reg.register_late_lint_pass(box infinite_iter::Pass); reg.register_late_lint_pass(box invalid_ref::InvalidRef); + reg.register_late_lint_pass(box identity_conversion::IdentityConversion::default()); reg.register_lint_group("clippy_restrictions", vec![ arithmetic::FLOAT_ARITHMETIC, @@ -431,6 +433,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { formatting::SUSPICIOUS_ELSE_FORMATTING, functions::NOT_UNSAFE_PTR_ARG_DEREF, functions::TOO_MANY_ARGUMENTS, + identity_conversion::IDENTITY_CONVERSION, identity_op::IDENTITY_OP, if_let_redundant_pattern_matching::IF_LET_REDUNDANT_PATTERN_MATCHING, infinite_iter::INFINITE_ITER, diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 2a2eabcca1f8..d517d32b64ca 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -26,11 +26,13 @@ pub const DOUBLE_ENDED_ITERATOR: [&'static str; 4] = ["core", "iter", "traits", pub const DROP: [&'static str; 3] = ["core", "mem", "drop"]; pub const FMT_ARGUMENTS_NEWV1: [&'static str; 4] = ["core", "fmt", "Arguments", "new_v1"]; pub const FMT_ARGUMENTV1_NEW: [&'static str; 4] = ["core", "fmt", "ArgumentV1", "new"]; +pub const FROM_FROM: [&'static str; 4] = ["core", "convert", "From", "from"]; pub const HASH: [&'static str; 2] = ["hash", "Hash"]; pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHSET: [&'static str; 5] = ["std", "collections", "hash", "set", "HashSet"]; pub const INIT: [&'static str; 4] = ["core", "intrinsics", "", "init"]; +pub const INTO: [&'static str; 3] = ["core", "convert", "Into"]; pub const INTO_ITERATOR: [&'static str; 4] = ["core", "iter", "traits", "IntoIterator"]; pub const IO_PRINT: [&'static str; 4] = ["std", "io", "stdio", "_print"]; pub const IO_READ: [&'static str; 3] = ["std", "io", "Read"]; diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs index 367235f7eeed..6044eaac3769 100644 --- a/clippy_lints/src/vec.rs +++ b/clippy_lints/src/vec.rs @@ -67,7 +67,7 @@ fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecA .eval(len) .is_ok() { - format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")).into() + format!("&[{}; {}]", snippet(cx, elem.span, "elem"), snippet(cx, len.span, "len")) } else { return; } @@ -75,7 +75,7 @@ fn check_vec_macro<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, vec_args: &higher::VecA higher::VecArgs::Vec(args) => if let Some(last) = args.iter().last() { let span = args[0].span.to(last.span); - format!("&[{}]", snippet(cx, span, "..")).into() + format!("&[{}]", snippet(cx, span, "..")) } else { "&[]".into() }, diff --git a/tests/ui/identity_conversion.rs b/tests/ui/identity_conversion.rs new file mode 100644 index 000000000000..81cbdd9643a4 --- /dev/null +++ b/tests/ui/identity_conversion.rs @@ -0,0 +1,35 @@ +#![deny(identity_conversion)] + +fn test_generic(val: T) -> T { + let _ = T::from(val); + val.into() +} + +fn test_generic2 + Into, U: From>(val: T) { + // ok + let _: i32 = val.into(); + let _: U = val.into(); + let _ = U::from(val); +} + +fn test_questionmark() -> Result<(), ()> { + { + let _: i32 = 0i32.into(); + Ok(Ok(())) + }??; + Ok(()) +} + +fn main() { + test_generic(10i32); + test_generic2::(10i32); + test_questionmark().unwrap(); + + let _: String = "foo".into(); + let _: String = From::from("foo"); + let _ = String::from("foo"); + + let _: String = "foo".to_string().into(); + let _: String = From::from("foo".to_string()); + let _ = String::from("foo".to_string()); +} diff --git a/tests/ui/identity_conversion.stderr b/tests/ui/identity_conversion.stderr new file mode 100644 index 000000000000..8e8d8a701249 --- /dev/null +++ b/tests/ui/identity_conversion.stderr @@ -0,0 +1,42 @@ +error: identical conversion + --> $DIR/identity_conversion.rs:4:13 + | +4 | let _ = T::from(val); + | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` + | +note: lint level defined here + --> $DIR/identity_conversion.rs:1:9 + | +1 | #![deny(identity_conversion)] + | ^^^^^^^^^^^^^^^^^^^ + +error: identical conversion + --> $DIR/identity_conversion.rs:5:5 + | +5 | val.into() + | ^^^^^^^^^^ help: consider removing `.into()`: `val` + +error: identical conversion + --> $DIR/identity_conversion.rs:17:22 + | +17 | let _: i32 = 0i32.into(); + | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` + +error: identical conversion + --> $DIR/identity_conversion.rs:32:21 + | +32 | let _: String = "foo".to_string().into(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` + +error: identical conversion + --> $DIR/identity_conversion.rs:33:21 + | +33 | let _: String = From::from("foo".to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` + +error: identical conversion + --> $DIR/identity_conversion.rs:34:13 + | +34 | let _ = String::from("foo".to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` + From 1b1b41a5e6c77f80762be0cff6f759461e70ce61 Mon Sep 17 00:00:00 2001 From: sinkuu Date: Wed, 4 Oct 2017 22:26:41 +0900 Subject: [PATCH 58/60] Test if #[allow] works --- tests/ui/identity_conversion.rs | 5 +++++ tests/ui/identity_conversion.stderr | 12 ++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/ui/identity_conversion.rs b/tests/ui/identity_conversion.rs index 81cbdd9643a4..d254b746d79f 100644 --- a/tests/ui/identity_conversion.rs +++ b/tests/ui/identity_conversion.rs @@ -28,6 +28,11 @@ fn main() { let _: String = "foo".into(); let _: String = From::from("foo"); let _ = String::from("foo"); + #[allow(identity_conversion)] + { + let _: String = "foo".into(); + let _ = String::from("foo"); + } let _: String = "foo".to_string().into(); let _: String = From::from("foo".to_string()); diff --git a/tests/ui/identity_conversion.stderr b/tests/ui/identity_conversion.stderr index 8e8d8a701249..152bb8882bda 100644 --- a/tests/ui/identity_conversion.stderr +++ b/tests/ui/identity_conversion.stderr @@ -23,20 +23,20 @@ error: identical conversion | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: identical conversion - --> $DIR/identity_conversion.rs:32:21 + --> $DIR/identity_conversion.rs:37:21 | -32 | let _: String = "foo".to_string().into(); +37 | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: identical conversion - --> $DIR/identity_conversion.rs:33:21 + --> $DIR/identity_conversion.rs:38:21 | -33 | let _: String = From::from("foo".to_string()); +38 | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: identical conversion - --> $DIR/identity_conversion.rs:34:13 + --> $DIR/identity_conversion.rs:39:13 | -34 | let _ = String::from("foo".to_string()); +39 | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` From d6b35f98397625fdae521fe3902f1f7077fdd707 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 5 Oct 2017 23:46:08 -0500 Subject: [PATCH 59/60] add never_loop test --- tests/ui/never_loop.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/ui/never_loop.rs b/tests/ui/never_loop.rs index 4866db1a5412..715a83efd93d 100644 --- a/tests/ui/never_loop.rs +++ b/tests/ui/never_loop.rs @@ -126,6 +126,19 @@ pub fn test12(a: bool, b: bool) { } } +pub fn test13() { + let mut a = true; + loop { // infinite loop + while a { + if true { + a = false; + continue; + } + return; + } + } +} + fn main() { test1(); test2(); @@ -139,5 +152,6 @@ fn main() { test10(); test11(|| 0); test12(true, false); + test13(); } From d92d5a88118c98477b33ed14b7ae3dc9ca4b394f Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 6 Oct 2017 00:04:39 -0500 Subject: [PATCH 60/60] fix never_loop --- clippy_lints/src/loops.rs | 65 +++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 76f1a603f242..8d2a2f8fac61 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -378,7 +378,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { match expr.node { ExprWhile(_, ref block, _) | ExprLoop(ref block, _, _) => { - if never_loop(block, &expr.id) { + if never_loop(block, expr.id) { span_lint(cx, NEVER_LOOP, expr.span, "this loop never actually loops"); } }, @@ -485,11 +485,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { } } -fn never_loop(block: &Block, id: &NodeId) -> bool { - !contains_continue_block(block, id) && loop_exit_block(block) +fn never_loop(block: &Block, id: NodeId) -> bool { + !contains_continue_block(block, Some(id)) && loop_exit_block(block, &mut vec![id]) } -fn contains_continue_block(block: &Block, dest: &NodeId) -> bool { +fn contains_continue_block(block: &Block, dest: Option) -> bool { block.stmts.iter().any(|e| contains_continue_stmt(e, dest)) || block.expr.as_ref().map_or( false, @@ -497,7 +497,7 @@ fn contains_continue_block(block: &Block, dest: &NodeId) -> bool { ) } -fn contains_continue_stmt(stmt: &Stmt, dest: &NodeId) -> bool { +fn contains_continue_stmt(stmt: &Stmt, dest: Option) -> bool { match stmt.node { StmtSemi(ref e, _) | StmtExpr(ref e, _) => contains_continue_expr(e, dest), @@ -505,7 +505,7 @@ fn contains_continue_stmt(stmt: &Stmt, dest: &NodeId) -> bool { } } -fn contains_continue_decl(decl: &Decl, dest: &NodeId) -> bool { +fn contains_continue_decl(decl: &Decl, dest: Option) -> bool { match decl.node { DeclLocal(ref local) => { local.init.as_ref().map_or( @@ -517,7 +517,7 @@ fn contains_continue_decl(decl: &Decl, dest: &NodeId) -> bool { } } -fn contains_continue_expr(expr: &Expr, dest: &NodeId) -> bool { +fn contains_continue_expr(expr: &Expr, dest: Option) -> bool { match expr.node { ExprRet(Some(ref e)) | ExprBox(ref e) | @@ -555,31 +555,32 @@ fn contains_continue_expr(expr: &Expr, dest: &NodeId) -> bool { |e| contains_continue_expr(e, dest), ) }, - ExprAgain(d) => d.target_id.opt_id().map_or(false, |id| id == *dest), + ExprAgain(d) => dest.map_or(true, |dest| d.target_id.opt_id().map_or(false, |id| id == dest)), _ => false, } } -fn loop_exit_block(block: &Block) -> bool { - block.stmts.iter().any(|e| loop_exit_stmt(e)) || block.expr.as_ref().map_or(false, |e| loop_exit_expr(e)) +fn loop_exit_block(block: &Block, loops: &mut Vec) -> bool { + block.stmts.iter().take_while(|s| !contains_continue_stmt(s, None)).any(|s| loop_exit_stmt(s, loops)) + || block.expr.as_ref().map_or(false, |e| loop_exit_expr(e, loops)) } -fn loop_exit_stmt(stmt: &Stmt) -> bool { +fn loop_exit_stmt(stmt: &Stmt, loops: &mut Vec) -> bool { match stmt.node { StmtSemi(ref e, _) | - StmtExpr(ref e, _) => loop_exit_expr(e), - StmtDecl(ref d, _) => loop_exit_decl(d), + StmtExpr(ref e, _) => loop_exit_expr(e, loops), + StmtDecl(ref d, _) => loop_exit_decl(d, loops), } } -fn loop_exit_decl(decl: &Decl) -> bool { +fn loop_exit_decl(decl: &Decl, loops: &mut Vec) -> bool { match decl.node { - DeclLocal(ref local) => local.init.as_ref().map_or(false, |e| loop_exit_expr(e)), + DeclLocal(ref local) => local.init.as_ref().map_or(false, |e| loop_exit_expr(e, loops)), _ => false, } } -fn loop_exit_expr(expr: &Expr) -> bool { +fn loop_exit_expr(expr: &Expr, loops: &mut Vec) -> bool { match expr.node { ExprBox(ref e) | ExprUnary(_, ref e) | @@ -588,22 +589,34 @@ fn loop_exit_expr(expr: &Expr) -> bool { ExprField(ref e, _) | ExprTupField(ref e, _) | ExprAddrOf(_, ref e) | - ExprRepeat(ref e, _) => loop_exit_expr(e), + ExprRepeat(ref e, _) => loop_exit_expr(e, loops), ExprArray(ref es) | ExprMethodCall(_, _, ref es) | - ExprTup(ref es) => es.iter().any(|e| loop_exit_expr(e)), - ExprCall(ref e, ref es) => loop_exit_expr(e) || es.iter().any(|e| loop_exit_expr(e)), + ExprTup(ref es) => es.iter().any(|e| loop_exit_expr(e, loops)), + ExprCall(ref e, ref es) => loop_exit_expr(e, loops) || es.iter().any(|e| loop_exit_expr(e, loops)), ExprBinary(_, ref e1, ref e2) | ExprAssign(ref e1, ref e2) | ExprAssignOp(_, ref e1, ref e2) | - ExprIndex(ref e1, ref e2) => [e1, e2].iter().any(|e| loop_exit_expr(e)), - ExprIf(ref e, ref e2, ref e3) => { - loop_exit_expr(e) || e3.as_ref().map_or(false, |e| loop_exit_expr(e)) && loop_exit_expr(e2) + ExprIndex(ref e1, ref e2) => [e1, e2].iter().any(|e| loop_exit_expr(e, loops)), + ExprIf(ref e, ref e2, ref e3) => loop_exit_expr(e, loops) + || e3.as_ref().map_or(false, |e3| loop_exit_expr(e3, loops)) && loop_exit_expr(e2, loops), + ExprLoop(ref b, _, _) => { + loops.push(expr.id); + let val = loop_exit_block(b, loops); + loops.pop(); + val }, - ExprWhile(ref e, ref b, _) => loop_exit_expr(e) || loop_exit_block(b), - ExprMatch(ref e, ref arms, _) => loop_exit_expr(e) || arms.iter().all(|a| loop_exit_expr(&a.body)), - ExprBlock(ref b) => loop_exit_block(b), - ExprBreak(_, _) | ExprAgain(_) | ExprRet(_) => true, + ExprWhile(ref e, ref b, _) => { + loops.push(expr.id); + let val = loop_exit_expr(e, loops) || loop_exit_block(b, loops); + loops.pop(); + val + }, + ExprMatch(ref e, ref arms, _) => loop_exit_expr(e, loops) || arms.iter().all(|a| loop_exit_expr(&a.body, loops)), + ExprBlock(ref b) => loop_exit_block(b, loops), + ExprAgain(d) => d.target_id.opt_id().map_or(false, |id| loops.iter().skip(1).all(|&id2| id != id2)), + ExprBreak(d, _) => d.target_id.opt_id().map_or(false, |id| loops[0] == id), + ExprRet(_) => true, _ => false, } }