]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/swap.rs
Auto merge of #4551 - mikerite:fix-ice-reporting, r=llogiq
[rust.git] / clippy_lints / src / swap.rs
index ddf33fcc411f7f081dc2447e3b7c75195f00feb1..cde49db2375b6ef8d574864ef11dbd51362b1e80 100644 (file)
@@ -1,63 +1,71 @@
 use crate::utils::sugg::Sugg;
 use crate::utils::{
-    differing_macro_contexts, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty, SpanlessEq,
+    differing_macro_contexts, is_type_diagnostic_item, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty,
+    SpanlessEq,
 };
 use if_chain::if_chain;
 use matches::matches;
 use rustc::hir::*;
 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use rustc::ty;
-use rustc::{declare_tool_lint, lint_array};
+use rustc::{declare_lint_pass, declare_tool_lint};
 use rustc_errors::Applicability;
+use syntax_pos::Symbol;
 
-/// **What it does:** Checks for manual swapping.
-///
-/// **Why is this bad?** The `std::mem::swap` function exposes the intent better
-/// without deinitializing or copying either variable.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// let t = b;
-/// b = a;
-/// a = t;
-/// ```
-/// Use std::mem::swap():
-/// ```rust
-/// std::mem::swap(&mut a, &mut b);
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for manual swapping.
+    ///
+    /// **Why is this bad?** The `std::mem::swap` function exposes the intent better
+    /// without deinitializing or copying either variable.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// let mut a = 42;
+    /// let mut b = 1337;
+    ///
+    /// let t = b;
+    /// b = a;
+    /// a = t;
+    /// ```
+    /// Use std::mem::swap():
+    /// ```rust
+    /// let mut a = 1;
+    /// let mut b = 2;
+    /// std::mem::swap(&mut a, &mut b);
+    /// ```
     pub MANUAL_SWAP,
     complexity,
     "manual swap of two variables"
 }
 
-/// **What it does:** Checks for `foo = bar; bar = foo` sequences.
-///
-/// **Why is this bad?** This looks like a failed attempt to swap.
-///
-/// **Known problems:** None.
-///
-/// **Example:**
-/// ```rust,ignore
-/// a = b;
-/// b = a;
-/// ```
 declare_clippy_lint! {
+    /// **What it does:** Checks for `foo = bar; bar = foo` sequences.
+    ///
+    /// **Why is this bad?** This looks like a failed attempt to swap.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # let mut a = 1;
+    /// # let mut b = 2;
+    /// a = b;
+    /// b = a;
+    /// ```
+    /// Could be written as:
+    /// ```rust
+    /// # let mut a = 1;
+    /// # let mut b = 2;
+    /// std::mem::swap(&mut a, &mut b);
+    /// ```
     pub ALMOST_SWAPPED,
     correctness,
     "`foo = bar; bar = foo` sequence"
 }
 
-#[derive(Copy, Clone)]
-pub struct Swap;
-
-impl LintPass for Swap {
-    fn get_lints(&self) -> LintArray {
-        lint_array![MANUAL_SWAP, ALMOST_SWAPPED]
-    }
-}
+declare_lint_pass!(Swap => [MANUAL_SWAP, ALMOST_SWAPPED]);
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Swap {
     fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block) {
@@ -73,7 +81,7 @@ fn check_manual_swap(cx: &LateContext<'_, '_>, block: &Block) {
             // let t = foo();
             if let StmtKind::Local(ref tmp) = w[0].node;
             if let Some(ref tmp_init) = tmp.init;
-            if let PatKind::Binding(_, _, ident, None) = tmp.pat.node;
+            if let PatKind::Binding(.., ident, None) = tmp.pat.node;
 
             // foo() = bar();
             if let StmtKind::Semi(ref first) = w[1].node;
@@ -101,7 +109,7 @@ fn check_for_slice<'a>(
 
                                 if matches!(ty.sty, ty::Slice(_)) ||
                                     matches!(ty.sty, ty::Array(_, _)) ||
-                                    match_type(cx, ty, &paths::VEC) ||
+                                    is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type")) ||
                                     match_type(cx, ty, &paths::VEC_DEQUE) {
                                         return Some((lhs1, idx1, idx2));
                                 }
@@ -112,6 +120,14 @@ fn check_for_slice<'a>(
                     None
                 }
 
+                if let ExprKind::Field(ref lhs1, _) = lhs1.node {
+                    if let ExprKind::Field(ref lhs2, _) = lhs2.node {
+                        if lhs1.hir_id.owner_def_id() == lhs2.hir_id.owner_def_id() {
+                            return;
+                        }
+                    }
+                }
+
                 let (replace, what, sugg) = if let Some((slice, idx1, idx2)) = check_for_slice(cx, lhs1, lhs2) {
                     if let Some(slice) = Sugg::hir_opt(cx, slice) {
                         (false,
@@ -138,7 +154,7 @@ fn check_for_slice<'a>(
                                    &format!("this looks like you are swapping{} manually", what),
                                    |db| {
                                        if !sugg.is_empty() {
-                                           db.span_suggestion_with_applicability(
+                                           db.span_suggestion(
                                                span,
                                                "try",
                                                sugg,
@@ -187,7 +203,7 @@ fn check_suspicious_swap(cx: &LateContext<'_, '_>, block: &Block) {
                                    &format!("this looks like you are trying to swap{}", what),
                                    |db| {
                                        if !what.is_empty() {
-                                           db.span_suggestion_with_applicability(
+                                           db.span_suggestion(
                                                span,
                                                "try",
                                                format!(