]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #3603 - xfix:random-state-lint, r=phansch
authorbors <bors@rust-lang.org>
Thu, 3 Jan 2019 02:00:46 +0000 (02:00 +0000)
committerbors <bors@rust-lang.org>
Thu, 3 Jan 2019 02:00:46 +0000 (02:00 +0000)
random_state lint

34 files changed:
README.md
clippy_lints/src/approx_const.rs
clippy_lints/src/arithmetic.rs
clippy_lints/src/assign_ops.rs
clippy_lints/src/attrs.rs
clippy_lints/src/bit_mask.rs
clippy_lints/src/blacklisted_name.rs
clippy_lints/src/block_in_if_condition.rs
clippy_lints/src/booleans.rs
clippy_lints/src/doc.rs
clippy_lints/src/infinite_iter.rs
clippy_lints/src/lib.rs
clippy_lints/src/use_self.rs
clippy_lints/src/utils/hir_utils.rs
clippy_lints/src/utils/mod.rs
rustc_tools_util/Cargo.toml
rustc_tools_util/src/lib.rs
tests/ui/builtin-type-shadow.stderr
tests/ui/copies.rs
tests/ui/copies.stderr
tests/ui/for_kv_map.rs [new file with mode: 0644]
tests/ui/for_kv_map.stderr [new file with mode: 0644]
tests/ui/for_loop.rs
tests/ui/for_loop.stderr
tests/ui/ifs_same_cond.rs [new file with mode: 0644]
tests/ui/ifs_same_cond.stderr [new file with mode: 0644]
tests/ui/infinite_iter.rs
tests/ui/infinite_iter.stderr
tests/ui/iter_skip_next.rs [new file with mode: 0644]
tests/ui/iter_skip_next.stderr [new file with mode: 0644]
tests/ui/methods.rs
tests/ui/methods.stderr
tests/ui/use_self.rs
tests/ui/use_self.stderr

index be24f1be8272ff29543a6cb1ec632e38c8662f3a..8ca10da416ddba62696cc2cba4d5e31d621807d4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -79,7 +79,7 @@ To have cargo compile your crate with Clippy without Clippy installation
 in your code, you can use:
 
 ```terminal
-RUSTFLAGS=--sysroot=`rustc --print sysroot` cargo run --bin cargo-clippy --manifest-path=path_to_clippys_Cargo.toml
+cargo run --bin cargo-clippy --manifest-path=path_to_clippys_Cargo.toml
 ```
 
 *[Note](https://github.com/rust-lang/rust-clippy/wiki#a-word-of-warning):*
index 4d502a6d0939338d896461bb4652016ed5258586..afbfdd32304c37459b99dd55f3e7a39e05d6e7e0 100644 (file)
@@ -73,7 +73,7 @@ fn get_lints(&self) -> LintArray {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
-        if let ExprKind::Lit(ref lit) = e.node {
+        if let ExprKind::Lit(lit) = &e.node {
             check_lit(cx, lit, e);
         }
     }
index 51d17b388826837d1d50c2e8e4477d5fa9f583f2..c466b8cd5c9dc890aae3ab81de74eb73cddc006b 100644 (file)
@@ -73,8 +73,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                 return;
             }
         }
