]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/loops.rs
Auto merge of #4551 - mikerite:fix-ice-reporting, r=llogiq
[rust.git] / clippy_lints / src / loops.rs
index 7b36fa7e284bdbeb715ff719e200d0758a41b908..2db8acc4b95e54e08623cac05367731f68608bb0 100644 (file)
@@ -11,7 +11,7 @@
 // use rustc::middle::region::CodeExtent;
 use crate::consts::{constant, Constant};
 use crate::utils::usage::mutated_variables;
-use crate::utils::{in_macro_or_desugar, sext, sugg};
+use crate::utils::{is_type_diagnostic_item, qpath_res, sext, sugg};
 use rustc::middle::expr_use_visitor::*;
 use rustc::middle::mem_categorization::cmt_;
 use rustc::middle::mem_categorization::Categorization;
 use std::mem;
 use syntax::ast;
 use syntax::source_map::Span;
-use syntax_pos::BytePos;
+use syntax_pos::{BytePos, Symbol};
 
 use crate::utils::paths;
 use crate::utils::{
-    get_enclosing_block, get_parent_expr, has_iter_method, higher, is_integer_literal, is_refutable, last_path_segment,
+    get_enclosing_block, get_parent_expr, has_iter_method, higher, is_integer_const, is_refutable, last_path_segment,
     match_trait_method, match_type, match_var, multispan_sugg, snippet, snippet_opt, snippet_with_applicability,
     span_help_and_lint, span_lint, span_lint_and_sugg, span_lint_and_then, SpanlessEq,
 };
     ///     dst[i + 64] = src[i];
     /// }
     /// ```
+    /// Could be written as:
+    /// ```rust
+    /// # let src = vec![1];
+    /// # let mut dst = vec![0; 65];
+    /// dst[64..(src.len() + 64)].clone_from_slice(&src[..]);
+    /// ```
     pub MANUAL_MEMCPY,
     perf,
     "manually copying items between slices"
     /// **What it does:** Checks `for` loops over slices with an explicit counter
     /// and suggests the use of `.enumerate()`.
     ///
-    /// **Why is it bad?** Not only is the version using `.enumerate()` more
-    /// readable, the compiler is able to remove bounds checks which can lead to
-    /// faster code in some instances.
+    /// **Why is it bad?** Using `.enumerate()` makes the intent more clear,
+    /// declutters the code and may be faster in some instances.
     ///
     /// **Known problems:** None.
     ///
     /// **Example:**
     /// ```rust
     /// # let v = vec![1];
-    /// # fn foo(bar: usize) {}
     /// # fn bar(bar: usize, baz: usize) {}
-    /// for i in 0..v.len() { foo(v[i]); }
-    /// for i in 0..v.len() { bar(i, v[i]); }
+    /// let mut i = 0;
+    /// for item in &v {
+    ///     bar(i, *item);
+    ///     i += 1;
+    /// }
+    /// ```
+    /// Could be written as
+    /// ```rust
+    /// # let v = vec![1];
+    /// # fn bar(bar: usize, baz: usize) {}
+    /// for (i, item) in v.iter().enumerate() { bar(i, *item); }
     /// ```
     pub EXPLICIT_COUNTER_LOOP,
     complexity,
