mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
Auto merge of #154176 - flip1995:clippy-subtree-update, r=matthiaskrgr
Clippy subtree update r? Manishearth 2 days late as I didn't get to it during the week.
This commit is contained in:
@@ -6,7 +6,103 @@ document.
|
||||
|
||||
## Unreleased / Beta / In Rust Nightly
|
||||
|
||||
[92b4b68...master](https://github.com/rust-lang/rust-clippy/compare/92b4b68...master)
|
||||
[500e0ff...master](https://github.com/rust-lang/rust-clippy/compare/500e0ff...master)
|
||||
|
||||
## Rust 1.94
|
||||
|
||||
Current stable, released 2026-03-05
|
||||
|
||||
[View all 94 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2025-11-29T21%3A01%3A29Z..2026-01-08T20%3A33%3A22Z+base%3Amaster)
|
||||
|
||||
### New Lints
|
||||
|
||||
* Added [`same_length_and_capacity`] to `pedantic`
|
||||
[#15656](https://github.com/rust-lang/rust-clippy/pull/15656)
|
||||
* Added [`manual_ilog2`] to `pedantic`
|
||||
[#15865](https://github.com/rust-lang/rust-clippy/pull/15865)
|
||||
* Added [`needless_type_cast`] to `nursery`
|
||||
[#16139](https://github.com/rust-lang/rust-clippy/pull/16139)
|
||||
* Added [`ptr_offset_by_literal`] to `pedantic`
|
||||
[#15606](https://github.com/rust-lang/rust-clippy/pull/15606)
|
||||
* Added [`decimal_bitwise_operands`] to `pedantic`
|
||||
[#15215](https://github.com/rust-lang/rust-clippy/pull/15215)
|
||||
|
||||
### Moves and Deprecations
|
||||
|
||||
* Moved [`multiple_bound_locations`] from `suspicious` to `style`
|
||||
[#16302](https://github.com/rust-lang/rust-clippy/pull/16302)
|
||||
* Moved [`collapsible_else_if`] from `style` to `pedantic`
|
||||
[#16211](https://github.com/rust-lang/rust-clippy/pull/16211)
|
||||
* Moved [`needless_type_cast`] from `pedantic` to `nursery`
|
||||
[#16246](https://github.com/rust-lang/rust-clippy/pull/16246)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [`never_loop`] do not consider `return` as preventing the iterator from looping; lint diverging
|
||||
iterator reduction closures like `for_each` and `fold`
|
||||
[#16364](https://github.com/rust-lang/rust-clippy/pull/16364)
|
||||
* [`single_range_in_vec_init`] don't apply the suggestion automatically
|
||||
[#16365](https://github.com/rust-lang/rust-clippy/pull/16365)
|
||||
* [`useless_conversion`] refine `.into_iter()` suggestions to stop at final target type
|
||||
[#16238](https://github.com/rust-lang/rust-clippy/pull/16238)
|
||||
* Multiple lints fix wrongly unmangled macros
|
||||
[#16337](https://github.com/rust-lang/rust-clippy/pull/16337)
|
||||
* [`large_stack_arrays`] do not warn for libtest harness
|
||||
[#16347](https://github.com/rust-lang/rust-clippy/pull/16347)
|
||||
* [`derive_ord_xor_partial_ord`] allow `expect` on `impl` block
|
||||
[#16303](https://github.com/rust-lang/rust-clippy/pull/16303)
|
||||
* [`match_bool`] restrict to 2 arms
|
||||
[#16333](https://github.com/rust-lang/rust-clippy/pull/16333)
|
||||
* [`multiple_inherent_impl`] fix false negatives for generic impl blocks
|
||||
[#16284](https://github.com/rust-lang/rust-clippy/pull/16284)
|
||||
* [`unnecessary_fold`] warn about semantics change and lint `Add::add`/`Mul::mul` folds
|
||||
[#16324](https://github.com/rust-lang/rust-clippy/pull/16324)
|
||||
* [`transmuting_null`] check const blocks and const integer casts
|
||||
[#16260](https://github.com/rust-lang/rust-clippy/pull/16260)
|
||||
* [`needless_pass_by_ref_mut`] preserve user-provided lifetime information
|
||||
[#16273](https://github.com/rust-lang/rust-clippy/pull/16273)
|
||||
* [`while_let_on_iterator`] use reborrow for non-`Sized` trait references
|
||||
[#16100](https://github.com/rust-lang/rust-clippy/pull/16100)
|
||||
* [`collapsible_else_if`] prevent emitting when arms only `if {..} else {..}`
|
||||
[#16286](https://github.com/rust-lang/rust-clippy/pull/16286)
|
||||
* [`multiple_unsafe_ops_per_block`] count only towards innermost unsafe block
|
||||
[#16117](https://github.com/rust-lang/rust-clippy/pull/16117)
|
||||
* [`manual_saturating_arithmetic`] lint `x.checked_sub(y).unwrap_or_default()`
|
||||
[#15845](https://github.com/rust-lang/rust-clippy/pull/15845)
|
||||
* [`transmute_ptr_to_ref`] handle pointer in struct
|
||||
[#15948](https://github.com/rust-lang/rust-clippy/pull/15948)
|
||||
* [`disallowed_methods`] skip compiler-generated code
|
||||
[#16186](https://github.com/rust-lang/rust-clippy/pull/16186)
|
||||
* [`missing_enforced_import_renames`] do not enforce for "as _"
|
||||
[#16352](https://github.com/rust-lang/rust-clippy/pull/16352)
|
||||
|
||||
### False Positive Fixes
|
||||
|
||||
* [`double_parens`] fix FP on macro repetition patterns
|
||||
[#16301](https://github.com/rust-lang/rust-clippy/pull/16301)
|
||||
* [`assertions_on_constants`] fix false positive when there is non-constant value in condition expr
|
||||
[#16297](https://github.com/rust-lang/rust-clippy/pull/16297)
|
||||
* [`use_self`] fix FP on type in const generics
|
||||
[#16172](https://github.com/rust-lang/rust-clippy/pull/16172)
|
||||
* [`set_contains_or_insert`] fix FP when set is mutated before `insert`
|
||||
[#16009](https://github.com/rust-lang/rust-clippy/pull/16009)
|
||||
* [`if_then_some_else_none`] fix FP when then block contains `await`
|
||||
[#16178](https://github.com/rust-lang/rust-clippy/pull/16178)
|
||||
* [`match_like_matches_macro`] fix FP with guards containing `if let`
|
||||
[#15876](https://github.com/rust-lang/rust-clippy/pull/15876)
|
||||
* [`tuple_array_conversions`] fix FP when binded vars are used before conversion
|
||||
[#16197](https://github.com/rust-lang/rust-clippy/pull/16197)
|
||||
* [`map_entry`] fix FP when it would cause `MutexGuard` to be held across await
|
||||
[#16199](https://github.com/rust-lang/rust-clippy/pull/16199)
|
||||
* [`panicking_unwrap`] fix FP on field access with implicit deref
|
||||
[#16196](https://github.com/rust-lang/rust-clippy/pull/16196)
|
||||
* [`large_stack_frames`] fix FP on compiler generated targets
|
||||
[#15101](https://github.com/rust-lang/rust-clippy/pull/15101)
|
||||
|
||||
### ICE Fixes
|
||||
|
||||
* [`needless_type_cast`] do not ICE on struct constructor
|
||||
[#16245](https://github.com/rust-lang/rust-clippy/pull/16245)
|
||||
|
||||
### New Lints
|
||||
|
||||
@@ -6705,6 +6801,7 @@ Released 2018-09-13
|
||||
[`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_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
|
||||
[`manual_range_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_patterns
|
||||
[`manual_rem_euclid`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid
|
||||
|
||||
@@ -5,11 +5,11 @@ check-inconsistent-struct-field-initializers = true
|
||||
lint-commented-code = true
|
||||
|
||||
[[disallowed-methods]]
|
||||
path = "rustc_lint::context::LintContext::lint"
|
||||
path = "rustc_lint::context::LintContext::opt_span_lint"
|
||||
reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead"
|
||||
|
||||
[[disallowed-methods]]
|
||||
path = "rustc_lint::context::LintContext::span_lint"
|
||||
path = "rustc_lint::context::LintContext::emit_span_lint"
|
||||
reason = "this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead"
|
||||
|
||||
[[disallowed-methods]]
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
os_str_slice,
|
||||
os_string_truncate,
|
||||
pattern,
|
||||
rustc_private,
|
||||
slice_split_once
|
||||
rustc_private
|
||||
)]
|
||||
#![warn(
|
||||
trivial_casts,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::HasSession;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{higher, is_else_clause, is_in_const_context, span_contains_comment};
|
||||
use rustc_ast::LitKind;
|
||||
@@ -60,7 +59,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
&& !is_in_const_context(cx)
|
||||
{
|
||||
let ty = cx.typeck_results().expr_ty(then);
|
||||
let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
|
||||
let mut applicability = if span_contains_comment(cx, expr.span) {
|
||||
Applicability::MaybeIncorrect
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
|
||||
@@ -691,7 +691,7 @@
|
||||
/// const SIZE: usize = 15;
|
||||
/// let arr: [u8; SIZE] = [0; SIZE];
|
||||
/// ```
|
||||
#[clippy::version = "1.93.0"]
|
||||
#[clippy::version = "1.94.0"]
|
||||
pub NEEDLESS_TYPE_CAST,
|
||||
nursery,
|
||||
"binding defined with one type but always cast to another"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::msrvs::Msrv;
|
||||
use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability};
|
||||
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 rustc_ast::{BinOpKind, MetaItemInner};
|
||||
use rustc_errors::Applicability;
|
||||
@@ -9,7 +9,6 @@
|
||||
use rustc_lexer::TokenKind;
|
||||
use rustc_lint::{LateContext, LateLintPass, Level};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::{BytePos, Span, Symbol};
|
||||
|
||||
declare_clippy_lint! {
|
||||
@@ -111,10 +110,8 @@ fn check_collapsible_else_if(&self, cx: &LateContext<'_>, then_span: Span, else_
|
||||
let up_to_else = then_span.between(else_block.span);
|
||||
let else_before_if = else_.span.shrink_to_lo().with_hi(else_if_cond.span.lo() - BytePos(1));
|
||||
if self.lint_commented_code
|
||||
&& let Some(else_keyword_span) =
|
||||
span_extract_keyword(cx.tcx.sess.source_map(), up_to_else, "else")
|
||||
&& let Some(else_if_keyword_span) =
|
||||
span_extract_keyword(cx.tcx.sess.source_map(), else_before_if, "if")
|
||||
&& let Some(else_keyword_span) = span_extract_keyword(cx, up_to_else, "else")
|
||||
&& let Some(else_if_keyword_span) = span_extract_keyword(cx, else_before_if, "if")
|
||||
{
|
||||
let else_keyword_span = else_keyword_span.with_leading_whitespace(cx).into_span();
|
||||
let else_open_bracket = else_block.span.split_at(1).0.with_leading_whitespace(cx).into_span();
|
||||
@@ -139,7 +136,7 @@ fn check_collapsible_else_if(&self, cx: &LateContext<'_>, then_span: Span, else_
|
||||
}
|
||||
|
||||
// Peel off any parentheses.
|
||||
let (_, else_block_span, _) = peel_parens(cx.tcx.sess.source_map(), else_.span);
|
||||
let (_, else_block_span, _) = peel_parens(cx, else_.span);
|
||||
|
||||
// Prevent "elseif"
|
||||
// Check that the "else" is followed by whitespace
|
||||
@@ -187,7 +184,7 @@ fn check_collapsible_if_if(&self, cx: &LateContext<'_>, expr: &Expr<'_>, check:
|
||||
.with_leading_whitespace(cx)
|
||||
.into_span()
|
||||
};
|
||||
let (paren_start, inner_if_span, paren_end) = peel_parens(cx.tcx.sess.source_map(), inner.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![
|
||||
// Remove the outer then block `{`
|
||||
@@ -320,33 +317,36 @@ pub(super) fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> {
|
||||
}
|
||||
}
|
||||
|
||||
fn span_extract_keyword(sm: &SourceMap, span: Span, keyword: &str) -> Option<Span> {
|
||||
let snippet = sm.span_to_snippet(span).ok()?;
|
||||
tokenize_with_text(&snippet)
|
||||
.filter(|(t, s, _)| matches!(t, TokenKind::Ident if *s == keyword))
|
||||
.map(|(_, _, inner)| {
|
||||
span.split_at(u32::try_from(inner.start).unwrap())
|
||||
.1
|
||||
.split_at(u32::try_from(inner.end - inner.start).unwrap())
|
||||
.0
|
||||
})
|
||||
.next()
|
||||
fn span_extract_keyword(cx: &impl HasSession, span: Span, keyword: &str) -> Option<Span> {
|
||||
span.with_source_text(cx, |snippet| {
|
||||
tokenize_with_text(snippet)
|
||||
.filter(|(t, s, _)| matches!(t, TokenKind::Ident if *s == keyword))
|
||||
.map(|(_, _, inner)| {
|
||||
span.split_at(u32::try_from(inner.start).unwrap())
|
||||
.1
|
||||
.split_at(u32::try_from(inner.end - inner.start).unwrap())
|
||||
.0
|
||||
})
|
||||
.next()
|
||||
})
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// Peel the parentheses from an `if` expression, e.g. `((if true {} else {}))`.
|
||||
pub(super) fn peel_parens(sm: &SourceMap, mut span: Span) -> (Span, Span, Span) {
|
||||
pub(super) fn peel_parens(cx: &impl HasSession, mut span: Span) -> (Span, Span, Span) {
|
||||
use crate::rustc_span::Pos;
|
||||
|
||||
let start = span.shrink_to_lo();
|
||||
let end = span.shrink_to_hi();
|
||||
|
||||
let snippet = sm.span_to_snippet(span).unwrap();
|
||||
if let Some((trim_start, _, trim_end)) = peel_parens_str(&snippet) {
|
||||
let mut data = span.data();
|
||||
data.lo = data.lo + BytePos::from_usize(trim_start);
|
||||
data.hi = data.hi - BytePos::from_usize(trim_end);
|
||||
span = data.span();
|
||||
}
|
||||
span.with_source_text(cx, |snippet| {
|
||||
if let Some((trim_start, _, trim_end)) = peel_parens_str(snippet) {
|
||||
let mut data = span.data();
|
||||
data.lo = data.lo + BytePos::from_usize(trim_start);
|
||||
data.hi = data.hi - BytePos::from_usize(trim_end);
|
||||
span = data.span();
|
||||
}
|
||||
});
|
||||
|
||||
(start.with_hi(span.lo()), span, end.with_lo(span.hi()))
|
||||
}
|
||||
|
||||
@@ -312,6 +312,7 @@
|
||||
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
|
||||
crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_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,
|
||||
crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
|
||||
crate::manual_retain::MANUAL_RETAIN_INFO,
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::SyntaxContext;
|
||||
use rustc_span::Spanned;
|
||||
use rustc_span::{Spanned, SyntaxContext};
|
||||
|
||||
use super::SUBOPTIMAL_FLOPS;
|
||||
|
||||
|
||||
@@ -210,6 +210,7 @@
|
||||
mod manual_main_separator_str;
|
||||
mod manual_non_exhaustive;
|
||||
mod manual_option_as_slice;
|
||||
mod manual_pop_if;
|
||||
mod manual_range_patterns;
|
||||
mod manual_rem_euclid;
|
||||
mod manual_retain;
|
||||
@@ -863,6 +864,7 @@ 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))),
|
||||
// add late passes here, used by `cargo dev new_lint`
|
||||
];
|
||||
store.late_passes.extend(late_lints);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_applicability};
|
||||
use clippy_utils::source::{indent_of, reindent_multiline, snippet_with_applicability};
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{higher, is_refutable, peel_blocks_with_stmt, span_contains_comment};
|
||||
use rustc_errors::Applicability;
|
||||
@@ -50,7 +50,7 @@ pub(super) fn check<'tcx>(
|
||||
format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used");
|
||||
|
||||
// Prepare the help message
|
||||
let mut applicability = if span_contains_comment(cx.sess().source_map(), body.span) {
|
||||
let mut applicability = if span_contains_comment(cx, body.span) {
|
||||
Applicability::MaybeIncorrect
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::{HasSession, snippet_with_applicability};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::{implements_trait, is_slice_like};
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment};
|
||||
@@ -93,7 +93,7 @@ fn sugg<'tcx>(
|
||||
slice_span: rustc_span::Span,
|
||||
assignval_span: rustc_span::Span,
|
||||
) {
|
||||
let mut app = if span_contains_comment(cx.sess().source_map(), body.span) {
|
||||
let mut app = if span_contains_comment(cx, body.span) {
|
||||
Applicability::MaybeIncorrect // Comments may be informational.
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
use clippy_utils::higher::If;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::HasSession as _;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::peel_and_count_ty_refs;
|
||||
use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment, sym};
|
||||
@@ -76,10 +75,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
(a, b) = (b, a);
|
||||
}
|
||||
let applicability = {
|
||||
let source_map = cx.sess().source_map();
|
||||
if span_contains_comment(source_map, if_expr.then.span)
|
||||
|| span_contains_comment(source_map, r#else.span)
|
||||
{
|
||||
if span_contains_comment(cx, if_expr.then.span) || span_contains_comment(cx, r#else.span) {
|
||||
Applicability::MaybeIncorrect
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
|
||||
@@ -58,7 +58,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
|
||||
"only a `panic!` in `if`-then statement",
|
||||
|diag| {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
|
||||
let mut comments = span_extract_comment(cx, expr.span);
|
||||
if !comments.is_empty() {
|
||||
comments += "\n";
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
/// let log = x.ilog2();
|
||||
/// let log = x.ilog2();
|
||||
/// ```
|
||||
#[clippy::version = "1.93.0"]
|
||||
#[clippy::version = "1.94.0"]
|
||||
pub MANUAL_ILOG2,
|
||||
pedantic,
|
||||
"manually reimplementing `ilog2`"
|
||||
|
||||
@@ -0,0 +1,434 @@
|
||||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
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 rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, PatKind, RustcVersion, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use std::fmt;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for code to be replaced by `pop_if` methods.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// 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.
|
||||
///
|
||||
/// ### Examples
|
||||
/// ```no_run
|
||||
/// # use std::collections::VecDeque;
|
||||
/// # let mut vec = vec![1, 2, 3, 4, 5];
|
||||
/// # let mut deque: VecDeque<i32> = VecDeque::from([1, 2, 3, 4, 5]);
|
||||
/// if vec.last().is_some_and(|x| *x > 5) {
|
||||
/// vec.pop().unwrap();
|
||||
/// }
|
||||
/// if deque.back().is_some_and(|x| *x > 5) {
|
||||
/// deque.pop_back().unwrap();
|
||||
/// }
|
||||
/// if deque.front().is_some_and(|x| *x > 5) {
|
||||
/// deque.pop_front().unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// # use std::collections::VecDeque;
|
||||
/// # let mut vec = vec![1, 2, 3, 4, 5];
|
||||
/// # let mut deque: VecDeque<i32> = VecDeque::from([1, 2, 3, 4, 5]);
|
||||
/// vec.pop_if(|x| *x > 5);
|
||||
/// deque.pop_back_if(|x| *x > 5);
|
||||
/// deque.pop_front_if(|x| *x > 5);
|
||||
/// ```
|
||||
#[clippy::version = "1.95.0"]
|
||||
pub MANUAL_POP_IF,
|
||||
complexity,
|
||||
"manual implementation of `pop_if` methods"
|
||||
}
|
||||
|
||||
impl_lint_pass!(ManualPopIf => [MANUAL_POP_IF]);
|
||||
|
||||
pub struct ManualPopIf {
|
||||
msrv: Msrv,
|
||||
}
|
||||
|
||||
impl ManualPopIf {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self { msrv: conf.msrv }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum ManualPopIfKind {
|
||||
Vec,
|
||||
VecDequeBack,
|
||||
VecDequeFront,
|
||||
}
|
||||
|
||||
impl ManualPopIfKind {
|
||||
fn check_method(self) -> Symbol {
|
||||
match self {
|
||||
ManualPopIfKind::Vec => sym::last,
|
||||
ManualPopIfKind::VecDequeBack => sym::back,
|
||||
ManualPopIfKind::VecDequeFront => sym::front,
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_method(self) -> Symbol {
|
||||
match self {
|
||||
ManualPopIfKind::Vec => sym::pop,
|
||||
ManualPopIfKind::VecDequeBack => sym::pop_back,
|
||||
ManualPopIfKind::VecDequeFront => sym::pop_front,
|
||||
}
|
||||
}
|
||||
|
||||
fn pop_if_method(self) -> Symbol {
|
||||
match self {
|
||||
ManualPopIfKind::Vec => sym::pop_if,
|
||||
ManualPopIfKind::VecDequeBack => sym::pop_back_if,
|
||||
ManualPopIfKind::VecDequeFront => sym::pop_front_if,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_diag_item(self, cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ManualPopIfKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ManualPopIfKind::Vec => write!(f, "`Vec::pop_if`"),
|
||||
ManualPopIfKind::VecDequeBack => write!(f, "`VecDeque::pop_back_if`"),
|
||||
ManualPopIfKind::VecDequeFront => write!(f, "`VecDeque::pop_front_if`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ManualPopIfPattern<'tcx> {
|
||||
kind: ManualPopIfKind,
|
||||
|
||||
/// The collection (`vec` in `vec.last()`)
|
||||
collection_expr: &'tcx Expr<'tcx>,
|
||||
|
||||
/// The closure (`*x > 5` in `|x| *x > 5`)
|
||||
predicate: &'tcx Expr<'tcx>,
|
||||
|
||||
/// Parameter name for the closure (`x` in `|x| *x > 5`)
|
||||
param_name: Symbol,
|
||||
|
||||
/// Span of the if expression (including the `if` keyword)
|
||||
if_span: Span,
|
||||
}
|
||||
|
||||
impl ManualPopIfPattern<'_> {
|
||||
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;
|
||||
let predicate_snippet = snippet_with_context(cx, self.predicate.span, ctxt, "..", &mut app).0;
|
||||
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(
|
||||
cx,
|
||||
MANUAL_POP_IF,
|
||||
self.if_span,
|
||||
format!("manual implementation of {}", self.kind),
|
||||
"try",
|
||||
suggestion,
|
||||
app,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
/// vec.pop().unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
fn check_is_some_and_pattern<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
cond: &'tcx Expr<'_>,
|
||||
then_block: &'tcx Expr<'_>,
|
||||
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 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
|
||||
&& 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)
|
||||
&& eq_expr_value(cx, collection_expr, pop_collection)
|
||||
&& let Some(param) = body.params.first()
|
||||
&& let Some(ident) = param.pat.simple_ident()
|
||||
{
|
||||
return Some(ManualPopIfPattern {
|
||||
kind,
|
||||
collection_expr,
|
||||
predicate: body.value,
|
||||
param_name: ident.name,
|
||||
if_span: if_expr_span,
|
||||
});
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Checks for the pattern:
|
||||
/// ```ignore
|
||||
/// if let Some(x) = vec.last() {
|
||||
/// if *x > 5 {
|
||||
/// vec.pop().unwrap();
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn check_if_let_pattern<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
cond: &'tcx Expr<'_>,
|
||||
then_block: &'tcx Expr<'_>,
|
||||
if_expr_span: Span,
|
||||
kind: ManualPopIfKind,
|
||||
) -> Option<ManualPopIfPattern<'tcx>> {
|
||||
let check_method = kind.check_method();
|
||||
let pop_method = kind.pop_method();
|
||||
|
||||
if let ExprKind::Let(let_expr) = cond.kind
|
||||
&& let PatKind::TupleStruct(qpath, [binding_pat], _) = let_expr.pat.kind
|
||||
{
|
||||
let res = cx.qpath_res(&qpath, let_expr.pat.hir_id);
|
||||
|
||||
if let Some(def_id) = res.opt_def_id()
|
||||
&& 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
|
||||
&& kind.is_diag_item(cx, collection_expr)
|
||||
&& let ExprKind::Block(block, _) = then_block.kind
|
||||
{
|
||||
// The inner if can be either a statement or a block expression
|
||||
let inner_if = match (block.stmts, block.expr) {
|
||||
([stmt], _) => match stmt.kind {
|
||||
StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr,
|
||||
_ => return None,
|
||||
},
|
||||
([], Some(expr)) => expr,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
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)
|
||||
&& eq_expr_value(cx, collection_expr, pop_collection)
|
||||
{
|
||||
return Some(ManualPopIfPattern {
|
||||
kind,
|
||||
collection_expr,
|
||||
predicate: inner_cond,
|
||||
param_name: binding_name.name,
|
||||
if_span: if_expr_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Checks for the pattern:
|
||||
/// ```ignore
|
||||
/// if let Some(x) = vec.last() && *x > 5 {
|
||||
/// vec.pop().unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
fn check_let_chain_pattern<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
cond: &'tcx Expr<'_>,
|
||||
then_block: &'tcx Expr<'_>,
|
||||
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 pop_method = kind.pop_method();
|
||||
|
||||
if let ExprKind::Binary(op, left, right) = cond.kind
|
||||
&& op.node == rustc_ast::BinOpKind::And
|
||||
&& let ExprKind::Let(let_expr) = left.kind
|
||||
&& let PatKind::TupleStruct(qpath, [binding_pat], _) = let_expr.pat.kind
|
||||
{
|
||||
let res = cx.qpath_res(&qpath, let_expr.pat.hir_id);
|
||||
|
||||
if let Some(def_id) = res.opt_def_id()
|
||||
&& 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
|
||||
&& 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)
|
||||
&& eq_expr_value(cx, collection_expr, pop_collection)
|
||||
{
|
||||
return Some(ManualPopIfPattern {
|
||||
kind,
|
||||
collection_expr,
|
||||
predicate: right,
|
||||
param_name: binding_name.name,
|
||||
if_span: if_expr_span,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Checks for the pattern:
|
||||
/// ```ignore
|
||||
/// if vec.last().map(|x| *x > 5).unwrap_or(false) {
|
||||
/// vec.pop().unwrap();
|
||||
/// }
|
||||
/// ```
|
||||
fn check_map_unwrap_or_pattern<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
cond: &'tcx Expr<'_>,
|
||||
then_block: &'tcx Expr<'_>,
|
||||
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 pop_method = kind.pop_method();
|
||||
|
||||
if let ExprKind::MethodCall(unwrap_path, receiver, [default_arg], _) = cond.kind
|
||||
&& unwrap_path.ident.name == sym::unwrap_or
|
||||
&& matches!(default_arg.kind, ExprKind::Lit(lit) if matches!(lit.node, LitKind::Bool(false)))
|
||||
&& 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
|
||||
&& 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)
|
||||
&& eq_expr_value(cx, collection_expr, pop_collection)
|
||||
&& let Some(param) = body.params.first()
|
||||
&& let Some(ident) = param.pat.simple_ident()
|
||||
{
|
||||
return Some(ManualPopIfPattern {
|
||||
kind,
|
||||
collection_expr,
|
||||
predicate: body.value,
|
||||
param_name: ident.name,
|
||||
if_span: if_expr_span,
|
||||
});
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// 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);
|
||||
|
||||
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
|
||||
{
|
||||
return Some((collection_expr, inner_expr.span));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for ManualPopIf {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let ExprKind::If(cond, then_block, None) = expr.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Do not lint if we are in an else-if branch.
|
||||
if is_else_clause(cx.tcx, expr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for kind in [
|
||||
ManualPopIfKind::Vec,
|
||||
ManualPopIfKind::VecDequeBack,
|
||||
ManualPopIfKind::VecDequeFront,
|
||||
] {
|
||||
if let Some(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())
|
||||
{
|
||||
pattern.emit_lint(cx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,7 +154,7 @@ fn check_arm<'tcx>(
|
||||
} else {
|
||||
outer_pat.span.shrink_to_hi()
|
||||
};
|
||||
let (paren_start, inner_if_span, paren_end) = peel_parens(cx.tcx.sess.source_map(), inner_expr.span);
|
||||
let (paren_start, inner_if_span, paren_end) = peel_parens(cx, inner_expr.span);
|
||||
let inner_if = inner_if_span.split_at(2).0;
|
||||
let mut sugg = vec![
|
||||
(inner.then.span.shrink_to_lo(), "=> ".to_string()),
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
use rustc_hir::LangItem::ResultErr;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::symbol::Ident;
|
||||
|
||||
@@ -130,7 +130,7 @@ fn is_none(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
/// `err`, depending on `is_ok`.
|
||||
fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok: bool) {
|
||||
let method = if is_ok { "ok" } else { "err" };
|
||||
let mut app = if span_contains_comment(cx.sess().source_map(), expr.span) {
|
||||
let mut app = if span_contains_comment(cx, expr.span) {
|
||||
Applicability::MaybeIncorrect
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, Pat, PatExpr, PatExprKind, PatKind, QPath};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{GenericArgKind, Ty};
|
||||
use rustc_span::sym;
|
||||
|
||||
@@ -101,7 +101,7 @@ fn handle(
|
||||
&& local_id == binding_id
|
||||
{
|
||||
// Machine applicable only if there are no comments present
|
||||
let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
|
||||
let mut applicability = if span_contains_comment(cx, expr.span) {
|
||||
Applicability::MaybeIncorrect
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Pat, PatKind, QPath};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::Spanned;
|
||||
|
||||
@@ -22,7 +22,7 @@ pub(crate) fn check_if_let<'tcx>(
|
||||
then_expr: &'tcx Expr<'_>,
|
||||
else_expr: &'tcx Expr<'_>,
|
||||
) {
|
||||
if !span_contains_comment(cx.sess().source_map(), expr.span)
|
||||
if !span_contains_comment(cx, expr.span)
|
||||
&& cx.typeck_results().expr_ty(expr).is_bool()
|
||||
&& let Some(b0) = find_bool_lit(then_expr)
|
||||
&& let Some(b1) = find_bool_lit(else_expr)
|
||||
@@ -71,7 +71,7 @@ pub(super) fn check_match<'tcx>(
|
||||
) -> bool {
|
||||
if let Some((last_arm, arms_without_last)) = arms.split_last()
|
||||
&& let Some((first_arm, middle_arms)) = arms_without_last.split_first()
|
||||
&& !span_contains_comment(cx.sess().source_map(), e.span)
|
||||
&& !span_contains_comment(cx, e.span)
|
||||
&& cx.typeck_results().expr_ty(e).is_bool()
|
||||
&& let Some(b0) = find_bool_lit(first_arm.body)
|
||||
&& let Some(b1) = find_bool_lit(last_arm.body)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExpr, PatExprKind, PatKind, RangeEnd};
|
||||
use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::{self, TypeckResults};
|
||||
use rustc_span::{ByteSymbol, ErrorGuaranteed, Span, Symbol};
|
||||
|
||||
use super::MATCH_SAME_ARMS;
|
||||
@@ -61,7 +61,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
|
||||
|
||||
let check_eq_with_pat = |expr_a: &Expr<'_>, expr_b: &Expr<'_>| {
|
||||
let mut local_map: HirIdMap<HirId> = HirIdMap::default();
|
||||
let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
|
||||
let eq_fallback = |a_typeck_results: &TypeckResults<'tcx>,
|
||||
a: &Expr<'_>,
|
||||
b_typeck_results: &TypeckResults<'tcx>,
|
||||
b: &Expr<'_>| {
|
||||
if let Some(a_id) = a.res_local_id()
|
||||
&& let Some(b_id) = b.res_local_id()
|
||||
&& let entry = match local_map.entry(a_id) {
|
||||
@@ -71,7 +74,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
|
||||
}
|
||||
// the names technically don't have to match; this makes the lint more conservative
|
||||
&& cx.tcx.hir_name(a_id) == cx.tcx.hir_name(b_id)
|
||||
&& cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b)
|
||||
&& a_typeck_results.expr_ty(a) == b_typeck_results.expr_ty(b)
|
||||
&& pat_contains_local(lhs.pat, a_id)
|
||||
&& pat_contains_local(rhs.pat, b_id)
|
||||
{
|
||||
|
||||
@@ -1093,12 +1093,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
}
|
||||
|
||||
redundant_pattern_match::check_match(cx, expr, ex, arms);
|
||||
let source_map = cx.tcx.sess.source_map();
|
||||
let mut match_comments = span_extract_comments(source_map, expr.span);
|
||||
let mut match_comments = span_extract_comments(cx, expr.span);
|
||||
// We remove comments from inside arms block.
|
||||
if !match_comments.is_empty() {
|
||||
for arm in arms {
|
||||
for comment in span_extract_comments(source_map, arm.body.span) {
|
||||
for comment in span_extract_comments(cx, arm.body.span) {
|
||||
if let Some(index) = match_comments
|
||||
.iter()
|
||||
.enumerate()
|
||||
|
||||
+1
-2
@@ -7,8 +7,7 @@
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::Spanned;
|
||||
use rustc_span::{Span, Spanned};
|
||||
|
||||
use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::TypeckResults;
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
@@ -136,7 +137,9 @@ pub fn check_map_call(
|
||||
// .map(|y| y[.acceptable_method()].unwrap())
|
||||
&& let simple_equal = (receiver.res_local_id() == Some(filter_param_id)
|
||||
&& map_arg_peeled.res_local_id() == Some(map_param_id))
|
||||
&& let eq_fallback = (|a: &Expr<'_>, b: &Expr<'_>| {
|
||||
&& let eq_fallback =
|
||||
(|a_typeck_results: &TypeckResults<'tcx>, a: &Expr<'_>,
|
||||
b_typeck_results: &TypeckResults<'tcx>, b: &Expr<'_>| {
|
||||
// in `filter(|x| ..)`, replace `*x` with `x`
|
||||
let a_path = if !is_filter_param_ref
|
||||
&& let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind
|
||||
@@ -144,7 +147,7 @@ pub fn check_map_call(
|
||||
// let the filter closure arg and the map closure arg be equal
|
||||
a_path.res_local_id() == Some(filter_param_id)
|
||||
&& b.res_local_id() == Some(map_param_id)
|
||||
&& cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
|
||||
&& a_typeck_results.expr_ty_adjusted(a) == b_typeck_results.expr_ty_adjusted(b)
|
||||
})
|
||||
&& (simple_equal
|
||||
|| SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(receiver, map_arg_peeled))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
|
||||
use clippy_utils::ty::get_iterator_item_ty;
|
||||
use hir::ExprKind;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME};
|
||||
|
||||
@@ -144,7 +144,7 @@ fn expression_type(
|
||||
) -> Option<FilterType> {
|
||||
if !cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
|
||||
|| parent_is_map(cx, expr)
|
||||
|| span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi()))
|
||||
|| span_contains_comment(cx, filter_span.with_hi(expr.span.hi()))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, map_
|
||||
let closure_snippet = snippet_with_applicability(cx, map_arg.span, "..", &mut applicability);
|
||||
let span = expr.span.with_lo(map_span.lo());
|
||||
// If the methods are separated with comments, we don't apply suggestion automatically.
|
||||
if span_contains_comment(cx.tcx.sess.source_map(), span) {
|
||||
if span_contains_comment(cx, span) {
|
||||
applicability = Applicability::Unspecified;
|
||||
}
|
||||
span_lint_and_sugg(
|
||||
|
||||
@@ -134,9 +134,8 @@
|
||||
mod unnecessary_lazy_eval;
|
||||
mod unnecessary_literal_unwrap;
|
||||
mod unnecessary_map_or;
|
||||
mod unnecessary_map_or_else;
|
||||
mod unnecessary_min_or_max;
|
||||
mod unnecessary_option_map_or_else;
|
||||
mod unnecessary_result_map_or_else;
|
||||
mod unnecessary_sort_by;
|
||||
mod unnecessary_to_owned;
|
||||
mod unwrap_expect_used;
|
||||
@@ -3030,7 +3029,7 @@
|
||||
/// ptr.sub(8);
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.92.0"]
|
||||
#[clippy::version = "1.94.0"]
|
||||
pub PTR_OFFSET_BY_LITERAL,
|
||||
pedantic,
|
||||
"unneeded pointer offset"
|
||||
@@ -4347,6 +4346,7 @@
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for usage of `.map_or_else()` "map closure" for `Option` type.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
@@ -5449,8 +5449,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
},
|
||||
(sym::map_or_else, [def, map]) => {
|
||||
result_map_or_else_none::check(cx, expr, recv, def, map);
|
||||
unnecessary_option_map_or_else::check(cx, expr, recv, def, map);
|
||||
unnecessary_result_map_or_else::check(cx, expr, recv, def, map);
|
||||
unnecessary_map_or_else::check(cx, expr, recv, def, map, call_span);
|
||||
},
|
||||
(sym::next, []) => {
|
||||
if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::Spanned;
|
||||
use rustc_span::{Span, Spanned};
|
||||
|
||||
use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS};
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_span::Spanned;
|
||||
use rustc_span::{Spanned, Symbol};
|
||||
|
||||
use super::SUSPICIOUS_SPLITN;
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_expr_identity_function;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use super::{UNNECESSARY_OPTION_MAP_OR_ELSE, UNNECESSARY_RESULT_MAP_OR_ELSE};
|
||||
|
||||
/// lint use of `_.map_or_else(|err| err, |n| n)` for `Result`s and `Option`s.
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
recv: &Expr<'_>,
|
||||
def_arg: &Expr<'_>,
|
||||
map_arg: &Expr<'_>,
|
||||
call_span: Span,
|
||||
) {
|
||||
let (symbol, lint) = match cx.typeck_results().expr_ty(recv).opt_diag_name(cx) {
|
||||
Some(x @ sym::Result) => (x, UNNECESSARY_RESULT_MAP_OR_ELSE),
|
||||
Some(x @ sym::Option) => (x, UNNECESSARY_OPTION_MAP_OR_ELSE),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
if is_expr_identity_function(cx, map_arg) {
|
||||
let msg = format!("unused \"map closure\" when calling `{symbol}::map_or_else` value");
|
||||
|
||||
span_lint_and_then(cx, lint, expr.span, msg, |diag| {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let err_snippet = snippet_with_applicability(cx, def_arg.span, "..", &mut applicability);
|
||||
let sugg = format!("unwrap_or_else({err_snippet})");
|
||||
|
||||
diag.span_suggestion_verbose(call_span, "consider using `unwrap_or_else`", sugg, applicability);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{expr_or_init, find_binding_init, peel_blocks};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{Body, BodyId, Closure, Expr, ExprKind, HirId, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use super::UNNECESSARY_OPTION_MAP_OR_ELSE;
|
||||
use super::utils::get_last_chain_binding_hir_id;
|
||||
|
||||
fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) {
|
||||
let msg = "unused \"map closure\" when calling `Option::map_or_else` value";
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let self_snippet = snippet_with_applicability(cx, recv.span, "_", &mut applicability);
|
||||
let err_snippet = snippet_with_applicability(cx, def_arg.span, "..", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNNECESSARY_OPTION_MAP_OR_ELSE,
|
||||
expr.span,
|
||||
msg,
|
||||
"consider using `unwrap_or_else`",
|
||||
format!("{self_snippet}.unwrap_or_else({err_snippet})"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
fn handle_qpath(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
recv: &Expr<'_>,
|
||||
def_arg: &Expr<'_>,
|
||||
expected_hir_id: HirId,
|
||||
qpath: QPath<'_>,
|
||||
) {
|
||||
if let QPath::Resolved(_, path) = qpath
|
||||
&& let Res::Local(hir_id) = path.res
|
||||
&& expected_hir_id == hir_id
|
||||
{
|
||||
emit_lint(cx, expr, recv, def_arg);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_closure(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, body_id: BodyId) {
|
||||
let body = cx.tcx.hir_body(body_id);
|
||||
handle_fn_body(cx, expr, recv, def_arg, body);
|
||||
}
|
||||
|
||||
fn handle_fn_body(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, body: &Body<'_>) {
|
||||
if let Some(first_param) = body.params.first() {
|
||||
let body_expr = peel_blocks(body.value);
|
||||
match body_expr.kind {
|
||||
ExprKind::Path(qpath) => {
|
||||
handle_qpath(cx, expr, recv, def_arg, first_param.pat.hir_id, qpath);
|
||||
},
|
||||
// If this is a block (that wasn't peeled off), then it means there are statements.
|
||||
ExprKind::Block(block, _) => {
|
||||
if let Some(block_expr) = block.expr
|
||||
// First we ensure that this is a "binding chain" (each statement is a binding
|
||||
// of the previous one) and that it is a binding of the closure argument.
|
||||
&& let Some(last_chain_binding_id) =
|
||||
get_last_chain_binding_hir_id(first_param.pat.hir_id, block.stmts)
|
||||
&& let ExprKind::Path(qpath) = block_expr.kind
|
||||
{
|
||||
handle_qpath(cx, expr, recv, def_arg, last_chain_binding_id, qpath);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// lint use of `_.map_or_else(|err| err, |n| n)` for `Option`s.
|
||||
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>, map_arg: &Expr<'_>) {
|
||||
// lint if the caller of `map_or_else()` is an `Option`
|
||||
if !cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Option) {
|
||||
return;
|
||||
}
|
||||
match map_arg.kind {
|
||||
// If the second argument is a closure, we can check its body.
|
||||
ExprKind::Closure(&Closure { body, .. }) => {
|
||||
handle_closure(cx, expr, recv, def_arg, body);
|
||||
},
|
||||
ExprKind::Path(qpath) => {
|
||||
let res = cx.qpath_res(&qpath, map_arg.hir_id);
|
||||
match res {
|
||||
// Case 1: Local variable (could be a closure)
|
||||
Res::Local(hir_id) => {
|
||||
if let Some(init_expr) = find_binding_init(cx, hir_id) {
|
||||
let origin = expr_or_init(cx, init_expr);
|
||||
if let ExprKind::Closure(&Closure { body, .. }) = origin.kind {
|
||||
handle_closure(cx, expr, recv, def_arg, body);
|
||||
}
|
||||
}
|
||||
},
|
||||
// Case 2: Function definition
|
||||
Res::Def(DefKind::Fn, def_id) => {
|
||||
if let Some(local_def_id) = def_id.as_local()
|
||||
&& let Some(body) = cx.tcx.hir_maybe_body_owned_by(local_def_id)
|
||||
{
|
||||
handle_fn_body(cx, expr, recv, def_arg, body);
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::peel_blocks;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{Closure, Expr, ExprKind, HirId, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use super::UNNECESSARY_RESULT_MAP_OR_ELSE;
|
||||
use super::utils::get_last_chain_binding_hir_id;
|
||||
|
||||
fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, def_arg: &Expr<'_>) {
|
||||
let msg = "unused \"map closure\" when calling `Result::map_or_else` value";
|
||||
let self_snippet = snippet(cx, recv.span, "..");
|
||||
let err_snippet = snippet(cx, def_arg.span, "..");
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNNECESSARY_RESULT_MAP_OR_ELSE,
|
||||
expr.span,
|
||||
msg,
|
||||
"consider using `unwrap_or_else`",
|
||||
format!("{self_snippet}.unwrap_or_else({err_snippet})"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
fn handle_qpath(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
recv: &Expr<'_>,
|
||||
def_arg: &Expr<'_>,
|
||||
expected_hir_id: HirId,
|
||||
qpath: QPath<'_>,
|
||||
) {
|
||||
if let QPath::Resolved(_, path) = qpath
|
||||
&& let hir::def::Res::Local(hir_id) = path.res
|
||||
&& expected_hir_id == hir_id
|
||||
{
|
||||
emit_lint(cx, expr, recv, def_arg);
|
||||
}
|
||||
}
|
||||
|
||||
/// lint use of `_.map_or_else(|err| err, |n| n)` for `Result`s.
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'_>,
|
||||
recv: &'tcx Expr<'_>,
|
||||
def_arg: &'tcx Expr<'_>,
|
||||
map_arg: &'tcx Expr<'_>,
|
||||
) {
|
||||
// lint if the caller of `map_or_else()` is a `Result`
|
||||
if cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result)
|
||||
&& let ExprKind::Closure(&Closure { body, .. }) = map_arg.kind
|
||||
&& let body = cx.tcx.hir_body(body)
|
||||
&& let Some(first_param) = body.params.first()
|
||||
{
|
||||
let body_expr = peel_blocks(body.value);
|
||||
|
||||
match body_expr.kind {
|
||||
ExprKind::Path(qpath) => {
|
||||
handle_qpath(cx, expr, recv, def_arg, first_param.pat.hir_id, qpath);
|
||||
},
|
||||
// If this is a block (that wasn't peeled off), then it means there are statements.
|
||||
ExprKind::Block(block, _) => {
|
||||
if let Some(block_expr) = block.expr
|
||||
// First we ensure that this is a "binding chain" (each statement is a binding
|
||||
// of the previous one) and that it is a binding of the closure argument.
|
||||
&& let Some(last_chain_binding_id) =
|
||||
get_last_chain_binding_hir_id(first_param.pat.hir_id, block.stmts)
|
||||
&& let ExprKind::Path(qpath) = block_expr.kind
|
||||
{
|
||||
handle_qpath(cx, expr, recv, def_arg, last_chain_binding_id, qpath);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,7 +108,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
then,
|
||||
r#else: Some(else_expr),
|
||||
}) = higher::If::hir(e)
|
||||
&& !span_contains_comment(cx.tcx.sess.source_map(), e.span)
|
||||
&& !span_contains_comment(cx, e.span)
|
||||
{
|
||||
let reduce = |ret, not| {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
@@ -221,7 +221,7 @@
|
||||
/// ```rust,no_run
|
||||
/// let a = 0b1110 & 0b0110;
|
||||
/// ```
|
||||
#[clippy::version = "1.93.0"]
|
||||
#[clippy::version = "1.94.0"]
|
||||
pub DECIMAL_BITWISE_OPERANDS,
|
||||
pedantic,
|
||||
"use binary, hex, or octal literals for bitwise operations"
|
||||
|
||||
@@ -143,7 +143,7 @@ fn init_expr_can_use_question_mark(cx: &LateContext<'_>, init_expr: &Expr<'_>) -
|
||||
&& init_expr_can_use_question_mark(cx, init_expr)
|
||||
&& let Some(ret) = find_let_else_ret_expression(els)
|
||||
&& let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, ret)
|
||||
&& !span_contains_comment(cx.tcx.sess.source_map(), els.span)
|
||||
&& !span_contains_comment(cx, els.span)
|
||||
&& !span_contains_cfg(cx, els.span)
|
||||
{
|
||||
let mut applicability = Applicability::MaybeIncorrect;
|
||||
@@ -501,7 +501,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
|
||||
let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_));
|
||||
let parent = cx.tcx.parent_hir_node(expr.hir_id);
|
||||
let requires_semi = matches!(parent, Node::Stmt(_)) || cx.typeck_results().expr_ty(expr).is_unit();
|
||||
let method_call_str = match by_ref {
|
||||
ByRef::Yes(_, Mutability::Mut) => ".as_mut()",
|
||||
ByRef::Yes(_, Mutability::Not) => ".as_ref()",
|
||||
@@ -512,7 +513,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
|
||||
"{receiver_str}{method_call_str}?{}",
|
||||
if requires_semi { ";" } else { "" }
|
||||
);
|
||||
if is_else_clause(cx.tcx, expr) {
|
||||
if is_else_clause(cx.tcx, expr) || (requires_semi && !matches!(parent, Node::Stmt(_) | Node::Block(_))) {
|
||||
sugg = format!("{{ {sugg} }}");
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
/// // This time, leverage the previously saved capacity:
|
||||
/// let reconstructed = unsafe { Vec::from_raw_parts(ptr, len, cap) };
|
||||
/// ```
|
||||
#[clippy::version = "1.93.0"]
|
||||
#[clippy::version = "1.94.0"]
|
||||
pub SAME_LENGTH_AND_CAPACITY,
|
||||
pedantic,
|
||||
"`from_raw_parts` with same length and capacity"
|
||||
|
||||
@@ -170,7 +170,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
||||
StmtKind::Semi(Expr {
|
||||
kind: ExprKind::Block(block, _),
|
||||
..
|
||||
}) if !block.span.from_expansion() => {
|
||||
}) if !block.span.from_expansion() && !block.targeted_by_break => {
|
||||
let attrs = cx.tcx.hir_attrs(stmt.hir_id);
|
||||
if !attrs.is_empty() && !cx.tcx.features().stmt_expr_attributes() {
|
||||
return;
|
||||
|
||||
@@ -208,7 +208,7 @@ fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocati
|
||||
.with_lo(vec_alloc.allocation_expr.span.source_callsite().lo());
|
||||
|
||||
// If there is no comment in `span_to_replace`, Clippy can automatically fix the code.
|
||||
let app = if span_contains_comment(cx.tcx.sess.source_map(), span_to_replace) {
|
||||
let app = if span_contains_comment(cx, span_to_replace) {
|
||||
Applicability::Unspecified
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::Spanned;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{Span, Spanned};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
||||
@@ -826,7 +826,9 @@ fn text_has_safety_comment(
|
||||
// Don't lint if the safety comment is part of a codeblock in a doc comment.
|
||||
// It may or may not be required, and we can't very easily check it (and we shouldn't, since
|
||||
// the safety comment isn't referring to the node we're currently checking)
|
||||
if line.trim_start_matches("///").trim_start().starts_with("```") {
|
||||
if let Some(doc) = line.strip_prefix("///").or_else(|| line.strip_prefix("//!"))
|
||||
&& doc.trim_start().starts_with("```")
|
||||
{
|
||||
in_codeblock = !in_codeblock;
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
|
||||
let help_msg = format!("you can use {} directly", suggest_ty.desc());
|
||||
// If the `vec!` macro contains comment, better not make the suggestion machine applicable as it
|
||||
// would remove them.
|
||||
let applicability = if span_contains_comment(cx.tcx.sess.source_map(), span) {
|
||||
let applicability = if span_contains_comment(cx, span) {
|
||||
Applicability::Unspecified
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
|
||||
@@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call:
|
||||
macro_call.span,
|
||||
format!("empty string literal in `{name}!`"),
|
||||
|diag| {
|
||||
if span_extract_comments(cx.sess().source_map(), macro_call.span).is_empty() {
|
||||
if span_extract_comments(cx, macro_call.span).is_empty() {
|
||||
let closing_paren = cx.sess().source_map().span_extend_to_prev_char_before(
|
||||
macro_call.span.shrink_to_hi(),
|
||||
')',
|
||||
|
||||
@@ -55,9 +55,9 @@ checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.1"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
||||
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
|
||||
|
||||
<!-- begin autogenerated nightly -->
|
||||
```
|
||||
nightly-2026-03-05
|
||||
nightly-2026-03-21
|
||||
```
|
||||
<!-- end autogenerated nightly -->
|
||||
|
||||
|
||||
@@ -841,12 +841,18 @@ fn fetch_path(&self, qpath: &QPath<'_>, id: HirId) -> Option<ConstValue> {
|
||||
&& ty.span.ctxt() == self.ctxt.get()
|
||||
&& ty_name.ident.span.ctxt() == self.ctxt.get()
|
||||
&& matches!(ty_path.res, Res::PrimTy(_))
|
||||
&& let Some((DefKind::AssocConst { .. }, did)) = self.typeck.type_dependent_def(id) =>
|
||||
&& let Some((DefKind::AssocConst { .. }, did)) = self.typeck.type_dependent_def(id)
|
||||
&& self.tcx.inherent_impl_of_assoc(did).is_some() =>
|
||||
{
|
||||
did
|
||||
},
|
||||
_ if let Res::Def(DefKind::Const { .. } | DefKind::AssocConst { .. }, did) =
|
||||
self.typeck.qpath_res(qpath, id) =>
|
||||
// TODO: revisit when feature `min_generic_const_args` is stabilized. In the meantime,
|
||||
// `TyCtxt::const_eval_resolve()` will trigger an ICE when evaluating the body of the
|
||||
// `type const` definition.
|
||||
_ if let Res::Def(
|
||||
DefKind::Const { is_type_const: false } | DefKind::AssocConst { is_type_const: false },
|
||||
did,
|
||||
) = self.typeck.qpath_res(qpath, id) =>
|
||||
{
|
||||
self.source.set(ConstantSource::NonLocal);
|
||||
did
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//! Thank you!
|
||||
//! ~The `INTERNAL_METADATA_COLLECTOR` lint
|
||||
|
||||
use rustc_errors::{Applicability, Diag, Diagnostic, DiagCtxtHandle, DiagMessage, Level, MultiSpan};
|
||||
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage, Diagnostic, Level, MultiSpan};
|
||||
#[cfg(debug_assertions)]
|
||||
use rustc_errors::{EmissionGuarantee, SubstitutionPart, Suggestions};
|
||||
use rustc_hir::HirId;
|
||||
@@ -252,15 +252,19 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
|
||||
|
||||
let sp = sp.into();
|
||||
#[expect(clippy::disallowed_methods)]
|
||||
cx.emit_span_lint(lint, sp.clone(), ClippyDiag(|diag: &mut Diag<'_, ()>| {
|
||||
diag.primary_message(msg);
|
||||
diag.span(sp);
|
||||
f(diag);
|
||||
docs_link(diag, lint);
|
||||
cx.emit_span_lint(
|
||||
lint,
|
||||
sp.clone(),
|
||||
ClippyDiag(|diag: &mut Diag<'_, ()>| {
|
||||
diag.primary_message(msg);
|
||||
diag.span(sp);
|
||||
f(diag);
|
||||
docs_link(diag, lint);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
validate_diag(diag);
|
||||
}));
|
||||
#[cfg(debug_assertions)]
|
||||
validate_diag(diag);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/// Like [`span_lint`], but emits the lint at the node identified by the given `HirId`.
|
||||
@@ -326,14 +330,19 @@ pub fn span_lint_hir_and_then(
|
||||
f: impl FnOnce(&mut Diag<'_, ()>),
|
||||
) {
|
||||
#[expect(clippy::disallowed_methods)]
|
||||
cx.tcx.emit_node_span_lint(lint, hir_id, sp, rustc_errors::DiagDecorator(|diag| {
|
||||
diag.primary_message(msg);
|
||||
f(diag);
|
||||
docs_link(diag, lint);
|
||||
cx.tcx.emit_node_span_lint(
|
||||
lint,
|
||||
hir_id,
|
||||
sp,
|
||||
rustc_errors::DiagDecorator(|diag| {
|
||||
diag.primary_message(msg);
|
||||
f(diag);
|
||||
docs_link(diag, lint);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
validate_diag(diag);
|
||||
}));
|
||||
#[cfg(debug_assertions)]
|
||||
validate_diag(diag);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/// Add a span lint with a suggestion on how to fix it.
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
|
||||
/// Callback that is called when two expressions are not equal in the sense of `SpanlessEq`, but
|
||||
/// other conditions would make them equal.
|
||||
type SpanlessEqCallback<'a> = dyn FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a;
|
||||
type SpanlessEqCallback<'a, 'tcx> =
|
||||
dyn FnMut(&TypeckResults<'tcx>, &Expr<'_>, &TypeckResults<'tcx>, &Expr<'_>) -> bool + 'a;
|
||||
|
||||
/// Determines how paths are hashed and compared for equality.
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
@@ -59,7 +60,7 @@ pub struct SpanlessEq<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
maybe_typeck_results: Option<(&'tcx TypeckResults<'tcx>, &'tcx TypeckResults<'tcx>)>,
|
||||
allow_side_effects: bool,
|
||||
expr_fallback: Option<Box<SpanlessEqCallback<'a>>>,
|
||||
expr_fallback: Option<Box<SpanlessEqCallback<'a, 'tcx>>>,
|
||||
path_check: PathCheck,
|
||||
}
|
||||
|
||||
@@ -94,7 +95,10 @@ pub fn paths_by_resolution(self) -> Self {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn expr_fallback(self, expr_fallback: impl FnMut(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self {
|
||||
pub fn expr_fallback(
|
||||
self,
|
||||
expr_fallback: impl FnMut(&TypeckResults<'tcx>, &Expr<'_>, &TypeckResults<'tcx>, &Expr<'_>) -> bool + 'a,
|
||||
) -> Self {
|
||||
Self {
|
||||
expr_fallback: Some(Box::new(expr_fallback)),
|
||||
..self
|
||||
@@ -639,7 +643,15 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
|
||||
) => false,
|
||||
};
|
||||
(is_eq && (!self.should_ignore(left) || !self.should_ignore(right)))
|
||||
|| self.inner.expr_fallback.as_mut().is_some_and(|f| f(left, right))
|
||||
|| self
|
||||
.inner
|
||||
.maybe_typeck_results
|
||||
.is_some_and(|(left_typeck_results, right_typeck_results)| {
|
||||
self.inner
|
||||
.expr_fallback
|
||||
.as_mut()
|
||||
.is_some_and(|f| f(left_typeck_results, left, right_typeck_results, right))
|
||||
})
|
||||
}
|
||||
|
||||
fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool {
|
||||
|
||||
@@ -1838,13 +1838,38 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
/// * `|[x, y]| [x, y]`
|
||||
/// * `|Foo(bar, baz)| Foo(bar, baz)`
|
||||
/// * `|Foo { bar, baz }| Foo { bar, baz }`
|
||||
/// * `|x| { let y = x; ...; let z = y; z }`
|
||||
/// * `|x| { let y = x; ...; let z = y; return z }`
|
||||
///
|
||||
/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
|
||||
fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
|
||||
fn is_body_identity_function<'hir>(cx: &LateContext<'_>, func: &Body<'hir>) -> bool {
|
||||
let [param] = func.params else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let mut param_pat = param.pat;
|
||||
|
||||
// Given a sequence of `Stmt`s of the form `let p = e` where `e` is an expr identical to the
|
||||
// current `param_pat`, advance the current `param_pat` to `p`.
|
||||
//
|
||||
// Note: This is similar to `clippy_utils::get_last_chain_binding_hir_id`, but it works
|
||||
// directly over a `Pattern` rather than a `HirId`. And it checks for compatibility via
|
||||
// `is_expr_identity_of_pat` rather than `HirId` equality
|
||||
let mut advance_param_pat_over_stmts = |stmts: &[Stmt<'hir>]| {
|
||||
for stmt in stmts {
|
||||
if let StmtKind::Let(local) = stmt.kind
|
||||
&& let Some(init) = local.init
|
||||
&& is_expr_identity_of_pat(cx, param_pat, init, true)
|
||||
{
|
||||
param_pat = local.pat;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
};
|
||||
|
||||
let mut expr = func.value;
|
||||
loop {
|
||||
match expr.kind {
|
||||
@@ -1873,7 +1898,30 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
_ => return is_expr_identity_of_pat(cx, param.pat, expr, true),
|
||||
ExprKind::Block(
|
||||
&Block {
|
||||
stmts, expr: Some(e), ..
|
||||
},
|
||||
_,
|
||||
) => {
|
||||
if !advance_param_pat_over_stmts(stmts) {
|
||||
return false;
|
||||
}
|
||||
|
||||
expr = e;
|
||||
},
|
||||
ExprKind::Block(&Block { stmts, expr: None, .. }, _) => {
|
||||
if let Some((last_stmt, stmts)) = stmts.split_last()
|
||||
&& advance_param_pat_over_stmts(stmts)
|
||||
&& let StmtKind::Semi(e) | StmtKind::Expr(e) = last_stmt.kind
|
||||
&& let ExprKind::Ret(Some(ret_val)) = e.kind
|
||||
{
|
||||
expr = ret_val;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
_ => return is_expr_identity_of_pat(cx, param_pat, expr, true),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2762,16 +2810,15 @@ pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str, Inn
|
||||
|
||||
/// Checks whether a given span has any comment token
|
||||
/// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
|
||||
pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
|
||||
let Ok(snippet) = sm.span_to_snippet(span) else {
|
||||
return false;
|
||||
};
|
||||
return tokenize(&snippet, FrontmatterAllowed::No).any(|token| {
|
||||
matches!(
|
||||
token.kind,
|
||||
TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
|
||||
)
|
||||
});
|
||||
pub fn span_contains_comment(cx: &impl source::HasSession, span: Span) -> bool {
|
||||
span.check_source_text(cx, |snippet| {
|
||||
tokenize(snippet, FrontmatterAllowed::No).any(|token| {
|
||||
matches!(
|
||||
token.kind,
|
||||
TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks whether a given span has any significant token. A significant token is a non-whitespace
|
||||
@@ -2779,30 +2826,32 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
|
||||
/// This is useful to determine if there are any actual code tokens in the span that are omitted in
|
||||
/// the late pass, such as platform-specific code.
|
||||
pub fn span_contains_non_whitespace(cx: &impl source::HasSession, span: Span, skip_comments: bool) -> bool {
|
||||
matches!(span.get_source_text(cx), Some(snippet) if tokenize_with_text(&snippet).any(|(token, _, _)|
|
||||
match token {
|
||||
span.check_source_text(cx, |snippet| {
|
||||
tokenize_with_text(snippet).any(|(token, _, _)| match token {
|
||||
TokenKind::Whitespace => false,
|
||||
TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => !skip_comments,
|
||||
_ => true,
|
||||
}
|
||||
))
|
||||
})
|
||||
})
|
||||
}
|
||||
/// Returns all the comments a given span contains
|
||||
///
|
||||
/// Comments are returned wrapped with their relevant delimiters
|
||||
pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
|
||||
span_extract_comments(sm, span).join("\n")
|
||||
pub fn span_extract_comment(cx: &impl source::HasSession, span: Span) -> String {
|
||||
span_extract_comments(cx, span).join("\n")
|
||||
}
|
||||
|
||||
/// Returns all the comments a given span contains.
|
||||
///
|
||||
/// Comments are returned wrapped with their relevant delimiters.
|
||||
pub fn span_extract_comments(sm: &SourceMap, span: Span) -> Vec<String> {
|
||||
let snippet = sm.span_to_snippet(span).unwrap_or_default();
|
||||
tokenize_with_text(&snippet)
|
||||
.filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
|
||||
.map(|(_, s, _)| s.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
pub fn span_extract_comments(cx: &impl source::HasSession, span: Span) -> Vec<String> {
|
||||
span.with_source_text(cx, |snippet| {
|
||||
tokenize_with_text(snippet)
|
||||
.filter(|(t, ..)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
|
||||
.map(|(_, s, _)| s.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
|
||||
|
||||
@@ -23,9 +23,11 @@ macro_rules! msrv_aliases {
|
||||
|
||||
// names may refer to stabilized feature flags or library items
|
||||
msrv_aliases! {
|
||||
1,93,0 { VEC_DEQUE_POP_BACK_IF, VEC_DEQUE_POP_FRONT_IF }
|
||||
1,91,0 { DURATION_FROM_MINUTES_HOURS }
|
||||
1,88,0 { LET_CHAINS }
|
||||
1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST }
|
||||
1,86,0 { VEC_POP_IF }
|
||||
1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL }
|
||||
1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
|
||||
1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
|
||||
|
||||
@@ -140,6 +140,7 @@ macro_rules! generate {
|
||||
as_str,
|
||||
assert_failed,
|
||||
author,
|
||||
back,
|
||||
binaryheap_iter,
|
||||
bool_then,
|
||||
borrow,
|
||||
@@ -295,6 +296,7 @@ macro_rules! generate {
|
||||
from_str_method,
|
||||
from_str_radix,
|
||||
from_weeks,
|
||||
front,
|
||||
fs,
|
||||
fs_create_dir,
|
||||
fuse,
|
||||
@@ -464,6 +466,12 @@ macro_rules! generate {
|
||||
peekable,
|
||||
permissions_from_mode,
|
||||
pin_macro,
|
||||
pop,
|
||||
pop_back,
|
||||
pop_back_if,
|
||||
pop_front,
|
||||
pop_front_if,
|
||||
pop_if,
|
||||
position,
|
||||
pow,
|
||||
powf,
|
||||
|
||||
@@ -29,8 +29,7 @@
|
||||
use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
|
||||
use rustc_trait_selection::traits::{Obligation, ObligationCause};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::debug_assert_matches;
|
||||
use std::{iter, mem};
|
||||
use std::{debug_assert_matches, iter, mem};
|
||||
|
||||
use crate::paths::{PathNS, lookup_path_str};
|
||||
use crate::res::{MaybeDef, MaybeQPath};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[toolchain]
|
||||
# begin autogenerated nightly
|
||||
channel = "nightly-2026-03-05"
|
||||
channel = "nightly-2026-03-21"
|
||||
# end autogenerated nightly
|
||||
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||
profile = "minimal"
|
||||
|
||||
@@ -12,17 +12,26 @@
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
pub fn a(cx: impl LintContext, lint: &'static Lint, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
|
||||
cx.span_lint(lint, span, |lint| {
|
||||
cx.emit_span_lint(
|
||||
//~^ disallowed_methods
|
||||
lint.primary_message(msg);
|
||||
});
|
||||
lint,
|
||||
span,
|
||||
DiagDecorator(|lint| {
|
||||
lint.primary_message(msg);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn b(tcx: TyCtxt<'_>, lint: &'static Lint, hir_id: HirId, span: impl Into<MultiSpan>, msg: impl Into<DiagMessage>) {
|
||||
tcx.emit_node_span_lint(lint, hir_id, span, DiagDecorator(|lint| {
|
||||
tcx.emit_node_span_lint(
|
||||
//~^ disallowed_methods
|
||||
lint.primary_message(msg);
|
||||
}));
|
||||
lint,
|
||||
hir_id,
|
||||
span,
|
||||
DiagDecorator(|lint| {
|
||||
lint.primary_message(msg);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
error: use of a disallowed method `rustc_lint::context::LintContext::span_lint`
|
||||
error: use of a disallowed method `rustc_lint::context::LintContext::emit_span_lint`
|
||||
--> tests/ui-internal/disallow_span_lint.rs:15:8
|
||||
|
|
||||
LL | cx.span_lint(lint, span, |lint| {
|
||||
| ^^^^^^^^^
|
||||
LL | cx.emit_span_lint(
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint*` functions instead
|
||||
note: the lint level is defined here
|
||||
@@ -11,11 +11,11 @@ note: the lint level is defined here
|
||||
LL | #![deny(clippy::disallowed_methods)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint`
|
||||
--> tests/ui-internal/disallow_span_lint.rs:22:9
|
||||
error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::emit_node_span_lint`
|
||||
--> tests/ui-internal/disallow_span_lint.rs:26:9
|
||||
|
|
||||
LL | tcx.node_span_lint(lint, hir_id, span, |lint| {
|
||||
| ^^^^^^^^^^^^^^
|
||||
LL | tcx.emit_node_span_lint(
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this function does not add a link to our documentation; please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
//@ check-pass
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(min_generic_const_args)]
|
||||
|
||||
trait Trait {
|
||||
type const N: usize;
|
||||
fn process();
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
type const N: usize = 3;
|
||||
fn process() {
|
||||
const N: usize = <()>::N;
|
||||
_ = 0..Self::N;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,8 @@
|
||||
clippy::uninlined_format_args,
|
||||
clippy::useless_vec,
|
||||
clippy::unnecessary_map_on_constructor,
|
||||
clippy::needless_lifetimes
|
||||
clippy::needless_lifetimes,
|
||||
clippy::unnecessary_option_map_or_else
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
clippy::uninlined_format_args,
|
||||
clippy::useless_vec,
|
||||
clippy::unnecessary_map_on_constructor,
|
||||
clippy::needless_lifetimes
|
||||
clippy::needless_lifetimes,
|
||||
clippy::unnecessary_option_map_or_else
|
||||
)]
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:34:27
|
||||
--> tests/ui/eta.rs:35:27
|
||||
|
|
||||
LL | let a = Some(1u8).map(|a| foo(a));
|
||||
| ^^^^^^^^^^ help: replace the closure with the function itself: `foo`
|
||||
@@ -8,31 +8,31 @@ LL | let a = Some(1u8).map(|a| foo(a));
|
||||
= help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:39:40
|
||||
--> tests/ui/eta.rs:40:40
|
||||
|
|
||||
LL | let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec!
|
||||
| ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:42:35
|
||||
--> tests/ui/eta.rs:43:35
|
||||
|
|
||||
LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
|
||||
| ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:45:26
|
||||
--> tests/ui/eta.rs:46:26
|
||||
|
|
||||
LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
|
||||
| ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:54:27
|
||||
--> tests/ui/eta.rs:55:27
|
||||
|
|
||||
LL | let e = Some(1u8).map(|a| generic(a));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:107:51
|
||||
--> tests/ui/eta.rs:108:51
|
||||
|
|
||||
LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
|
||||
| ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
|
||||
@@ -41,229 +41,229 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
|
||||
= help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:109:51
|
||||
--> tests/ui/eta.rs:110:51
|
||||
|
|
||||
LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:112:42
|
||||
--> tests/ui/eta.rs:113:42
|
||||
|
|
||||
LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
|
||||
| ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:117:29
|
||||
--> tests/ui/eta.rs:118:29
|
||||
|
|
||||
LL | let e = Some("str").map(|s| s.to_string());
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:119:27
|
||||
--> tests/ui/eta.rs:120:27
|
||||
|
|
||||
LL | let e = Some('a').map(|s| s.to_uppercase());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:122:65
|
||||
--> tests/ui/eta.rs:123:65
|
||||
|
|
||||
LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:139:23
|
||||
--> tests/ui/eta.rs:140:23
|
||||
|
|
||||
LL | let _ = x.map(|x| x.parse::<i16>());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `str::parse::<i16>`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:192:22
|
||||
--> tests/ui/eta.rs:193:22
|
||||
|
|
||||
LL | requires_fn_once(|| x());
|
||||
| ^^^^^^ help: replace the closure with the function itself: `x`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:200:27
|
||||
--> tests/ui/eta.rs:201:27
|
||||
|
|
||||
LL | let a = Some(1u8).map(|a| foo_ptr(a));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:206:27
|
||||
--> tests/ui/eta.rs:207:27
|
||||
|
|
||||
LL | let a = Some(1u8).map(|a| closure(a));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:239:28
|
||||
--> tests/ui/eta.rs:240:28
|
||||
|
|
||||
LL | x.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:241:28
|
||||
--> tests/ui/eta.rs:242:28
|
||||
|
|
||||
LL | y.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:243:28
|
||||
--> tests/ui/eta.rs:244:28
|
||||
|
|
||||
LL | z.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:251:21
|
||||
--> tests/ui/eta.rs:252:21
|
||||
|
|
||||
LL | Some(1).map(|n| closure(n));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:256:21
|
||||
--> tests/ui/eta.rs:257:21
|
||||
|
|
||||
LL | Some(1).map(|n| in_loop(n));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:350:18
|
||||
--> tests/ui/eta.rs:351:18
|
||||
|
|
||||
LL | takes_fn_mut(|| f());
|
||||
| ^^^^^^ help: replace the closure with the function itself: `&mut f`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:354:19
|
||||
--> tests/ui/eta.rs:355:19
|
||||
|
|
||||
LL | takes_fn_once(|| f());
|
||||
| ^^^^^^ help: replace the closure with the function itself: `&mut f`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:359:26
|
||||
--> tests/ui/eta.rs:360:26
|
||||
|
|
||||
LL | move || takes_fn_mut(|| f_used_once())
|
||||
| ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:372:19
|
||||
--> tests/ui/eta.rs:373:19
|
||||
|
|
||||
LL | array_opt.map(|a| a.as_slice());
|
||||
| ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:376:19
|
||||
--> tests/ui/eta.rs:377:19
|
||||
|
|
||||
LL | slice_opt.map(|s| s.len());
|
||||
| ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:380:17
|
||||
--> tests/ui/eta.rs:381:17
|
||||
|
|
||||
LL | ptr_opt.map(|p| p.is_null());
|
||||
| ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:385:17
|
||||
--> tests/ui/eta.rs:386:17
|
||||
|
|
||||
LL | dyn_opt.map(|d| d.method_on_dyn());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:446:19
|
||||
--> tests/ui/eta.rs:447:19
|
||||
|
|
||||
LL | let _ = f(&0, |x, y| f2(x, y));
|
||||
| ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:475:22
|
||||
--> tests/ui/eta.rs:476:22
|
||||
|
|
||||
LL | test.map(|t| t.method())
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:480:22
|
||||
--> tests/ui/eta.rs:481:22
|
||||
|
|
||||
LL | test.map(|t| t.method())
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:494:18
|
||||
--> tests/ui/eta.rs:495:18
|
||||
|
|
||||
LL | test.map(|t| t.method())
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:502:30
|
||||
--> tests/ui/eta.rs:503:30
|
||||
|
|
||||
LL | test.map(|t| t.method())
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:522:38
|
||||
--> tests/ui/eta.rs:523:38
|
||||
|
|
||||
LL | let x = Box::new(|| None.map(|x| f(x)));
|
||||
| ^^^^^^^^ help: replace the closure with the function itself: `&f`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:527:38
|
||||
--> tests/ui/eta.rs:528:38
|
||||
|
|
||||
LL | let x = Box::new(|| None.map(|x| f(x)));
|
||||
| ^^^^^^^^ help: replace the closure with the function itself: `f`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:545:35
|
||||
--> tests/ui/eta.rs:546:35
|
||||
|
|
||||
LL | let _field = bind.or_else(|| get_default()).unwrap();
|
||||
| ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:592:16
|
||||
--> tests/ui/eta.rs:593:16
|
||||
|
|
||||
LL | accepts_fn(|| f());
|
||||
| ^^^^^^ help: replace the closure with the function itself: `**f`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:596:16
|
||||
--> tests/ui/eta.rs:597:16
|
||||
|
|
||||
LL | accepts_fn(|| g());
|
||||
| ^^^^^^ help: replace the closure with the function itself: `g`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:609:16
|
||||
--> tests/ui/eta.rs:610:16
|
||||
|
|
||||
LL | accepts_fn(|| b());
|
||||
| ^^^^^^ help: replace the closure with the function itself: `***b`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:633:14
|
||||
--> tests/ui/eta.rs:634:14
|
||||
|
|
||||
LL | .map(|n| MyError::A(n))
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the tuple variant itself: `MyError::A`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:630:14
|
||||
--> tests/ui/eta.rs:631:14
|
||||
|
|
||||
LL | .map(|n| S(n))
|
||||
| ^^^^^^^^ help: replace the closure with the tuple struct itself: `S`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:627:14
|
||||
--> tests/ui/eta.rs:628:14
|
||||
|
|
||||
LL | .map(|n| g(n))
|
||||
| ^^^^^^^^ help: replace the closure with the function itself: `g`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:624:14
|
||||
--> tests/ui/eta.rs:625:14
|
||||
|
|
||||
LL | .map(|n| f(n))
|
||||
| ^^^^^^^^ help: replace the closure with the function itself: `f`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:651:31
|
||||
--> tests/ui/eta.rs:652:31
|
||||
|
|
||||
LL | array.iter().for_each(|item| item.method());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Self::method`
|
||||
|
||||
error: redundant closure
|
||||
--> tests/ui/eta.rs:661:38
|
||||
--> tests/ui/eta.rs:662:38
|
||||
|
|
||||
LL | (0..10).flat_map(|x| (0..10).map(|y| closure(y))).count();
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&*closure`
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
#![warn(clippy::manual_pop_if)]
|
||||
#![allow(clippy::collapsible_if, clippy::redundant_closure)]
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// FakeVec has the same methods as Vec but isn't actually a Vec
|
||||
struct FakeVec<T>(PhantomData<T>);
|
||||
|
||||
impl<T> FakeVec<T> {
|
||||
fn last(&self) -> Option<&T> {
|
||||
None
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> Option<T> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn is_some_and_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
deque.pop_back_if(|x| *x > 2);
|
||||
|
||||
deque.pop_front_if(|x| *x > 2);
|
||||
}
|
||||
|
||||
fn is_some_and_pattern_negative(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
// Do not lint, different vectors
|
||||
let mut vec2 = vec![0];
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
vec2.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, non-Vec type
|
||||
let mut fake_vec: FakeVec<i32> = FakeVec(PhantomData);
|
||||
if fake_vec.last().is_some_and(|x| *x > 2) {
|
||||
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()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
fn if_let_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
deque.pop_back_if(|x| *x > 2);
|
||||
|
||||
deque.pop_front_if(|x| *x > 2);
|
||||
}
|
||||
|
||||
fn if_let_pattern_negative(mut vec: Vec<i32>) {
|
||||
// Do not lint, different vectors
|
||||
let mut vec2 = vec![0];
|
||||
if let Some(x) = vec.last() {
|
||||
if *x > 2 {
|
||||
vec2.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Do not lint, intervening statements
|
||||
if let Some(x) = vec.last() {
|
||||
println!("Checking {}", x);
|
||||
if *x > 2 {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Do not lint, bound variable not used in condition
|
||||
if let Some(_x) = vec.last() {
|
||||
if vec.len() > 2 {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// 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 }
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
fn let_chain_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
deque.pop_back_if(|x| *x > 2);
|
||||
|
||||
deque.pop_front_if(|x| *x > 2);
|
||||
}
|
||||
|
||||
fn let_chain_pattern_negative(mut vec: Vec<i32>) {
|
||||
// Do not lint, different vectors
|
||||
let mut vec2 = vec![0];
|
||||
if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
{
|
||||
vec2.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, bound variable not used in condition
|
||||
if let Some(_x) = vec.last()
|
||||
&& vec.len() > 2
|
||||
{
|
||||
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
|
||||
{
|
||||
vec.pop().unwrap()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
fn map_unwrap_or_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
vec.pop_if(|x| *x > 2);
|
||||
|
||||
deque.pop_back_if(|x| *x > 2);
|
||||
|
||||
deque.pop_front_if(|x| *x > 2);
|
||||
}
|
||||
|
||||
fn map_unwrap_or_pattern_negative(mut vec: Vec<i32>) {
|
||||
// Do not lint, unwrap_or(true) instead of false
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(true) {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, different vectors
|
||||
let mut vec2 = vec![0];
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
vec2.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, non-Vec type
|
||||
let mut fake_vec: FakeVec<i32> = FakeVec(PhantomData);
|
||||
if fake_vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
fake_vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, map returns non-boolean
|
||||
if vec.last().map(|x| x + 1).unwrap_or(0) > 2 {
|
||||
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()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
// this makes sure we do not expand vec![] in the suggestion
|
||||
fn handle_macro_in_closure(mut vec: Vec<Vec<i32>>) {
|
||||
vec.pop_if(|e| *e == vec![1]);
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.85.0"]
|
||||
fn msrv_too_low_vec(mut vec: Vec<i32>) {
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.92.0"]
|
||||
fn msrv_too_low_vecdeque(mut deque: VecDeque<i32>) {
|
||||
if deque.back().is_some_and(|x| *x > 2) {
|
||||
deque.pop_back().unwrap();
|
||||
}
|
||||
|
||||
if deque.front().is_some_and(|x| *x > 2) {
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.86.0"]
|
||||
fn msrv_high_enough_vec(mut vec: Vec<i32>) {
|
||||
vec.pop_if(|x| *x > 2);
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.93.0"]
|
||||
fn msrv_high_enough_vecdeque(mut deque: VecDeque<i32>) {
|
||||
deque.pop_back_if(|x| *x > 2);
|
||||
|
||||
deque.pop_front_if(|x| *x > 2);
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
#![warn(clippy::manual_pop_if)]
|
||||
#![allow(clippy::collapsible_if, clippy::redundant_closure)]
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// FakeVec has the same methods as Vec but isn't actually a Vec
|
||||
struct FakeVec<T>(PhantomData<T>);
|
||||
|
||||
impl<T> FakeVec<T> {
|
||||
fn last(&self) -> Option<&T> {
|
||||
None
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> Option<T> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn is_some_and_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
vec.pop().expect("element");
|
||||
}
|
||||
|
||||
if deque.back().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_back().unwrap();
|
||||
}
|
||||
|
||||
if deque.front().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn is_some_and_pattern_negative(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
// Do not lint, different vectors
|
||||
let mut vec2 = vec![0];
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
vec2.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, non-Vec type
|
||||
let mut fake_vec: FakeVec<i32> = FakeVec(PhantomData);
|
||||
if fake_vec.last().is_some_and(|x| *x > 2) {
|
||||
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()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
fn if_let_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
if let Some(x) = vec.last() {
|
||||
//~^ manual_pop_if
|
||||
if *x > 2 {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(x) = vec.last() {
|
||||
//~^ manual_pop_if
|
||||
if *x > 2 {
|
||||
vec.pop().expect("element");
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(x) = deque.back() {
|
||||
//~^ manual_pop_if
|
||||
if *x > 2 {
|
||||
deque.pop_back().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(x) = deque.front() {
|
||||
//~^ manual_pop_if
|
||||
if *x > 2 {
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn if_let_pattern_negative(mut vec: Vec<i32>) {
|
||||
// Do not lint, different vectors
|
||||
let mut vec2 = vec![0];
|
||||
if let Some(x) = vec.last() {
|
||||
if *x > 2 {
|
||||
vec2.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Do not lint, intervening statements
|
||||
if let Some(x) = vec.last() {
|
||||
println!("Checking {}", x);
|
||||
if *x > 2 {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// Do not lint, bound variable not used in condition
|
||||
if let Some(_x) = vec.last() {
|
||||
if vec.len() > 2 {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// 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 }
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
fn let_chain_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<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
|
||||
{
|
||||
vec.pop().expect("element");
|
||||
}
|
||||
|
||||
if let Some(x) = deque.back() //~ manual_pop_if
|
||||
&& *x > 2
|
||||
{
|
||||
deque.pop_back().unwrap();
|
||||
}
|
||||
|
||||
if let Some(x) = deque.front() //~ manual_pop_if
|
||||
&& *x > 2
|
||||
{
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn let_chain_pattern_negative(mut vec: Vec<i32>) {
|
||||
// Do not lint, different vectors
|
||||
let mut vec2 = vec![0];
|
||||
if let Some(x) = vec.last()
|
||||
&& *x > 2
|
||||
{
|
||||
vec2.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, bound variable not used in condition
|
||||
if let Some(_x) = vec.last()
|
||||
&& vec.len() > 2
|
||||
{
|
||||
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
|
||||
{
|
||||
vec.pop().unwrap()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
fn map_unwrap_or_pattern_positive(mut vec: Vec<i32>, mut deque: VecDeque<i32>) {
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
//~^ manual_pop_if
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
//~^ manual_pop_if
|
||||
vec.pop().expect("element");
|
||||
}
|
||||
|
||||
if deque.back().map(|x| *x > 2).unwrap_or(false) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_back().unwrap();
|
||||
}
|
||||
|
||||
if deque.front().map(|x| *x > 2).unwrap_or(false) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn map_unwrap_or_pattern_negative(mut vec: Vec<i32>) {
|
||||
// Do not lint, unwrap_or(true) instead of false
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(true) {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, different vectors
|
||||
let mut vec2 = vec![0];
|
||||
if vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
vec2.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, non-Vec type
|
||||
let mut fake_vec: FakeVec<i32> = FakeVec(PhantomData);
|
||||
if fake_vec.last().map(|x| *x > 2).unwrap_or(false) {
|
||||
fake_vec.pop().unwrap();
|
||||
}
|
||||
|
||||
// Do not lint, map returns non-boolean
|
||||
if vec.last().map(|x| x + 1).unwrap_or(0) > 2 {
|
||||
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()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
// this makes sure we do not expand vec![] in the suggestion
|
||||
fn handle_macro_in_closure(mut vec: Vec<Vec<i32>>) {
|
||||
if vec.last().is_some_and(|e| *e == vec![1]) {
|
||||
//~^ manual_pop_if
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.85.0"]
|
||||
fn msrv_too_low_vec(mut vec: Vec<i32>) {
|
||||
if vec.last().is_some_and(|x| *x > 2) {
|
||||
vec.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.92.0"]
|
||||
fn msrv_too_low_vecdeque(mut deque: VecDeque<i32>) {
|
||||
if deque.back().is_some_and(|x| *x > 2) {
|
||||
deque.pop_back().unwrap();
|
||||
}
|
||||
|
||||
if deque.front().is_some_and(|x| *x > 2) {
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.86.0"]
|
||||
fn msrv_high_enough_vec(mut vec: Vec<i32>) {
|
||||
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>) {
|
||||
if deque.back().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_back().unwrap();
|
||||
}
|
||||
|
||||
if deque.front().is_some_and(|x| *x > 2) {
|
||||
//~^ manual_pop_if
|
||||
deque.pop_front().unwrap();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:21: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);`
|
||||
|
|
||||
= 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.rs:26:5
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
LL | / if let Some(x) = vec.last()
|
||||
LL | | && *x > 2
|
||||
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:157: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);`
|
||||
|
||||
error: manual implementation of `VecDeque::pop_back_if`
|
||||
--> tests/ui/manual_pop_if.rs:163: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);`
|
||||
|
||||
error: manual implementation of `VecDeque::pop_front_if`
|
||||
--> tests/ui/manual_pop_if.rs:169: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);`
|
||||
|
||||
error: manual implementation of `Vec::pop_if`
|
||||
--> tests/ui/manual_pop_if.rs:217:5
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
|
||||
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
|
||||
|
||||
@@ -140,3 +140,35 @@ fn main() {
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
fn issue16678() {
|
||||
// ICE in Rust 1.94.0
|
||||
match true {
|
||||
true => {
|
||||
fn wrapper(_arg: ()) {
|
||||
_arg;
|
||||
}
|
||||
},
|
||||
false => {
|
||||
fn wrapper(_arg: ()) {
|
||||
_arg;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16698() {
|
||||
trait Foo {
|
||||
const X: u8;
|
||||
}
|
||||
impl Foo for u8 {
|
||||
const X: u8 = 2;
|
||||
}
|
||||
impl Foo for i8 {
|
||||
const X: u8 = 2;
|
||||
}
|
||||
match true {
|
||||
false => u8::X,
|
||||
true => i8::X,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -149,3 +149,35 @@ fn main() {
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
fn issue16678() {
|
||||
// ICE in Rust 1.94.0
|
||||
match true {
|
||||
true => {
|
||||
fn wrapper(_arg: ()) {
|
||||
_arg;
|
||||
}
|
||||
},
|
||||
false => {
|
||||
fn wrapper(_arg: ()) {
|
||||
_arg;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn issue16698() {
|
||||
trait Foo {
|
||||
const X: u8;
|
||||
}
|
||||
impl Foo for u8 {
|
||||
const X: u8 = 2;
|
||||
}
|
||||
impl Foo for i8 {
|
||||
const X: u8 = 2;
|
||||
}
|
||||
match true {
|
||||
false => u8::X,
|
||||
true => i8::X,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -524,3 +524,16 @@ fn issue16429(b: i32) -> Option<i32> {
|
||||
|
||||
Some(0)
|
||||
}
|
||||
|
||||
fn issue16654() -> Result<(), i32> {
|
||||
let result = func_returning_result();
|
||||
|
||||
#[allow(clippy::collapsible_if)]
|
||||
if true {
|
||||
result?;
|
||||
}
|
||||
|
||||
_ = [{ result?; }];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -649,3 +649,22 @@ fn issue16429(b: i32) -> Option<i32> {
|
||||
|
||||
Some(0)
|
||||
}
|
||||
|
||||
fn issue16654() -> Result<(), i32> {
|
||||
let result = func_returning_result();
|
||||
|
||||
#[allow(clippy::collapsible_if)]
|
||||
if true {
|
||||
if let Err(err) = result {
|
||||
//~^ question_mark
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
_ = [if let Err(err) = result {
|
||||
//~^ question_mark
|
||||
return Err(err);
|
||||
}];
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -362,5 +362,24 @@ LL | | return None;
|
||||
LL | | };
|
||||
| |_____^ help: replace it with: `{ a? }`
|
||||
|
||||
error: aborting due to 38 previous errors
|
||||
error: this block may be rewritten with the `?` operator
|
||||
--> tests/ui/question_mark.rs:658:9
|
||||
|
|
||||
LL | / if let Err(err) = result {
|
||||
LL | |
|
||||
LL | | return Err(err);
|
||||
LL | | }
|
||||
| |_________^ help: replace it with: `result?;`
|
||||
|
||||
error: this block may be rewritten with the `?` operator
|
||||
--> tests/ui/question_mark.rs:664:10
|
||||
|
|
||||
LL | _ = [if let Err(err) = result {
|
||||
| __________^
|
||||
LL | |
|
||||
LL | | return Err(err);
|
||||
LL | | }];
|
||||
| |_____^ help: replace it with: `{ result?; }`
|
||||
|
||||
error: aborting due to 40 previous errors
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
clippy::double_parens
|
||||
)]
|
||||
#![warn(clippy::semicolon_inside_block)]
|
||||
#![feature(try_blocks)]
|
||||
|
||||
macro_rules! m {
|
||||
(()) => {
|
||||
@@ -106,3 +107,11 @@ pub fn issue15388() {
|
||||
#[rustfmt::skip]
|
||||
{0; 0};
|
||||
}
|
||||
|
||||
fn issue_try_blocks() {
|
||||
// try blocks should NOT trigger semicolon_inside_block:
|
||||
// moving `;` inside changes the return type (e.g. `Option<i32>` -> `Option<()>`)
|
||||
// which in turn changes the type constraints on `?` operators inside the block,
|
||||
// causing type errors.
|
||||
try { Some(1)? };
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
clippy::double_parens
|
||||
)]
|
||||
#![warn(clippy::semicolon_inside_block)]
|
||||
#![feature(try_blocks)]
|
||||
|
||||
macro_rules! m {
|
||||
(()) => {
|
||||
@@ -106,3 +107,11 @@ pub fn issue15388() {
|
||||
#[rustfmt::skip]
|
||||
{0; 0};
|
||||
}
|
||||
|
||||
fn issue_try_blocks() {
|
||||
// try blocks should NOT trigger semicolon_inside_block:
|
||||
// moving `;` inside changes the return type (e.g. `Option<i32>` -> `Option<()>`)
|
||||
// which in turn changes the type constraints on `?` operators inside the block,
|
||||
// causing type errors.
|
||||
try { Some(1)? };
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: consider moving the `;` inside the block for consistent formatting
|
||||
--> tests/ui/semicolon_inside_block.rs:39:5
|
||||
--> tests/ui/semicolon_inside_block.rs:40:5
|
||||
|
|
||||
LL | { unit_fn_block() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -13,7 +13,7 @@ LL + { unit_fn_block(); }
|
||||
|
|
||||
|
||||
error: consider moving the `;` inside the block for consistent formatting
|
||||
--> tests/ui/semicolon_inside_block.rs:41:5
|
||||
--> tests/ui/semicolon_inside_block.rs:42:5
|
||||
|
|
||||
LL | unsafe { unit_fn_block() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -25,7 +25,7 @@ LL + unsafe { unit_fn_block(); }
|
||||
|
|
||||
|
||||
error: consider moving the `;` inside the block for consistent formatting
|
||||
--> tests/ui/semicolon_inside_block.rs:50:5
|
||||
--> tests/ui/semicolon_inside_block.rs:51:5
|
||||
|
|
||||
LL | / {
|
||||
LL | |
|
||||
@@ -41,7 +41,7 @@ LL ~ }
|
||||
|
|
||||
|
||||
error: consider moving the `;` inside the block for consistent formatting
|
||||
--> tests/ui/semicolon_inside_block.rs:64:5
|
||||
--> tests/ui/semicolon_inside_block.rs:65:5
|
||||
|
|
||||
LL | { m!(()) };
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
@@ -3,13 +3,10 @@
|
||||
clippy::let_and_return,
|
||||
clippy::let_unit_value,
|
||||
clippy::unnecessary_lazy_evaluations,
|
||||
clippy::unnecessary_literal_unwrap
|
||||
clippy::unnecessary_literal_unwrap,
|
||||
clippy::needless_return
|
||||
)]
|
||||
|
||||
const fn identity<T>(x: T) -> T {
|
||||
x
|
||||
}
|
||||
|
||||
const fn double_it(x: i32) -> i32 {
|
||||
x * 2
|
||||
}
|
||||
@@ -18,31 +15,42 @@ fn main() {
|
||||
// Expected errors
|
||||
// Basic scenario
|
||||
let option = Some(());
|
||||
option.unwrap_or_else(|| ()); //~ ERROR: unused "map closure" when calling
|
||||
option.unwrap_or_else(|| ()); //~ unnecessary_option_map_or_else
|
||||
|
||||
// Type ascription
|
||||
let option = Some(());
|
||||
option.unwrap_or_else(|| ()); //~ ERROR: unused "map closure" when calling
|
||||
option.unwrap_or_else(|| ()); //~ unnecessary_option_map_or_else
|
||||
|
||||
// Auto-deref
|
||||
let string = String::new();
|
||||
let option = Some(&string);
|
||||
let _: &str = option.unwrap_or_else(|| &string); //~ ERROR: unused "map closure" when calling
|
||||
let _: &str = option.map_or_else(|| &string, |x| x);
|
||||
// This should in theory lint with a smarter check
|
||||
|
||||
// Temporary variable
|
||||
let option = Some(());
|
||||
option.unwrap_or_else(|| ());
|
||||
|
||||
// Identity
|
||||
// Temporary variable with pattern
|
||||
let option = Some(((), ()));
|
||||
option.unwrap_or_else(|| ((), ()));
|
||||
|
||||
// std::convert::identity
|
||||
let string = String::new();
|
||||
let option = Some(&string);
|
||||
let _: &str = option.unwrap_or_else(|| &string); //~ ERROR: unused "map closure" when calling
|
||||
let _: &str = option.unwrap_or_else(|| &string); //~ unnecessary_option_map_or_else
|
||||
|
||||
// Closure bound to a variable
|
||||
let do_nothing = |x: String| x;
|
||||
let string = String::new();
|
||||
let option = Some(string.clone());
|
||||
let _: String = option.unwrap_or_else(|| string); //~ ERROR: unused "map closure" when calling
|
||||
let x: Option<((), ())> = Some(((), ()));
|
||||
x.unwrap_or_else(|| ((), ()));
|
||||
//~^ unnecessary_option_map_or_else
|
||||
|
||||
// Returned temporary variable.
|
||||
let x: Option<()> = Some(());
|
||||
x.unwrap_or_else(|| ());
|
||||
|
||||
// Returned temporary variable with pattern
|
||||
let x: Option<((), ())> = Some(((), ()));
|
||||
x.unwrap_or_else(|| ((), ()));
|
||||
|
||||
// Correct usages
|
||||
let option = Some(());
|
||||
|
||||
@@ -3,13 +3,10 @@
|
||||
clippy::let_and_return,
|
||||
clippy::let_unit_value,
|
||||
clippy::unnecessary_lazy_evaluations,
|
||||
clippy::unnecessary_literal_unwrap
|
||||
clippy::unnecessary_literal_unwrap,
|
||||
clippy::needless_return
|
||||
)]
|
||||
|
||||
const fn identity<T>(x: T) -> T {
|
||||
x
|
||||
}
|
||||
|
||||
const fn double_it(x: i32) -> i32 {
|
||||
x * 2
|
||||
}
|
||||
@@ -18,21 +15,22 @@ fn main() {
|
||||
// Expected errors
|
||||
// Basic scenario
|
||||
let option = Some(());
|
||||
option.map_or_else(|| (), |x| x); //~ ERROR: unused "map closure" when calling
|
||||
option.map_or_else(|| (), |x| x); //~ unnecessary_option_map_or_else
|
||||
|
||||
// Type ascription
|
||||
let option = Some(());
|
||||
option.map_or_else(|| (), |x: ()| x); //~ ERROR: unused "map closure" when calling
|
||||
option.map_or_else(|| (), |x: ()| x); //~ unnecessary_option_map_or_else
|
||||
|
||||
// Auto-deref
|
||||
let string = String::new();
|
||||
let option = Some(&string);
|
||||
let _: &str = option.map_or_else(|| &string, |x| x); //~ ERROR: unused "map closure" when calling
|
||||
let _: &str = option.map_or_else(|| &string, |x| x);
|
||||
// This should in theory lint with a smarter check
|
||||
|
||||
// Temporary variable
|
||||
let option = Some(());
|
||||
option.map_or_else(
|
||||
//~^ ERROR: unused "map closure" when calling
|
||||
//~^ unnecessary_option_map_or_else
|
||||
|| (),
|
||||
|x| {
|
||||
let tmp = x;
|
||||
@@ -40,16 +38,50 @@ fn main() {
|
||||
},
|
||||
);
|
||||
|
||||
// Identity
|
||||
// Temporary variable with pattern
|
||||
let option = Some(((), ()));
|
||||
option.map_or_else(
|
||||
//~^ unnecessary_option_map_or_else
|
||||
|| ((), ()),
|
||||
|x| {
|
||||
let tmp = x;
|
||||
let (a, b) = tmp;
|
||||
(a, b)
|
||||
},
|
||||
);
|
||||
|
||||
// std::convert::identity
|
||||
let string = String::new();
|
||||
let option = Some(&string);
|
||||
let _: &str = option.map_or_else(|| &string, identity); //~ ERROR: unused "map closure" when calling
|
||||
let _: &str = option.map_or_else(|| &string, std::convert::identity); //~ unnecessary_option_map_or_else
|
||||
|
||||
// Closure bound to a variable
|
||||
let do_nothing = |x: String| x;
|
||||
let string = String::new();
|
||||
let option = Some(string.clone());
|
||||
let _: String = option.map_or_else(|| string, do_nothing); //~ ERROR: unused "map closure" when calling
|
||||
let x: Option<((), ())> = Some(((), ()));
|
||||
x.map_or_else(|| ((), ()), |(a, b)| (a, b));
|
||||
//~^ unnecessary_option_map_or_else
|
||||
|
||||
// Returned temporary variable.
|
||||
let x: Option<()> = Some(());
|
||||
x.map_or_else(
|
||||
//~^ unnecessary_option_map_or_else
|
||||
|| (),
|
||||
|n| {
|
||||
let tmp = n;
|
||||
let tmp2 = tmp;
|
||||
return tmp2;
|
||||
},
|
||||
);
|
||||
|
||||
// Returned temporary variable with pattern
|
||||
let x: Option<((), ())> = Some(((), ()));
|
||||
x.map_or_else(
|
||||
//~^ unnecessary_option_map_or_else
|
||||
|| ((), ()),
|
||||
|n| {
|
||||
let tmp = n;
|
||||
let (a, b) = tmp;
|
||||
return (a, b);
|
||||
},
|
||||
);
|
||||
|
||||
// Correct usages
|
||||
let option = Some(());
|
||||
|
||||
@@ -1,26 +1,31 @@
|
||||
error: unused "map closure" when calling `Option::map_or_else` value
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:21:5
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:18:5
|
||||
|
|
||||
LL | option.map_or_else(|| (), |x| x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::unnecessary-option-map-or-else` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_option_map_or_else)]`
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - option.map_or_else(|| (), |x| x);
|
||||
LL + option.unwrap_or_else(|| ());
|
||||
|
|
||||
|
||||
error: unused "map closure" when calling `Option::map_or_else` value
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:25:5
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:22:5
|
||||
|
|
||||
LL | option.map_or_else(|| (), |x: ()| x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
|
||||
|
||||
error: unused "map closure" when calling `Option::map_or_else` value
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:30:19
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - option.map_or_else(|| (), |x: ()| x);
|
||||
LL + option.unwrap_or_else(|| ());
|
||||
|
|
||||
LL | let _: &str = option.map_or_else(|| &string, |x| x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| &string)`
|
||||
|
||||
error: unused "map closure" when calling `Option::map_or_else` value
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:34:5
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:32:5
|
||||
|
|
||||
LL | / option.map_or_else(
|
||||
LL | |
|
||||
@@ -29,19 +34,122 @@ LL | | |x| {
|
||||
... |
|
||||
LL | | },
|
||||
LL | | );
|
||||
| |_____^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| ())`
|
||||
| |_____^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - option.map_or_else(
|
||||
LL -
|
||||
LL - || (),
|
||||
LL - |x| {
|
||||
LL - let tmp = x;
|
||||
LL - tmp
|
||||
LL - },
|
||||
LL - );
|
||||
LL + option.unwrap_or_else(|| ());
|
||||
|
|
||||
|
||||
error: unused "map closure" when calling `Option::map_or_else` value
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:46:19
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:43:5
|
||||
|
|
||||
LL | / option.map_or_else(
|
||||
LL | |
|
||||
LL | | || ((), ()),
|
||||
LL | | |x| {
|
||||
... |
|
||||
LL | | },
|
||||
LL | | );
|
||||
| |_____^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - option.map_or_else(
|
||||
LL -
|
||||
LL - || ((), ()),
|
||||
LL - |x| {
|
||||
LL - let tmp = x;
|
||||
LL - let (a, b) = tmp;
|
||||
LL - (a, b)
|
||||
LL - },
|
||||
LL - );
|
||||
LL + option.unwrap_or_else(|| ((), ()));
|
||||
|
|
||||
LL | let _: &str = option.map_or_else(|| &string, identity);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| &string)`
|
||||
|
||||
error: unused "map closure" when calling `Option::map_or_else` value
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:52:21
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:56:19
|
||||
|
|
||||
LL | let _: &str = option.map_or_else(|| &string, std::convert::identity);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - let _: &str = option.map_or_else(|| &string, std::convert::identity);
|
||||
LL + let _: &str = option.unwrap_or_else(|| &string);
|
||||
|
|
||||
LL | let _: String = option.map_or_else(|| string, do_nothing);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `option.unwrap_or_else(|| string)`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: unused "map closure" when calling `Option::map_or_else` value
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:59:5
|
||||
|
|
||||
LL | x.map_or_else(|| ((), ()), |(a, b)| (a, b));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - x.map_or_else(|| ((), ()), |(a, b)| (a, b));
|
||||
LL + x.unwrap_or_else(|| ((), ()));
|
||||
|
|
||||
|
||||
error: unused "map closure" when calling `Option::map_or_else` value
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:64:5
|
||||
|
|
||||
LL | / x.map_or_else(
|
||||
LL | |
|
||||
LL | | || (),
|
||||
LL | | |n| {
|
||||
... |
|
||||
LL | | },
|
||||
LL | | );
|
||||
| |_____^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - x.map_or_else(
|
||||
LL -
|
||||
LL - || (),
|
||||
LL - |n| {
|
||||
LL - let tmp = n;
|
||||
LL - let tmp2 = tmp;
|
||||
LL - return tmp2;
|
||||
LL - },
|
||||
LL - );
|
||||
LL + x.unwrap_or_else(|| ());
|
||||
|
|
||||
|
||||
error: unused "map closure" when calling `Option::map_or_else` value
|
||||
--> tests/ui/unnecessary_option_map_or_else.rs:76:5
|
||||
|
|
||||
LL | / x.map_or_else(
|
||||
LL | |
|
||||
LL | | || ((), ()),
|
||||
LL | | |n| {
|
||||
... |
|
||||
LL | | },
|
||||
LL | | );
|
||||
| |_____^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - x.map_or_else(
|
||||
LL -
|
||||
LL - || ((), ()),
|
||||
LL - |n| {
|
||||
LL - let tmp = n;
|
||||
LL - let (a, b) = tmp;
|
||||
LL - return (a, b);
|
||||
LL - },
|
||||
LL - );
|
||||
LL + x.unwrap_or_else(|| ((), ()));
|
||||
|
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#![warn(clippy::unnecessary_result_map_or_else)]
|
||||
#![allow(clippy::unnecessary_literal_unwrap, clippy::let_and_return, clippy::let_unit_value)]
|
||||
#![allow(
|
||||
clippy::unnecessary_literal_unwrap,
|
||||
clippy::let_and_return,
|
||||
clippy::let_unit_value,
|
||||
clippy::needless_return
|
||||
)]
|
||||
|
||||
fn main() {
|
||||
let x: Result<(), ()> = Ok(());
|
||||
@@ -14,13 +19,17 @@ fn main() {
|
||||
// Auto-deref.
|
||||
let y = String::new();
|
||||
let x: Result<&String, &String> = Ok(&y);
|
||||
let y: &str = x.unwrap_or_else(|err| err);
|
||||
//~^ unnecessary_result_map_or_else
|
||||
let y: &str = x.map_or_else(|err| err, |n| n);
|
||||
// This should lint with a smarter check
|
||||
|
||||
// Temporary variable.
|
||||
let x: Result<(), ()> = Ok(());
|
||||
x.unwrap_or_else(|err| err);
|
||||
|
||||
// Temporary variable with pattern
|
||||
let x: Result<((), ()), ((), ())> = Ok(((), ()));
|
||||
x.unwrap_or_else(|err| err);
|
||||
|
||||
// Should not warn.
|
||||
let x: Result<usize, usize> = Ok(0);
|
||||
x.map_or_else(|err| err, |n| n + 1);
|
||||
@@ -61,4 +70,16 @@ fn main() {
|
||||
y
|
||||
},
|
||||
);
|
||||
|
||||
let x: Result<((), ()), ((), ())> = Ok(((), ()));
|
||||
x.unwrap_or_else(|err| err);
|
||||
//~^ unnecessary_result_map_or_else
|
||||
|
||||
// Returned temporary variable.
|
||||
let x: Result<(), ()> = Ok(());
|
||||
x.unwrap_or_else(|err| err);
|
||||
|
||||
// Returned temporary variable with pattern
|
||||
let x: Result<((), ()), ((), ())> = Ok(((), ()));
|
||||
x.unwrap_or_else(|err| err);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#![warn(clippy::unnecessary_result_map_or_else)]
|
||||
#![allow(clippy::unnecessary_literal_unwrap, clippy::let_and_return, clippy::let_unit_value)]
|
||||
#![allow(
|
||||
clippy::unnecessary_literal_unwrap,
|
||||
clippy::let_and_return,
|
||||
clippy::let_unit_value,
|
||||
clippy::needless_return
|
||||
)]
|
||||
|
||||
fn main() {
|
||||
let x: Result<(), ()> = Ok(());
|
||||
@@ -15,7 +20,7 @@ fn main() {
|
||||
let y = String::new();
|
||||
let x: Result<&String, &String> = Ok(&y);
|
||||
let y: &str = x.map_or_else(|err| err, |n| n);
|
||||
//~^ unnecessary_result_map_or_else
|
||||
// This should lint with a smarter check
|
||||
|
||||
// Temporary variable.
|
||||
let x: Result<(), ()> = Ok(());
|
||||
@@ -29,6 +34,18 @@ fn main() {
|
||||
},
|
||||
);
|
||||
|
||||
// Temporary variable with pattern
|
||||
let x: Result<((), ()), ((), ())> = Ok(((), ()));
|
||||
x.map_or_else(
|
||||
//~^ unnecessary_result_map_or_else
|
||||
|err| err,
|
||||
|n| {
|
||||
let tmp = n;
|
||||
let (a, b) = tmp;
|
||||
(a, b)
|
||||
},
|
||||
);
|
||||
|
||||
// Should not warn.
|
||||
let x: Result<usize, usize> = Ok(0);
|
||||
x.map_or_else(|err| err, |n| n + 1);
|
||||
@@ -69,4 +86,32 @@ fn main() {
|
||||
y
|
||||
},
|
||||
);
|
||||
|
||||
let x: Result<((), ()), ((), ())> = Ok(((), ()));
|
||||
x.map_or_else(|err| err, |(a, b)| (a, b));
|
||||
//~^ unnecessary_result_map_or_else
|
||||
|
||||
// Returned temporary variable.
|
||||
let x: Result<(), ()> = Ok(());
|
||||
x.map_or_else(
|
||||
//~^ unnecessary_result_map_or_else
|
||||
|err| err,
|
||||
|n| {
|
||||
let tmp = n;
|
||||
let tmp2 = tmp;
|
||||
return tmp2;
|
||||
},
|
||||
);
|
||||
|
||||
// Returned temporary variable with pattern
|
||||
let x: Result<((), ()), ((), ())> = Ok(((), ()));
|
||||
x.map_or_else(
|
||||
//~^ unnecessary_result_map_or_else
|
||||
|err| err,
|
||||
|n| {
|
||||
let tmp = n;
|
||||
let (a, b) = tmp;
|
||||
return (a, b);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,31 @@
|
||||
error: unused "map closure" when calling `Result::map_or_else` value
|
||||
--> tests/ui/unnecessary_result_map_or_else.rs:6:5
|
||||
|
|
||||
LL | x.map_or_else(|err| err, |n| n);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)`
|
||||
|
|
||||
= note: `-D clippy::unnecessary-result-map-or-else` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_result_map_or_else)]`
|
||||
|
||||
error: unused "map closure" when calling `Result::map_or_else` value
|
||||
--> tests/ui/unnecessary_result_map_or_else.rs:11:5
|
||||
|
|
||||
LL | x.map_or_else(|err: ()| err, |n: ()| n);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err: ()| err)`
|
||||
|
||||
error: unused "map closure" when calling `Result::map_or_else` value
|
||||
--> tests/ui/unnecessary_result_map_or_else.rs:17:19
|
||||
LL | x.map_or_else(|err| err, |n| n);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::unnecessary-result-map-or-else` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_result_map_or_else)]`
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - x.map_or_else(|err| err, |n| n);
|
||||
LL + x.unwrap_or_else(|err| err);
|
||||
|
|
||||
LL | let y: &str = x.map_or_else(|err| err, |n| n);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)`
|
||||
|
||||
error: unused "map closure" when calling `Result::map_or_else` value
|
||||
--> tests/ui/unnecessary_result_map_or_else.rs:22:5
|
||||
--> tests/ui/unnecessary_result_map_or_else.rs:16:5
|
||||
|
|
||||
LL | x.map_or_else(|err: ()| err, |n: ()| n);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - x.map_or_else(|err: ()| err, |n: ()| n);
|
||||
LL + x.unwrap_or_else(|err: ()| err);
|
||||
|
|
||||
|
||||
error: unused "map closure" when calling `Result::map_or_else` value
|
||||
--> tests/ui/unnecessary_result_map_or_else.rs:27:5
|
||||
|
|
||||
LL | / x.map_or_else(
|
||||
LL | |
|
||||
@@ -29,7 +34,111 @@ LL | | |n| {
|
||||
... |
|
||||
LL | | },
|
||||
LL | | );
|
||||
| |_____^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)`
|
||||
| |_____^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - x.map_or_else(
|
||||
LL -
|
||||
LL - |err| err,
|
||||
LL - |n| {
|
||||
LL - let tmp = n;
|
||||
LL - let tmp2 = tmp;
|
||||
LL - tmp2
|
||||
LL - },
|
||||
LL - );
|
||||
LL + x.unwrap_or_else(|err| err);
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: unused "map closure" when calling `Result::map_or_else` value
|
||||
--> tests/ui/unnecessary_result_map_or_else.rs:39:5
|
||||
|
|
||||
LL | / x.map_or_else(
|
||||
LL | |
|
||||
LL | | |err| err,
|
||||
LL | | |n| {
|
||||
... |
|
||||
LL | | },
|
||||
LL | | );
|
||||
| |_____^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - x.map_or_else(
|
||||
LL -
|
||||
LL - |err| err,
|
||||
LL - |n| {
|
||||
LL - let tmp = n;
|
||||
LL - let (a, b) = tmp;
|
||||
LL - (a, b)
|
||||
LL - },
|
||||
LL - );
|
||||
LL + x.unwrap_or_else(|err| err);
|
||||
|
|
||||
|
||||
error: unused "map closure" when calling `Result::map_or_else` value
|
||||
--> tests/ui/unnecessary_result_map_or_else.rs:91:5
|
||||
|
|
||||
LL | x.map_or_else(|err| err, |(a, b)| (a, b));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - x.map_or_else(|err| err, |(a, b)| (a, b));
|
||||
LL + x.unwrap_or_else(|err| err);
|
||||
|
|
||||
|
||||
error: unused "map closure" when calling `Result::map_or_else` value
|
||||
--> tests/ui/unnecessary_result_map_or_else.rs:96:5
|
||||
|
|
||||
LL | / x.map_or_else(
|
||||
LL | |
|
||||
LL | | |err| err,
|
||||
LL | | |n| {
|
||||
... |
|
||||
LL | | },
|
||||
LL | | );
|
||||
| |_____^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - x.map_or_else(
|
||||
LL -
|
||||
LL - |err| err,
|
||||
LL - |n| {
|
||||
LL - let tmp = n;
|
||||
LL - let tmp2 = tmp;
|
||||
LL - return tmp2;
|
||||
LL - },
|
||||
LL - );
|
||||
LL + x.unwrap_or_else(|err| err);
|
||||
|
|
||||
|
||||
error: unused "map closure" when calling `Result::map_or_else` value
|
||||
--> tests/ui/unnecessary_result_map_or_else.rs:108:5
|
||||
|
|
||||
LL | / x.map_or_else(
|
||||
LL | |
|
||||
LL | | |err| err,
|
||||
LL | | |n| {
|
||||
... |
|
||||
LL | | },
|
||||
LL | | );
|
||||
| |_____^
|
||||
|
|
||||
help: consider using `unwrap_or_else`
|
||||
|
|
||||
LL - x.map_or_else(
|
||||
LL -
|
||||
LL - |err| err,
|
||||
LL - |n| {
|
||||
LL - let tmp = n;
|
||||
LL - let (a, b) = tmp;
|
||||
LL - return (a, b);
|
||||
LL - },
|
||||
LL - );
|
||||
LL + x.unwrap_or_else(|err| err);
|
||||
|
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
||||
@@ -100,3 +100,13 @@ pub fn point_to_five() -> *const u8 {
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
mod issue16553 {
|
||||
//! ```
|
||||
//! // SAFETY: All is well.
|
||||
//! unsafe {
|
||||
//! foo()
|
||||
//! }
|
||||
//! ```
|
||||
mod blah {}
|
||||
}
|
||||
|
||||
@@ -174,13 +174,13 @@ Otherwise, have a great day =^.^=
|
||||
<h2 class="lint-title"> {# #}
|
||||
<div class="panel-title-name" id="lint-{{lint.id}}"> {# #}
|
||||
{{lint.id ~}}
|
||||
<a href="#{{lint.id}}" class="anchor label label-default">¶</a> {#+ #}
|
||||
<a href="" class="copy-to-clipboard anchor label label-default"> {# #}
|
||||
<a href="#{{lint.id}}" class="anchor label">¶</a> {#+ #}
|
||||
<a href="" class="copy-to-clipboard anchor label"> {# #}
|
||||
📋 {# #}
|
||||
</a> {# #}
|
||||
</div> {# #}
|
||||
|
||||
<span class="label label-default lint-group group-{{lint.group}}">{{lint.group}}</span> {#+ #}
|
||||
<span class="label lint-group group-{{lint.group}}">{{lint.group}}</span> {#+ #}
|
||||
|
||||
<span class="label lint-level level-{{lint.level}}">{{lint.level}}</span> {#+ #}
|
||||
|
||||
@@ -194,24 +194,20 @@ Otherwise, have a great day =^.^=
|
||||
{# Applicability #}
|
||||
<div> {# #}
|
||||
Applicability: {#+ #}
|
||||
<span class="label label-default applicability">{{ lint.applicability_str() }}</span> {# #}
|
||||
<span class="label applicability">{{ lint.applicability_str() }}</span> {# #}
|
||||
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/enum.Applicability.html#variants">(?)</a> {# #}
|
||||
</div>
|
||||
{# Clippy version #}
|
||||
<div> {# #}
|
||||
{% if lint.group == "deprecated" %}Deprecated{% else %} Added{% endif +%} in: {#+ #}
|
||||
<span class="label label-default label-version">{{lint.version}}</span> {# #}
|
||||
<span class="label label-version">{{lint.version}}</span> {# #}
|
||||
</div>
|
||||
{# Open related issues #}
|
||||
<div> {# #}
|
||||
<a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a> {# #}
|
||||
</div>
|
||||
<a href="https://github.com/rust-lang/rust-clippy/issues?q=is%3Aissue+{{lint.id}}">Related Issues</a>
|
||||
|
||||
{# Jump to source #}
|
||||
{% if let Some(id_location) = lint.id_location %}
|
||||
<div> {# #}
|
||||
<a href="https://github.com/rust-lang/rust-clippy/blob/master/{{id_location}}">View Source</a> {# #}
|
||||
</div>
|
||||
<a href="https://github.com/rust-lang/rust-clippy/blob/master/{{id_location}}">View Source</a>
|
||||
{% endif %}
|
||||
</div> {# #}
|
||||
</div> {# #}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
body {
|
||||
--icon-filter: initial;
|
||||
--label-background: #777;
|
||||
}
|
||||
|
||||
body.ayu {
|
||||
@@ -230,7 +231,10 @@ button .caret {
|
||||
|
||||
.panel-title-name { flex: 1; min-width: 400px;}
|
||||
|
||||
.panel-title-name .anchor { display: none; }
|
||||
.panel-title-name .anchor {
|
||||
display: none;
|
||||
background-color: var(--label-background);
|
||||
}
|
||||
article:hover .panel-title-name .anchor { display: inline;}
|
||||
|
||||
.search-control {
|
||||
@@ -397,10 +401,6 @@ article:hover .panel-title-name .anchor { display: inline;}
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.label-default {
|
||||
background-color: #777;
|
||||
}
|
||||
|
||||
.lint-level {
|
||||
min-width: 4em;
|
||||
}
|
||||
@@ -420,6 +420,7 @@ article:hover .panel-title-name .anchor { display: inline;}
|
||||
|
||||
.lint-group {
|
||||
min-width: 8em;
|
||||
background-color: var(--label-background);
|
||||
}
|
||||
.group-deprecated {
|
||||
opacity: 0.5;
|
||||
@@ -459,7 +460,7 @@ article:hover .panel-title-name .anchor { display: inline;}
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
.lint-additional-info > div + div {
|
||||
.lint-additional-info > * + * {
|
||||
border-top: 1px solid var(--theme-popup-border);
|
||||
}
|
||||
}
|
||||
@@ -468,12 +469,12 @@ article:hover .panel-title-name .anchor { display: inline;}
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
}
|
||||
.lint-additional-info > div + div {
|
||||
.lint-additional-info > * + * {
|
||||
border-left: 1px solid var(--theme-popup-border);
|
||||
}
|
||||
}
|
||||
|
||||
.lint-additional-info > div {
|
||||
.lint-additional-info > * {
|
||||
display: inline-flex;
|
||||
min-width: 200px;
|
||||
flex-grow: 1;
|
||||
|
||||
Reference in New Issue
Block a user