-        match expr.node {
-            hir::ExprKind::Binary(ref op, ref l, ref r) => {
+        match &expr.node {
+            hir::ExprKind::Binary(op, l, r) => {
                 match op.node {
                     hir::BinOpKind::And
                     | hir::BinOpKind::Or
@@ -100,7 +100,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                     self.expr_span = Some(expr.span);
                 }
             },
-            hir::ExprKind::Unary(hir::UnOp::UnNeg, ref arg) => {
+            hir::ExprKind::Unary(hir::UnOp::UnNeg, arg) => {
                 let ty = cx.tables.expr_ty(arg);
                 if ty.is_integral() {
                     span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
index a595050d0c0f363079f8e9e1efbc476addaf5664..496b6d659938c214368dc3dd936a221d886f9ae4 100644 (file)
@@ -70,9 +70,9 @@ fn get_lints(&self) -> LintArray {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AssignOps {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
-        match expr.node {
-            hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
-                if let hir::ExprKind::Binary(binop, ref l, ref r) = rhs.node {
+        match &expr.node {
+            hir::ExprKind::AssignOp(op, lhs, rhs) => {
+                if let hir::ExprKind::Binary(binop, l, r) = &rhs.node {
                     if op.node == binop.node {
                         let lint = |assignee: &hir::Expr, rhs_other: &hir::Expr| {
                             span_lint_and_then(
@@ -122,8 +122,8 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
                     }
                 }
             },
-            hir::ExprKind::Assign(ref assignee, ref e) => {
-                if let hir::ExprKind::Binary(op, ref l, ref r) = e.node {
+            hir::ExprKind::Assign(assignee, e) => {
+                if let hir::ExprKind::Binary(op, l, r) = &e.node {
                     #[allow(clippy::cyclomatic_complexity)]
                     let lint = |assignee: &hir::Expr, rhs: &hir::Expr| {
                         let ty = cx.tables.expr_ty(assignee);
@@ -150,8 +150,8 @@ macro_rules! ops {
                                         if_chain! {
                                             if parent_impl != ast::CRATE_NODE_ID;
                                             if let hir::Node::Item(item) = cx.tcx.hir().get(parent_impl);
-                                            if let hir::ItemKind::Impl(_, _, _, _, Some(ref trait_ref), _, _) =
-                                                item.node;
+                                            if let hir::ItemKind::Impl(_, _, _, _, Some(trait_ref), _, _) =
+                                                &item.node;
                                             if trait_ref.path.def.def_id() == trait_id;
                                             then { return; }
                                         }
index 2757593e2ee484b28651e9a15fa64b2256a4091f..41946d06293816872aca063458f3ff0e34e28bb8 100644 (file)
@@ -212,7 +212,7 @@ fn get_lints(&self) -> LintArray {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for AttrPass {
     fn check_attribute(&mut self, cx: &LateContext<'a, 'tcx>, attr: &'tcx Attribute) {
-        if let Some(ref items) = attr.meta_item_list() {
+        if let Some(items) = &attr.meta_item_list() {
             match &*attr.name().as_str() {
                 "allow" | "warn" | "deny" | "forbid" => {
                     check_clippy_lint_names(cx, items);
@@ -224,8 +224,8 @@ fn check_attribute(&mut self, cx: &LateContext<'a, 'tcx>, attr: &'tcx Attribute)
             }
             for item in items {
                 if_chain! {
-                    if let NestedMetaItemKind::MetaItem(ref mi) = item.node;
-                    if let MetaItemKind::NameValue(ref lit) = mi.node;
+                    if let NestedMetaItemKind::MetaItem(mi) = &item.node;
+                    if let MetaItemKind::NameValue(lit) = &mi.node;
                     if mi.name() == "since";
                     then {
                         check_semver(cx, item.span, lit);
@@ -244,7 +244,7 @@ fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
                 let skip_unused_imports = item.attrs.iter().any(|attr| attr.name() == "macro_use");
 
                 for attr in &item.attrs {
-                    if let Some(ref lint_list) = attr.meta_item_list() {
+                    if let Some(lint_list) = &attr.meta_item_list() {
                         match &*attr.name().as_str() {
                             "allow" | "warn" | "deny" | "forbid" => {
                                 // whitelist `unused_imports` and `deprecated` for `use` items
@@ -381,9 +381,9 @@ fn is_relevant_trait(tcx: TyCtxt<'_, '_, '_>, item: &TraitItem) -> bool {
 
 fn is_relevant_block(tcx: TyCtxt<'_, '_, '_>, tables: &ty::TypeckTables<'_>, block: &Block) -> bool {
     if let Some(stmt) = block.stmts.first() {
-        match stmt.node {
+        match &stmt.node {
             StmtKind::Decl(_, _) => true,
-            StmtKind::Expr(ref expr, _) | StmtKind::Semi(ref expr, _) => is_relevant_expr(tcx, tables, expr),
+            StmtKind::Expr(expr, _) | StmtKind::Semi(expr, _) => is_relevant_expr(tcx, tables, expr),
         }
     } else {
         block.expr.as_ref().map_or(false, |e| is_relevant_expr(tcx, tables, e))
@@ -391,12 +391,12 @@ fn is_relevant_block(tcx: TyCtxt<'_, '_, '_>, tables: &ty::TypeckTables<'_>, blo
 }
 
 fn is_relevant_expr(tcx: TyCtxt<'_, '_, '_>, tables: &ty::TypeckTables<'_>, expr: &Expr) -> bool {
-    match expr.node {
-        ExprKind::Block(ref block, _) => is_relevant_block(tcx, tables, block),
-        ExprKind::Ret(Some(ref e)) => is_relevant_expr(tcx, tables, e),
+    match &expr.node {
+        ExprKind::Block(block, _) => is_relevant_block(tcx, tables, block),
+        ExprKind::Ret(Some(e)) => is_relevant_expr(tcx, tables, e),
         ExprKind::Ret(None) | ExprKind::Break(_, None) => false,
-        ExprKind::Call(ref path_expr, _) => {
-            if let ExprKind::Path(ref qpath) = path_expr.node {
+        ExprKind::Call(path_expr, _) => {
+            if let ExprKind::Path(qpath) = &path_expr.node {
                 if let Some(fun_id) = opt_def_id(tables.qpath_def(qpath, path_expr.hir_id)) {
                     !match_def_path(tcx, fun_id, &paths::BEGIN_PANIC)
                 } else {
@@ -443,7 +443,7 @@ fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attrib
             }
         }
 
-        if let Some(ref values) = attr.meta_item_list() {
+        if let Some(values) = attr.meta_item_list() {
             if values.len() != 1 || attr.name() != "inline" {
                 continue;
             }
@@ -463,7 +463,7 @@ fn check_attrs(cx: &LateContext<'_, '_>, span: Span, name: Name, attrs: &[Attrib
 }
 
 fn check_semver(cx: &LateContext<'_, '_>, span: Span, lit: &Lit) {
-    if let LitKind::Str(ref is, _) = lit.node {
+    if let LitKind::Str(is, _) = lit.node {
         if Version::parse(&is.as_str()).is_ok() {
             return;
         }
@@ -477,7 +477,7 @@ fn check_semver(cx: &LateContext<'_, '_>, span: Span, lit: &Lit) {
 }
 
 fn is_word(nmi: &NestedMetaItem, expected: &str) -> bool {
-    if let NestedMetaItemKind::MetaItem(ref mi) = nmi.node {
+    if let NestedMetaItemKind::MetaItem(mi) = &nmi.node {
         mi.is_word() && mi.name() == expected
     } else {
         false
@@ -512,7 +512,7 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
         if_chain! {
             // check cfg_attr
             if attr.name() == "cfg_attr";
-            if let Some(ref items) = attr.meta_item_list();
+            if let Some(items) = attr.meta_item_list();
             if items.len() == 2;
             // check for `rustfmt`
             if let Some(feature_item) = items[0].meta_item();
index abdd624146c7573e49b492902eb0255cc9514654..9af80493af1c366d69bb2933979f7140ee8c0d58 100644 (file)
@@ -121,7 +121,7 @@ fn get_lints(&self) -> LintArray {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BitMask {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
-        if let ExprKind::Binary(ref cmp, ref left, ref right) = e.node {
+        if let ExprKind::Binary(cmp, left, right) = &e.node {
             if cmp.node.is_comparison() {
                 if let Some(cmp_opt) = fetch_int_literal(cx, right) {
                     check_compare(cx, left, cmp.node, cmp_opt, e.span)
@@ -131,13 +131,13 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
             }
         }
         if_chain! {
-            if let ExprKind::Binary(ref op, ref left, ref right) = e.node;
+            if let ExprKind::Binary(op, left, right) = &e.node;
             if BinOpKind::Eq == op.node;
-            if let ExprKind::Binary(ref op1, ref left1, ref right1) = left.node;
+            if let ExprKind::Binary(op1, left1, right1) = &left.node;
             if BinOpKind::BitAnd == op1.node;
-            if let ExprKind::Lit(ref lit) = right1.node;
+            if let ExprKind::Lit(lit) = &right1.node;
             if let LitKind::Int(n, _) = lit.node;
-            if let ExprKind::Lit(ref lit1) = right.node;
+            if let ExprKind::Lit(lit1) = &right.node;
             if let LitKind::Int(0, _) = lit1.node;
             if n.leading_zeros() == n.count_zeros();
             if n > u128::from(self.verbose_bit_mask_threshold);
@@ -173,7 +173,7 @@ fn invert_cmp(cmp: BinOpKind) -> BinOpKind {
 }
 
 fn check_compare(cx: &LateContext<'_, '_>, bit_op: &Expr, cmp_op: BinOpKind, cmp_value: u128, span: Span) {
-    if let ExprKind::Binary(ref op, ref left, ref right) = bit_op.node {
+    if let ExprKind::Binary(op, left, right) = &bit_op.node {
         if op.node != BinOpKind::BitAnd && op.node != BinOpKind::BitOr {
             return;
         }
index ce7da4194971226438db8d2512eaf9a3cdd703de..ed7437e495b9f11f64f3b814293c43186b4fd9b3 100644 (file)
@@ -11,6 +11,7 @@
 use rustc::hir::*;
 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::{declare_tool_lint, lint_array};
+use rustc_data_structures::fx::FxHashSet;
 
 /// **What it does:** Checks for usage of blacklisted names for variables, such
 /// as `foo`.
 
 #[derive(Clone, Debug)]
 pub struct BlackListedName {
-    blacklist: Vec<String>,
+    blacklist: FxHashSet<String>,
 }
 
 impl BlackListedName {
-    pub fn new(blacklist: Vec<String>) -> Self {
+    pub fn new(blacklist: FxHashSet<String>) -> Self {
         Self { blacklist }
     }
 }
@@ -50,7 +51,7 @@ fn get_lints(&self) -> LintArray {
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlackListedName {
     fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
         if let PatKind::Binding(_, _, ident, _) = pat.node {
-            if self.blacklist.iter().any(|s| ident.name == *s) {
+            if self.blacklist.contains(&ident.name.to_string()) {
                 span_lint(
                     cx,
                     BLACKLISTED_NAME,
index b68b43354f798da7535a05b1b4bcec9e6358ae30..92979dc024d3d60fb8d944bef274807b10b252b6 100644 (file)
@@ -88,11 +88,11 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BlockInIfCondition {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
-        if let ExprKind::If(ref check, ref then, _) = expr.node {
-            if let ExprKind::Block(ref block, _) = check.node {
+        if let ExprKind::If(check, then, _) = &expr.node {
+            if let ExprKind::Block(block, _) = &check.node {
                 if block.rules == DefaultBlock {
                     if block.stmts.is_empty() {
-                        if let Some(ref ex) = block.expr {
+                        if let Some(ex) = &block.expr {
                             // don't dig into the expression here, just suggest that they remove
                             // the block
                             if in_macro(expr.span) || differing_macro_contexts(expr.span, ex.span) {
index 844f9fb886564df520d72628718b2505f3797921..2279d24af95f77417711635635a7b193a2eb0a3b 100644 (file)
@@ -96,7 +96,7 @@ struct Hir2Qmm<'a, 'tcx: 'a, 'v> {
 impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
     fn extract(&mut self, op: BinOpKind, a: &[&'v Expr], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> {
         for a in a {
-            if let ExprKind::Binary(binop, ref lhs, ref rhs) = a.node {
+            if let ExprKind::Binary(binop, lhs, rhs) = &a.node {
                 if binop.node == op {
                     v = self.extract(op, &[lhs, rhs], v)?;
                     continue;
@@ -110,14 +110,14 @@ fn extract(&mut self, op: BinOpKind, a: &[&'v Expr], mut v: Vec<Bool>) -> Result
     fn run(&mut self, e: &'v Expr) -> Result<Bool, String> {
         // prevent folding of `cfg!` macros and the like
         if !in_macro(e.span) {
-            match e.node {
-                ExprKind::Unary(UnNot, ref inner) => return Ok(Bool::Not(box self.run(inner)?)),
-                ExprKind::Binary(binop, ref lhs, ref rhs) => match binop.node {
+            match &e.node {
+                ExprKind::Unary(UnNot, inner) => return Ok(Bool::Not(box self.run(inner)?)),
+                ExprKind::Binary(binop, lhs, rhs) => match &binop.node {
                     BinOpKind::Or => return Ok(Bool::Or(self.extract(BinOpKind::Or, &[lhs, rhs], Vec::new())?)),
                     BinOpKind::And => return Ok(Bool::And(self.extract(BinOpKind::And, &[lhs, rhs], Vec::new())?)),
                     _ => (),
                 },
-                ExprKind::Lit(ref lit) => match lit.node {
+                ExprKind::Lit(lit) => match lit.node {
                     LitKind::Bool(true) => return Ok(Bool::True),
                     LitKind::Bool(false) => return Ok(Bool::False),
                     _ => (),
@@ -130,8 +130,8 @@ fn run(&mut self, e: &'v Expr) -> Result<Bool, String> {
                 #[allow(clippy::cast_possible_truncation)]
                 return Ok(Bool::Term(n as u8));
             }
-            let negated = match e.node {
-                ExprKind::Binary(binop, ref lhs, ref rhs) => {
+            let negated = match &e.node {
+                ExprKind::Binary(binop, lhs, rhs) => {
                     if !implements_ord(self.cx, lhs) {
                         continue;
                     }
@@ -184,8 +184,8 @@ fn snip(&self, e: &Expr) -> Option<String> {
     }
 
     fn simplify_not(&self, expr: &Expr) -> Option<String> {
-        match expr.node {
-            ExprKind::Binary(binop, ref lhs, ref rhs) => {
+        match &expr.node {
+            ExprKind::Binary(binop, lhs, rhs) => {
                 if !implements_ord(self.cx, lhs) {
                     return None;
                 }
@@ -201,7 +201,7 @@ fn simplify_not(&self, expr: &Expr) -> Option<String> {
                 }
                 .and_then(|op| Some(format!("{}{}{}", self.snip(lhs)?, op, self.snip(rhs)?)))
             },
-            ExprKind::MethodCall(ref path, _, ref args) if args.len() == 1 => {
+            ExprKind::MethodCall(path, _, args) if args.len() == 1 => {
                 let type_of_receiver = self.cx.tables.expr_ty(&args[0]);
                 if !match_type(self.cx, type_of_receiver, &paths::OPTION)
                     && !match_type(self.cx, type_of_receiver, &paths::RESULT)
@@ -221,14 +221,14 @@ fn simplify_not(&self, expr: &Expr) -> Option<String> {
 
     fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
         use quine_mc_cluskey::Bool::*;
-        match *suggestion {
+        match suggestion {
             True => {
                 self.output.push_str("true");
             },
             False => {
                 self.output.push_str("false");
             },
-            Not(ref inner) => match **inner {
+            Not(inner) => match **inner {
                 And(_) | Or(_) => {
                     self.output.push('!');
                     self.output.push('(');
@@ -251,7 +251,7 @@ fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
                     self.recurse(inner)?;
                 },
             },
-            And(ref v) => {
+            And(v) => {
                 for (index, inner) in v.iter().enumerate() {
                     if index > 0 {
                         self.output.push_str(" && ");
@@ -265,7 +265,7 @@ fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
                     }
                 }
             },
-            Or(ref v) => {
+            Or(v) => {
                 for (index, inner) in v.iter().enumerate() {
                     if index > 0 {
                         self.output.push_str(" || ");
@@ -273,7 +273,7 @@ fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
                     self.recurse(inner);
                 }
             },
-            Term(n) => {
+            &Term(n) => {
                 let snip = self.snip(self.terminals[n as usize])?;
                 self.output.push_str(&snip);
             },
@@ -325,22 +325,22 @@ struct Stats {
 
 fn terminal_stats(b: &Bool) -> Stats {
     fn recurse(b: &Bool, stats: &mut Stats) {
-        match *b {
+        match b {
             True | False => stats.ops += 1,
-            Not(ref inner) => {
+            Not(inner) => {
                 match **inner {
                     And(_) | Or(_) => stats.ops += 1, // brackets are also operations
                     _ => stats.negations += 1,
                 }
                 recurse(inner, stats);
             },
-            And(ref v) | Or(ref v) => {
+            And(v) | Or(v) => {
                 stats.ops += v.len() - 1;
                 for inner in v {
                     recurse(inner, stats);
                 }
             },
-            Term(n) => stats.terminals[n as usize] += 1,
+            &Term(n) => stats.terminals[n as usize] += 1,
         }
     }
     use quine_mc_cluskey::Bool::*;
@@ -461,11 +461,11 @@ fn visit_expr(&mut self, e: &'tcx Expr) {
         if in_macro(e.span) {
             return;
         }
-        match e.node {
+        match &e.node {
             ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
                 self.bool_expr(e)
             },
-            ExprKind::Unary(UnNot, ref inner) => {
+            ExprKind::Unary(UnNot, inner) => {
                 if self.cx.tables.node_types()[inner.hir_id].is_bool() {
                     self.bool_expr(e);
                 } else {
index 024907185e9e041a2233e008133dc861d74fadc9..a3504e7e3303d777220ae1111ce6e7402a2ed1c0 100644 (file)
@@ -12,6 +12,7 @@
 use pulldown_cmark;
 use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
 use rustc::{declare_tool_lint, lint_array};
+use rustc_data_structures::fx::FxHashSet;
 use syntax::ast;
 use syntax::source_map::{BytePos, Span};
 use syntax_pos::Pos;
 
 #[derive(Clone)]
 pub struct Doc {
-    valid_idents: Vec<String>,
+    valid_idents: FxHashSet<String>,
 }
 
 impl Doc {
-    pub fn new(valid_idents: Vec<String>) -> Self {
+    pub fn new(valid_idents: FxHashSet<String>) -> Self {
         Self { valid_idents }
     }
 }
@@ -144,7 +145,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(
     panic!("not a doc-comment: {}", comment);
 }
 
-pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &[String], attrs: &'a [ast::Attribute]) {
+pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, attrs: &'a [ast::Attribute]) {
     let mut doc = String::new();
     let mut spans = vec![];
 
@@ -192,7 +193,7 @@ pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &[String], attrs: &'
 
 fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
     cx: &EarlyContext<'_>,
-    valid_idents: &[String],
+    valid_idents: &FxHashSet<String>,
     docs: Events,
     spans: &[(usize, Span)],
 ) {
@@ -237,14 +238,14 @@ fn check_doc<'a, Events: Iterator<Item = (usize, pulldown_cmark::Event<'a>)>>(
     }
 }
 
-fn check_text(cx: &EarlyContext<'_>, valid_idents: &[String], text: &str, span: Span) {
+fn check_text(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, text: &str, span: Span) {
     for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
         // Trim punctuation as in `some comment (see foo::bar).`
         //                                                   ^^
         // Or even as in `_foo bar_` which is emphasized.
         let word = word.trim_matches(|c: char| !c.is_alphanumeric());
 
-        if valid_idents.iter().any(|i| i == word) {
+        if valid_idents.contains(word) {
             continue;
         }
 
index 2f7c5895af8d09361e7f46d5475937bce8d2f5bc..e2da8461f4110e9fd11b2354285e811d143c8dac 100644 (file)
@@ -7,7 +7,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, paths, span_lint};
+use crate::utils::{get_trait_def_id, higher, implements_trait, match_qpath, match_type, paths, span_lint};
 use rustc::hir::*;
 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::{declare_tool_lint, lint_array};
@@ -200,7 +200,6 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
 /// their iterators
 static COMPLETING_METHODS: &[(&str, usize)] = &[
     ("count", 1),
-    ("collect", 1),
     ("fold", 3),
     ("for_each", 2),
     ("partition", 2),
@@ -214,6 +213,18 @@ fn is_infinite(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
     ("product", 1),
 ];
 
+/// the paths of types that are known to be infinitely allocating
+static INFINITE_COLLECTORS: &[&[&str]] = &[
+    &paths::BINARY_HEAP,
+    &paths::BTREEMAP,
+    &paths::BTREESET,
+    &paths::HASHMAP,
+    &paths::HASHSET,
+    &paths::LINKED_LIST,
+    &paths::VEC,
+    &paths::VEC_DEQUE,
+];
+
 fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
     match expr.node {
         ExprKind::MethodCall(ref method, _, ref args) => {
@@ -233,6 +244,11 @@ fn complete_infinite_iter(cx: &LateContext<'_, '_>, expr: &Expr) -> Finiteness {
                 if not_double_ended {
                     return is_infinite(cx, &args[0]);
                 }
+            } else if method.ident.name == "collect" {
+                let ty = cx.tables.expr_ty(expr);
+                if INFINITE_COLLECTORS.iter().any(|path| match_type(cx, ty, path)) {
+                    return is_infinite(cx, &args[0]);
+                }
             }
         },
         ExprKind::Binary(op, ref l, ref r) => {
index 0aa9ff5985f49df86916314c385031cdbfcc5773..31cd58d2c78d75bbb8a633008697d20f952fc1e5 100644 (file)
@@ -424,9 +424,11 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) {
     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::default());
-    reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(conf.blacklisted_names.clone()));
+    reg.register_late_lint_pass(box blacklisted_name::BlackListedName::new(
+            conf.blacklisted_names.iter().cloned().collect()
+    ));
     reg.register_late_lint_pass(box functions::Functions::new(conf.too_many_arguments_threshold));
-    reg.register_early_lint_pass(box doc::Doc::new(conf.doc_valid_idents.clone()));
+    reg.register_early_lint_pass(box doc::Doc::new(conf.doc_valid_idents.iter().cloned().collect()));
     reg.register_late_lint_pass(box neg_multiply::NegMultiply);
     reg.register_early_lint_pass(box unsafe_removed_from_name::UnsafeNameRemoval);
     reg.register_late_lint_pass(box mem_discriminant::MemDiscriminant);
index 653b6630b3c9c1e8ffc4e810499fe526586b5676..b031e8b1c44481a02addc0ea2090e21ece53290c 100644 (file)
@@ -9,6 +9,7 @@
 
 use crate::utils::{in_macro, span_lint_and_sugg};
 use if_chain::if_chain;
+use rustc::hir::def::{CtorKind, Def};
 use rustc::hir::intravisit::{walk_path, walk_ty, NestedVisitorMap, Visitor};
 use rustc::hir::*;
 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 /// name
 /// feels inconsistent.
 ///
-/// **Known problems:** None.
+/// **Known problems:**
+/// - False positive when using associated types (#2843)
+/// - False positives in some situations when using generics (#3410)
+/// - False positive when type from outer function can't be used (#3463)
 ///
 /// **Example:**
 /// ```rust
@@ -226,10 +230,15 @@ struct UseSelfVisitor<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> Visitor<'tcx> for UseSelfVisitor<'a, 'tcx> {
     fn visit_path(&mut self, path: &'tcx Path, _id: HirId) {
-        if self.item_path.def == path.def && path.segments.last().expect(SEGMENTS_MSG).ident.name != SelfUpper.name() {
-            span_use_self_lint(self.cx, path);
+        if path.segments.last().expect(SEGMENTS_MSG).ident.name != SelfUpper.name() {
+            if self.item_path.def == path.def {
+                span_use_self_lint(self.cx, path);
+            } else if let Def::StructCtor(ctor_did, CtorKind::Fn) = path.def {
+                if self.item_path.def.opt_def_id() == self.cx.tcx.parent_def_id(ctor_did) {
+                    span_use_self_lint(self.cx, path);
+                }
+            }
         }
-
         walk_path(self, path);
     }
 
index 79c9de13571c1590fa5718f77790a2dd15bc45d1..377e56ddcac92f4fa18ded611fbb8a137333b4a9 100644 (file)
@@ -54,7 +54,9 @@ pub fn eq_stmt(&mut self, left: &Stmt, right: &Stmt) -> bool {
         match (&left.node, &right.node) {
             (&StmtKind::Decl(ref l, _), &StmtKind::Decl(ref r, _)) => {
                 if let (&DeclKind::Local(ref l), &DeclKind::Local(ref r)) = (&l.node, &r.node) {
-                    both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
+                    self.eq_pat(&l.pat, &r.pat)
+                        && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
+                        && both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
                 } else {
                     false
                 }
index e92529dc0a25793dda2af5df4d3ead58d40c4b34..647bae1ae6bd5742a4e0f55607f0240315870285 100644 (file)
@@ -62,6 +62,15 @@ pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
     rhs.ctxt() != lhs.ctxt()
 }
 
+/// Returns `true` if the given `NodeId` is inside a constant context
+///
+/// # Example
+///
+/// ```rust,ignore
+/// if in_constant(cx, expr.id) {
+///     // Do something
+/// }
+/// ```
 pub fn in_constant(cx: &LateContext<'_, '_>, id: NodeId) -> bool {
     let parent_id = cx.tcx.hir().get_parent(id);
     match cx.tcx.hir().body_owner_kind(parent_id) {
@@ -377,6 +386,9 @@ pub fn contains_name(name: Name, expr: &Expr) -> bool {
 
 /// Convert a span to a code snippet if available, otherwise use default.
 ///
+/// This is useful if you want to provide suggestions for your lint or more generally, if you want
+/// to convert a given `Span` to a `str`.
+///
 /// # Example
 /// ```rust,ignore
 /// snippet(cx, expr.span, "..")
@@ -430,7 +442,7 @@ pub fn snippet_opt<'a, T: LintContext<'a>>(cx: &T, span: Span) -> Option<String>
 ///
 /// # Example
 /// ```rust,ignore
-/// snippet(cx, expr.span, "..")
+/// snippet_block(cx, expr.span, "..")
 /// ```
 pub fn snippet_block<'a, 'b, T: LintContext<'b>>(cx: &T, span: Span, default: &'a str) -> Cow<'a, str> {
     let snip = snippet(cx, span, default);
@@ -741,6 +753,13 @@ pub fn is_integer_literal(expr: &Expr, value: u128) -> bool {
     false
 }
 
+/// Returns `true` if the given `Expr` has been coerced before.
+///
+/// Examples of coercions can be found in the Nomicon at
+/// <https://doc.rust-lang.org/nomicon/coercions.html>.
+///
+/// See `rustc::ty::adjustment::Adjustment` and `rustc_typeck::check::coercion` for more
+/// information on adjustments and coercions.
 pub fn is_adjusted(cx: &LateContext<'_, '_>, e: &Expr) -> bool {
     cx.tables.adjustments().get(e.hir_id).is_some()
 }
index b73d7ca56060454e0ad4c9fc09af199e125558a6..70ff86c49afe953de4a21dbd830c97f3691d744d 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "rustc_tools_util"
-version = "0.1.0"
+version = "0.1.1"
 authors = ["Matthias Krüger <matthias.krueger@famsik.de>"]
 description = "small helper to generate version information for git packages"
 repository = "https://github.com/rust-lang/rust-clippy"
index d1640c758bb30e9854e07404326d73726d2f06f4..49bfb7d8b59963a23a22f09ae57e00ee272c433d 100644 (file)
@@ -46,16 +46,17 @@ pub struct VersionInfo {
 
 impl std::fmt::Display for VersionInfo {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        if self.commit_hash.is_some() {
+        let hash = self.commit_hash.clone().unwrap_or_default();
+        let hash_trimmed = hash.trim();
+
+        let date = self.commit_date.clone().unwrap_or_default();
+        let date_trimmed = date.trim();
+
+        if (hash_trimmed.len() + date_trimmed.len()) > 0 {
             write!(
                 f,
                 "{} {}.{}.{} ({} {})",
-                self.crate_name,
-                self.major,
-                self.minor,
-                self.patch,
-                self.commit_hash.clone().unwrap_or_default().trim(),
-                self.commit_date.clone().unwrap_or_default().trim(),
+                self.crate_name, self.major, self.minor, self.patch, hash_trimmed, date_trimmed,
             )?;
         } else {
             write!(f, "{} {}.{}.{}", self.crate_name, self.major, self.minor, self.patch)?;
@@ -121,7 +122,7 @@ fn test_struct_local() {
         let vi = get_version_info!();
         assert_eq!(vi.major, 0);
         assert_eq!(vi.minor, 1);
-        assert_eq!(vi.patch, 0);
+        assert_eq!(vi.patch, 1);
         assert_eq!(vi.crate_name, "rustc_tools_util");
         // hard to make positive tests for these since they will always change
         assert!(vi.commit_hash.is_none());
@@ -131,7 +132,7 @@ fn test_struct_local() {
     #[test]
     fn test_display_local() {
         let vi = get_version_info!();
-        assert_eq!(vi.to_string(), "rustc_tools_util 0.1.0");
+        assert_eq!(vi.to_string(), "rustc_tools_util 0.1.1");
     }
 
     #[test]
@@ -140,7 +141,7 @@ fn test_debug_local() {
         let s = format!("{:?}", vi);
         assert_eq!(
             s,
-            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 1, patch: 0 }"
+            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 1, patch: 1 }"
         );
     }
 
index 9bfed9dbba87465c8f05385e5ed22008a66651d1..940a6dc2bcc8c97c664f0cf2ac600618489f6515 100644 (file)
@@ -12,7 +12,7 @@ error[E0308]: mismatched types
 LL | fn foo<u32>(a: u32) -> u32 {
    |                        --- expected `u32` because of return type
 LL |     42
-   |     ^^ expected type parameter, found integral variable
+   |     ^^ expected type parameter, found integer
    |
    = note: expected type `u32`
               found type `{integer}`
index 00e1d726207ac1344844f504db99cd8e99ae2437..5db82006deaa2340e86545ea5e499373eec06bcb 100644 (file)
@@ -335,49 +335,16 @@ fn if_same_then_else() -> Result<&'static str, ()> {
         let foo = "";
         return Ok(&foo[0..]);
     }
-}
-
-#[warn(clippy::ifs_same_cond)]
-#[allow(clippy::if_same_then_else)] // all empty blocks
-fn ifs_same_cond() {
-    let a = 0;
-    let b = false;
-
-    if b {
-    } else if b {
-        //~ ERROR ifs same condition
-    }
-
-    if a == 1 {
-    } else if a == 1 {
-        //~ ERROR ifs same condition
-    }
-
-    if 2 * a == 1 {
-    } else if 2 * a == 2 {
-    } else if 2 * a == 1 {
-        //~ ERROR ifs same condition
-    } else if a == 1 {
-    }
 
-    // See #659
-    if cfg!(feature = "feature1-659") {
-        1
-    } else if cfg!(feature = "feature2-659") {
-        2
+    // false positive if_same_then_else, let(x,y) vs let(y,x), see #3559
+    if true {
+        let foo = "";
+        let (x, y) = (1, 2);
+        return Ok(&foo[x..y]);
     } else {
-        3
-    };
-
-    let mut v = vec![1];
-    if v.pop() == None {
-        // ok, functions
-    } else if v.pop() == None {
-    }
-
-    if v.len() == 42 {
-        // ok, functions
-    } else if v.len() == 42 {
+        let foo = "";
+        let (y, x) = (1, 2);
+        return Ok(&foo[x..y]);
     }
 }
 
index 659abf6fa7e7243aaa46e888c89ad988beee0344..3fbc279b5374515e2e6a5b57bc189fb1ee04d35f 100644 (file)
@@ -351,42 +351,5 @@ LL | |         try!(Ok("foo"));
 LL | |     } else {
    | |_____^
 
-error: this `if` has the same condition as a previous if
-  --> $DIR/copies.rs:347:15
-   |
-LL |     } else if b {
-   |               ^
-   |
-   = note: `-D clippy::ifs-same-cond` implied by `-D warnings`
-note: same as this
-  --> $DIR/copies.rs:346:8
-   |
-LL |     if b {
-   |        ^
-
-error: this `if` has the same condition as a previous if
-  --> $DIR/copies.rs:352:15
-   |
-LL |     } else if a == 1 {
-   |               ^^^^^^
-   |
-note: same as this
-  --> $DIR/copies.rs:351:8
-   |
-LL |     if a == 1 {
-   |        ^^^^^^
-
-error: this `if` has the same condition as a previous if
-  --> $DIR/copies.rs:358:15
-   |
-LL |     } else if 2 * a == 1 {
-   |               ^^^^^^^^^^
-   |
-note: same as this
-  --> $DIR/copies.rs:356:8
-   |
-LL |     if 2 * a == 1 {
-   |        ^^^^^^^^^^
-
-error: aborting due to 20 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/tests/ui/for_kv_map.rs b/tests/ui/for_kv_map.rs
new file mode 100644 (file)
index 0000000..d79ea4b
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![warn(clippy::for_kv_map)]
+#![allow(clippy::used_underscore_binding)]
+
+use std::collections::*;
+use std::rc::Rc;
+
+fn main() {
+    let m: HashMap<u64, u64> = HashMap::new();
+    for (_, v) in &m {
+        let _v = v;
+    }
+
+    let m: Rc<HashMap<u64, u64>> = Rc::new(HashMap::new());
+    for (_, v) in &*m {
+        let _v = v;
+        // Here the `*` is not actually necessary, but the test tests that we don't
+        // suggest
+        // `in *m.values()` as we used to
+    }
+
+    let mut m: HashMap<u64, u64> = HashMap::new();
+    for (_, v) in &mut m {
+        let _v = v;
+    }
+
+    let m: &mut HashMap<u64, u64> = &mut HashMap::new();
+    for (_, v) in &mut *m {
+        let _v = v;
+    }
+
+    let m: HashMap<u64, u64> = HashMap::new();
+    let rm = &m;
+    for (k, _value) in rm {
+        let _k = k;
+    }
+    test_for_kv_map();
+}
+
+fn test_for_kv_map() {
+    let m: HashMap<u64, u64> = HashMap::new();
+
+    // No error, _value is actually used
+    for (k, _value) in &m {
+        let _ = _value;
+        let _k = k;
+    }
+}
diff --git a/tests/ui/for_kv_map.stderr b/tests/ui/for_kv_map.stderr
new file mode 100644 (file)
index 0000000..7b65c58
--- /dev/null
@@ -0,0 +1,54 @@
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:18:19
+   |
+LL |     for (_, v) in &m {
+   |                   ^^
+   |
+   = note: `-D clippy::for-kv-map` implied by `-D warnings`
+help: use the corresponding method
+   |
+LL |     for v in m.values() {
+   |         ^    ^^^^^^^^^^
+
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:23:19
+   |
+LL |     for (_, v) in &*m {
+   |                   ^^^
+help: use the corresponding method
+   |
+LL |     for v in (*m).values() {
+   |         ^    ^^^^^^^^^^^^^
+
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:31:19
+   |
+LL |     for (_, v) in &mut m {
+   |                   ^^^^^^
+help: use the corresponding method
+   |
+LL |     for v in m.values_mut() {
+   |         ^    ^^^^^^^^^^^^^^
+
+error: you seem to want to iterate on a map's values
+  --> $DIR/for_kv_map.rs:36:19
+   |
+LL |     for (_, v) in &mut *m {
+   |                   ^^^^^^^
+help: use the corresponding method
+   |
+LL |     for v in (*m).values_mut() {
+   |         ^    ^^^^^^^^^^^^^^^^^
+
+error: you seem to want to iterate on a map's keys
+  --> $DIR/for_kv_map.rs:42:24
+   |
+LL |     for (k, _value) in rm {
+   |                        ^^
+help: use the corresponding method
+   |
+LL |     for k in rm.keys() {
+   |         ^    ^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
index 4747269bccdd175fed7d28d7a98f5bc1028547dc..c172b0b3b7709373e37f58894cc198df17e0186b 100644 (file)
@@ -333,37 +333,6 @@ fn main() {
     }
     println!("index: {}", index);
 
-    let m: HashMap<u64, u64> = HashMap::new();
-    for (_, v) in &m {
-        let _v = v;
-    }
-
-    let m: Rc<HashMap<u64, u64>> = Rc::new(HashMap::new());
-    for (_, v) in &*m {
-        let _v = v;
-        // Here the `*` is not actually necessary, but the test tests that we don't
-        // suggest
-        // `in *m.values()` as we used to
-    }
-
-    let mut m: HashMap<u64, u64> = HashMap::new();
-    for (_, v) in &mut m {
-        let _v = v;
-    }
-
-    let m: &mut HashMap<u64, u64> = &mut HashMap::new();
-    for (_, v) in &mut *m {
-        let _v = v;
-    }
-
-    let m: HashMap<u64, u64> = HashMap::new();
-    let rm = &m;
-    for (k, _value) in rm {
-        let _k = k;
-    }
-
-    test_for_kv_map();
-
     fn f<T>(_: &T, _: &T) -> bool {
         unimplemented!()
     }
@@ -381,17 +350,6 @@ fn g<T>(_: &mut [T], _: usize, _: usize) {
     }
 }
 
-#[allow(clippy::used_underscore_binding)]
-fn test_for_kv_map() {
-    let m: HashMap<u64, u64> = HashMap::new();
-
-    // No error, _value is actually used
-    for (k, _value) in &m {
-        let _ = _value;
-        let _k = k;
-    }
-}
-
 #[allow(dead_code)]
 fn partition<T: PartialOrd + Send>(v: &mut [T]) -> usize {
     let pivot = v.len() - 1;
index 937bef9f8a6f165e8fb85298561be1a10202f42f..4ded425b3210dba474cd529a88d415f9aac1f0f2 100644 (file)
@@ -292,60 +292,8 @@ LL |     vec.iter().cloned().map(|x| out.push(x)).collect::<Vec<_>>();
    |
    = note: `-D clippy::unused-collect` implied by `-D warnings`
 
-error: you seem to want to iterate on a map's values
-  --> $DIR/for_loop.rs:337:19
-   |
-LL |     for (_, v) in &m {
-   |                   ^^
-   |
-   = note: `-D clippy::for-kv-map` implied by `-D warnings`
-help: use the corresponding method
-   |
-LL |     for v in m.values() {
-   |         ^    ^^^^^^^^^^
-
-error: you seem to want to iterate on a map's values
-  --> $DIR/for_loop.rs:342:19
-   |
-LL |     for (_, v) in &*m {
-   |                   ^^^
-help: use the corresponding method
-   |
-LL |     for v in (*m).values() {
-   |         ^    ^^^^^^^^^^^^^
-
-error: you seem to want to iterate on a map's values
-  --> $DIR/for_loop.rs:350:19
-   |
-LL |     for (_, v) in &mut m {
-   |                   ^^^^^^
-help: use the corresponding method
-   |
-LL |     for v in m.values_mut() {
-   |         ^    ^^^^^^^^^^^^^^
-
-error: you seem to want to iterate on a map's values
-  --> $DIR/for_loop.rs:355:19
-   |
-LL |     for (_, v) in &mut *m {
-   |                   ^^^^^^^
-help: use the corresponding method
-   |
-LL |     for v in (*m).values_mut() {
-   |         ^    ^^^^^^^^^^^^^^^^^
-
-error: you seem to want to iterate on a map's keys
-  --> $DIR/for_loop.rs:361:24
-   |
-LL |     for (k, _value) in rm {
-   |                        ^^
-help: use the corresponding method
-   |
-LL |     for k in rm.keys() {
-   |         ^    ^^^^^^^^^
-
 error: it looks like you're manually copying between slices
-  --> $DIR/for_loop.rs:414:14
+  --> $DIR/for_loop.rs:372:14
    |
 LL |     for i in 0..src.len() {
    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
@@ -353,31 +301,31 @@ LL |     for i in 0..src.len() {
    = note: `-D clippy::manual-memcpy` implied by `-D warnings`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/for_loop.rs:419:14
+  --> $DIR/for_loop.rs:377:14
    |
 LL |     for i in 0..src.len() {
    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[10..(src.len() + 10)].clone_from_slice(&src[..])`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/for_loop.rs:424:14
+  --> $DIR/for_loop.rs:382:14
    |
 LL |     for i in 0..src.len() {
    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..])`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/for_loop.rs:429:14
+  --> $DIR/for_loop.rs:387:14
    |
 LL |     for i in 11..src.len() {
    |              ^^^^^^^^^^^^^ help: try replacing the loop by: `dst[11..src.len()].clone_from_slice(&src[(11 - 10)..(src.len() - 10)])`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/for_loop.rs:434:14
+  --> $DIR/for_loop.rs:392:14
    |
 LL |     for i in 0..dst.len() {
    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst.clone_from_slice(&src[..dst.len()])`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/for_loop.rs:447:14
+  --> $DIR/for_loop.rs:405:14
    |
 LL |     for i in 10..256 {
    |              ^^^^^^^
@@ -388,34 +336,34 @@ LL |     dst2[(10 + 500)..(256 + 500)].clone_from_slice(&src[10..256]) {
    |
 
 error: it looks like you're manually copying between slices
-  --> $DIR/for_loop.rs:459:14
+  --> $DIR/for_loop.rs:417:14
    |
 LL |     for i in 10..LOOP_OFFSET {
    |              ^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].clone_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)])`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/for_loop.rs:472:14
+  --> $DIR/for_loop.rs:430:14
    |
 LL |     for i in 0..src_vec.len() {
    |              ^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst_vec[..src_vec.len()].clone_from_slice(&src_vec[..])`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/for_loop.rs:501:14
+  --> $DIR/for_loop.rs:459:14
    |
 LL |     for i in from..from + src.len() {
    |              ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src[0..(from + src.len() - from)])`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/for_loop.rs:505:14
+  --> $DIR/for_loop.rs:463:14
    |
 LL |     for i in from..from + 3 {
    |              ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + 3].clone_from_slice(&src[0..(from + 3 - from)])`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/for_loop.rs:512:14
+  --> $DIR/for_loop.rs:470:14
    |
 LL |     for i in 0..src.len() {
    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
 
-error: aborting due to 51 previous errors
+error: aborting due to 46 previous errors
 
diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs
new file mode 100644 (file)
index 0000000..b67e730
--- /dev/null
@@ -0,0 +1,46 @@
+#![warn(clippy::ifs_same_cond)]
+#![allow(clippy::if_same_then_else)] // all empty blocks
+
+fn ifs_same_cond() {
+    let a = 0;
+    let b = false;
+
+    if b {
+    } else if b {
+        //~ ERROR ifs same condition
+    }
+
+    if a == 1 {
+    } else if a == 1 {
+        //~ ERROR ifs same condition
+    }
+
+    if 2 * a == 1 {
+    } else if 2 * a == 2 {
+    } else if 2 * a == 1 {
+        //~ ERROR ifs same condition
+    } else if a == 1 {
+    }
+
+    // See #659
+    if cfg!(feature = "feature1-659") {
+        1
+    } else if cfg!(feature = "feature2-659") {
+        2
+    } else {
+        3
+    };
+
+    let mut v = vec![1];
+    if v.pop() == None {
+        // ok, functions
+    } else if v.pop() == None {
+    }
+
+    if v.len() == 42 {
+        // ok, functions
+    } else if v.len() == 42 {
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/ifs_same_cond.stderr b/tests/ui/ifs_same_cond.stderr
new file mode 100644 (file)
index 0000000..0b0dd24
--- /dev/null
@@ -0,0 +1,39 @@
+error: this `if` has the same condition as a previous if
+  --> $DIR/ifs_same_cond.rs:9:15
+   |
+LL |     } else if b {
+   |               ^
+   |
+   = note: `-D clippy::ifs-same-cond` implied by `-D warnings`
+note: same as this
+  --> $DIR/ifs_same_cond.rs:8:8
+   |
+LL |     if b {
+   |        ^
+
+error: this `if` has the same condition as a previous if
+  --> $DIR/ifs_same_cond.rs:14:15
+   |
+LL |     } else if a == 1 {
+   |               ^^^^^^
+   |
+note: same as this
+  --> $DIR/ifs_same_cond.rs:13:8
+   |
+LL |     if a == 1 {
+   |        ^^^^^^
+
+error: this `if` has the same condition as a previous if
+  --> $DIR/ifs_same_cond.rs:20:15
+   |
+LL |     } else if 2 * a == 1 {
+   |               ^^^^^^^^^^
+   |
+note: same as this
+  --> $DIR/ifs_same_cond.rs:18:8
+   |
+LL |     if 2 * a == 1 {
+   |        ^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
index 8f41e3ae98d9cf67d8012c7dde3ef007594c14cf..bd266368dc4b161c0a559240f25aba791d6e67b1 100644 (file)
@@ -58,3 +58,22 @@ fn main() {
     infinite_iters();
     potential_infinite_iters();
 }
+
+mod finite_collect {
+    use std::collections::HashSet;
+    use std::iter::FromIterator;
+
+    struct C;
+    impl FromIterator<i32> for C {
+        fn from_iter<I: IntoIterator<Item = i32>>(iter: I) -> Self {
+            C
+        }
+    }
+
+    fn check_collect() {
+        let _: HashSet<i32> = (0..).collect(); // Infinite iter
+
+        // Some data structures don't collect infinitely, such as `ArrayVec`
+        let _: C = (0..).collect();
+    }
+}
index c64b3918db467577cc655c70cb3bee700e058e27..288285d9aaebaa1a5b869cc22aa5706530f7b905 100644 (file)
@@ -105,5 +105,13 @@ error: possible infinite iteration detected
 LL |     (0..).all(|x| x == 24); // maybe infinite iter
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 14 previous errors
+error: infinite iteration detected
+  --> $DIR/infinite_iter.rs:74:31
+   |
+LL |         let _: HashSet<i32> = (0..).collect(); // Infinite iter
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: #[deny(clippy::infinite_iter)] on by default
+
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs
new file mode 100644 (file)
index 0000000..4628bfb
--- /dev/null
@@ -0,0 +1,61 @@
+// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![warn(clippy::iter_skip_next)]
+#![allow(clippy::blacklisted_name)]
+
+/// Struct to generate false positive for Iterator-based lints
+#[derive(Copy, Clone)]
+struct IteratorFalsePositives {
+    foo: u32,
+}
+
+impl IteratorFalsePositives {
+    fn filter(self) -> IteratorFalsePositives {
+        self
+    }
+
+    fn next(self) -> IteratorFalsePositives {
+        self
+    }
+
+    fn find(self) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    fn position(self) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    fn rposition(self) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    fn nth(self, n: usize) -> Option<u32> {
+        Some(self.foo)
+    }
+
+    fn skip(self, _: usize) -> IteratorFalsePositives {
+        self
+    }
+}
+
+/// Checks implementation of `ITER_SKIP_NEXT` lint
+fn iter_skip_next() {
+    let mut some_vec = vec![0, 1, 2, 3];
+    let _ = some_vec.iter().skip(42).next();
+    let _ = some_vec.iter().cycle().skip(42).next();
+    let _ = (1..10).skip(10).next();
+    let _ = &some_vec[..].iter().skip(3).next();
+    let foo = IteratorFalsePositives { foo: 0 };
+    let _ = foo.skip(42).next();
+    let _ = foo.filter().skip(42).next();
+}
+
+fn main() {}
diff --git a/tests/ui/iter_skip_next.stderr b/tests/ui/iter_skip_next.stderr
new file mode 100644 (file)
index 0000000..6b65c1e
--- /dev/null
@@ -0,0 +1,28 @@
+error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
+  --> $DIR/iter_skip_next.rs:52:13
+   |
+LL |     let _ = some_vec.iter().skip(42).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::iter-skip-next` implied by `-D warnings`
+
+error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
+  --> $DIR/iter_skip_next.rs:53:13
+   |
+LL |     let _ = some_vec.iter().cycle().skip(42).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
+  --> $DIR/iter_skip_next.rs:54:13
+   |
+LL |     let _ = (1..10).skip(10).next();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
+  --> $DIR/iter_skip_next.rs:55:14
+   |
+LL |     let _ = &some_vec[..].iter().skip(3).next();
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
index ebf71f67a004f91052c8ea6741b455e71f7c2329..b470a12f7a399a16a22c26c43c6bd7d4fd9d86d9 100644 (file)
@@ -390,18 +390,6 @@ fn iter_nth() {
     let ok_mut = false_positive.iter_mut().nth(3);
 }
 
-/// Checks implementation of `ITER_SKIP_NEXT` lint
-fn iter_skip_next() {
-    let mut some_vec = vec![0, 1, 2, 3];
-    let _ = some_vec.iter().skip(42).next();
-    let _ = some_vec.iter().cycle().skip(42).next();
-    let _ = (1..10).skip(10).next();
-    let _ = &some_vec[..].iter().skip(3).next();
-    let foo = IteratorFalsePositives { foo : 0 };
-    let _ = foo.skip(42).next();
-    let _ = foo.filter().skip(42).next();
-}
-
 #[allow(clippy::similar_names)]
 fn main() {
     let opt = Some(0);
index b0b693f3e1691eeac04377df8389baf06f354aee..e87e61fbe0e4d4aa1d2833079fa2206c883c98f5 100644 (file)
@@ -367,39 +367,13 @@ error: called `.iter_mut().nth()` on a VecDeque. Calling `.get_mut()` is both fa
 LL |         let bad_vec_deque = some_vec_deque.iter_mut().nth(3);
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
-  --> $DIR/methods.rs:396:13
-   |
-LL |     let _ = some_vec.iter().skip(42).next();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::iter-skip-next` implied by `-D warnings`
-
-error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
-  --> $DIR/methods.rs:397:13
-   |
-LL |     let _ = some_vec.iter().cycle().skip(42).next();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
-  --> $DIR/methods.rs:398:13
-   |
-LL |     let _ = (1..10).skip(10).next();
-   |             ^^^^^^^^^^^^^^^^^^^^^^^
-
-error: called `skip(x).next()` on an iterator. This is more succinctly expressed by calling `nth(x)`
-  --> $DIR/methods.rs:399:14
-   |
-LL |     let _ = &some_vec[..].iter().skip(3).next();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: used unwrap() on an Option value. If you don't want to handle the None case gracefully, consider using expect() to provide a better panic message
-  --> $DIR/methods.rs:408:13
+  --> $DIR/methods.rs:396:13
    |
 LL |     let _ = opt.unwrap();
    |             ^^^^^^^^^^^^
    |
    = note: `-D clippy::option-unwrap-used` implied by `-D warnings`
 
-error: aborting due to 50 previous errors
+error: aborting due to 46 previous errors
 
index c21df403035f78481abec9fb9ea1b9fac4c27fbc..b201e160ebd93e2ac2555372f82442c84afd60f2 100644 (file)
@@ -51,8 +51,6 @@ fn default() -> Self {
     }
 }
 
-//todo the lint does not handle lifetimed struct
-//the following module should trigger the lint on the third method only
 mod lifetimes {
     struct Foo<'a> {
         foo_str: &'a str,
@@ -69,7 +67,8 @@ fn bar() -> Foo<'static> {
             Foo { foo_str: "foo" }
         }
 
-        // `Self` is applicable here
+        // FIXME: the lint does not handle lifetimed struct
+        // `Self` should be applicable here
         fn clone(&self) -> Foo<'a> {
             Foo { foo_str: self.foo_str }
         }
@@ -217,6 +216,16 @@ fn good(foos: &[Self]) -> impl Iterator<Item = &Self> {
     }
 }
 
+mod tuple_structs {
+    pub struct TS(i32);
+
+    impl TS {
+        pub fn ts() -> Self {
+            TS(0)
+        }
+    }
+}
+
 mod issue3410 {
 
     struct A;
index 82b44d424df5dede7cfe3d03aa571040d94c2bb2..d52fce76de598f54a60561299f2ad20463a1b073 100644 (file)
@@ -37,94 +37,100 @@ LL |             Foo::new()
    |             ^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:96:22
+  --> $DIR/use_self.rs:95:22
    |
 LL |         fn refs(p1: &Bad) -> &Bad {
    |                      ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:96:31
+  --> $DIR/use_self.rs:95:31
    |
 LL |         fn refs(p1: &Bad) -> &Bad {
    |                               ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:100:37
+  --> $DIR/use_self.rs:99:37
    |
 LL |         fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad {
    |                                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:100:53
+  --> $DIR/use_self.rs:99:53
    |
 LL |         fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad {
    |                                                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:104:30
+  --> $DIR/use_self.rs:103:30
    |
 LL |         fn mut_refs(p1: &mut Bad) -> &mut Bad {
    |                              ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:104:43
+  --> $DIR/use_self.rs:103:43
    |
 LL |         fn mut_refs(p1: &mut Bad) -> &mut Bad {
    |                                           ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:108:28
+  --> $DIR/use_self.rs:107:28
    |
 LL |         fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {}
    |                            ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:108:46
+  --> $DIR/use_self.rs:107:46
    |
 LL |         fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {}
    |                                              ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:110:20
+  --> $DIR/use_self.rs:109:20
    |
 LL |         fn vals(_: Bad) -> Bad {
    |                    ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:110:28
+  --> $DIR/use_self.rs:109:28
    |
 LL |         fn vals(_: Bad) -> Bad {
    |                            ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:111:13
+  --> $DIR/use_self.rs:110:13
    |
 LL |             Bad::default()
    |             ^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:116:23
+  --> $DIR/use_self.rs:115:23
    |
 LL |         type Output = Bad;
    |                       ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:118:27
+  --> $DIR/use_self.rs:117:27
    |
 LL |         fn mul(self, rhs: Bad) -> Bad {
    |                           ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:118:35
+  --> $DIR/use_self.rs:117:35
    |
 LL |         fn mul(self, rhs: Bad) -> Bad {
    |                                   ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:210:56
+  --> $DIR/use_self.rs:209:56
    |
 LL |         fn bad(foos: &[Self]) -> impl Iterator<Item = &Foo> {
    |                                                        ^^^ help: use the applicable keyword: `Self`
 
-error: aborting due to 21 previous errors
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:224:13
+   |
+LL |             TS(0)
+   |             ^^ help: use the applicable keyword: `Self`
+
+error: aborting due to 22 previous errors