Use snippet_with_context more

This commit is contained in:
Jason Newcomb 2023-03-02 14:29:45 -05:00
parent 113c704d22
commit efbcb99b73
17 changed files with 159 additions and 129 deletions

View File

@ -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,

View File

@ -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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
&& 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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
}
}
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()
}

View File

@ -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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
_ => 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, "<arg>", &mut applicability);
let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "<arg>", &mut applicability);
format!("{}.to_string()", sugg.maybe_par())
};
span_useless_format(cx, call_site, sugg, applicability);

View File

@ -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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
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);
}
}

View File

@ -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, "<instant>", &mut applicability).0;
let right_expr = snippet_with_context(cx, right_expr.span, ctxt, "<duration>", &mut applicability).0;
diagnostics::span_lint_and_sugg(
cx,

View File

@ -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 @@
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,

View File

@ -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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
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(

View File

@ -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,
);
}
}

View File

@ -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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
};
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,

View File

@ -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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
};
if_chain! {
if let ExprKind::MethodCall(ok_path, result_types_0, ..) = let_expr.kind; //check is expr.ok() has type Result<T,E>.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<T,E>.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('.'),

View File

@ -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}")

View File

@ -53,6 +53,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|| 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 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
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 {

View File

@ -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_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 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
}
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, "<slice>", &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, "<slice>", &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
}

View File

@ -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

View File

@ -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

View File

@ -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() {

View File

@ -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`?