mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
@@ -6797,9 +6797,11 @@ Released 2018-09-13
|
||||
[`manual_midpoint`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_midpoint
|
||||
[`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back
|
||||
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
|
||||
[`manual_noop_waker`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_noop_waker
|
||||
[`manual_ok_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_err
|
||||
[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
|
||||
[`manual_option_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_option_as_slice
|
||||
[`manual_option_zip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_option_zip
|
||||
[`manual_pattern_char_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison
|
||||
[`manual_pop_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pop_if
|
||||
[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#![feature(
|
||||
exit_status_error,
|
||||
new_range,
|
||||
new_range_api,
|
||||
os_str_slice,
|
||||
os_string_truncate,
|
||||
pattern,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::numeric_literal::NumericLiteral;
|
||||
use clippy_utils::res::MaybeResPath as _;
|
||||
use clippy_utils::source::{SpanRangeExt, snippet_opt};
|
||||
use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability};
|
||||
use clippy_utils::sugg::has_enclosing_paren;
|
||||
use clippy_utils::visitors::{Visitable, for_each_expr_without_closures};
|
||||
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, sym};
|
||||
use rustc_ast::{LitFloatType, LitIntType, LitKind};
|
||||
@@ -24,7 +25,8 @@ pub(super) fn check<'tcx>(
|
||||
cast_from: Ty<'tcx>,
|
||||
cast_to: Ty<'tcx>,
|
||||
) -> bool {
|
||||
let cast_str = snippet_opt(cx, cast_expr.span).unwrap_or_default();
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let cast_str = snippet_with_applicability(cx, cast_expr.span, "_", &mut app);
|
||||
|
||||
if let ty::RawPtr(..) = cast_from.kind()
|
||||
// check both mutability and type are the same
|
||||
@@ -47,16 +49,23 @@ pub(super) fn check<'tcx>(
|
||||
_ => {},
|
||||
}
|
||||
|
||||
span_lint_and_sugg(
|
||||
// Preserve parentheses around `expr` in case of cascaded casts
|
||||
let surrounding =
|
||||
if matches!(cast_expr.kind, ExprKind::Cast(..)) && has_enclosing_paren(snippet(cx, expr.span, "")) {
|
||||
MaybeParenOrBlock::Paren
|
||||
} else {
|
||||
MaybeParenOrBlock::Nothing
|
||||
};
|
||||
|
||||
emit_lint(
|
||||
cx,
|
||||
UNNECESSARY_CAST,
|
||||
expr.span,
|
||||
expr,
|
||||
format!(
|
||||
"casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"
|
||||
),
|
||||
"try",
|
||||
cast_str.clone(),
|
||||
Applicability::MaybeIncorrect,
|
||||
&cast_str,
|
||||
surrounding,
|
||||
app.max(Applicability::MaybeIncorrect),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -143,12 +152,6 @@ pub(super) fn check<'tcx>(
|
||||
}
|
||||
|
||||
if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) {
|
||||
enum MaybeParenOrBlock {
|
||||
Paren,
|
||||
Block,
|
||||
Nothing,
|
||||
}
|
||||
|
||||
fn is_borrow_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
matches!(expr.kind, ExprKind::AddrOf(..))
|
||||
|| cx
|
||||
@@ -188,18 +191,13 @@ fn is_in_allowed_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
_ => MaybeParenOrBlock::Nothing,
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
emit_lint(
|
||||
cx,
|
||||
UNNECESSARY_CAST,
|
||||
expr.span,
|
||||
expr,
|
||||
format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
|
||||
"try",
|
||||
match surrounding {
|
||||
MaybeParenOrBlock::Paren => format!("({cast_str})"),
|
||||
MaybeParenOrBlock::Block => format!("{{ {cast_str} }}"),
|
||||
MaybeParenOrBlock::Nothing => cast_str,
|
||||
},
|
||||
Applicability::MachineApplicable,
|
||||
&cast_str,
|
||||
surrounding,
|
||||
app,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
@@ -312,3 +310,33 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
|
||||
})
|
||||
.is_some()
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum MaybeParenOrBlock {
|
||||
Paren,
|
||||
Block,
|
||||
Nothing,
|
||||
}
|
||||
|
||||
fn emit_lint(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
msg: String,
|
||||
sugg: &str,
|
||||
surrounding: MaybeParenOrBlock,
|
||||
applicability: Applicability,
|
||||
) {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNNECESSARY_CAST,
|
||||
expr.span,
|
||||
msg,
|
||||
"try",
|
||||
match surrounding {
|
||||
MaybeParenOrBlock::Paren => format!("({sugg})"),
|
||||
MaybeParenOrBlock::Block => format!("{{ {sugg} }}"),
|
||||
MaybeParenOrBlock::Nothing => sugg.to_string(),
|
||||
},
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::msrvs::Msrv;
|
||||
use clippy_utils::source::{HasSession, IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability};
|
||||
use clippy_utils::{can_use_if_let_chains, span_contains_non_whitespace, sym, tokenize_with_text};
|
||||
use clippy_utils::{can_use_if_let_chains, span_contains_cfg, span_contains_non_whitespace, sym, tokenize_with_text};
|
||||
use rustc_ast::{BinOpKind, MetaItemInner};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, StmtKind};
|
||||
@@ -169,6 +169,11 @@ fn check_collapsible_if_if(&self, cx: &LateContext<'_>, expr: &Expr<'_>, check:
|
||||
&& self.eligible_condition(cx, check_inner)
|
||||
&& expr.span.eq_ctxt(inner.span)
|
||||
&& self.check_significant_tokens_and_expect_attrs(cx, then, inner, sym::collapsible_if)
|
||||
&& let then_closing_bracket = {
|
||||
let end = then.span.shrink_to_hi();
|
||||
end.with_lo(end.lo() - BytePos(1))
|
||||
}
|
||||
&& !span_contains_cfg(cx, inner.span.between(then_closing_bracket))
|
||||
{
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
@@ -178,12 +183,7 @@ fn check_collapsible_if_if(&self, cx: &LateContext<'_>, expr: &Expr<'_>, check:
|
||||
"this `if` statement can be collapsed",
|
||||
|diag| {
|
||||
let then_open_bracket = then.span.split_at(1).0.with_leading_whitespace(cx).into_span();
|
||||
let then_closing_bracket = {
|
||||
let end = then.span.shrink_to_hi();
|
||||
end.with_lo(end.lo() - BytePos(1))
|
||||
.with_leading_whitespace(cx)
|
||||
.into_span()
|
||||
};
|
||||
let then_closing_bracket = then_closing_bracket.with_leading_whitespace(cx).into_span();
|
||||
let (paren_start, inner_if_span, paren_end) = peel_parens(cx, inner.span);
|
||||
let inner_if = inner_if_span.split_at(2).0;
|
||||
let mut sugg = vec![
|
||||
|
||||
@@ -311,6 +311,7 @@
|
||||
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
|
||||
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
|
||||
crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
|
||||
crate::manual_noop_waker::MANUAL_NOOP_WAKER_INFO,
|
||||
crate::manual_option_as_slice::MANUAL_OPTION_AS_SLICE_INFO,
|
||||
crate::manual_pop_if::MANUAL_POP_IF_INFO,
|
||||
crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO,
|
||||
@@ -418,6 +419,7 @@
|
||||
crate::methods::MANUAL_IS_VARIANT_AND_INFO,
|
||||
crate::methods::MANUAL_NEXT_BACK_INFO,
|
||||
crate::methods::MANUAL_OK_OR_INFO,
|
||||
crate::methods::MANUAL_OPTION_ZIP_INFO,
|
||||
crate::methods::MANUAL_REPEAT_N_INFO,
|
||||
crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO,
|
||||
crate::methods::MANUAL_SPLIT_ONCE_INFO,
|
||||
|
||||
@@ -209,6 +209,7 @@
|
||||
mod manual_let_else;
|
||||
mod manual_main_separator_str;
|
||||
mod manual_non_exhaustive;
|
||||
mod manual_noop_waker;
|
||||
mod manual_option_as_slice;
|
||||
mod manual_pop_if;
|
||||
mod manual_range_patterns;
|
||||
@@ -864,7 +865,8 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
|
||||
Box::new(move |tcx| Box::new(duration_suboptimal_units::DurationSuboptimalUnits::new(tcx, conf))),
|
||||
Box::new(move |_| Box::new(manual_take::ManualTake::new(conf))),
|
||||
Box::new(|_| Box::new(manual_checked_ops::ManualCheckedOps)),
|
||||
Box::new(move |_| Box::new(manual_pop_if::ManualPopIf::new(conf))),
|
||||
Box::new(move |tcx| Box::new(manual_pop_if::ManualPopIf::new(tcx, conf))),
|
||||
Box::new(|_| Box::new(manual_noop_waker::ManualNoopWaker)),
|
||||
// add late passes here, used by `cargo dev new_lint`
|
||||
];
|
||||
store.late_passes.extend(late_lints);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use super::{EXPLICIT_COUNTER_LOOP, IncrementVisitor, InitializeVisitor, make_iterator_snippet};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::Range;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::{EMPTY, Sugg};
|
||||
use clippy_utils::{get_enclosing_block, is_integer_const, is_integer_literal_untyped};
|
||||
@@ -83,6 +84,26 @@ pub(super) fn check<'tcx>(
|
||||
snippet
|
||||
});
|
||||
|
||||
// If the loop variable is unused and the range is `0..n`, suggest `(init..).take(n)`.
|
||||
if pat_snippet == "_"
|
||||
&& let Some(range) = Range::hir(cx, arg)
|
||||
&& range.limits == RangeLimits::HalfOpen
|
||||
&& range.start.is_some_and(|start| is_integer_const(cx, start, 0))
|
||||
&& let Some(end) = range.end
|
||||
{
|
||||
let end = snippet_with_applicability(cx, end.span, "..", &mut applicability);
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"consider using",
|
||||
format!(
|
||||
"{loop_label}for {name} in ({}).take({end})",
|
||||
initializer.range(&EMPTY, RangeLimits::HalfOpen)
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
diag.span_suggestion(
|
||||
span,
|
||||
"consider using",
|
||||
|
||||
@@ -385,8 +385,8 @@ fn get_offset<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>]
|
||||
ExprKind::Binary(op, lhs, rhs) => match op.node {
|
||||
BinOpKind::Add => {
|
||||
let offset_opt = get_start(lhs, starts)
|
||||
.and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, o)))
|
||||
.or_else(|| get_start(rhs, starts).and_then(|s| get_offset(cx, lhs, starts).map(|o| (s, o))));
|
||||
.zip(get_offset(cx, rhs, starts))
|
||||
.or_else(|| get_start(rhs, starts).zip(get_offset(cx, lhs, starts)));
|
||||
|
||||
offset_opt.map(|(s, o)| (s, Offset::positive(o)))
|
||||
},
|
||||
|
||||
@@ -91,6 +91,13 @@ enum CharRange {
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if !matches!(
|
||||
expr.kind,
|
||||
ExprKind::Match(_, [_, ..], _) | ExprKind::MethodCall(_, _, [_], _)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.msrv.meets(cx, msrvs::IS_ASCII_DIGIT) {
|
||||
return;
|
||||
}
|
||||
@@ -99,8 +106,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
return;
|
||||
}
|
||||
|
||||
let (arg, span, range) = if let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro)
|
||||
&& let ExprKind::Match(recv, [arm, ..], _) = expr.kind
|
||||
let (arg, span, range) = if let ExprKind::Match(recv, [arm, ..], _) = expr.kind
|
||||
&& let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro)
|
||||
{
|
||||
let recv = peel_ref_operators(cx, recv);
|
||||
let range = check_pat(&arm.pat.kind);
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::{is_empty_block, sym};
|
||||
use rustc_hir::{ImplItemKind, Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for manual implementations of `std::task::Wake` that are empty.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// `Waker::noop()` provides a more performant and cleaner way to create a
|
||||
/// waker that does nothing, avoiding unnecessary `Arc` allocations and
|
||||
/// reference count increments.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # use std::sync::Arc;
|
||||
/// # use std::task::Wake;
|
||||
/// struct MyWaker;
|
||||
/// impl Wake for MyWaker {
|
||||
/// fn wake(self: Arc<Self>) {}
|
||||
/// fn wake_by_ref(self: &Arc<Self>) {}
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// use std::task::Waker;
|
||||
/// let waker = Waker::noop();
|
||||
/// ```
|
||||
#[clippy::version = "1.96.0"]
|
||||
pub MANUAL_NOOP_WAKER,
|
||||
complexity,
|
||||
"manual implementations of noop wakers can be simplified using Waker::noop()"
|
||||
}
|
||||
|
||||
declare_lint_pass!(ManualNoopWaker => [MANUAL_NOOP_WAKER]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualNoopWaker {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
if let ItemKind::Impl(imp) = item.kind
|
||||
&& let Some(trait_ref) = imp.of_trait
|
||||
&& let Some(trait_id) = trait_ref.trait_ref.trait_def_id()
|
||||
&& cx.tcx.is_diagnostic_item(sym::Wake, trait_id)
|
||||
{
|
||||
for impl_item_ref in imp.items {
|
||||
let impl_item = cx
|
||||
.tcx
|
||||
.hir_node_by_def_id(impl_item_ref.owner_id.def_id)
|
||||
.expect_impl_item();
|
||||
|
||||
if let ImplItemKind::Fn(_, body_id) = &impl_item.kind {
|
||||
let body = cx.tcx.hir_body(*body_id);
|
||||
if !is_empty_block(body.value) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
MANUAL_NOOP_WAKER,
|
||||
trait_ref.trait_ref.path.span,
|
||||
"manual implementation of a no-op waker",
|
||||
None,
|
||||
"use `std::task::Waker::noop()` instead",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,19 @@
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{eq_expr_value, is_else_clause, is_lang_item_or_ctor, peel_blocks_with_stmt, sym};
|
||||
use clippy_utils::visitors::{for_each_expr_without_closures, is_local_used};
|
||||
use clippy_utils::{eq_expr_value, is_else_clause, is_lang_item_or_ctor, span_contains_non_whitespace, sym};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, PatKind, RustcVersion, StmtKind};
|
||||
use rustc_errors::{Applicability, MultiSpan};
|
||||
use rustc_hir::{BlockCheckMode, Expr, ExprKind, LangItem, PatKind, StmtKind, UnsafeSource};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
use std::fmt;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@@ -21,11 +23,9 @@
|
||||
/// Using `pop_if` is more concise and idiomatic.
|
||||
///
|
||||
/// ### Known issues
|
||||
/// Currently, the lint does not handle the case where the
|
||||
/// `if` condition is part of an `else if` branch.
|
||||
///
|
||||
/// The lint also does not handle the case where
|
||||
/// the popped value is assigned and used.
|
||||
/// When the popped value is assigned or used in an expression,
|
||||
/// or when the `if` condition is part of an `else if` branch, the
|
||||
/// lint will trigger but will not provide an automatic suggestion.
|
||||
///
|
||||
/// ### Examples
|
||||
/// ```no_run
|
||||
@@ -61,11 +61,24 @@
|
||||
|
||||
pub struct ManualPopIf {
|
||||
msrv: Msrv,
|
||||
binary_heap_pop_if_feature_enabled: bool,
|
||||
}
|
||||
|
||||
impl ManualPopIf {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self { msrv: conf.msrv }
|
||||
pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
msrv: conf.msrv,
|
||||
binary_heap_pop_if_feature_enabled: tcx.features().enabled(sym::binary_heap_pop_if),
|
||||
}
|
||||
}
|
||||
|
||||
fn msrv_compatible(&self, cx: &LateContext<'_>, kind: ManualPopIfKind) -> bool {
|
||||
match kind {
|
||||
ManualPopIfKind::Vec => self.msrv.meets(cx, msrvs::VEC_POP_IF),
|
||||
ManualPopIfKind::VecDequeBack => self.msrv.meets(cx, msrvs::VEC_DEQUE_POP_BACK_IF),
|
||||
ManualPopIfKind::VecDequeFront => self.msrv.meets(cx, msrvs::VEC_DEQUE_POP_FRONT_IF),
|
||||
ManualPopIfKind::BinaryHeap => self.binary_heap_pop_if_feature_enabled,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,20 +88,22 @@ enum ManualPopIfKind {
|
||||
Vec,
|
||||
VecDequeBack,
|
||||
VecDequeFront,
|
||||
BinaryHeap,
|
||||
}
|
||||
|
||||
impl ManualPopIfKind {
|
||||
fn check_method(self) -> Symbol {
|
||||
fn peek_method(self) -> Symbol {
|
||||
match self {
|
||||
ManualPopIfKind::Vec => sym::last,
|
||||
ManualPopIfKind::VecDequeBack => sym::back,
|
||||
ManualPopIfKind::VecDequeFront => sym::front,
|
||||
ManualPopIfKind::BinaryHeap => sym::peek,
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_method(self) -> Symbol {
|
||||
match self {
|
||||
ManualPopIfKind::Vec => sym::pop,
|
||||
ManualPopIfKind::Vec | ManualPopIfKind::BinaryHeap => sym::pop,
|
||||
ManualPopIfKind::VecDequeBack => sym::pop_back,
|
||||
ManualPopIfKind::VecDequeFront => sym::pop_front,
|
||||
}
|
||||
@@ -96,7 +111,7 @@ fn pop_method(self) -> Symbol {
|
||||
|
||||
fn pop_if_method(self) -> Symbol {
|
||||
match self {
|
||||
ManualPopIfKind::Vec => sym::pop_if,
|
||||
ManualPopIfKind::Vec | ManualPopIfKind::BinaryHeap => sym::pop_if,
|
||||
ManualPopIfKind::VecDequeBack => sym::pop_back_if,
|
||||
ManualPopIfKind::VecDequeFront => sym::pop_front_if,
|
||||
}
|
||||
@@ -107,14 +122,7 @@ fn is_diag_item(self, cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
match self {
|
||||
ManualPopIfKind::Vec => ty.is_diag_item(cx, sym::Vec),
|
||||
ManualPopIfKind::VecDequeBack | ManualPopIfKind::VecDequeFront => ty.is_diag_item(cx, sym::VecDeque),
|
||||
}
|
||||
}
|
||||
|
||||
fn msrv(self) -> RustcVersion {
|
||||
match self {
|
||||
ManualPopIfKind::Vec => msrvs::VEC_POP_IF,
|
||||
ManualPopIfKind::VecDequeBack => msrvs::VEC_DEQUE_POP_BACK_IF,
|
||||
ManualPopIfKind::VecDequeFront => msrvs::VEC_DEQUE_POP_FRONT_IF,
|
||||
ManualPopIfKind::BinaryHeap => ty.is_diag_item(cx, sym::BinaryHeap),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,6 +133,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
ManualPopIfKind::Vec => write!(f, "`Vec::pop_if`"),
|
||||
ManualPopIfKind::VecDequeBack => write!(f, "`VecDeque::pop_back_if`"),
|
||||
ManualPopIfKind::VecDequeFront => write!(f, "`VecDeque::pop_front_if`"),
|
||||
ManualPopIfKind::BinaryHeap => write!(f, "`BinaryHeap::pop_if`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,10 +152,18 @@ struct ManualPopIfPattern<'tcx> {
|
||||
|
||||
/// Span of the if expression (including the `if` keyword)
|
||||
if_span: Span,
|
||||
|
||||
/// Span of the:
|
||||
/// - check call (`vec.last().is_some_and(|x| *x > 5)`)
|
||||
/// - pop+unwrap call (`vec.pop().unwrap()`)
|
||||
spans: MultiSpan,
|
||||
|
||||
/// Whether we are able to provide a suggestion
|
||||
suggestable: bool,
|
||||
}
|
||||
|
||||
impl ManualPopIfPattern<'_> {
|
||||
fn emit_lint(&self, cx: &LateContext<'_>) {
|
||||
fn emit_lint(self, cx: &LateContext<'_>) {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let ctxt = self.if_span.ctxt();
|
||||
let collection_snippet = snippet_with_context(cx, self.collection_expr.span, ctxt, "..", &mut app).0;
|
||||
@@ -154,36 +171,23 @@ fn emit_lint(&self, cx: &LateContext<'_>) {
|
||||
let param_name = self.param_name;
|
||||
let pop_if_method = self.kind.pop_if_method();
|
||||
|
||||
let suggestion = format!("{collection_snippet}.{pop_if_method}(|{param_name}| {predicate_snippet});");
|
||||
|
||||
span_lint_and_sugg(
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_POP_IF,
|
||||
self.if_span,
|
||||
self.spans,
|
||||
format!("manual implementation of {}", self.kind),
|
||||
"try",
|
||||
suggestion,
|
||||
app,
|
||||
|diag| {
|
||||
let sugg = format!("{collection_snippet}.{pop_if_method}(|{param_name}| {predicate_snippet});");
|
||||
if self.suggestable {
|
||||
diag.span_suggestion_verbose(self.if_span, "try", sugg, app);
|
||||
} else {
|
||||
diag.help(format!("try refactoring the code using `{sugg}`"));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_value_is_used(then_block: &Expr<'_>) -> bool {
|
||||
let ExprKind::Block(block, _) = then_block.kind else {
|
||||
return true;
|
||||
};
|
||||
|
||||
if block.expr.is_some() {
|
||||
return true;
|
||||
}
|
||||
|
||||
match block.stmts {
|
||||
[stmt] => !matches!(stmt.kind, StmtKind::Semi(_) | StmtKind::Item(_)),
|
||||
[.., last] => matches!(last.kind, StmtKind::Expr(_)),
|
||||
[] => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks for the pattern:
|
||||
/// ```ignore
|
||||
/// if vec.last().is_some_and(|x| *x > 5) {
|
||||
@@ -197,21 +201,17 @@ fn check_is_some_and_pattern<'tcx>(
|
||||
if_expr_span: Span,
|
||||
kind: ManualPopIfKind,
|
||||
) -> Option<ManualPopIfPattern<'tcx>> {
|
||||
if pop_value_is_used(then_block) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let check_method = kind.check_method();
|
||||
let peek_method = kind.peek_method();
|
||||
let pop_method = kind.pop_method();
|
||||
|
||||
if let ExprKind::MethodCall(path, receiver, [closure_arg], _) = cond.kind
|
||||
&& path.ident.name == sym::is_some_and
|
||||
&& let ExprKind::MethodCall(check_path, collection_expr, [], _) = receiver.kind
|
||||
&& check_path.ident.name == check_method
|
||||
&& check_path.ident.name == peek_method
|
||||
&& kind.is_diag_item(cx, collection_expr)
|
||||
&& let ExprKind::Closure(closure) = closure_arg.kind
|
||||
&& let body = cx.tcx.hir_body(closure.body)
|
||||
&& let Some((pop_collection, _pop_span)) = check_pop_unwrap(then_block, pop_method)
|
||||
&& let Some((pop_collection, pop_span, suggestable)) = check_pop_unwrap(cx, then_block, pop_method)
|
||||
&& eq_expr_value(cx, collection_expr, pop_collection)
|
||||
&& let Some(param) = body.params.first()
|
||||
&& let Some(ident) = param.pat.simple_ident()
|
||||
@@ -222,6 +222,8 @@ fn check_is_some_and_pattern<'tcx>(
|
||||
predicate: body.value,
|
||||
param_name: ident.name,
|
||||
if_span: if_expr_span,
|
||||
spans: MultiSpan::from(vec![if_expr_span.with_hi(cond.span.hi()), pop_span]),
|
||||
suggestable,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -243,7 +245,7 @@ fn check_if_let_pattern<'tcx>(
|
||||
if_expr_span: Span,
|
||||
kind: ManualPopIfKind,
|
||||
) -> Option<ManualPopIfPattern<'tcx>> {
|
||||
let check_method = kind.check_method();
|
||||
let peek_method = kind.peek_method();
|
||||
let pop_method = kind.pop_method();
|
||||
|
||||
if let ExprKind::Let(let_expr) = cond.kind
|
||||
@@ -255,7 +257,7 @@ fn check_if_let_pattern<'tcx>(
|
||||
&& is_lang_item_or_ctor(cx, def_id, LangItem::OptionSome)
|
||||
&& let PatKind::Binding(_, binding_id, binding_name, _) = binding_pat.kind
|
||||
&& let ExprKind::MethodCall(path, collection_expr, [], _) = let_expr.init.kind
|
||||
&& path.ident.name == check_method
|
||||
&& path.ident.name == peek_method
|
||||
&& kind.is_diag_item(cx, collection_expr)
|
||||
&& let ExprKind::Block(block, _) = then_block.kind
|
||||
{
|
||||
@@ -271,8 +273,7 @@ fn check_if_let_pattern<'tcx>(
|
||||
|
||||
if let ExprKind::If(inner_cond, inner_then, None) = inner_if.kind
|
||||
&& is_local_used(cx, inner_cond, binding_id)
|
||||
&& !pop_value_is_used(inner_then)
|
||||
&& let Some((pop_collection, _pop_span)) = check_pop_unwrap(inner_then, pop_method)
|
||||
&& let Some((pop_collection, pop_span, suggestable)) = check_pop_unwrap(cx, inner_then, pop_method)
|
||||
&& eq_expr_value(cx, collection_expr, pop_collection)
|
||||
{
|
||||
return Some(ManualPopIfPattern {
|
||||
@@ -281,6 +282,12 @@ fn check_if_let_pattern<'tcx>(
|
||||
predicate: inner_cond,
|
||||
param_name: binding_name.name,
|
||||
if_span: if_expr_span,
|
||||
spans: MultiSpan::from(vec![
|
||||
if_expr_span.with_hi(cond.span.hi()),
|
||||
inner_if.span.with_hi(inner_cond.span.hi()),
|
||||
pop_span,
|
||||
]),
|
||||
suggestable,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -302,11 +309,7 @@ fn check_let_chain_pattern<'tcx>(
|
||||
if_expr_span: Span,
|
||||
kind: ManualPopIfKind,
|
||||
) -> Option<ManualPopIfPattern<'tcx>> {
|
||||
if pop_value_is_used(then_block) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let check_method = kind.check_method();
|
||||
let peek_method = kind.peek_method();
|
||||
let pop_method = kind.pop_method();
|
||||
|
||||
if let ExprKind::Binary(op, left, right) = cond.kind
|
||||
@@ -320,11 +323,10 @@ fn check_let_chain_pattern<'tcx>(
|
||||
&& is_lang_item_or_ctor(cx, def_id, LangItem::OptionSome)
|
||||
&& let PatKind::Binding(_, binding_id, binding_name, _) = binding_pat.kind
|
||||
&& let ExprKind::MethodCall(path, collection_expr, [], _) = let_expr.init.kind
|
||||
&& path.ident.name == check_method
|
||||
&& path.ident.name == peek_method
|
||||
&& kind.is_diag_item(cx, collection_expr)
|
||||
&& is_local_used(cx, right, binding_id)
|
||||
&& !pop_value_is_used(then_block)
|
||||
&& let Some((pop_collection, _pop_span)) = check_pop_unwrap(then_block, pop_method)
|
||||
&& let Some((pop_collection, pop_span, suggestable)) = check_pop_unwrap(cx, then_block, pop_method)
|
||||
&& eq_expr_value(cx, collection_expr, pop_collection)
|
||||
{
|
||||
return Some(ManualPopIfPattern {
|
||||
@@ -333,6 +335,8 @@ fn check_let_chain_pattern<'tcx>(
|
||||
predicate: right,
|
||||
param_name: binding_name.name,
|
||||
if_span: if_expr_span,
|
||||
spans: MultiSpan::from(vec![if_expr_span.with_hi(cond.span.hi()), pop_span]),
|
||||
suggestable,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -353,11 +357,7 @@ fn check_map_unwrap_or_pattern<'tcx>(
|
||||
if_expr_span: Span,
|
||||
kind: ManualPopIfKind,
|
||||
) -> Option<ManualPopIfPattern<'tcx>> {
|
||||
if pop_value_is_used(then_block) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let check_method = kind.check_method();
|
||||
let peek_method = kind.peek_method();
|
||||
let pop_method = kind.pop_method();
|
||||
|
||||
if let ExprKind::MethodCall(unwrap_path, receiver, [default_arg], _) = cond.kind
|
||||
@@ -366,12 +366,12 @@ fn check_map_unwrap_or_pattern<'tcx>(
|
||||
&& let ExprKind::MethodCall(map_path, map_receiver, [closure_arg], _) = receiver.kind
|
||||
&& map_path.ident.name == sym::map
|
||||
&& let ExprKind::MethodCall(check_path, collection_expr, [], _) = map_receiver.kind
|
||||
&& check_path.ident.name == check_method
|
||||
&& check_path.ident.name == peek_method
|
||||
&& kind.is_diag_item(cx, collection_expr)
|
||||
&& let ExprKind::Closure(closure) = closure_arg.kind
|
||||
&& let body = cx.tcx.hir_body(closure.body)
|
||||
&& cx.typeck_results().expr_ty(body.value).is_bool()
|
||||
&& let Some((pop_collection, _pop_span)) = check_pop_unwrap(then_block, pop_method)
|
||||
&& let Some((pop_collection, pop_span, suggestable)) = check_pop_unwrap(cx, then_block, pop_method)
|
||||
&& eq_expr_value(cx, collection_expr, pop_collection)
|
||||
&& let Some(param) = body.params.first()
|
||||
&& let Some(ident) = param.pat.simple_ident()
|
||||
@@ -382,6 +382,8 @@ fn check_map_unwrap_or_pattern<'tcx>(
|
||||
predicate: body.value,
|
||||
param_name: ident.name,
|
||||
if_span: if_expr_span,
|
||||
spans: MultiSpan::from(vec![if_expr_span.with_hi(cond.span.hi()), pop_span]),
|
||||
suggestable,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -389,19 +391,72 @@ fn check_map_unwrap_or_pattern<'tcx>(
|
||||
}
|
||||
|
||||
/// Checks for `collection.<pop_method>().unwrap()` or `collection.<pop_method>().expect(..)`
|
||||
/// and returns the collection and the span of the peeled expr
|
||||
fn check_pop_unwrap<'tcx>(expr: &'tcx Expr<'_>, pop_method: Symbol) -> Option<(&'tcx Expr<'tcx>, Span)> {
|
||||
let inner_expr = peel_blocks_with_stmt(expr);
|
||||
/// and returns the collection expression and the span of the pop+unwrap call.
|
||||
/// If the pop+unwrap is the only statement in the block, the result is marked as
|
||||
/// suggestable (we can provide an automatic fix).
|
||||
fn check_pop_unwrap<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
pop_method: Symbol,
|
||||
) -> Option<(&'tcx Expr<'tcx>, Span, bool)> {
|
||||
let ExprKind::Block(block, _) = expr.kind else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if let ExprKind::MethodCall(unwrap_path, receiver, _, _) = inner_expr.kind
|
||||
&& matches!(unwrap_path.ident.name, sym::unwrap | sym::expect)
|
||||
&& let ExprKind::MethodCall(pop_path, collection_expr, [], _) = receiver.kind
|
||||
&& pop_path.ident.name == pop_method
|
||||
let as_pop_unwrap = |expr: &Expr<'tcx>| -> Option<(&'tcx Expr<'tcx>, Span)> {
|
||||
if let ExprKind::MethodCall(unwrap_path, receiver, _, _) = expr.kind
|
||||
&& matches!(
|
||||
unwrap_path.ident.name,
|
||||
sym::unwrap | sym::unwrap_unchecked | sym::expect
|
||||
)
|
||||
&& let ExprKind::MethodCall(pop_path, collection_expr, [], _) = receiver.kind
|
||||
&& pop_path.ident.name == pop_method
|
||||
{
|
||||
Some((collection_expr, expr.span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
// Peel through an `unsafe` block for `unwrap_unchecked`.
|
||||
let peel_unsafe = |expr: &'tcx Expr<'tcx>| -> &'tcx Expr<'tcx> {
|
||||
if let ExprKind::Block(block, _) = expr.kind
|
||||
&& block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
|
||||
&& block.stmts.is_empty()
|
||||
&& let Some(inner) = block.expr
|
||||
{
|
||||
inner
|
||||
} else {
|
||||
expr
|
||||
}
|
||||
};
|
||||
|
||||
// Check for single statement with the pop unwrap (not in a macro or other expression)
|
||||
// and that there are no comments or other text before or after the pop call.
|
||||
if let [stmt] = block.stmts
|
||||
&& block.expr.is_none()
|
||||
&& let StmtKind::Semi(stmt_expr) | StmtKind::Expr(stmt_expr) = &stmt.kind
|
||||
&& !stmt_expr.span.from_expansion()
|
||||
&& let Some((collection_expr, span)) = as_pop_unwrap(peel_unsafe(stmt_expr))
|
||||
{
|
||||
return Some((collection_expr, inner_expr.span));
|
||||
let span_before = block
|
||||
.span
|
||||
.with_lo(block.span.lo() + BytePos(1))
|
||||
.with_hi(stmt_expr.span.lo());
|
||||
let span_after = stmt.span.shrink_to_hi().with_hi(block.span.hi() - BytePos(1));
|
||||
let suggestable = !span_contains_non_whitespace(cx, span_before, false)
|
||||
&& !span_contains_non_whitespace(cx, span_after, false);
|
||||
return Some((collection_expr, span, suggestable));
|
||||
}
|
||||
|
||||
None
|
||||
// Check if the pop unwrap is present at all
|
||||
for_each_expr_without_closures(block, |expr| {
|
||||
if let Some((collection_expr, span)) = as_pop_unwrap(expr) {
|
||||
ControlFlow::Break((collection_expr, span, false))
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualPopIf {
|
||||
@@ -410,22 +465,24 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
return;
|
||||
};
|
||||
|
||||
// Do not lint if we are in an else-if branch.
|
||||
if is_else_clause(cx.tcx, expr) {
|
||||
return;
|
||||
}
|
||||
let in_else_clause = is_else_clause(cx.tcx, expr);
|
||||
|
||||
for kind in [
|
||||
ManualPopIfKind::Vec,
|
||||
ManualPopIfKind::VecDequeBack,
|
||||
ManualPopIfKind::VecDequeFront,
|
||||
ManualPopIfKind::BinaryHeap,
|
||||
] {
|
||||
if let Some(pattern) = check_is_some_and_pattern(cx, cond, then_block, expr.span, kind)
|
||||
if let Some(mut pattern) = check_is_some_and_pattern(cx, cond, then_block, expr.span, kind)
|
||||
.or_else(|| check_if_let_pattern(cx, cond, then_block, expr.span, kind))
|
||||
.or_else(|| check_let_chain_pattern(cx, cond, then_block, expr.span, kind))
|
||||
.or_else(|| check_map_unwrap_or_pattern(cx, cond, then_block, expr.span, kind))
|
||||
&& self.msrv.meets(cx, kind.msrv())
|
||||
&& self.msrv_compatible(cx, kind)
|
||||
{
|
||||
if in_else_clause {
|
||||
pattern.suggestable = false;
|
||||
}
|
||||
|
||||
pattern.emit_lint(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,17 @@
|
||||
use clippy_utils::msrvs::Msrv;
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet};
|
||||
use clippy_utils::usage::mutated_variables;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{SpanlessEq, get_ref_operators, is_unit_expr, peel_blocks_with_stmt, peel_ref_operators};
|
||||
use rustc_ast::BorrowKind;
|
||||
use rustc_errors::{Applicability, MultiSpan};
|
||||
use rustc_hir::LangItem::OptionNone;
|
||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatExpr, PatExprKind, PatKind};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdSet, Pat, PatExpr, PatExprKind, PatKind};
|
||||
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::FakeReadCause;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{BytePos, Span};
|
||||
|
||||
@@ -129,6 +133,7 @@ fn check_arm<'tcx>(
|
||||
(None, Some(e)) | (Some(e), None) => is_unit_expr(e),
|
||||
(Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
|
||||
}
|
||||
&& !pat_bindings_moved_or_mutated(cx, outer_pat, inner.cond)
|
||||
{
|
||||
span_lint_hir_and_then(
|
||||
cx,
|
||||
@@ -255,3 +260,48 @@ fn build_ref_method_chain(expr: Vec<&Expr<'_>>) -> Option<String> {
|
||||
|
||||
Some(req_method_calls)
|
||||
}
|
||||
|
||||
/// Checks if any of the bindings in the `pat` are moved or mutated in the `expr`. It is invalid to
|
||||
/// move or mutate bindings in `if` guards.
|
||||
fn pat_bindings_moved_or_mutated<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
|
||||
let mut delegate = MovedVarDelegate {
|
||||
moved: HirIdSet::default(),
|
||||
};
|
||||
if ExprUseVisitor::for_clippy(cx, expr.hir_id.owner.def_id, &mut delegate)
|
||||
.walk_expr(expr)
|
||||
.is_err()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
let mut candidates = delegate.moved;
|
||||
if let Some(mutated) = mutated_variables(expr, cx) {
|
||||
candidates.extend(mutated);
|
||||
}
|
||||
|
||||
!pat.walk_short(|pat| {
|
||||
if let PatKind::Binding(_, hir_id, ..) = pat.kind
|
||||
&& candidates.contains(&hir_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
true
|
||||
})
|
||||
}
|
||||
|
||||
struct MovedVarDelegate {
|
||||
moved: HirIdSet,
|
||||
}
|
||||
|
||||
impl<'tcx> Delegate<'tcx> for MovedVarDelegate {
|
||||
fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
|
||||
if let PlaceBase::Local(hir_id) = cmt.place.base {
|
||||
self.moved.insert(hir_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
|
||||
fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {}
|
||||
fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
|
||||
fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
|
||||
}
|
||||
|
||||
@@ -247,11 +247,11 @@ fn hir(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, filter_param_id: HirId) -
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
} else if matching_root_macro_call(cx, expr.span, sym::matches_macro).is_some()
|
||||
} else if let ExprKind::Match(scrutinee, [arm, _], _) = expr.kind
|
||||
// we know for a fact that the wildcard pattern is the second arm
|
||||
&& let ExprKind::Match(scrutinee, [arm, _], _) = expr.kind
|
||||
&& scrutinee.res_local_id() == Some(filter_param_id)
|
||||
&& let PatKind::TupleStruct(QPath::Resolved(_, path), ..) = arm.pat.kind
|
||||
&& matching_root_macro_call(cx, expr.span, sym::matches_macro).is_some()
|
||||
&& let Some(variant_def_id) = path.res.opt_def_id()
|
||||
{
|
||||
Some(OffendingFilterExpr::Matches { variant_def_id })
|
||||
|
||||
@@ -48,14 +48,20 @@ pub(super) fn check<'tcx>(
|
||||
if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind
|
||||
&& let [local_ident] = path.segments
|
||||
&& local_ident.ident.name == bound_ident.name
|
||||
&& [sym::map, sym::flat_map].contains(&method_name)
|
||||
{
|
||||
let identity_map_equivalent = match method_name {
|
||||
sym::map => "",
|
||||
sym::flat_map => ".flatten()",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
ITER_KV_MAP,
|
||||
expr.span,
|
||||
format!("iterating on a map's {replacement_kind}s"),
|
||||
"try",
|
||||
format!("{recv_snippet}.{into_prefix}{replacement_kind}s()"),
|
||||
format!("{recv_snippet}.{into_prefix}{replacement_kind}s(){identity_map_equivalent}"),
|
||||
applicability,
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::peel_blocks;
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::visitors::for_each_expr_without_closures;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{self as hir, Expr, ExprKind, HirId, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::symbol::sym;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use super::MANUAL_OPTION_ZIP;
|
||||
|
||||
/// Checks for `a.and_then(|a| b.map(|b| (a, b)))` and suggests `a.zip(b)`.
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
recv: &'tcx Expr<'_>,
|
||||
arg: &'tcx Expr<'_>,
|
||||
msrv: Msrv,
|
||||
) {
|
||||
// Looking for: `a.and_then(|a| b.map(|b| (a, b)))`.
|
||||
// `and_then(|a| ...)`
|
||||
if let ExprKind::Closure(&hir::Closure { body: outer_body_id, .. }) = arg.kind
|
||||
&& let hir::Body { params: [outer_param], value: outer_value, .. } = cx.tcx.hir_body(outer_body_id)
|
||||
&& let PatKind::Binding(_, outer_param_id, _, None) = outer_param.pat.kind
|
||||
&& cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option)
|
||||
// `b.map(|b| ...)`
|
||||
&& let ExprKind::MethodCall(method_path, map_recv, [map_arg], _) = peel_blocks(outer_value).kind
|
||||
&& method_path.ident.name == sym::map
|
||||
&& cx.typeck_results().expr_ty(map_recv).is_diag_item(cx, sym::Option)
|
||||
// `b` does not reference the outer closure parameter `a`.
|
||||
&& for_each_expr_without_closures(map_recv, |e| {
|
||||
if e.res_local_id() == Some(outer_param_id) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}).is_none()
|
||||
// `|b| (a, b)`
|
||||
&& let ExprKind::Closure(&hir::Closure { body: inner_body_id, .. }) = map_arg.kind
|
||||
&& let hir::Body { params: [inner_param], value: inner_value, .. } = cx.tcx.hir_body(inner_body_id)
|
||||
&& let PatKind::Binding(_, inner_param_id, _, None) = inner_param.pat.kind
|
||||
// `(a, b)` or `(b, a)` — tuple of outer and inner param in either order.
|
||||
&& let ExprKind::Tup([first, second]) = peel_blocks(inner_value).kind
|
||||
&& let Some((zip_recv, zip_arg)) = zip_operands(first, second, outer_param_id, inner_param_id, recv, map_recv)
|
||||
// `Option.zip()` is available.
|
||||
&& msrv.meets(cx, msrvs::OPTION_ZIP)
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let zip_recv_snip = snippet_with_applicability(cx, zip_recv.span, "_", &mut applicability);
|
||||
let zip_arg_snip = snippet_with_applicability(cx, zip_arg.span, "_", &mut applicability);
|
||||
let suggestion = format!("{zip_recv_snip}.zip({zip_arg_snip})");
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_OPTION_ZIP,
|
||||
expr.span,
|
||||
"manual implementation of `Option::zip`",
|
||||
"use",
|
||||
suggestion,
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Given the two tuple elements and the `and_then` receiver / `map` receiver, returns the
|
||||
/// `(zip_receiver, zip_argument)` expressions for the `.zip()` suggestion.
|
||||
///
|
||||
/// For `(outer, inner)` order the zip is `recv.zip(map_recv)`.
|
||||
/// For `(inner, outer)` (reversed) the zip is `map_recv.zip(recv)`.
|
||||
/// Returns `None` if the tuple elements don't match either order.
|
||||
fn zip_operands<'a>(
|
||||
first: &Expr<'_>,
|
||||
second: &Expr<'_>,
|
||||
outer_param_id: HirId,
|
||||
inner_param_id: HirId,
|
||||
recv: &'a Expr<'a>,
|
||||
map_recv: &'a Expr<'a>,
|
||||
) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
|
||||
if first.res_local_id() == Some(outer_param_id) && second.res_local_id() == Some(inner_param_id) {
|
||||
Some((recv, map_recv))
|
||||
} else if first.res_local_id() == Some(inner_param_id) && second.res_local_id() == Some(outer_param_id) {
|
||||
Some((map_recv, recv))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,7 @@
|
||||
mod manual_is_variant_and;
|
||||
mod manual_next_back;
|
||||
mod manual_ok_or;
|
||||
mod manual_option_zip;
|
||||
mod manual_repeat_n;
|
||||
mod manual_saturating_arithmetic;
|
||||
mod manual_str_repeat;
|
||||
@@ -1950,6 +1951,34 @@
|
||||
"finds patterns that can be encoded more concisely with `Option::ok_or`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `a.and_then(|a| b.map(|b| (a, b)))` which can be
|
||||
/// more concisely expressed as `a.zip(b)`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// `Option::zip` is more concise and directly expresses the intent of
|
||||
/// combining two `Option` values into a tuple.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// let a: Option<i32> = Some(1);
|
||||
/// let b: Option<i32> = Some(2);
|
||||
/// let _ = a.and_then(|x| b.map(|y| (x, y)));
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// let a: Option<i32> = Some(1);
|
||||
/// let b: Option<i32> = Some(2);
|
||||
/// let _ = a.zip(b);
|
||||
/// ```
|
||||
#[clippy::version = "1.95.0"]
|
||||
pub MANUAL_OPTION_ZIP,
|
||||
complexity,
|
||||
"manual reimplementation of `Option::zip`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
///
|
||||
@@ -4814,6 +4843,7 @@
|
||||
MANUAL_IS_VARIANT_AND,
|
||||
MANUAL_NEXT_BACK,
|
||||
MANUAL_OK_OR,
|
||||
MANUAL_OPTION_ZIP,
|
||||
MANUAL_REPEAT_N,
|
||||
MANUAL_SATURATING_ARITHMETIC,
|
||||
MANUAL_SPLIT_ONCE,
|
||||
@@ -5115,6 +5145,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
}
|
||||
},
|
||||
(sym::and_then, [arg]) => {
|
||||
manual_option_zip::check(cx, expr, recv, arg, self.msrv);
|
||||
let biom_option_linted = bind_instead_of_map::check_and_then_some(cx, expr, recv, arg);
|
||||
let biom_result_linted = bind_instead_of_map::check_and_then_ok(cx, expr, recv, arg);
|
||||
if !biom_option_linted && !biom_result_linted {
|
||||
|
||||
@@ -105,10 +105,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::If(..) => {
|
||||
self.found = true;
|
||||
return;
|
||||
},
|
||||
ExprKind::Path(_) => {
|
||||
if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id)
|
||||
&& adj
|
||||
|
||||
@@ -52,7 +52,11 @@
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for names that are very similar and thus confusing.
|
||||
/// Checks for names that are very similar and thus confusing. In particular,
|
||||
/// the lint checks for names with a single character change.
|
||||
///
|
||||
/// It does not warn about names that have a single additional character at
|
||||
/// the beginning nor the end; only insertions in the middle are considered.
|
||||
///
|
||||
/// Note: this lint looks for similar names throughout each
|
||||
/// scope. To allow it, you need to allow it on the scope
|
||||
@@ -65,7 +69,13 @@
|
||||
/// ### Example
|
||||
/// ```ignore
|
||||
/// let checked_exp = something;
|
||||
/// let checked_expr = something_else;
|
||||
/// let checked_eap = something_else;
|
||||
/// ```
|
||||
///
|
||||
/// ### Example 2
|
||||
/// ```ignore
|
||||
/// let orange = val;
|
||||
/// let ornange = val2;
|
||||
/// ```
|
||||
#[clippy::version = "pre 1.29.0"]
|
||||
pub SIMILAR_NAMES,
|
||||
|
||||
@@ -77,8 +77,8 @@ fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, s
|
||||
|
||||
/// Checks `vec![Vec::with_capacity(x); n]`
|
||||
fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if matching_root_macro_call(cx, expr.span, sym::vec_macro).is_some()
|
||||
&& let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr)
|
||||
if let Some(VecArgs::Repeat(repeat_expr, len_expr)) = VecArgs::hir(cx, expr)
|
||||
&& matching_root_macro_call(cx, expr.span, sym::vec_macro).is_some()
|
||||
&& fn_def_id(cx, repeat_expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::vec_with_capacity, did))
|
||||
&& !len_expr.span.from_expansion()
|
||||
&& let Some(Constant::Int(2..)) = ConstEvalCtxt::new(cx).eval(expr_or_init(cx, len_expr))
|
||||
|
||||
@@ -166,9 +166,9 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<
|
||||
},
|
||||
ExprKind::Binary(op, _, _) if op.node == BinOpKind::Or => ControlFlow::Continue(Descend::Yes),
|
||||
ExprKind::Match(match_value, [arm, _], _) => {
|
||||
if matching_root_macro_call(cx, sub_expr.span, sym::matches_macro).is_none()
|
||||
|| arm.guard.is_some()
|
||||
if arm.guard.is_some()
|
||||
|| match_value.res_local_id() != Some(binding)
|
||||
|| matching_root_macro_call(cx, sub_expr.span, sym::matches_macro).is_none()
|
||||
{
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::expr_type_is_certain;
|
||||
use clippy_utils::{is_expr_default, is_from_proc_macro};
|
||||
use clippy_utils::{is_empty_block, is_expr_default, is_from_proc_macro};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind};
|
||||
use rustc_lint::LateContext;
|
||||
@@ -205,20 +205,6 @@ fn is_block_with_no_expr(expr: &Expr<'_>) -> bool {
|
||||
matches!(expr.kind, ExprKind::Block(Block { expr: None, .. }, _))
|
||||
}
|
||||
|
||||
fn is_empty_block(expr: &Expr<'_>) -> bool {
|
||||
matches!(
|
||||
expr.kind,
|
||||
ExprKind::Block(
|
||||
Block {
|
||||
stmts: [],
|
||||
expr: None,
|
||||
..
|
||||
},
|
||||
_,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fn fmt_stmts_and_call(
|
||||
cx: &LateContext<'_>,
|
||||
call_expr: &Expr<'_>,
|
||||
|
||||
@@ -311,6 +311,21 @@ pub fn as_some_expr<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Optio
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the given `Expr` is an empty block (i.e. `{}`) or not.
|
||||
pub fn is_empty_block(expr: &Expr<'_>) -> bool {
|
||||
matches!(
|
||||
expr.kind,
|
||||
ExprKind::Block(
|
||||
Block {
|
||||
stmts: [],
|
||||
expr: None,
|
||||
..
|
||||
},
|
||||
_,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/// Checks if `expr` is an empty block or an empty tuple.
|
||||
pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
|
||||
matches!(
|
||||
|
||||
@@ -60,7 +60,7 @@ macro_rules! msrv_aliases {
|
||||
1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS }
|
||||
1,50,0 { BOOL_THEN, CLAMP, SLICE_FILL }
|
||||
1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN, SATURATING_SUB_CONST }
|
||||
1,46,0 { CONST_IF_MATCH }
|
||||
1,46,0 { CONST_IF_MATCH, OPTION_ZIP }
|
||||
1,45,0 { STR_STRIP_PREFIX }
|
||||
1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS }
|
||||
1,42,0 { MATCHES_MACRO, SLICE_PATTERNS, PTR_SLICE_RAW_PARTS }
|
||||
|
||||
@@ -133,6 +133,8 @@ macro_rules! $name {
|
||||
macro_path: PathNS::Macro,
|
||||
}
|
||||
|
||||
// Paths in the standard library missing a diagnostic item
|
||||
|
||||
// Paths in external crates
|
||||
pub static FUTURES_IO_ASYNCREADEXT: PathLookup = type_path!(futures_util::AsyncReadExt);
|
||||
pub static FUTURES_IO_ASYNCWRITEEXT: PathLookup = type_path!(futures_util::AsyncWriteExt);
|
||||
|
||||
@@ -122,6 +122,7 @@ macro_rules! generate {
|
||||
V6,
|
||||
VecDeque,
|
||||
Visitor,
|
||||
Wake,
|
||||
Waker,
|
||||
Weak,
|
||||
Wrapping,
|
||||
@@ -141,6 +142,7 @@ macro_rules! generate {
|
||||
assert_failed,
|
||||
author,
|
||||
back,
|
||||
binary_heap_pop_if,
|
||||
binaryheap_iter,
|
||||
bool_then,
|
||||
borrow,
|
||||
|
||||
@@ -21,7 +21,7 @@ rayon = "1.5.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0.85"
|
||||
strip-ansi-escapes = "0.2.0"
|
||||
tar = "0.4"
|
||||
tar = "0.4.45"
|
||||
toml = "0.9.7"
|
||||
ureq = { version = "2.2", features = ["json"] }
|
||||
walkdir = "2.3"
|
||||
|
||||
@@ -18,3 +18,19 @@ fn issue13365() {
|
||||
}
|
||||
//~^^^^ ERROR: this lint expectation is unfulfilled
|
||||
}
|
||||
|
||||
#[allow(unexpected_cfgs)]
|
||||
fn issue16715(o: Option<i32>) {
|
||||
if let Some(x) = o {
|
||||
if x > 0 {
|
||||
println!("Positive: {}", x);
|
||||
}
|
||||
|
||||
#[cfg(feature = "some_feature")]
|
||||
{
|
||||
if x % 2 == 0 {
|
||||
println!("Even: {}", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,3 +389,58 @@ fn foo<T, U>(t: T) -> U {
|
||||
fn take<T>(t: T) {}
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn issue16705(x: Option<String>) {
|
||||
fn takes_ownership(s: String) -> bool {
|
||||
true
|
||||
}
|
||||
fn borrows_mut(s: &mut str) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
let _ = match x {
|
||||
Some(val) => {
|
||||
if takes_ownership(val) {
|
||||
return;
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let mut x: Option<&mut str> = Some(&mut String::new());
|
||||
let _ = match x {
|
||||
Some(val) => {
|
||||
if borrows_mut(val) {
|
||||
return;
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let mut x = Some(String::new());
|
||||
let _ = match x {
|
||||
Some(ref mut val) => {
|
||||
if borrows_mut(val) {
|
||||
return;
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let _ = match &mut x {
|
||||
Some(val) => {
|
||||
if borrows_mut(val) {
|
||||
return;
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -332,3 +332,34 @@ fn add_assign(&mut self, rhs: u8) {
|
||||
priority += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn issue_16642() {
|
||||
let mut base = 100;
|
||||
const MAX: usize = 10;
|
||||
for _ in 0..MAX {
|
||||
//~^ explicit_counter_loop
|
||||
base += 1;
|
||||
}
|
||||
|
||||
let mut base = 100;
|
||||
|
||||
let nums = vec![1, 2, 3, 4];
|
||||
for _ in nums {
|
||||
//~^ explicit_counter_loop
|
||||
base += 1;
|
||||
}
|
||||
|
||||
// inclusive range: should not suggest .take()
|
||||
let mut base = 100;
|
||||
for _ in 0..=MAX {
|
||||
//~^ explicit_counter_loop
|
||||
base += 1;
|
||||
}
|
||||
|
||||
// non-zero start: should not suggest .take(), falls through to zip
|
||||
let mut base = 100;
|
||||
for _ in 5..MAX {
|
||||
//~^ explicit_counter_loop
|
||||
base += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,5 +81,29 @@ error: the variable `j` is used as a loop counter
|
||||
LL | for item in &v {
|
||||
| ^^^^^^^^^^^^^^ help: consider using: `for (j, item) in (s + 1..).zip(v.iter())`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: the variable `base` is used as a loop counter
|
||||
--> tests/ui/explicit_counter_loop.rs:339:5
|
||||
|
|
||||
LL | for _ in 0..MAX {
|
||||
| ^^^^^^^^^^^^^^^ help: consider using: `for base in (100..).take(MAX)`
|
||||
|
||||
error: the variable `base` is used as a loop counter
|
||||
--> tests/ui/explicit_counter_loop.rs:347:5
|
||||
|
|
||||
LL | for _ in nums {
|
||||
| ^^^^^^^^^^^^^ help: consider using: `for (base, _) in (100..).zip(nums.into_iter())`
|
||||
|
||||
error: the variable `base` is used as a loop counter
|
||||
--> tests/ui/explicit_counter_loop.rs:354:5
|
||||
|
|
||||
LL | for _ in 0..=MAX {
|
||||
| ^^^^^^^^^^^^^^^^ help: consider using: `for (base, _) in (100..).zip((0..=MAX))`
|
||||
|
||||
error: the variable `base` is used as a loop counter
|
||||
--> tests/ui/explicit_counter_loop.rs:361:5
|
||||
|
|
||||
LL | for _ in 5..MAX {
|
||||
| ^^^^^^^^^^^^^^^ help: consider using: `for (base, _) in (100..).zip((5..MAX))`
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
|
||||
@@ -231,3 +231,15 @@ fn issue16515() {
|
||||
hash_map.into_values().filter_map(|v| (v > 0).then_some(1));
|
||||
//~^ iter_kv_map
|
||||
}
|
||||
|
||||
fn issue16742() {
|
||||
let map: HashMap<u32, Vec<u32>> = HashMap::new();
|
||||
map.values().flat_map(|v| v.iter().map(|i| *i + 1));
|
||||
//~^ iter_kv_map
|
||||
map.values().flatten();
|
||||
//~^ iter_kv_map
|
||||
|
||||
let map: HashMap<u32, Vec<u32>> = HashMap::new();
|
||||
map.into_values().flatten();
|
||||
//~^ iter_kv_map
|
||||
}
|
||||
|
||||
@@ -235,3 +235,15 @@ fn issue16515() {
|
||||
hash_map.into_iter().filter_map(|(_, v)| (v > 0).then_some(1));
|
||||
//~^ iter_kv_map
|
||||
}
|
||||
|
||||
fn issue16742() {
|
||||
let map: HashMap<u32, Vec<u32>> = HashMap::new();
|
||||
map.iter().flat_map(|(_, v)| v.iter().map(|i| *i + 1));
|
||||
//~^ iter_kv_map
|
||||
map.iter().flat_map(|(_, v)| v);
|
||||
//~^ iter_kv_map
|
||||
|
||||
let map: HashMap<u32, Vec<u32>> = HashMap::new();
|
||||
map.into_iter().flat_map(|(_, v)| v);
|
||||
//~^ iter_kv_map
|
||||
}
|
||||
|
||||
@@ -323,5 +323,23 @@ error: iterating on a map's values
|
||||
LL | hash_map.into_iter().filter_map(|(_, v)| (v > 0).then_some(1));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.into_values().filter_map(|v| (v > 0).then_some(1))`
|
||||
|
||||
error: aborting due to 48 previous errors
|
||||
error: iterating on a map's values
|
||||
--> tests/ui/iter_kv_map.rs:241:5
|
||||
|
|
||||
LL | map.iter().flat_map(|(_, v)| v.iter().map(|i| *i + 1));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().flat_map(|v| v.iter().map(|i| *i + 1))`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> tests/ui/iter_kv_map.rs:243:5
|
||||
|
|
||||
LL | map.iter().flat_map(|(_, v)| v);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().flatten()`
|
||||
|
||||
error: iterating on a map's values
|
||||
--> tests/ui/iter_kv_map.rs:247:5
|
||||
|
|
||||
LL | map.into_iter().flat_map(|(_, v)| v);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.into_values().flatten()`
|
||||
|
||||
error: aborting due to 51 previous errors
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#![warn(clippy::manual_noop_waker)]
|
||||
use std::sync::Arc;
|
||||
use std::task::Wake;
|
||||
|
||||
struct PartialWaker;
|
||||
impl Wake for PartialWaker {
|
||||
//~^ ERROR: manual implementation of a no-op waker
|
||||
fn wake(self: Arc<Self>) {}
|
||||
}
|
||||
|
||||
struct MyWakerPartial;
|
||||
impl Wake for MyWakerPartial {
|
||||
//~^ manual_noop_waker
|
||||
fn wake(self: Arc<Self>) {}
|
||||
// wake_by_ref not implemented, uses default
|
||||
}
|
||||
|
||||
trait CustomWake {
|
||||
fn wake(self);
|
||||
}
|
||||
|
||||
impl CustomWake for () {
|
||||
fn wake(self) {}
|
||||
}
|
||||
|
||||
mod custom_module {
|
||||
use std::sync::Arc;
|
||||
|
||||
// Custom Wake trait that should NOT trigger the lint
|
||||
pub trait Wake {
|
||||
fn wake(self: Arc<Self>);
|
||||
fn wake_by_ref(self: &Arc<Self>);
|
||||
}
|
||||
|
||||
pub struct CustomWaker;
|
||||
impl Wake for CustomWaker {
|
||||
fn wake(self: Arc<Self>) {}
|
||||
fn wake_by_ref(self: &Arc<Self>) {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
error: manual implementation of a no-op waker
|
||||
--> tests/ui/manual_noop_waker.rs:6:6
|
||||
|
|
||||
LL | impl Wake for PartialWaker {
|
||||
| ^^^^
|
||||
|
|
||||
= help: use `std::task::Waker::noop()` instead
|
||||
= note: `-D clippy::manual-noop-waker` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::manual_noop_waker)]`
|
||||
|
||||
error: manual implementation of a no-op waker
|
||||
--> tests/ui/manual_noop_waker.rs:12:6
|
||||
|
|
||||
LL | impl Wake for MyWakerPartial {
|
||||
| ^^^^
|
||||
|
|
||||
= help: use `std::task::Waker::noop()` instead
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
#![warn(clippy::manual_option_zip)]
|
||||
#![allow(clippy::bind_instead_of_map)]
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn should_lint() {
|
||||
// basic case
|
||||
let a: Option<i32> = Some(1);
|
||||
let b: Option<i32> = Some(2);
|
||||
let _ = a.zip(b);
|
||||
//~^ manual_option_zip
|
||||
|
||||
// different types
|
||||
let a: Option<String> = Some(String::new());
|
||||
let b: Option<i32> = Some(1);
|
||||
let _ = a.zip(b);
|
||||
//~^ manual_option_zip
|
||||
|
||||
// with None receiver
|
||||
let b: Option<i32> = Some(2);
|
||||
let _ = None::<i32>.zip(b);
|
||||
//~^ manual_option_zip
|
||||
|
||||
// with function call as map receiver
|
||||
let a: Option<i32> = Some(1);
|
||||
let _ = a.zip(get_option());
|
||||
//~^ manual_option_zip
|
||||
|
||||
// tuple order reversed: (inner, outer) instead of (outer, inner)
|
||||
let a: Option<i32> = Some(1);
|
||||
let b: Option<i32> = Some(2);
|
||||
let _ = b.zip(a);
|
||||
//~^ manual_option_zip
|
||||
|
||||
// closure bodies wrapped in blocks
|
||||
let a: Option<i32> = Some(1);
|
||||
let b: Option<i32> = Some(2);
|
||||
#[rustfmt::skip]
|
||||
let _ = a.zip(b);
|
||||
//~^ manual_option_zip
|
||||
#[rustfmt::skip]
|
||||
let _ = a.zip(b);
|
||||
//~^ manual_option_zip
|
||||
#[rustfmt::skip]
|
||||
let _ = a.zip(b);
|
||||
//~^ manual_option_zip
|
||||
}
|
||||
|
||||
fn should_not_lint() {
|
||||
let a: Option<i32> = Some(1);
|
||||
let b: Option<i32> = Some(2);
|
||||
|
||||
// tuple has more than 2 elements
|
||||
let _ = a.and_then(|a| b.map(|b| (a, b, 1)));
|
||||
|
||||
// three-element tuple but with either `a` or `b` as the elements
|
||||
let _ = a.and_then(|a| b.map(|b| (a, b, a)));
|
||||
|
||||
// inner closure body is not a simple tuple of the params
|
||||
let _ = a.and_then(|a| b.map(|b| (a, b + 1)));
|
||||
|
||||
// map receiver uses the outer closure parameter
|
||||
let _ = a.and_then(|a| a.checked_add(1).map(|b| (a, b)));
|
||||
|
||||
// .map receiver is not an Option type.
|
||||
let _ = a.and_then(|a| NotOption(Some(1)).map(|b| (a, b)));
|
||||
|
||||
// .and_then receiver is not an Option type.
|
||||
let _ = NotOption(Some(1)).and_then(|a| b.map(|b| (a, b)));
|
||||
|
||||
// closure body is not a map call
|
||||
let a: Option<i32> = Some(1);
|
||||
let _ = a.and_then(|a| Some((a, 1)));
|
||||
|
||||
// single-element tuple
|
||||
let _ = a.and_then(|a| b.map(|_b| (a,)));
|
||||
|
||||
// the outer param used in the map receiver (cannot extract)
|
||||
let opts: Vec<Option<i32>> = vec![Some(1), Some(2)];
|
||||
let _ = a.and_then(|a| opts[a as usize].map(|b| (a, b)));
|
||||
|
||||
// extra statements in outer closure body
|
||||
let _ = a.and_then(|a| {
|
||||
let _x = 1;
|
||||
b.map(|b| (a, b))
|
||||
});
|
||||
|
||||
// extra statements in inner closure body
|
||||
let _ = a.and_then(|a| {
|
||||
b.map(|b| {
|
||||
let _x = 1;
|
||||
(a, b)
|
||||
})
|
||||
});
|
||||
|
||||
// n-ary zip where n > 2, which is out of scope for this lint (for now)
|
||||
let c: Option<i32> = Some(3);
|
||||
let _ = a.and_then(|a| b.and_then(|b| c.map(|c| (a, b, c))));
|
||||
|
||||
// not Option type (Result)
|
||||
let a: Result<i32, &str> = Ok(1);
|
||||
let b: Result<i32, &str> = Ok(2);
|
||||
let _ = a.and_then(|a| b.map(|b| (a, b)));
|
||||
}
|
||||
|
||||
fn get_option() -> Option<i32> {
|
||||
Some(123)
|
||||
}
|
||||
|
||||
struct NotOption(Option<i32>);
|
||||
impl NotOption {
|
||||
fn map<U>(self, f: impl FnOnce(i32) -> U) -> Option<U> {
|
||||
self.0.map(f)
|
||||
}
|
||||
fn and_then<U>(self, f: impl FnOnce(i32) -> Option<U>) -> Option<U> {
|
||||
self.0.and_then(f)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
#![warn(clippy::manual_option_zip)]
|
||||
#![allow(clippy::bind_instead_of_map)]
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn should_lint() {
|
||||
// basic case
|
||||
let a: Option<i32> = Some(1);
|
||||
let b: Option<i32> = Some(2);
|
||||
let _ = a.and_then(|a| b.map(|b| (a, b)));
|
||||
//~^ manual_option_zip
|
||||
|
||||
// different types
|
||||
let a: Option<String> = Some(String::new());
|
||||
let b: Option<i32> = Some(1);
|
||||
let _ = a.and_then(|a| b.map(|b| (a, b)));
|
||||
//~^ manual_option_zip
|
||||
|
||||
// with None receiver
|
||||
let b: Option<i32> = Some(2);
|
||||
let _ = None::<i32>.and_then(|a| b.map(|b| (a, b)));
|
||||
//~^ manual_option_zip
|
||||
|
||||
// with function call as map receiver
|
||||
let a: Option<i32> = Some(1);
|
||||
let _ = a.and_then(|a| get_option().map(|b| (a, b)));
|
||||
//~^ manual_option_zip
|
||||
|
||||
// tuple order reversed: (inner, outer) instead of (outer, inner)
|
||||
let a: Option<i32> = Some(1);
|
||||
let b: Option<i32> = Some(2);
|
||||
let _ = a.and_then(|a| b.map(|b| (b, a)));
|
||||
//~^ manual_option_zip
|
||||
|
||||
// closure bodies wrapped in blocks
|
||||
let a: Option<i32> = Some(1);
|
||||
let b: Option<i32> = Some(2);
|
||||
#[rustfmt::skip]
|
||||
let _ = a.and_then(|a| { b.map(|b| (a, b)) });
|
||||
//~^ manual_option_zip
|
||||
#[rustfmt::skip]
|
||||
let _ = a.and_then(|a| b.map(|b| { (a, b) }));
|
||||
//~^ manual_option_zip
|
||||
#[rustfmt::skip]
|
||||
let _ = a.and_then(|a| { b.map(|b| { (a, b) }) });
|
||||
//~^ manual_option_zip
|
||||
}
|
||||
|
||||
fn should_not_lint() {
|
||||
let a: Option<i32> = Some(1);
|
||||
let b: Option<i32> = Some(2);
|
||||
|
||||
// tuple has more than 2 elements
|
||||
let _ = a.and_then(|a| b.map(|b| (a, b, 1)));
|
||||
|
||||
// three-element tuple but with either `a` or `b` as the elements
|
||||
let _ = a.and_then(|a| b.map(|b| (a, b, a)));
|
||||
|
||||
// inner closure body is not a simple tuple of the params
|
||||
let _ = a.and_then(|a| b.map(|b| (a, b + 1)));
|
||||
|
||||
// map receiver uses the outer closure parameter
|
||||
let _ = a.and_then(|a| a.checked_add(1).map(|b| (a, b)));
|
||||
|
||||
// .map receiver is not an Option type.
|
||||
let _ = a.and_then(|a| NotOption(Some(1)).map(|b| (a, b)));
|
||||
|
||||
// .and_then receiver is not an Option type.
|
||||
let _ = NotOption(Some(1)).and_then(|a| b.map(|b| (a, b)));
|
||||
|
||||
// closure body is not a map call
|
||||
let a: Option<i32> = Some(1);
|
||||
let _ = a.and_then(|a| Some((a, 1)));
|
||||
|
||||
// single-element tuple
|
||||
let _ = a.and_then(|a| b.map(|_b| (a,)));
|
||||
|
||||
// the outer param used in the map receiver (cannot extract)
|
||||
let opts: Vec<Option<i32>> = vec![Some(1), Some(2)];
|
||||
let _ = a.and_then(|a| opts[a as usize].map(|b| (a, b)));
|
||||
|
||||
// extra statements in outer closure body
|
||||
let _ = a.and_then(|a| {
|
||||
let _x = 1;
|
||||
b.map(|b| (a, b))
|
||||
});
|
||||
|
||||
// extra statements in inner closure body
|
||||
let _ = a.and_then(|a| {
|
||||
b.map(|b| {
|
||||
let _x = 1;
|
||||
(a, b)
|
||||
})
|
||||
});
|
||||
|
||||
// n-ary zip where n > 2, which is out of scope for this lint (for now)
|
||||
let c: Option<i32> = Some(3);
|
||||
let _ = a.and_then(|a| b.and_then(|b| c.map(|c| (a, b, c))));
|
||||
|
||||
// not Option type (Result)
|
||||
let a: Result<i32, &str> = Ok(1);
|
||||
let b: Result<i32, &str> = Ok(2);
|
||||
let _ = a.and_then(|a| b.map(|b| (a, b)));
|
||||
}
|
||||
|
||||
fn get_option() -> Option<i32> {
|
||||
Some(123)
|
||||
}
|
||||
|
||||
struct NotOption(Option<i32>);
|
||||
impl NotOption {
|
||||
fn map<U>(self, f: impl FnOnce(i32) -> U) -> Option<U> {
|
||||
self.0.map(f)
|
||||
}
|
||||
fn and_then<U>(self, f: impl FnOnce(i32) -> Option<U>) -> Option<U> {
|
||||
self.0.and_then(f)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
error: manual implementation of `Option::zip`
|
||||
--> tests/ui/manual_option_zip.rs:10:13
|
||||
|
|
||||
LL | let _ = a.and_then(|a| b.map(|b| (a, b)));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)`
|
||||
|
|
||||
= note: `-D clippy::manual-option-zip` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::manual_option_zip)]`
|
||||
|
||||
error: manual implementation of `Option::zip`
|
||||
--> tests/ui/manual_option_zip.rs:16:13
|
||||
|
|
||||
LL | let _ = a.and_then(|a| b.map(|b| (a, b)));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)`
|
||||
|
||||
error: manual implementation of `Option::zip`
|
||||
--> tests/ui/manual_option_zip.rs:21:13
|
||||
|
|
||||
LL | let _ = None::<i32>.and_then(|a| b.map(|b| (a, b)));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `None::<i32>.zip(b)`
|
||||
|
||||
error: manual implementation of `Option::zip`
|
||||
--> tests/ui/manual_option_zip.rs:26:13
|
||||
|
|
||||
LL | let _ = a.and_then(|a| get_option().map(|b| (a, b)));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(get_option())`
|
||||
|
||||
error: manual implementation of `Option::zip`
|
||||
--> tests/ui/manual_option_zip.rs:32:13
|
||||
|
|
||||
LL | let _ = a.and_then(|a| b.map(|b| (b, a)));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `b.zip(a)`
|
||||
|
||||
error: manual implementation of `Option::zip`
|
||||
--> tests/ui/manual_option_zip.rs:39:13
|
||||
|
|
||||
LL | let _ = a.and_then(|a| { b.map(|b| (a, b)) });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)`
|
||||
|
||||
error: manual implementation of `Option::zip`
|
||||
--> tests/ui/manual_option_zip.rs:42:13
|
||||
|
|
||||
LL | let _ = a.and_then(|a| b.map(|b| { (a, b) }));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)`
|
||||
|
||||
error: manual implementation of `Option::zip`
|
||||
--> tests/ui/manual_option_zip.rs:45:13
|
||||
|
|
||||
LL | let _ = a.and_then(|a| { b.map(|b| { (a, b) }) });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `a.zip(b)`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#![warn(clippy::manual_pop_if)]
|
||||
#![allow(clippy::collapsible_if, clippy::redundant_closure)]
|
||||
#![feature(binary_heap_pop_if)]
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::{BinaryHeap, VecDeque};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
fn main() {}
|
||||
|
||||
// FakeVec has the same methods as Vec but isn't actually a Vec
|
||||
struct FakeVec<T>(PhantomData<T>);
|
||||
|
||||
@@ -17,14 +20,24 @@ impl<T> FakeVec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_some_and_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
fn is_some_and_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>, mut heap: BinaryHeap<i32>) {
|
||||
//~v manual_pop_if
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
deque.pop_back_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
deque.pop_front_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
heap.pop_if(|x| *x > 2);
|
||||
}
|
||||
|
||||
fn is_some_and_pattern_negative(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
@@ -40,24 +53,6 @@ fn is_some_and_pattern_negative(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
fake_vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, else-if branch
|
||||
if false {
|
||||
// something
|
||||
} else if vec.last().is_some_and(|x| *x > 2) {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, value used in let binding
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
let _value = vec.pop().unwrap();
|
||||
println!("Popped: {}", _value);
|
||||
}
|
||||
|
||||
// Do not lint, value used in expression
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
println!("Popped: {}", vec.pop().unwrap());
|
||||
}
|
||||
|
||||
// Do not lint, else block
|
||||
let _result = if vec.last().is_some_and(|x| *x > 2) {
|
||||
vec.pop().unwrap()
|
||||
@@ -66,14 +61,24 @@ fn is_some_and_pattern_negative(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
};
|
||||
}
|
||||
|
||||
fn if_let_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
fn if_let_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>, mut heap: BinaryHeap<i32>) {
|
||||
//~v manual_pop_if
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
deque.pop_back_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
deque.pop_front_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
heap.pop_if(|x| *x > 2);
|
||||
}
|
||||
|
||||
fn if_let_pattern_negative(mut vec: Vec<i32>) {
|
||||
@@ -100,13 +105,6 @@ fn if_let_pattern_negative(mut vec: Vec<i32>) {
|
||||
}
|
||||
}
|
||||
|
||||
// Do not lint, value used in let binding
|
||||
if let Some(x) = vec.last() {
|
||||
if *x > 2 {
|
||||
let _val = vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Do not lint, else block
|
||||
let _result = if let Some(x) = vec.last() {
|
||||
if *x > 2 { vec.pop().unwrap() } else { 0 }
|
||||
@@ -115,7 +113,9 @@ fn if_let_pattern_negative(mut vec: Vec<i32>) {
|
||||
};
|
||||
}
|
||||
|
||||
fn let_chain_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
fn let_chain_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>, mut heap: BinaryHeap<i32>) {
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
vec.pop_if(|x| *x > 2);
|
||||
@@ -123,6 +123,8 @@ fn let_chain_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
deque.pop_back_if(|x| *x > 2);
|
||||
|
||||
deque.pop_front_if(|x| *x > 2);
|
||||
|
||||
heap.pop_if(|x| *x > 2);
|
||||
}
|
||||
|
||||
fn let_chain_pattern_negative(mut vec: Vec<i32>) {
|
||||
@@ -141,20 +143,6 @@ fn let_chain_pattern_negative(mut vec: Vec<i32>) {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, value used in let binding
|
||||
if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
{
|
||||
let _val = vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, value used in expression
|
||||
if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
{
|
||||
println!("Popped: {}", vec.pop().unwrap());
|
||||
}
|
||||
|
||||
// Do not lint, else block
|
||||
let _result = if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
@@ -165,14 +153,24 @@ fn let_chain_pattern_negative(mut vec: Vec<i32>) {
|
||||
};
|
||||
}
|
||||
|
||||
fn map_unwrap_or_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
fn map_unwrap_or_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>, mut heap: BinaryHeap<i32>) {
|
||||
//~v manual_pop_if
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
deque.pop_back_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
deque.pop_front_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
heap.pop_if(|x| *x > 2);
|
||||
}
|
||||
|
||||
fn map_unwrap_or_pattern_negative(mut vec: Vec<i32>) {
|
||||
@@ -198,11 +196,6 @@ fn map_unwrap_or_pattern_negative(mut vec: Vec<i32>) {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, value used in let binding
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
let _val = vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, else block
|
||||
let _result = if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
vec.pop().unwrap()
|
||||
@@ -213,6 +206,7 @@ fn map_unwrap_or_pattern_negative(mut vec: Vec<i32>) {
|
||||
|
||||
// this makes sure we do not expand vec![] in the suggestion
|
||||
fn handle_macro_in_closure(mut vec: Vec<Vec<i32>>) {
|
||||
//~v manual_pop_if
|
||||
vec.pop_if(|e| *e == vec![1]);
|
||||
}
|
||||
|
||||
@@ -236,12 +230,15 @@ fn msrv_too_low_vecdeque(mut deque: VecDeque<i32>) {
|
||||
|
||||
#[clippy::msrv = "1.86.0"]
|
||||
fn msrv_high_enough_vec(mut vec: Vec<i32>) {
|
||||
//~v manual_pop_if
|
||||
vec.pop_if(|x| *x > 2);
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.93.0"]
|
||||
fn msrv_high_enough_vecdeque(mut deque: VecDeque<i32>) {
|
||||
//~v manual_pop_if
|
||||
deque.pop_back_if(|x| *x > 2);
|
||||
|
||||
//~v manual_pop_if
|
||||
deque.pop_front_if(|x| *x > 2);
|
||||
}
|
||||
|
||||
+70
-65
@@ -1,9 +1,12 @@
|
||||
#![warn(clippy::manual_pop_if)]
|
||||
#![allow(clippy::collapsible_if, clippy::redundant_closure)]
|
||||
#![feature(binary_heap_pop_if)]
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::{BinaryHeap, VecDeque};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
fn main() {}
|
||||
|
||||
// FakeVec has the same methods as Vec but isn't actually a Vec
|
||||
struct FakeVec<T>(PhantomData<T>);
|
||||
|
||||
@@ -17,26 +20,36 @@ fn pop(&mut self) -> Option<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn is_some_and_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
fn is_some_and_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>, mut heap: BinaryHeap<i32>) {
|
||||
//~v manual_pop_if
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
unsafe { vec.pop().unwrap_unchecked() };
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
vec.pop().expect("element");
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if deque.back().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_back().unwrap();
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if deque.front().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if heap.peek().is_some_and(|x| *x > 2) {
|
||||
heap.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn is_some_and_pattern_negative(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
@@ -52,24 +65,6 @@ fn is_some_and_pattern_negative(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
fake_vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, else-if branch
|
||||
if false {
|
||||
// something
|
||||
} else if vec.last().is_some_and(|x| *x > 2) {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, value used in let binding
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
let _value = vec.pop().unwrap();
|
||||
println!("Popped: {}", _value);
|
||||
}
|
||||
|
||||
// Do not lint, value used in expression
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
println!("Popped: {}", vec.pop().unwrap());
|
||||
}
|
||||
|
||||
// Do not lint, else block
|
||||
let _result = if vec.last().is_some_and(|x| *x > 2) {
|
||||
vec.pop().unwrap()
|
||||
@@ -78,34 +73,48 @@ fn is_some_and_pattern_negative(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
};
|
||||
}
|
||||
|
||||
fn if_let_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
fn if_let_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>, mut heap: BinaryHeap<i32>) {
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = vec.last() {
|
||||
//~^ manual_pop_if
|
||||
if *x > 2 {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = vec.last() {
|
||||
if *x > 2 {
|
||||
unsafe { vec.pop().unwrap_unchecked() };
|
||||
}
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = vec.last() {
|
||||
//~^ manual_pop_if
|
||||
if *x > 2 {
|
||||
vec.pop().expect("element");
|
||||
}
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = deque.back() {
|
||||
//~^ manual_pop_if
|
||||
if *x > 2 {
|
||||
deque.pop_back().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = deque.front() {
|
||||
//~^ manual_pop_if
|
||||
if *x > 2 {
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = heap.peek() {
|
||||
if *x > 2 {
|
||||
heap.pop().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn if_let_pattern_negative(mut vec: Vec<i32>) {
|
||||
@@ -132,13 +141,6 @@ fn if_let_pattern_negative(mut vec: Vec<i32>) {
|
||||
}
|
||||
}
|
||||
|
||||
// Do not lint, value used in let binding
|
||||
if let Some(x) = vec.last() {
|
||||
if *x > 2 {
|
||||
let _val = vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Do not lint, else block
|
||||
let _result = if let Some(x) = vec.last() {
|
||||
if *x > 2 { vec.pop().unwrap() } else { 0 }
|
||||
@@ -147,13 +149,19 @@ fn if_let_pattern_negative(mut vec: Vec<i32>) {
|
||||
};
|
||||
}
|
||||
|
||||
fn let_chain_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
fn let_chain_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>, mut heap: BinaryHeap<i32>) {
|
||||
if let Some(x) = vec.last() //~ manual_pop_if
|
||||
&& *x > 2
|
||||
{
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
if let Some(x) = vec.last() //~ manual_pop_if
|
||||
&& *x > 2
|
||||
{
|
||||
unsafe { vec.pop().unwrap_unchecked() };
|
||||
}
|
||||
|
||||
if let Some(x) = vec.last() //~ manual_pop_if
|
||||
&& *x > 2
|
||||
{
|
||||
@@ -171,6 +179,12 @@ fn let_chain_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
{
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
|
||||
if let Some(x) = heap.peek() //~ manual_pop_if
|
||||
&& *x > 2
|
||||
{
|
||||
heap.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn let_chain_pattern_negative(mut vec: Vec<i32>) {
|
||||
@@ -189,20 +203,6 @@ fn let_chain_pattern_negative(mut vec: Vec<i32>) {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, value used in let binding
|
||||
if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
{
|
||||
let _val = vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, value used in expression
|
||||
if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
{
|
||||
println!("Popped: {}", vec.pop().unwrap());
|
||||
}
|
||||
|
||||
// Do not lint, else block
|
||||
let _result = if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
@@ -213,26 +213,36 @@ fn let_chain_pattern_negative(mut vec: Vec<i32>) {
|
||||
};
|
||||
}
|
||||
|
||||
fn map_unwrap_or_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
fn map_unwrap_or_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>, mut heap: BinaryHeap<i32>) {
|
||||
//~v manual_pop_if
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
//~^ manual_pop_if
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
unsafe { vec.pop().unwrap_unchecked() };
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
//~^ manual_pop_if
|
||||
vec.pop().expect("element");
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if deque.back().map(|x| *x > 2).unwrap_or(false) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_back().unwrap();
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if deque.front().map(|x| *x > 2).unwrap_or(false) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if heap.peek().map(|x| *x > 2).unwrap_or(false) {
|
||||
heap.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn map_unwrap_or_pattern_negative(mut vec: Vec<i32>) {
|
||||
@@ -258,11 +268,6 @@ fn map_unwrap_or_pattern_negative(mut vec: Vec<i32>) {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, value used in let binding
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
let _val = vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, else block
|
||||
let _result = if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
vec.pop().unwrap()
|
||||
@@ -273,8 +278,8 @@ fn map_unwrap_or_pattern_negative(mut vec: Vec<i32>) {
|
||||
|
||||
// this makes sure we do not expand vec![] in the suggestion
|
||||
fn handle_macro_in_closure(mut vec: Vec<Vec<i32>>) {
|
||||
//~v manual_pop_if
|
||||
if vec.last().is_some_and(|e| *e == vec![1]) {
|
||||
//~^ manual_pop_if
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
@@ -299,21 +304,21 @@ fn msrv_too_low_vecdeque(mut deque: VecDeque<i32>) {
|
||||
|
||||
#[clippy::msrv = "1.86.0"]
|
||||
fn msrv_high_enough_vec(mut vec: Vec<i32>) {
|
||||
//~v manual_pop_if
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.93.0"]
|
||||
fn msrv_high_enough_vecdeque(mut deque: VecDeque<i32>) {
|
||||
//~v manual_pop_if
|
||||
if deque.back().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_back().unwrap();
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if deque.front().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
+428
-125
@@ -1,197 +1,500 @@
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:21:5
|
||||
--> tests/ui/manual_pop_if.rs:25:5
|
||||
|
|
||||
LL | / if vec.last().is_some_and(|x| *x > 2) {
|
||||
LL | |
|
||||
LL | | vec.pop().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `vec.pop_if(|x| *x > 2);`
|
||||
LL | if vec.last().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::manual-pop-if` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::manual_pop_if)]`
|
||||
help: try
|
||||
|
|
||||
LL - if vec.last().is_some_and(|x| *x > 2) {
|
||||
LL - vec.pop().unwrap();
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:26:5
|
||||
--> tests/ui/manual_pop_if.rs:30:5
|
||||
|
|
||||
LL | if vec.last().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe { vec.pop().unwrap_unchecked() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if vec.last().is_some_and(|x| *x > 2) {
|
||||
LL - unsafe { vec.pop().unwrap_unchecked() };
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:35:5
|
||||
|
|
||||
LL | if vec.last().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | vec.pop().expect("element");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if vec.last().is_some_and(|x| *x > 2) {
|
||||
LL - vec.pop().expect("element");
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if vec.last().is_some_and(|x| *x > 2) {
|
||||
LL | |
|
||||
LL | | vec.pop().expect("element");
|
||||
LL | | }
|
||||
| |_____^ help: try: `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `VecDeque::pop_back_if`
|
||||
--> tests/ui/manual_pop_if.rs:31:5
|
||||
--> tests/ui/manual_pop_if.rs:40:5
|
||||
|
|
||||
LL | if deque.back().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | deque.pop_back().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if deque.back().is_some_and(|x| *x > 2) {
|
||||
LL - deque.pop_back().unwrap();
|
||||
LL - }
|
||||
LL + deque.pop_back_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if deque.back().is_some_and(|x| *x > 2) {
|
||||
LL | |
|
||||
LL | | deque.pop_back().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `deque.pop_back_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `VecDeque::pop_front_if`
|
||||
--> tests/ui/manual_pop_if.rs:36:5
|
||||
--> tests/ui/manual_pop_if.rs:45:5
|
||||
|
|
||||
LL | if deque.front().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | deque.pop_front().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if deque.front().is_some_and(|x| *x > 2) {
|
||||
LL - deque.pop_front().unwrap();
|
||||
LL - }
|
||||
LL + deque.pop_front_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `BinaryHeap::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:50:5
|
||||
|
|
||||
LL | if heap.peek().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | heap.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if heap.peek().is_some_and(|x| *x > 2) {
|
||||
LL - heap.pop().unwrap();
|
||||
LL - }
|
||||
LL + heap.pop_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if deque.front().is_some_and(|x| *x > 2) {
|
||||
LL | |
|
||||
LL | | deque.pop_front().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `deque.pop_front_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:82:5
|
||||
--> tests/ui/manual_pop_if.rs:78:5
|
||||
|
|
||||
LL | if let Some(x) = vec.last() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | if *x > 2 {
|
||||
| ^^^^^^^^^
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = vec.last() {
|
||||
LL - if *x > 2 {
|
||||
LL - vec.pop().unwrap();
|
||||
LL - }
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if let Some(x) = vec.last() {
|
||||
LL | |
|
||||
LL | | if *x > 2 {
|
||||
LL | | vec.pop().unwrap();
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_____^ help: try: `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:89:5
|
||||
--> tests/ui/manual_pop_if.rs:85:5
|
||||
|
|
||||
LL | if let Some(x) = vec.last() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | if *x > 2 {
|
||||
| ^^^^^^^^^
|
||||
LL | unsafe { vec.pop().unwrap_unchecked() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = vec.last() {
|
||||
LL - if *x > 2 {
|
||||
LL - unsafe { vec.pop().unwrap_unchecked() };
|
||||
LL - }
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:92:5
|
||||
|
|
||||
LL | if let Some(x) = vec.last() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | if *x > 2 {
|
||||
| ^^^^^^^^^
|
||||
LL | vec.pop().expect("element");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = vec.last() {
|
||||
LL - if *x > 2 {
|
||||
LL - vec.pop().expect("element");
|
||||
LL - }
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if let Some(x) = vec.last() {
|
||||
LL | |
|
||||
LL | | if *x > 2 {
|
||||
LL | | vec.pop().expect("element");
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_____^ help: try: `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `VecDeque::pop_back_if`
|
||||
--> tests/ui/manual_pop_if.rs:96:5
|
||||
--> tests/ui/manual_pop_if.rs:99:5
|
||||
|
|
||||
LL | if let Some(x) = deque.back() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | if *x > 2 {
|
||||
| ^^^^^^^^^
|
||||
LL | deque.pop_back().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = deque.back() {
|
||||
LL - if *x > 2 {
|
||||
LL - deque.pop_back().unwrap();
|
||||
LL - }
|
||||
LL - }
|
||||
LL + deque.pop_back_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if let Some(x) = deque.back() {
|
||||
LL | |
|
||||
LL | | if *x > 2 {
|
||||
LL | | deque.pop_back().unwrap();
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_____^ help: try: `deque.pop_back_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `VecDeque::pop_front_if`
|
||||
--> tests/ui/manual_pop_if.rs:103:5
|
||||
--> tests/ui/manual_pop_if.rs:106:5
|
||||
|
|
||||
LL | if let Some(x) = deque.front() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | if *x > 2 {
|
||||
| ^^^^^^^^^
|
||||
LL | deque.pop_front().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = deque.front() {
|
||||
LL - if *x > 2 {
|
||||
LL - deque.pop_front().unwrap();
|
||||
LL - }
|
||||
LL - }
|
||||
LL + deque.pop_front_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `BinaryHeap::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:113:5
|
||||
|
|
||||
LL | if let Some(x) = heap.peek() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | if *x > 2 {
|
||||
| ^^^^^^^^^
|
||||
LL | heap.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = heap.peek() {
|
||||
LL - if *x > 2 {
|
||||
LL - heap.pop().unwrap();
|
||||
LL - }
|
||||
LL - }
|
||||
LL + heap.pop_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if let Some(x) = deque.front() {
|
||||
LL | |
|
||||
LL | | if *x > 2 {
|
||||
LL | | deque.pop_front().unwrap();
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_____^ help: try: `deque.pop_front_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:151:5
|
||||
--> tests/ui/manual_pop_if.rs:153:5
|
||||
|
|
||||
LL | / if let Some(x) = vec.last()
|
||||
LL | | && *x > 2
|
||||
LL | | {
|
||||
LL | | vec.pop().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `vec.pop_if(|x| *x > 2);`
|
||||
| |_________________^
|
||||
LL | {
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = vec.last()
|
||||
LL - && *x > 2
|
||||
LL - {
|
||||
LL - vec.pop().unwrap();
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:157:5
|
||||
--> tests/ui/manual_pop_if.rs:159:5
|
||||
|
|
||||
LL | / if let Some(x) = vec.last()
|
||||
LL | | && *x > 2
|
||||
LL | | {
|
||||
LL | | vec.pop().expect("element");
|
||||
LL | | }
|
||||
| |_____^ help: try: `vec.pop_if(|x| *x > 2);`
|
||||
| |_________________^
|
||||
LL | {
|
||||
LL | unsafe { vec.pop().unwrap_unchecked() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = vec.last()
|
||||
LL - && *x > 2
|
||||
LL - {
|
||||
LL - unsafe { vec.pop().unwrap_unchecked() };
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:165:5
|
||||
|
|
||||
LL | / if let Some(x) = vec.last()
|
||||
LL | | && *x > 2
|
||||
| |_________________^
|
||||
LL | {
|
||||
LL | vec.pop().expect("element");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = vec.last()
|
||||
LL - && *x > 2
|
||||
LL - {
|
||||
LL - vec.pop().expect("element");
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `VecDeque::pop_back_if`
|
||||
--> tests/ui/manual_pop_if.rs:163:5
|
||||
--> tests/ui/manual_pop_if.rs:171:5
|
||||
|
|
||||
LL | / if let Some(x) = deque.back()
|
||||
LL | | && *x > 2
|
||||
LL | | {
|
||||
LL | | deque.pop_back().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `deque.pop_back_if(|x| *x > 2);`
|
||||
| |_________________^
|
||||
LL | {
|
||||
LL | deque.pop_back().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = deque.back()
|
||||
LL - && *x > 2
|
||||
LL - {
|
||||
LL - deque.pop_back().unwrap();
|
||||
LL - }
|
||||
LL + deque.pop_back_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `VecDeque::pop_front_if`
|
||||
--> tests/ui/manual_pop_if.rs:169:5
|
||||
--> tests/ui/manual_pop_if.rs:177:5
|
||||
|
|
||||
LL | / if let Some(x) = deque.front()
|
||||
LL | | && *x > 2
|
||||
LL | | {
|
||||
LL | | deque.pop_front().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `deque.pop_front_if(|x| *x > 2);`
|
||||
| |_________________^
|
||||
LL | {
|
||||
LL | deque.pop_front().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = deque.front()
|
||||
LL - && *x > 2
|
||||
LL - {
|
||||
LL - deque.pop_front().unwrap();
|
||||
LL - }
|
||||
LL + deque.pop_front_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `BinaryHeap::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:183:5
|
||||
|
|
||||
LL | / if let Some(x) = heap.peek()
|
||||
LL | | && *x > 2
|
||||
| |_________________^
|
||||
LL | {
|
||||
LL | heap.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if let Some(x) = heap.peek()
|
||||
LL - && *x > 2
|
||||
LL - {
|
||||
LL - heap.pop().unwrap();
|
||||
LL - }
|
||||
LL + heap.pop_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:217:5
|
||||
--> tests/ui/manual_pop_if.rs:218:5
|
||||
|
|
||||
LL | if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
LL - vec.pop().unwrap();
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
LL | |
|
||||
LL | | vec.pop().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:222:5
|
||||
--> tests/ui/manual_pop_if.rs:223:5
|
||||
|
|
||||
LL | if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe { vec.pop().unwrap_unchecked() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
LL - unsafe { vec.pop().unwrap_unchecked() };
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:228:5
|
||||
|
|
||||
LL | if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | vec.pop().expect("element");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
LL - vec.pop().expect("element");
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
LL | |
|
||||
LL | | vec.pop().expect("element");
|
||||
LL | | }
|
||||
| |_____^ help: try: `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `VecDeque::pop_back_if`
|
||||
--> tests/ui/manual_pop_if.rs:227:5
|
||||
--> tests/ui/manual_pop_if.rs:233:5
|
||||
|
|
||||
LL | if deque.back().map(|x| *x > 2).unwrap_or(false) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | deque.pop_back().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if deque.back().map(|x| *x > 2).unwrap_or(false) {
|
||||
LL - deque.pop_back().unwrap();
|
||||
LL - }
|
||||
LL + deque.pop_back_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if deque.back().map(|x| *x > 2).unwrap_or(false) {
|
||||
LL | |
|
||||
LL | | deque.pop_back().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `deque.pop_back_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `VecDeque::pop_front_if`
|
||||
--> tests/ui/manual_pop_if.rs:232:5
|
||||
--> tests/ui/manual_pop_if.rs:238:5
|
||||
|
|
||||
LL | if deque.front().map(|x| *x > 2).unwrap_or(false) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | deque.pop_front().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if deque.front().map(|x| *x > 2).unwrap_or(false) {
|
||||
LL - deque.pop_front().unwrap();
|
||||
LL - }
|
||||
LL + deque.pop_front_if(|x| *x > 2);
|
||||
|
|
||||
|
||||
error: manual implementation of `BinaryHeap::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:243:5
|
||||
|
|
||||
LL | if heap.peek().map(|x| *x > 2).unwrap_or(false) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | heap.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if heap.peek().map(|x| *x > 2).unwrap_or(false) {
|
||||
LL - heap.pop().unwrap();
|
||||
LL - }
|
||||
LL + heap.pop_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if deque.front().map(|x| *x > 2).unwrap_or(false) {
|
||||
LL | |
|
||||
LL | | deque.pop_front().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `deque.pop_front_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:276:5
|
||||
--> tests/ui/manual_pop_if.rs:282:5
|
||||
|
|
||||
LL | if vec.last().is_some_and(|e| *e == vec![1]) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if vec.last().is_some_and(|e| *e == vec![1]) {
|
||||
LL - vec.pop().unwrap();
|
||||
LL - }
|
||||
LL + vec.pop_if(|e| *e == vec![1]);
|
||||
|
|
||||
LL | / if vec.last().is_some_and(|e| *e == vec![1]) {
|
||||
LL | |
|
||||
LL | | vec.pop().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `vec.pop_if(|e| *e == vec![1]);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:302:5
|
||||
--> tests/ui/manual_pop_if.rs:308:5
|
||||
|
|
||||
LL | if vec.last().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if vec.last().is_some_and(|x| *x > 2) {
|
||||
LL - vec.pop().unwrap();
|
||||
LL - }
|
||||
LL + vec.pop_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if vec.last().is_some_and(|x| *x > 2) {
|
||||
LL | |
|
||||
LL | | vec.pop().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `VecDeque::pop_back_if`
|
||||
--> tests/ui/manual_pop_if.rs:310:5
|
||||
--> tests/ui/manual_pop_if.rs:316:5
|
||||
|
|
||||
LL | if deque.back().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | deque.pop_back().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if deque.back().is_some_and(|x| *x > 2) {
|
||||
LL - deque.pop_back().unwrap();
|
||||
LL - }
|
||||
LL + deque.pop_back_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if deque.back().is_some_and(|x| *x > 2) {
|
||||
LL | |
|
||||
LL | | deque.pop_back().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `deque.pop_back_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `VecDeque::pop_front_if`
|
||||
--> tests/ui/manual_pop_if.rs:315:5
|
||||
--> tests/ui/manual_pop_if.rs:321:5
|
||||
|
|
||||
LL | if deque.front().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | deque.pop_front().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL - if deque.front().is_some_and(|x| *x > 2) {
|
||||
LL - deque.pop_front().unwrap();
|
||||
LL - }
|
||||
LL + deque.pop_front_if(|x| *x > 2);
|
||||
|
|
||||
LL | / if deque.front().is_some_and(|x| *x > 2) {
|
||||
LL | |
|
||||
LL | | deque.pop_front().unwrap();
|
||||
LL | | }
|
||||
| |_____^ help: try: `deque.pop_front_if(|x| *x > 2);`
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
error: aborting due to 28 previous errors
|
||||
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
#![warn(clippy::manual_pop_if)]
|
||||
#![allow(clippy::collapsible_if, clippy::redundant_closure)]
|
||||
//@no-rustfix
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn is_some_and_pattern(mut vec: Vec<i32>) {
|
||||
if false {
|
||||
// something
|
||||
} else if vec.last().is_some_and(|x| *x > 2) {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
//~^^^ manual_pop_if
|
||||
|
||||
//~v manual_pop_if
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
let val = vec.pop().unwrap();
|
||||
println!("Popped: {}", val);
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
println!("Popped: {}", vec.pop().unwrap());
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
// a comment before the pop
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
vec.pop().unwrap();
|
||||
// a comment after the pop
|
||||
}
|
||||
}
|
||||
|
||||
fn if_let_pattern(mut vec: Vec<i32>) {
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = vec.last() {
|
||||
if *x > 2 {
|
||||
let val = vec.pop().unwrap();
|
||||
println!("Popped: {}", val);
|
||||
}
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = vec.last() {
|
||||
if *x > 2 {
|
||||
println!("Popped: {}", vec.pop().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = vec.last() {
|
||||
if *x > 2 {
|
||||
// a comment before the pop
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = vec.last() {
|
||||
if *x > 2 {
|
||||
vec.pop().unwrap();
|
||||
// a comment after the pop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn let_chain_pattern(mut vec: Vec<i32>) {
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
{
|
||||
let val = vec.pop().unwrap();
|
||||
println!("Popped: {}", val);
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
{
|
||||
println!("Popped: {}", vec.pop().unwrap());
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
{
|
||||
// a comment before the pop
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
{
|
||||
vec.pop().unwrap();
|
||||
// a comment after the pop
|
||||
}
|
||||
}
|
||||
|
||||
fn map_unwrap_or_pattern(mut vec: Vec<i32>) {
|
||||
//~v manual_pop_if
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
let val = vec.pop().unwrap();
|
||||
println!("Popped: {}", val);
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
println!("Popped: {}", vec.pop().unwrap());
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
// a comment before the pop
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
//~v manual_pop_if
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
vec.pop().unwrap();
|
||||
// a comment after the pop
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:10:12
|
||||
|
|
||||
LL | } else if vec.last().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
= note: `-D clippy::manual-pop-if` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::manual_pop_if)]`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:16:5
|
||||
|
|
||||
LL | if vec.last().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let val = vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:22:5
|
||||
|
|
||||
LL | if vec.last().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | println!("Popped: {}", vec.pop().unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:27:5
|
||||
|
|
||||
LL | if vec.last().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | // a comment before the pop
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:33:5
|
||||
|
|
||||
LL | if vec.last().is_some_and(|x| *x > 2) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:41:5
|
||||
|
|
||||
LL | if let Some(x) = vec.last() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | if *x > 2 {
|
||||
| ^^^^^^^^^
|
||||
LL | let val = vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:49:5
|
||||
|
|
||||
LL | if let Some(x) = vec.last() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | if *x > 2 {
|
||||
| ^^^^^^^^^
|
||||
LL | println!("Popped: {}", vec.pop().unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:56:5
|
||||
|
|
||||
LL | if let Some(x) = vec.last() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | if *x > 2 {
|
||||
| ^^^^^^^^^
|
||||
LL | // a comment before the pop
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:64:5
|
||||
|
|
||||
LL | if let Some(x) = vec.last() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | if *x > 2 {
|
||||
| ^^^^^^^^^
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:74:5
|
||||
|
|
||||
LL | / if let Some(x) = vec.last()
|
||||
LL | | && *x > 2
|
||||
| |_________________^
|
||||
LL | {
|
||||
LL | let val = vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:82:5
|
||||
|
|
||||
LL | / if let Some(x) = vec.last()
|
||||
LL | | && *x > 2
|
||||
| |_________________^
|
||||
LL | {
|
||||
LL | println!("Popped: {}", vec.pop().unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:89:5
|
||||
|
|
||||
LL | / if let Some(x) = vec.last()
|
||||
LL | | && *x > 2
|
||||
| |_________________^
|
||||
...
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:97:5
|
||||
|
|
||||
LL | / if let Some(x) = vec.last()
|
||||
LL | | && *x > 2
|
||||
| |_________________^
|
||||
LL | {
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:107:5
|
||||
|
|
||||
LL | if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | let val = vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:113:5
|
||||
|
|
||||
LL | if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | println!("Popped: {}", vec.pop().unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:118:5
|
||||
|
|
||||
LL | if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | // a comment before the pop
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if_unfixable.rs:124:5
|
||||
|
|
||||
LL | if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | vec.pop().unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try refactoring the code using `vec.pop_if(|x| *x > 2);`
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
|
||||
@@ -47,11 +47,18 @@ fn main() {
|
||||
let bluby: i32;
|
||||
//~^ similar_names
|
||||
|
||||
let cake: i32;
|
||||
let orange: i32;
|
||||
let ornange: i32;
|
||||
//~^ similar_names
|
||||
|
||||
let cakes: i32;
|
||||
let cake: i32;
|
||||
let coke: i32;
|
||||
//~^ similar_names
|
||||
|
||||
let wagon: i32;
|
||||
let twagon: i32;
|
||||
|
||||
match 5 {
|
||||
cheese @ 1 => {},
|
||||
rabbit => panic!(),
|
||||
@@ -93,6 +100,9 @@ fn main() {
|
||||
// 3 letter names are allowed to be similar
|
||||
let kta: i32;
|
||||
let ktv: i32;
|
||||
|
||||
let checked_exp: i32;
|
||||
let checked_expr: i32;
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
|
||||
@@ -13,52 +13,64 @@ LL | let blubx: i32;
|
||||
= help: to override `-D warnings` add `#[allow(clippy::similar_names)]`
|
||||
|
||||
error: binding's name is too similar to existing binding
|
||||
--> tests/ui/similar_names.rs:52:9
|
||||
--> tests/ui/similar_names.rs:51:9
|
||||
|
|
||||
LL | let ornange: i32;
|
||||
| ^^^^^^^
|
||||
|
|
||||
note: existing binding defined here
|
||||
--> tests/ui/similar_names.rs:50:9
|
||||
|
|
||||
LL | let orange: i32;
|
||||
| ^^^^^^
|
||||
|
||||
error: binding's name is too similar to existing binding
|
||||
--> tests/ui/similar_names.rs:56:9
|
||||
|
|
||||
LL | let coke: i32;
|
||||
| ^^^^
|
||||
|
|
||||
note: existing binding defined here
|
||||
--> tests/ui/similar_names.rs:50:9
|
||||
--> tests/ui/similar_names.rs:55:9
|
||||
|
|
||||
LL | let cake: i32;
|
||||
| ^^^^
|
||||
|
||||
error: binding's name is too similar to existing binding
|
||||
--> tests/ui/similar_names.rs:71:9
|
||||
--> tests/ui/similar_names.rs:78:9
|
||||
|
|
||||
LL | let xyzeabc: i32;
|
||||
| ^^^^^^^
|
||||
|
|
||||
note: existing binding defined here
|
||||
--> tests/ui/similar_names.rs:69:9
|
||||
--> tests/ui/similar_names.rs:76:9
|
||||
|
|
||||
LL | let xyz1abc: i32;
|
||||
| ^^^^^^^
|
||||
|
||||
error: binding's name is too similar to existing binding
|
||||
--> tests/ui/similar_names.rs:76:9
|
||||
--> tests/ui/similar_names.rs:83:9
|
||||
|
|
||||
LL | let parsee: i32;
|
||||
| ^^^^^^
|
||||
|
|
||||
note: existing binding defined here
|
||||
--> tests/ui/similar_names.rs:74:9
|
||||
--> tests/ui/similar_names.rs:81:9
|
||||
|
|
||||
LL | let parser: i32;
|
||||
| ^^^^^^
|
||||
|
||||
error: binding's name is too similar to existing binding
|
||||
--> tests/ui/similar_names.rs:102:16
|
||||
--> tests/ui/similar_names.rs:112:16
|
||||
|
|
||||
LL | bpple: sprang,
|
||||
| ^^^^^^
|
||||
|
|
||||
note: existing binding defined here
|
||||
--> tests/ui/similar_names.rs:101:16
|
||||
--> tests/ui/similar_names.rs:111:16
|
||||
|
|
||||
LL | apple: spring,
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
||||
@@ -285,3 +285,11 @@ mod fixable {
|
||||
//~^ unnecessary_cast
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16475() -> *const u8 {
|
||||
static NONE: Option<((), &'static u8)> = None;
|
||||
unsafe {
|
||||
*(&NONE as *const _ as *const _ as *const *const u8)
|
||||
//~^ unnecessary_cast
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,3 +285,11 @@ fn issue_14640() {
|
||||
//~^ unnecessary_cast
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16475() -> *const u8 {
|
||||
static NONE: Option<((), &'static u8)> = None;
|
||||
unsafe {
|
||||
*(&NONE as *const _ as *const _ as *const *const u8 as *const *const u8)
|
||||
//~^ unnecessary_cast
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,5 +277,11 @@ error: casting to the same type is unnecessary (`i64` -> `i64`)
|
||||
LL | let _ = 5i32 as i64 as i64;
|
||||
| ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64`
|
||||
|
||||
error: aborting due to 46 previous errors
|
||||
error: casting raw pointers to the same type and constness is unnecessary (`*const *const u8` -> `*const *const u8`)
|
||||
--> tests/ui/unnecessary_cast.rs:292:10
|
||||
|
|
||||
LL | *(&NONE as *const _ as *const _ as *const *const u8 as *const *const u8)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&NONE as *const _ as *const _ as *const *const u8)`
|
||||
|
||||
error: aborting due to 47 previous errors
|
||||
|
||||
|
||||
Reference in New Issue
Block a user