From efbcb99b73d3180f6d667fdad2efdbe6317c30d4 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Thu, 2 Mar 2023 14:29:45 -0500 Subject: [PATCH] Use `snippet_with_context` more --- .../src/casts/cast_slice_from_raw_parts.rs | 8 +- .../src/default_instead_of_iter_empty.rs | 16 ++- clippy_lints/src/format.rs | 6 +- clippy_lints/src/implicit_saturating_add.rs | 16 ++- clippy_lints/src/instant_subtraction.rs | 13 +- clippy_lints/src/len_zero.rs | 17 +-- clippy_lints/src/manual_bits.rs | 11 +- clippy_lints/src/manual_is_ascii_check.rs | 15 +-- clippy_lints/src/manual_rem_euclid.rs | 8 +- clippy_lints/src/match_result_ok.rs | 25 ++-- clippy_lints/src/neg_multiply.rs | 6 +- .../src/non_octal_unix_permissions.rs | 2 + clippy_lints/src/swap.rs | 111 ++++++++++-------- tests/ui/match_result_ok.fixed | 2 +- tests/ui/match_result_ok.stderr | 2 +- tests/ui/swap.fixed | 6 +- tests/ui/swap.stderr | 24 ++-- 17 files changed, 159 insertions(+), 129 deletions(-) diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 627b795d6..1233c632a 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -34,6 +34,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, if let ExprKind::Path(ref qpath) = fun.kind; if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); if let Some(rpk) = raw_parts_kind(cx, fun_def_id); + let ctxt = expr.span.ctxt(); + if cast_expr.span.ctxt() == ctxt; then { let func = match rpk { RawPartsKind::Immutable => "from_raw_parts", @@ -41,8 +43,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, }; let span = expr.span; let mut applicability = Applicability::MachineApplicable; - let ptr = snippet_with_applicability(cx, ptr_arg.span, "ptr", &mut applicability); - let len = snippet_with_applicability(cx, len_arg.span, "len", &mut applicability); + let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0; + let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0; span_lint_and_sugg( cx, CAST_SLICE_FROM_RAW_PARTS, diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs index 1ad929864..f296b80d2 100644 --- a/clippy_lints/src/default_instead_of_iter_empty.rs +++ b/clippy_lints/src/default_instead_of_iter_empty.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::last_path_segment; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::{match_def_path, paths}; use rustc_errors::Applicability; use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::SyntaxContext; declare_clippy_lint! { /// ### What it does @@ -38,9 +39,11 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { && let QPath::Resolved(None, path) = ty_path && let def::Res::Def(_, def_id) = &path.res && match_def_path(cx, *def_id, &paths::ITER_EMPTY) + && let ctxt = expr.span.ctxt() + && ty.span.ctxt() == ctxt { let mut applicability = Applicability::MachineApplicable; - let sugg = make_sugg(cx, ty_path, &mut applicability); + let sugg = make_sugg(cx, ty_path, ctxt, &mut applicability); span_lint_and_sugg( cx, DEFAULT_INSTEAD_OF_ITER_EMPTY, @@ -54,14 +57,19 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty { } } -fn make_sugg(cx: &LateContext<'_>, ty_path: &rustc_hir::QPath<'_>, applicability: &mut Applicability) -> String { +fn make_sugg( + cx: &LateContext<'_>, + ty_path: &rustc_hir::QPath<'_>, + ctxt: SyntaxContext, + applicability: &mut Applicability, +) -> String { if let Some(last) = last_path_segment(ty_path).args && let Some(iter_ty) = last.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), _ => None, }) { - format!("std::iter::empty::<{}>()", snippet_with_applicability(cx, iter_ty.span, "..", applicability)) + format!("std::iter::empty::<{}>()", snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0) } else { "std::iter::empty()".to_owned() } diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index d0fab6949..8040938c6 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; @@ -84,9 +84,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { _ => false, }; let sugg = if is_new_string { - snippet_with_applicability(cx, value.span, "..", &mut applicability).into_owned() + snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned() } else { - let sugg = Sugg::hir_with_applicability(cx, value, "", &mut applicability); + let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "", &mut applicability); format!("{}.to_string()", sugg.maybe_par()) }; span_useless_format(cx, call_site, sugg, applicability); diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs index 6e1934393..57e6caa87 100644 --- a/clippy_lints/src/implicit_saturating_add.rs +++ b/clippy_lints/src/implicit_saturating_add.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use if_chain::if_chain; use rustc_ast::ast::{LitIntType, LitKind}; use rustc_errors::Applicability; @@ -55,6 +55,9 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { if let ExprKind::AssignOp(op1, target, value) = ex.kind; let ty = cx.typeck_results().expr_ty(target); if Some(c) == get_int_max(ty); + let ctxt = expr.span.ctxt(); + if ex.span.ctxt() == ctxt; + if expr1.span.ctxt() == ctxt; if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target); if BinOpKind::Add == op1.node; if let ExprKind::Lit(ref lit) = value.kind; @@ -62,8 +65,15 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { if block.expr.is_none(); then { let mut app = Applicability::MachineApplicable; - let code = snippet_with_applicability(cx, target.span, "_", &mut app); - let sugg = if let Some(parent) = get_parent_expr(cx, expr) && let ExprKind::If(_cond, _then, Some(else_)) = parent.kind && else_.hir_id == expr.hir_id {format!("{{{code} = {code}.saturating_add(1); }}")} else {format!("{code} = {code}.saturating_add(1);")}; + let code = snippet_with_context(cx, target.span, ctxt, "_", &mut app).0; + let sugg = if let Some(parent) = get_parent_expr(cx, expr) + && let ExprKind::If(_cond, _then, Some(else_)) = parent.kind + && else_.hir_id == expr.hir_id + { + format!("{{{code} = {code}.saturating_add(1); }}") + } else { + format!("{code} = {code}.saturating_add(1);") + }; span_lint_and_sugg(cx, IMPLICIT_SATURATING_ADD, expr.span, "manual saturating add detected", "use instead", sugg, app); } } diff --git a/clippy_lints/src/instant_subtraction.rs b/clippy_lints/src/instant_subtraction.rs index 668110c7c..34e999158 100644 --- a/clippy_lints/src/instant_subtraction.rs +++ b/clippy_lints/src/instant_subtraction.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{self, span_lint_and_sugg}; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::ty; use rustc_errors::Applicability; @@ -161,14 +161,9 @@ fn print_unchecked_duration_subtraction_sugg( ) { let mut applicability = Applicability::MachineApplicable; - let left_expr = - source::snippet_with_applicability(cx, left_expr.span, "std::time::Instant::now()", &mut applicability); - let right_expr = source::snippet_with_applicability( - cx, - right_expr.span, - "std::time::Duration::from_secs(1)", - &mut applicability, - ); + let ctxt = expr.span.ctxt(); + let left_expr = snippet_with_context(cx, left_expr.span, ctxt, "", &mut applicability).0; + let right_expr = snippet_with_context(cx, right_expr.span, ctxt, "", &mut applicability).0; diagnostics::span_lint_and_sugg( cx, diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index e13bc4797..6c32393dc 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators}; +use clippy_utils::source::snippet_with_context; +use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators, sugg::Sugg}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def_id::DefIdSet; use rustc_hir::{ def_id::DefId, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, ImplItem, ImplItemKind, ImplicitSelfKind, Item, - ItemKind, Mutability, Node, TraitItemRef, TyKind, UnOp, + ItemKind, Mutability, Node, TraitItemRef, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AssocKind, FnSig, Ty}; @@ -16,7 +16,6 @@ use rustc_span::{ source_map::{Span, Spanned, Symbol}, symbol::sym, }; -use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -431,7 +430,7 @@ fn check_len( &format!("using `{op}is_empty` is clearer and more explicit"), format!( "{op}{}.is_empty()", - snippet_with_applicability(cx, receiver.span, "_", &mut applicability) + snippet_with_context(cx, receiver.span, span.ctxt(), "_", &mut applicability).0, ), applicability, ); @@ -444,13 +443,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex let mut applicability = Applicability::MachineApplicable; let lit1 = peel_ref_operators(cx, lit1); - let mut lit_str = snippet_with_applicability(cx, lit1.span, "_", &mut applicability); - - // Wrap the expression in parentheses if it's a deref expression. Otherwise operator precedence will - // cause the code to dereference boolean(won't compile). - if let ExprKind::Unary(UnOp::Deref, _) = lit1.kind { - lit_str = Cow::from(format!("({lit_str})")); - } + let lit_str = Sugg::hir_with_context(cx, lit1, span.ctxt(), "_", &mut applicability).maybe_par(); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 462d73cf0..bc815dc4a 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_expr; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; @@ -55,13 +56,17 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits { if_chain! { if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind; if let BinOpKind::Mul = &bin_op.node; + if !in_external_macro(cx.sess(), expr.span); + let ctxt = expr.span.ctxt(); + if left_expr.span.ctxt() == ctxt; + if right_expr.span.ctxt() == ctxt; if let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr); if matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_)); if let ExprKind::Lit(lit) = &other_expr.kind; if let LitKind::Int(8, _) = lit.node; then { let mut app = Applicability::MachineApplicable; - let ty_snip = snippet_with_applicability(cx, real_ty.span, "..", &mut app); + let ty_snip = snippet_with_context(cx, real_ty.span, ctxt, "..", &mut app).0; let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS")); span_lint_and_sugg( diff --git a/clippy_lints/src/manual_is_ascii_check.rs b/clippy_lints/src/manual_is_ascii_check.rs index 2fd32c009..31264261f 100644 --- a/clippy_lints/src/manual_is_ascii_check.rs +++ b/clippy_lints/src/manual_is_ascii_check.rs @@ -1,5 +1,5 @@ use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, source::snippet}; +use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, sugg::Sugg}; use rustc_ast::ast::RangeLimits; use rustc_ast::LitKind::{Byte, Char}; use rustc_errors::Applicability; @@ -115,15 +115,8 @@ fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &Cha CharRange::Otherwise => None, } { let default_snip = ".."; - // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for - // macro span, so we check applicability manually by comparing `recv` is not default. - let recv = snippet(cx, recv.span, default_snip); - - let applicability = if recv == default_snip { - Applicability::HasPlaceholders - } else { - Applicability::MachineApplicable - }; + let mut app = Applicability::MachineApplicable; + let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par(); span_lint_and_sugg( cx, @@ -132,7 +125,7 @@ fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &Cha "manual check for common ascii range", "try", format!("{recv}.{sugg}()"), - applicability, + app, ); } } diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs index 38f41d077..aafee9271 100644 --- a/clippy_lints/src/manual_rem_euclid.rs +++ b/clippy_lints/src/manual_rem_euclid.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::{constant_full_int, FullInt}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::{in_constant, path_to_local}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind}; @@ -60,12 +60,16 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { return; } + // (x % c + c) % c if let ExprKind::Binary(op1, expr1, right) = expr.kind && op1.node == BinOpKind::Rem + && let ctxt = expr.span.ctxt() + && expr1.span.ctxt() == ctxt && let Some(const1) = check_for_unsigned_int_constant(cx, right) && let ExprKind::Binary(op2, left, right) = expr1.kind && op2.node == BinOpKind::Add && let Some((const2, expr2)) = check_for_either_unsigned_int_constant(cx, left, right) + && expr2.span.ctxt() == ctxt && let ExprKind::Binary(op3, expr3, right) = expr2.kind && op3.node == BinOpKind::Rem && let Some(const3) = check_for_unsigned_int_constant(cx, right) @@ -86,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { }; let mut app = Applicability::MachineApplicable; - let rem_of = snippet_with_applicability(cx, expr3.span, "_", &mut app); + let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0; span_lint_and_sugg( cx, MANUAL_REM_EUCLID, diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index a020282d2..6ec978403 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher; -use clippy_utils::method_chain_args; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::is_res_lang_ctor; +use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, PatKind, QPath}; +use rustc_hir::{Expr, ExprKind, LangItem, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -58,17 +58,18 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { }; if_chain! { - if let ExprKind::MethodCall(ok_path, result_types_0, ..) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) - if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation - if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result); - if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some"; - + if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) + if let PatKind::TupleStruct(ref pat_path, [ok_pat], _) = let_pat.kind; //get operation + if ok_path.ident.as_str() == "ok"; + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); + if is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome); + let ctxt = expr.span.ctxt(); + if let_expr.span.ctxt() == ctxt; + if let_pat.span.ctxt() == ctxt; then { - let mut applicability = Applicability::MachineApplicable; - let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability); - let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_path.ident.span), "", &mut applicability); + let some_expr_string = snippet_with_context(cx, ok_pat.span, ctxt, "", &mut applicability).0; + let trimmed_ok = snippet_with_context(cx, recv.span, ctxt, "", &mut applicability).0; let sugg = format!( "{ifwhile} let Ok({some_expr_string}) = {}", trimmed_ok.trim().trim_end_matches('.'), diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs index fb9a4abd0..ed3e2c6e7 100644 --- a/clippy_lints/src/neg_multiply.rs +++ b/clippy_lints/src/neg_multiply.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::{self, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::has_enclosing_paren; use if_chain::if_chain; use rustc_ast::util::parser::PREC_PREFIX; @@ -60,8 +60,8 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { then { let mut applicability = Applicability::MachineApplicable; - let snip = snippet_with_applicability(cx, exp.span, "..", &mut applicability); - let suggestion = if exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) { + let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability); + let suggestion = if !from_macro && exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) { format!("-({snip})") } else { format!("-{snip}") diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index 2ecb04874..e1de494eb 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -53,6 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { || is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder))) || (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS)); if let ExprKind::Lit(_) = param.kind; + if param.span.ctxt() == expr.span.ctxt(); then { let Some(snip) = snippet_opt(cx, param.span) else { @@ -71,6 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE); if let ExprKind::Lit(_) = param.kind; + if param.span.ctxt() == expr.span.ctxt(); if let Some(snip) = snippet_opt(cx, param.span); if !snip.starts_with("0o"); then { diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 0f062cecf..1aeac724a 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core}; @@ -10,6 +10,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; +use rustc_span::SyntaxContext; use rustc_span::{sym, symbol::Ident, Span}; declare_clippy_lint! { @@ -80,43 +81,45 @@ impl<'tcx> LateLintPass<'tcx> for Swap { } fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, span: Span, is_xor_based: bool) { + let ctxt = span.ctxt(); let mut applicability = Applicability::MachineApplicable; if !can_mut_borrow_both(cx, e1, e2) { - if let ExprKind::Index(lhs1, idx1) = e1.kind { - if let ExprKind::Index(lhs2, idx2) = e2.kind { - if eq_expr_value(cx, lhs1, lhs2) { - let ty = cx.typeck_results().expr_ty(lhs1).peel_refs(); + if let ExprKind::Index(lhs1, idx1) = e1.kind + && let ExprKind::Index(lhs2, idx2) = e2.kind + && eq_expr_value(cx, lhs1, lhs2) + && e1.span.ctxt() == ctxt + && e2.span.ctxt() == ctxt + { + let ty = cx.typeck_results().expr_ty(lhs1).peel_refs(); - if matches!(ty.kind(), ty::Slice(_)) - || matches!(ty.kind(), ty::Array(_, _)) - || is_type_diagnostic_item(cx, ty, sym::Vec) - || is_type_diagnostic_item(cx, ty, sym::VecDeque) - { - let slice = Sugg::hir_with_applicability(cx, lhs1, "", &mut applicability); - span_lint_and_sugg( - cx, - MANUAL_SWAP, - span, - &format!("this looks like you are swapping elements of `{slice}` manually"), - "try", - format!( - "{}.swap({}, {})", - slice.maybe_par(), - snippet_with_applicability(cx, idx1.span, "..", &mut applicability), - snippet_with_applicability(cx, idx2.span, "..", &mut applicability), - ), - applicability, - ); - } - } + if matches!(ty.kind(), ty::Slice(_)) + || matches!(ty.kind(), ty::Array(_, _)) + || is_type_diagnostic_item(cx, ty, sym::Vec) + || is_type_diagnostic_item(cx, ty, sym::VecDeque) + { + let slice = Sugg::hir_with_applicability(cx, lhs1, "", &mut applicability); + span_lint_and_sugg( + cx, + MANUAL_SWAP, + span, + &format!("this looks like you are swapping elements of `{slice}` manually"), + "try", + format!( + "{}.swap({}, {});", + slice.maybe_par(), + snippet_with_context(cx, idx1.span, ctxt, "..", &mut applicability).0, + snippet_with_context(cx, idx2.span, ctxt, "..", &mut applicability).0, + ), + applicability, + ); } } return; } - let first = Sugg::hir_with_applicability(cx, e1, "..", &mut applicability); - let second = Sugg::hir_with_applicability(cx, e2, "..", &mut applicability); + let first = Sugg::hir_with_context(cx, e1, ctxt, "..", &mut applicability); + let second = Sugg::hir_with_context(cx, e2, ctxt, "..", &mut applicability); let Some(sugg) = std_or_core(cx) else { return }; span_lint_and_then( @@ -128,7 +131,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa diag.span_suggestion( span, "try", - format!("{sugg}::mem::swap({}, {})", first.mut_addr(), second.mut_addr()), + format!("{sugg}::mem::swap({}, {});", first.mut_addr(), second.mut_addr()), applicability, ); if !is_xor_based { @@ -144,19 +147,19 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { return; } - for w in block.stmts.windows(3) { + for [s1, s2, s3] in block.stmts.array_windows::<3>() { if_chain! { // let t = foo(); - if let StmtKind::Local(tmp) = w[0].kind; + if let StmtKind::Local(tmp) = s1.kind; if let Some(tmp_init) = tmp.init; if let PatKind::Binding(.., ident, None) = tmp.pat.kind; // foo() = bar(); - if let StmtKind::Semi(first) = w[1].kind; + if let StmtKind::Semi(first) = s2.kind; if let ExprKind::Assign(lhs1, rhs1, _) = first.kind; // bar() = t; - if let StmtKind::Semi(second) = w[2].kind; + if let StmtKind::Semi(second) = s3.kind; if let ExprKind::Assign(lhs2, rhs2, _) = second.kind; if let ExprKind::Path(QPath::Resolved(None, rhs2)) = rhs2.kind; if rhs2.segments.len() == 1; @@ -164,8 +167,15 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) { if ident.name == rhs2.segments[0].ident.name; if eq_expr_value(cx, tmp_init, lhs1); if eq_expr_value(cx, rhs1, lhs2); + + let ctxt = s1.span.ctxt(); + if s2.span.ctxt() == ctxt; + if s3.span.ctxt() == ctxt; + if first.span.ctxt() == ctxt; + if second.span.ctxt() == ctxt; + then { - let span = w[0].span.to(second.span); + let span = s1.span.to(s3.span); generate_swap_warning(cx, lhs1, lhs2, span, false); } } @@ -246,17 +256,20 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr< /// Implementation of the xor case for `MANUAL_SWAP` lint. fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) { - for window in block.stmts.windows(3) { + for [s1, s2, s3] in block.stmts.array_windows::<3>() { if_chain! { - if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(&window[0]); - if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(&window[1]); - if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(&window[2]); + let ctxt = s1.span.ctxt(); + if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt); + if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(s2, ctxt); + if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(s3, ctxt); if eq_expr_value(cx, lhs0, rhs1); if eq_expr_value(cx, lhs2, rhs1); if eq_expr_value(cx, lhs1, rhs0); if eq_expr_value(cx, lhs1, rhs2); + if s2.span.ctxt() == ctxt; + if s3.span.ctxt() == ctxt; then { - let span = window[0].span.to(window[2].span); + let span = s1.span.to(s3.span); generate_swap_warning(cx, lhs0, rhs0, span, true); } }; @@ -264,9 +277,12 @@ fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) { } /// Returns the lhs and rhs of an xor assignment statement. -fn extract_sides_of_xor_assign<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(&'a Expr<'hir>, &'a Expr<'hir>)> { - if let StmtKind::Semi(expr) = stmt.kind { - if let ExprKind::AssignOp( +fn extract_sides_of_xor_assign<'a, 'hir>( + stmt: &'a Stmt<'hir>, + ctxt: SyntaxContext, +) -> Option<(&'a Expr<'hir>, &'a Expr<'hir>)> { + if let StmtKind::Semi(expr) = stmt.kind + && let ExprKind::AssignOp( Spanned { node: BinOpKind::BitXor, .. @@ -274,9 +290,10 @@ fn extract_sides_of_xor_assign<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(&'a Ex lhs, rhs, ) = expr.kind - { - return Some((lhs, rhs)); - } + && expr.span.ctxt() == ctxt + { + Some((lhs, rhs)) + } else { + None } - None } diff --git a/tests/ui/match_result_ok.fixed b/tests/ui/match_result_ok.fixed index 8b91b9854..10ae1ee52 100644 --- a/tests/ui/match_result_ok.fixed +++ b/tests/ui/match_result_ok.fixed @@ -16,7 +16,7 @@ fn str_to_int_ok(x: &str) -> i32 { #[rustfmt::skip] fn strange_some_no_else(x: &str) -> i32 { { - if let Ok(y) = x . parse() { + if let Ok(y) = x . parse() { return y; }; 0 diff --git a/tests/ui/match_result_ok.stderr b/tests/ui/match_result_ok.stderr index 98a95705c..cbdc56aa2 100644 --- a/tests/ui/match_result_ok.stderr +++ b/tests/ui/match_result_ok.stderr @@ -18,7 +18,7 @@ LL | if let Some(y) = x . parse() . ok () { | help: consider matching on `Ok(y)` and removing the call to `ok` instead | -LL | if let Ok(y) = x . parse() { +LL | if let Ok(y) = x . parse() { | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: matching on `Some` with `ok()` is redundant diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed index fa89706a8..04008c0d9 100644 --- a/tests/ui/swap.fixed +++ b/tests/ui/swap.fixed @@ -65,19 +65,19 @@ fn xor_swap_locals() { // This is an xor-based swap of local variables. let mut a = 0; let mut b = 1; - std::mem::swap(&mut a, &mut b) + std::mem::swap(&mut a, &mut b); } fn xor_field_swap() { // This is an xor-based swap of fields in a struct. let mut bar = Bar { a: 0, b: 1 }; - std::mem::swap(&mut bar.a, &mut bar.b) + std::mem::swap(&mut bar.a, &mut bar.b); } fn xor_slice_swap() { // This is an xor-based swap of a slice let foo = &mut [1, 2]; - foo.swap(0, 1) + foo.swap(0, 1); } fn xor_no_swap() { diff --git a/tests/ui/swap.stderr b/tests/ui/swap.stderr index f0acbfe25..825c9261e 100644 --- a/tests/ui/swap.stderr +++ b/tests/ui/swap.stderr @@ -4,7 +4,7 @@ error: this looks like you are swapping `bar.a` and `bar.b` manually LL | / let temp = bar.a; LL | | bar.a = bar.b; LL | | bar.b = temp; - | |________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b)` + | |_________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);` | = note: or maybe you should use `std::mem::replace`? = note: `-D clippy::manual-swap` implied by `-D warnings` @@ -15,7 +15,7 @@ error: this looks like you are swapping elements of `foo` manually LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; LL | | foo[1] = temp; - | |_________________^ help: try: `foo.swap(0, 1)` + | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually --> $DIR/swap.rs:46:5 @@ -23,7 +23,7 @@ error: this looks like you are swapping elements of `foo` manually LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; LL | | foo[1] = temp; - | |_________________^ help: try: `foo.swap(0, 1)` + | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually --> $DIR/swap.rs:65:5 @@ -31,7 +31,7 @@ error: this looks like you are swapping elements of `foo` manually LL | / let temp = foo[0]; LL | | foo[0] = foo[1]; LL | | foo[1] = temp; - | |_________________^ help: try: `foo.swap(0, 1)` + | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `a` and `b` manually --> $DIR/swap.rs:76:5 @@ -39,7 +39,7 @@ error: this looks like you are swapping `a` and `b` manually LL | / a ^= b; LL | | b ^= a; LL | | a ^= b; - | |___________^ help: try: `std::mem::swap(&mut a, &mut b)` + | |___________^ help: try: `std::mem::swap(&mut a, &mut b);` error: this looks like you are swapping `bar.a` and `bar.b` manually --> $DIR/swap.rs:84:5 @@ -47,7 +47,7 @@ error: this looks like you are swapping `bar.a` and `bar.b` manually LL | / bar.a ^= bar.b; LL | | bar.b ^= bar.a; LL | | bar.a ^= bar.b; - | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b)` + | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);` error: this looks like you are swapping elements of `foo` manually --> $DIR/swap.rs:92:5 @@ -55,7 +55,7 @@ error: this looks like you are swapping elements of `foo` manually LL | / foo[0] ^= foo[1]; LL | | foo[1] ^= foo[0]; LL | | foo[0] ^= foo[1]; - | |_____________________^ help: try: `foo.swap(0, 1)` + | |_____________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually --> $DIR/swap.rs:121:5 @@ -63,7 +63,7 @@ error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually LL | / let temp = foo[0][1]; LL | | foo[0][1] = bar[1][0]; LL | | bar[1][0] = temp; - | |____________________^ help: try: `std::mem::swap(&mut foo[0][1], &mut bar[1][0])` + | |_____________________^ help: try: `std::mem::swap(&mut foo[0][1], &mut bar[1][0]);` | = note: or maybe you should use `std::mem::replace`? @@ -74,7 +74,7 @@ LL | ; let t = a; | _______^ LL | | a = b; LL | | b = t; - | |_________^ help: try: `std::mem::swap(&mut a, &mut b)` + | |__________^ help: try: `std::mem::swap(&mut a, &mut b);` | = note: or maybe you should use `std::mem::replace`? @@ -85,7 +85,7 @@ LL | ; let t = c.0; | _______^ LL | | c.0 = a; LL | | a = t; - | |_________^ help: try: `std::mem::swap(&mut c.0, &mut a)` + | |__________^ help: try: `std::mem::swap(&mut c.0, &mut a);` | = note: or maybe you should use `std::mem::replace`? @@ -95,7 +95,7 @@ error: this looks like you are swapping `b` and `a` manually LL | / let t = b; LL | | b = a; LL | | a = t; - | |_________^ help: try: `std::mem::swap(&mut b, &mut a)` + | |__________^ help: try: `std::mem::swap(&mut b, &mut a);` | = note: or maybe you should use `std::mem::replace`? @@ -151,7 +151,7 @@ error: this looks like you are swapping `s.0.x` and `s.0.y` manually LL | / let t = s.0.x; LL | | s.0.x = s.0.y; LL | | s.0.y = t; - | |_____________^ help: try: `std::mem::swap(&mut s.0.x, &mut s.0.y)` + | |______________^ help: try: `std::mem::swap(&mut s.0.x, &mut s.0.y);` | = note: or maybe you should use `std::mem::replace`?