@@ -464,7 +477,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Loops {
     #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         // we don't want to check expanded macros
-        if in_macro_or_desugar(expr.span) {
+        if expr.span.from_expansion() {
             return;
         }
 
@@ -741,7 +754,7 @@ fn same_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: HirId) -> bo
         if let ExprKind::Path(ref qpath) = expr.node;
         if let QPath::Resolved(None, ref path) = *qpath;
         if path.segments.len() == 1;
-        if let Res::Local(local_id) = cx.tables.qpath_res(qpath, expr.hir_id);
+        if let Res::Local(local_id) = qpath_res(cx, qpath, expr.hir_id);
         // our variable!
         if local_id == var;
         then {
@@ -782,7 +795,7 @@ fn is_slice_like<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'_>) -> bool {
         _ => false,
     };
 
-    is_slice || match_type(cx, ty, &paths::VEC) || match_type(cx, ty, &paths::VEC_DEQUE)
+    is_slice || is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type")) || match_type(cx, ty, &paths::VEC_DEQUE)
 }
 
 fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: HirId) -> Option<FixedOffsetVar> {
@@ -1028,7 +1041,7 @@ fn check_for_loop_range<'a, 'tcx>(
     body: &'tcx Expr,
     expr: &'tcx Expr,
 ) {
-    if in_macro_or_desugar(expr.span) {
+    if expr.span.from_expansion() {
         return;
     }
 
@@ -1083,7 +1096,7 @@ fn check_for_loop_range<'a, 'tcx>(
                     return;
                 }
 
-                let starts_at_zero = is_integer_literal(start, 0);
+                let starts_at_zero = is_integer_const(cx, start, 0);
 
                 let skip = if starts_at_zero {
                     String::new()
@@ -1605,7 +1618,7 @@ fn check_for_mutability(cx: &LateContext<'_, '_>, bound: &Expr) -> Option<HirId>
         if let ExprKind::Path(ref qpath) = bound.node;
         if let QPath::Resolved(None, _) = *qpath;
         then {
-            let res = cx.tables.qpath_res(qpath, bound.hir_id);
+            let res = qpath_res(cx, qpath, bound.hir_id);
             if let Res::Local(node_id) = res {
                 let node_str = cx.tcx.hir().get(node_id);
                 if_chain! {
@@ -1749,7 +1762,7 @@ fn check(&mut self, idx: &'tcx Expr, seqexpr: &'tcx Expr, expr: &'tcx Expr) -> b
                     if self.prefer_mutable {
                         self.indexed_mut.insert(seqvar.segments[0].ident.name);
                     }
-                    let res = self.cx.tables.qpath_res(seqpath, seqexpr.hir_id);
+                    let res = qpath_res(self.cx, seqpath, seqexpr.hir_id);
                     match res {
                         Res::Local(hir_id) => {
                             let parent_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
@@ -1811,7 +1824,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
             if let QPath::Resolved(None, ref path) = *qpath;
             if path.segments.len() == 1;
             then {
-                if let Res::Local(local_id) = self.cx.tables.qpath_res(qpath, expr.hir_id) {
+                if let Res::Local(local_id) = qpath_res(self.cx, qpath, expr.hir_id) {
                     if local_id == self.var {
                         self.nonindex = true;
                     } else {
@@ -1937,7 +1950,7 @@ fn is_ref_iterable_type(cx: &LateContext<'_, '_>, e: &Expr) -> bool {
     // will allow further borrows afterwards
     let ty = cx.tables.expr_ty(e);
     is_iterable_array(ty, cx) ||
-    match_type(cx, ty, &paths::VEC) ||
+    is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type")) ||
     match_type(cx, ty, &paths::LINKED_LIST) ||
     match_type(cx, ty, &paths::HASHMAP) ||
     match_type(cx, ty, &paths::HASHSET) ||
@@ -1990,10 +2003,7 @@ fn extract_first_expr(block: &Block) -> Option<&Expr> {
 fn is_simple_break_expr(expr: &Expr) -> bool {
     match expr.node {
         ExprKind::Break(dest, ref passed_expr) if dest.label.is_none() && passed_expr.is_none() => true,
-        ExprKind::Block(ref b, _) => match extract_first_expr(b) {
-            Some(subexpr) => is_simple_break_expr(subexpr),
-            None => false,
-        },
+        ExprKind::Block(ref b, _) => extract_first_expr(b).map_or(false, |subexpr| is_simple_break_expr(subexpr)),
         _ => false,
     }
 }
@@ -2032,7 +2042,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
                 match parent.node {
                     ExprKind::AssignOp(op, ref lhs, ref rhs) => {
                         if lhs.hir_id == expr.hir_id {
-                            if op.node == BinOpKind::Add && is_integer_literal(rhs, 1) {
+                            if op.node == BinOpKind::Add && is_integer_const(self.cx, rhs, 1) {
                                 *state = match *state {
                                     VarState::Initial if self.depth == 0 => VarState::IncrOnce,
                                     _ => VarState::DontWarn,
@@ -2084,7 +2094,7 @@ fn visit_stmt(&mut self, stmt: &'tcx Stmt) {
                     self.name = Some(ident.name);
 
                     self.state = if let Some(ref init) = local.init {
-                        if is_integer_literal(init, 0) {
+                        if is_integer_const(&self.cx, init, 0) {
                             VarState::Warn
                         } else {
                             VarState::Declared
@@ -2120,7 +2130,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr) {
                         self.state = VarState::DontWarn;
                     },
                     ExprKind::Assign(ref lhs, ref rhs) if lhs.hir_id == expr.hir_id => {
-                        self.state = if is_integer_literal(rhs, 0) && self.depth == 0 {
+                        self.state = if is_integer_const(&self.cx, rhs, 0) && self.depth == 0 {
                             VarState::Warn
                         } else {
                             VarState::DontWarn
@@ -2153,7 +2163,7 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
 
 fn var_def_id(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<HirId> {
     if let ExprKind::Path(ref qpath) = expr.node {
-        let path_res = cx.tables.qpath_res(qpath, expr.hir_id);
+        let path_res = qpath_res(cx, qpath, expr.hir_id);
         if let Res::Local(node_id) = path_res {
             return Some(node_id);
         }
@@ -2345,7 +2355,7 @@ fn insert_def_id(&mut self, ex: &'tcx Expr) {
         if_chain! {
             if let ExprKind::Path(ref qpath) = ex.node;
             if let QPath::Resolved(None, _) = *qpath;
-            let res = self.cx.tables.qpath_res(qpath, ex.hir_id);
+            let res = qpath_res(self.cx, qpath, ex.hir_id);
             then {
                 match res {
                     Res::Local(node_id) => {
@@ -2389,7 +2399,7 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr, cx: &LateContext<'a, 'tcx>
         if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
         then {
             let ty = cx.tables.node_type(ty.hir_id);
-            if match_type(cx, ty, &paths::VEC) ||
+            if is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type")) ||
                 match_type(cx, ty, &paths::VEC_DEQUE) ||
                 match_type(cx, ty, &paths::BTREEMAP) ||
                 match_type(cx, ty, &paths::HASHMAP) {