-use matches::matches;
-use crate::rustc::hir::*;
-use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
-use crate::rustc::{declare_tool_lint, lint_array};
-use if_chain::if_chain;
-use crate::rustc::ty;
-use crate::utils::{differing_macro_contexts, match_type, paths, snippet, span_lint_and_then, walk_ptrs_ty, SpanlessEq};
use crate::utils::sugg::Sugg;
-use crate::rustc_errors::Applicability;
-
-/// **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);
-/// ```
+use crate::utils::{
+ 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_lint_pass, declare_tool_lint};
+use rustc_errors::Applicability;
+use syntax_pos::Symbol;
+
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) {
for w in block.stmts.windows(3) {
if_chain! {
// let t = foo();
- if let StmtKind::Decl(ref tmp, _) = w[0].node;
- if let DeclKind::Local(ref tmp) = tmp.node;
+ 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;
+ if let StmtKind::Semi(ref first) = w[1].node;
if let ExprKind::Assign(ref lhs1, ref rhs1) = first.node;
// bar() = t;
- if let StmtKind::Semi(ref second, _) = w[2].node;
+ if let StmtKind::Semi(ref second) = w[2].node;
if let ExprKind::Assign(ref lhs2, ref rhs2) = second.node;
if let ExprKind::Path(QPath::Resolved(None, ref rhs2)) = rhs2.node;
if rhs2.segments.len() == 1;
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));
}
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,
&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,
fn check_suspicious_swap(cx: &LateContext<'_, '_>, block: &Block) {
for w in block.stmts.windows(2) {
if_chain! {
- if let StmtKind::Semi(ref first, _) = w[0].node;
- if let StmtKind::Semi(ref second, _) = w[1].node;
+ if let StmtKind::Semi(ref first) = w[0].node;
+ if let StmtKind::Semi(ref second) = w[1].node;
if !differing_macro_contexts(first.span, second.span);
if let ExprKind::Assign(ref lhs0, ref rhs0) = first.node;
if let ExprKind::Assign(ref lhs1, ref rhs1) = second.node;
&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!(