mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 15:11:30 +00:00
Auto merge of #10438 - Jarcho:use_snip_ctxt, r=dswij
Use `snippet_with_context` more No tests at the moment. Need to find a way to write macro tests without writing a pile of macros. changelog: None
This commit is contained in:
commit
783bc621a1
17 changed files with 159 additions and 129 deletions
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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, "<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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<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('.'),
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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, "<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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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`?
|
||||
|
||||
|
|
Loading…
Reference in a new issue