Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
603ceb4
Add relevant tests for the new lint
jakubadamw Feb 21, 2026
8234ab6
Add `manual_option_zip` lint
jakubadamw Feb 20, 2026
c46b065
Address the lint's findings in the Clippy codebase
jakubadamw Feb 21, 2026
e0d5ea2
Update CHANGELOG.md
jakubadamw Feb 21, 2026
5d33d06
Add a test for a ternary tuple that we don't want the lint to trigger on
jakubadamw Feb 21, 2026
4aa7b3f
Move two clauses that are somewhat expensive a bit further down the i…
jakubadamw Feb 21, 2026
1e893cb
Apply suggestions from code review
jakubadamw Feb 21, 2026
f7e0e04
Remove two function calls from the test's `main()`
jakubadamw Feb 21, 2026
3cc92d8
Detect reversed tuple order in the inner-most closure
jakubadamw Feb 21, 2026
3b86820
Import `Expr` from `rustc_hir`.
jakubadamw Feb 22, 2026
04b8823
Add a few more tests per review feedback.
jakubadamw Feb 22, 2026
7707acc
Test: add `NotOption::and_then()` and a test case using it
jakubadamw Feb 23, 2026
974fe5f
Move one test case closer to the one it's related to
jakubadamw Feb 24, 2026
ee14362
Move the `MAP_OPTION_ZIP` declaration to the rightful position alphab…
jakubadamw Mar 5, 2026
47f8753
Simplify find_attr! for HirId usage
mehdiakiki Mar 9, 2026
47ee2e2
Add macro matcher for `guard` fragment specifier
SpriteOvO Mar 11, 2026
a3b7636
fix: `collapsible_match` FP when the pat binding is moved or mutated
profetia Mar 12, 2026
f049a64
Update Clippy test expectations for or-pattern parenthesization
aytey Mar 19, 2026
86390a3
Merge commit '256c21c543ca422b3ab8810a0d081d722408e896' into clippy-s…
flip1995 Mar 21, 2026
fe4fa8b
`iter_kv_map`: handle identity map for `map` and `flat_map`
zihan0822 Mar 22, 2026
9bf6faf
Add `BinaryHeap::pop_if()` to `manual_pop_if`
max-heller Mar 19, 2026
ac86fd1
Add `BinaryHeap::pop_if()` to `manual_pop_if` (#16734)
samueltardieu Mar 22, 2026
7e148fc
Factor out lint emission
samueltardieu Jan 28, 2026
dfb718b
Preserve parentheses in suggestion in presence of cascaded casts
samueltardieu Jan 28, 2026
4521a3f
Rollup merge of #154085 - aytey:fix-at-or-pattern-parens, r=chenyukang
JonathanBrouwer Mar 23, 2026
55a87b9
Rollup merge of #153582 - mehdiakiki:simplify-find-attr-hir-id, r=Jon…
JonathanBrouwer Mar 23, 2026
79db615
manual_pop_if: lint more cases, even if we do not provide a suggestion
pbor Mar 23, 2026
f77c980
Auto merge of #154253 - JonathanBrouwer:rollup-LLZUsz2, r=JonathanBro…
bors Mar 23, 2026
6101edd
perf: manual_is_ascii_check, remove 797 million instructions
blyxyas Mar 23, 2026
b8ce22d
perf: manual_is_ascii_check, remove 822 million instructions (#16755)
samueltardieu Mar 23, 2026
6eda8b0
perf: reduce `matching_root_macro_call` usage
blyxyas Mar 23, 2026
fef8a71
fix: `collapsible_if` FP when the inner if contains cfg
profetia Mar 24, 2026
807dea0
Fix `collapsible_match` FP when the pat binding is moved or mutated (…
Jarcho Mar 24, 2026
96c1c7a
perf: reduce `matching_root_macro_call` usage (23b -> 22.24b) (#16756)
Jarcho Mar 24, 2026
f923257
Fix `collapsible_if` FP when the inner if contains cfg (#16757)
dswij Mar 24, 2026
4213928
manual_pop_if: lint more cases, even if we do not provide a suggestio…
ada4a Mar 24, 2026
f7649ef
`iter_kv_map`: handle identity map for `map` and `flat_map` (#16743)
dswij Mar 24, 2026
ddfb974
Rollup merge of #153702 - SpriteOvO:guard-matcher, r=davidtwco
JonathanBrouwer Mar 25, 2026
daad0fb
fix(explicit_counter_loop): suggest `.take(n)` for `for _ in 0..n` co…
zayutaha Mar 3, 2026
0a29aac
fix(explicit_counter_loop): suggest `.take(n)` for `for _ in 0..n` co…
Jarcho Mar 27, 2026
b0c0292
Add typeck_root_def_id_local
zetanumbers Mar 27, 2026
6e68667
Use tcx.local_parent() more often
zetanumbers Mar 27, 2026
a7a0fc3
chore(deps): update rust crate tar to v0.4.45
xtqqczze Mar 27, 2026
e43491b
chore(deps): update rust crate tar to v0.4.45 (#16771)
Jarcho Mar 27, 2026
75813d3
Preserve parentheses in suggestion in presence of cascaded casts (#16…
Jarcho Mar 27, 2026
ea5bc07
similar_names not triggered by example
alt440 Dec 25, 2025
4443573
Correct dogfood tests
alt440 Dec 25, 2025
df8f576
Executed cargo fmt
alt440 Dec 25, 2025
c5b3fcf
Revert "Executed cargo fmt"
alt440 Jan 30, 2026
111b8dc
Revert "Correct dogfood tests"
alt440 Jan 30, 2026
837e891
Revert "similar_names not triggered by example"
alt440 Jan 30, 2026
ee7896e
similar_names not triggered by example
alt440 Jan 30, 2026
453a482
Ran cargo dev fmt
alt440 Jan 30, 2026
fee9100
Issue #16110: similar_names not triggered by example (#16300)
Jarcho Mar 28, 2026
26740ea
impl manual_noop_waker lint
jaroslawroszyk Mar 7, 2026
e4683d2
impl manual_noop_waker lint (#16687)
samueltardieu Mar 28, 2026
c07baa4
Add `manual_option_zip` lint (`a.and_then(|x| b.map(|y| (x, y)))`) (#…
llogiq Mar 28, 2026
7d9ab57
don't drop arguments' temporaries in `dbg!`
dianne Mar 19, 2026
e689235
update diagnostic for variables moved by `dbg!`
dianne Mar 29, 2026
4efda7a
Rollup merge of #154074 - dianne:dbg-temp-scopes, r=Mark-Simulacrum
JonathanBrouwer Mar 29, 2026
1d55118
Merge remote-tracking branch 'upstream/master' into rustup
flip1995 Apr 2, 2026
994d5b4
Bump nightly version -> 2026-04-02
flip1995 Apr 2, 2026
750e578
clippy_dev/new_lint: fix path to the file where MSRVs reside
GrigorenkoPV Apr 2, 2026
a390a52
clippy_dev/new_lint: sort imports in the snippet
GrigorenkoPV Apr 2, 2026
174df86
Few small fixes for `clippy_dev/new_lint` (#16795)
Jarcho Apr 2, 2026
f4d6d69
Remove internal lint DERIVE_DESERIALIZE_ALLOWING_UNKNOWN
flip1995 Apr 3, 2026
88f787d
Rustup (#16791)
llogiq Apr 3, 2026
29bd9b3
Merge commit '88f787d193fb1f0491b001288e82b5574c080606' into clippy-s…
flip1995 Apr 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/tools/clippy/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6797,9 +6797,11 @@ Released 2018-09-13
[`manual_midpoint`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_midpoint
[`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
[`manual_noop_waker`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_noop_waker
[`manual_ok_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_err
[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
[`manual_option_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_option_as_slice
[`manual_option_zip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_option_zip
[`manual_pattern_char_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison
[`manual_pop_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_pop_if
[`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
Expand Down
1 change: 0 additions & 1 deletion src/tools/clippy/clippy_config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
unused_qualifications
)]
#![allow(clippy::must_use_candidate, clippy::missing_panics_doc)]
#![deny(clippy::derive_deserialize_allowing_unknown)]

extern crate rustc_data_structures;
extern crate rustc_errors;
Expand Down
1 change: 0 additions & 1 deletion src/tools/clippy/clippy_dev/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#![feature(
exit_status_error,
new_range,
new_range_api,
os_str_slice,
os_string_truncate,
pattern,
Expand Down
4 changes: 2 additions & 2 deletions src/tools/clippy/clippy_dev/src/new_lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,8 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
let _: fmt::Result = writedoc!(
result,
r"
use clippy_utils::msrvs::{{self, {msrv_ty}}};
use clippy_config::Conf;
use clippy_utils::msrvs::{{self, {msrv_ty}}};
{pass_import}
use rustc_lint::{{{context_import}, {pass_type}}};
use rustc_session::impl_lint_pass;
Expand Down Expand Up @@ -319,7 +319,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {

impl {pass_type}{pass_lifetimes} for {name_camel} {{{extract_msrv}}}

// TODO: Add MSRV level to `clippy_config/src/msrvs.rs` if needed.
// TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
// TODO: Update msrv config comment in `clippy_config/src/conf.rs`
"
);
Expand Down
76 changes: 52 additions & 24 deletions src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::numeric_literal::NumericLiteral;
use clippy_utils::res::MaybeResPath as _;
use clippy_utils::source::{SpanRangeExt, snippet_opt};
use clippy_utils::source::{SpanRangeExt, snippet, snippet_with_applicability};
use clippy_utils::sugg::has_enclosing_paren;
use clippy_utils::visitors::{Visitable, for_each_expr_without_closures};
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, sym};
use rustc_ast::{LitFloatType, LitIntType, LitKind};
Expand All @@ -24,7 +25,8 @@ pub(super) fn check<'tcx>(
cast_from: Ty<'tcx>,
cast_to: Ty<'tcx>,
) -> bool {
let cast_str = snippet_opt(cx, cast_expr.span).unwrap_or_default();
let mut app = Applicability::MachineApplicable;
let cast_str = snippet_with_applicability(cx, cast_expr.span, "_", &mut app);

if let ty::RawPtr(..) = cast_from.kind()
// check both mutability and type are the same
Expand All @@ -47,16 +49,23 @@ pub(super) fn check<'tcx>(
_ => {},
}

span_lint_and_sugg(
// Preserve parentheses around `expr` in case of cascaded casts
let surrounding =
if matches!(cast_expr.kind, ExprKind::Cast(..)) && has_enclosing_paren(snippet(cx, expr.span, "")) {
MaybeParenOrBlock::Paren
} else {
MaybeParenOrBlock::Nothing
};

emit_lint(
cx,
UNNECESSARY_CAST,
expr.span,
expr,
format!(
"casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"
),
"try",
cast_str.clone(),
Applicability::MaybeIncorrect,
&cast_str,
surrounding,
app.max(Applicability::MaybeIncorrect),
);
}

Expand Down Expand Up @@ -143,12 +152,6 @@ pub(super) fn check<'tcx>(
}

if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) {
enum MaybeParenOrBlock {
Paren,
Block,
Nothing,
}

fn is_borrow_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
matches!(expr.kind, ExprKind::AddrOf(..))
|| cx
Expand Down Expand Up @@ -188,18 +191,13 @@ pub(super) fn check<'tcx>(
_ => MaybeParenOrBlock::Nothing,
};

span_lint_and_sugg(
emit_lint(
cx,
UNNECESSARY_CAST,
expr.span,
expr,
format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
"try",
match surrounding {
MaybeParenOrBlock::Paren => format!("({cast_str})"),
MaybeParenOrBlock::Block => format!("{{ {cast_str} }}"),
MaybeParenOrBlock::Nothing => cast_str,
},
Applicability::MachineApplicable,
&cast_str,
surrounding,
app,
);
return true;
}
Expand Down Expand Up @@ -312,3 +310,33 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
})
.is_some()
}

#[derive(Clone, Copy)]
enum MaybeParenOrBlock {
Paren,
Block,
Nothing,
}

fn emit_lint(
cx: &LateContext<'_>,
expr: &Expr<'_>,
msg: String,
sugg: &str,
surrounding: MaybeParenOrBlock,
applicability: Applicability,
) {
span_lint_and_sugg(
cx,
UNNECESSARY_CAST,
expr.span,
msg,
"try",
match surrounding {
MaybeParenOrBlock::Paren => format!("({sugg})"),
MaybeParenOrBlock::Block => format!("{{ {sugg} }}"),
MaybeParenOrBlock::Nothing => sugg.to_string(),
},
applicability,
);
}
20 changes: 9 additions & 11 deletions src/tools/clippy/clippy_lints/src/collapsible_if.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::msrvs::Msrv;
use clippy_utils::source::{HasSession, IntoSpan as _, SpanRangeExt, snippet, snippet_block_with_applicability};
use clippy_utils::{can_use_if_let_chains, span_contains_non_whitespace, sym, tokenize_with_text};
use clippy_utils::{can_use_if_let_chains, span_contains_cfg, span_contains_non_whitespace, sym, tokenize_with_text};
use rustc_ast::BinOpKind;
use rustc_errors::Applicability;
use rustc_hir::attrs::{AttributeKind, LintAttributeKind};
Expand Down Expand Up @@ -170,6 +170,11 @@ impl CollapsibleIf {
&& self.eligible_condition(cx, check_inner)
&& expr.span.eq_ctxt(inner.span)
&& self.check_significant_tokens_and_expect_attrs(cx, then, inner, sym::collapsible_if)
&& let then_closing_bracket = {
let end = then.span.shrink_to_hi();
end.with_lo(end.lo() - BytePos(1))
}
&& !span_contains_cfg(cx, inner.span.between(then_closing_bracket))
{
span_lint_hir_and_then(
cx,
Expand All @@ -179,12 +184,7 @@ impl CollapsibleIf {
"this `if` statement can be collapsed",
|diag| {
let then_open_bracket = then.span.split_at(1).0.with_leading_whitespace(cx).into_span();
let then_closing_bracket = {
let end = then.span.shrink_to_hi();
end.with_lo(end.lo() - BytePos(1))
.with_leading_whitespace(cx)
.into_span()
};
let then_closing_bracket = then_closing_bracket.with_leading_whitespace(cx).into_span();
let (paren_start, inner_if_span, paren_end) = peel_parens(cx, inner.span);
let inner_if = inner_if_span.split_at(2).0;
let mut sugg = vec![
Expand Down Expand Up @@ -238,12 +238,10 @@ impl CollapsibleIf {
!span_contains_non_whitespace(cx, span, self.lint_commented_code)
},

[
Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs)),
] => {
[Attribute::Parsed(AttributeKind::LintAttributes(sub_attrs))] => {
sub_attrs
.into_iter()
.filter(|attr|attr.kind == LintAttributeKind::Expect)
.filter(|attr| attr.kind == LintAttributeKind::Expect)
.flat_map(|attr| attr.lint_instances.iter().map(|group| (attr.attr_span, group)))
.filter(|(_, lint_id)| {
lint_id.tool_is_named(sym::clippy)
Expand Down
2 changes: 2 additions & 0 deletions src/tools/clippy/clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
crate::manual_noop_waker::MANUAL_NOOP_WAKER_INFO,
crate::manual_option_as_slice::MANUAL_OPTION_AS_SLICE_INFO,
crate::manual_pop_if::MANUAL_POP_IF_INFO,
crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO,
Expand Down Expand Up @@ -418,6 +419,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
crate::methods::MANUAL_IS_VARIANT_AND_INFO,
crate::methods::MANUAL_NEXT_BACK_INFO,
crate::methods::MANUAL_OK_OR_INFO,
crate::methods::MANUAL_OPTION_ZIP_INFO,
crate::methods::MANUAL_REPEAT_N_INFO,
crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO,
crate::methods::MANUAL_SPLIT_ONCE_INFO,
Expand Down
4 changes: 3 additions & 1 deletion src/tools/clippy/clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ mod manual_is_power_of_two;
mod manual_let_else;
mod manual_main_separator_str;
mod manual_non_exhaustive;
mod manual_noop_waker;
mod manual_option_as_slice;
mod manual_pop_if;
mod manual_range_patterns;
Expand Down Expand Up @@ -864,7 +865,8 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
Box::new(move |tcx| Box::new(duration_suboptimal_units::DurationSuboptimalUnits::new(tcx, conf))),
Box::new(move |_| Box::new(manual_take::ManualTake::new(conf))),
Box::new(|_| Box::new(manual_checked_ops::ManualCheckedOps)),
Box::new(move |_| Box::new(manual_pop_if::ManualPopIf::new(conf))),
Box::new(move |tcx| Box::new(manual_pop_if::ManualPopIf::new(tcx, conf))),
Box::new(|_| Box::new(manual_noop_waker::ManualNoopWaker)),
// add late passes here, used by `cargo dev new_lint`
];
store.late_passes.extend(late_lints);
Expand Down
21 changes: 21 additions & 0 deletions src/tools/clippy/clippy_lints/src/loops/explicit_counter_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::borrow::Cow;

use super::{EXPLICIT_COUNTER_LOOP, IncrementVisitor, InitializeVisitor, make_iterator_snippet};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::Range;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::{EMPTY, Sugg};
use clippy_utils::{get_enclosing_block, is_integer_const, is_integer_literal_untyped};
Expand Down Expand Up @@ -83,6 +84,26 @@ pub(super) fn check<'tcx>(
snippet
});

// If the loop variable is unused and the range is `0..n`, suggest `(init..).take(n)`.
if pat_snippet == "_"
&& let Some(range) = Range::hir(cx, arg)
&& range.limits == RangeLimits::HalfOpen
&& range.start.is_some_and(|start| is_integer_const(cx, start, 0))
&& let Some(end) = range.end
{
let end = snippet_with_applicability(cx, end.span, "..", &mut applicability);
diag.span_suggestion(
span,
"consider using",
format!(
"{loop_label}for {name} in ({}).take({end})",
initializer.range(&EMPTY, RangeLimits::HalfOpen)
),
applicability,
);
return;
}

diag.span_suggestion(
span,
"consider using",
Expand Down
4 changes: 2 additions & 2 deletions src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,8 @@ fn get_details_from_idx<'tcx>(
ExprKind::Binary(op, lhs, rhs) => match op.node {
BinOpKind::Add => {
let offset_opt = get_start(lhs, starts)
.and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, o)))
.or_else(|| get_start(rhs, starts).and_then(|s| get_offset(cx, lhs, starts).map(|o| (s, o))));
.zip(get_offset(cx, rhs, starts))
.or_else(|| get_start(rhs, starts).zip(get_offset(cx, lhs, starts)));

offset_opt.map(|(s, o)| (s, Offset::positive(o)))
},
Expand Down
11 changes: 9 additions & 2 deletions src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ enum CharRange {

impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !matches!(
expr.kind,
ExprKind::Match(_, [_, ..], _) | ExprKind::MethodCall(_, _, [_], _)
) {
return;
}

if !self.msrv.meets(cx, msrvs::IS_ASCII_DIGIT) {
return;
}
Expand All @@ -99,8 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
return;
}

let (arg, span, range) = if let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro)
&& let ExprKind::Match(recv, [arm, ..], _) = expr.kind
let (arg, span, range) = if let ExprKind::Match(recv, [arm, ..], _) = expr.kind
&& let Some(macro_call) = matching_root_macro_call(cx, expr.span, sym::matches_macro)
{
let recv = peel_ref_operators(cx, recv);
let range = check_pat(&arm.pat.kind);
Expand Down
71 changes: 71 additions & 0 deletions src/tools/clippy/clippy_lints/src/manual_noop_waker.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{is_empty_block, sym};
use rustc_hir::{ImplItemKind, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;

declare_clippy_lint! {
/// ### What it does
/// Checks for manual implementations of `std::task::Wake` that are empty.
///
/// ### Why is this bad?
/// `Waker::noop()` provides a more performant and cleaner way to create a
/// waker that does nothing, avoiding unnecessary `Arc` allocations and
/// reference count increments.
///
/// ### Example
/// ```rust
/// # use std::sync::Arc;
/// # use std::task::Wake;
/// struct MyWaker;
/// impl Wake for MyWaker {
/// fn wake(self: Arc<Self>) {}
/// fn wake_by_ref(self: &Arc<Self>) {}
/// }
/// ```
///
/// Use instead:
/// ```rust
/// use std::task::Waker;
/// let waker = Waker::noop();
/// ```
#[clippy::version = "1.96.0"]
pub MANUAL_NOOP_WAKER,
complexity,
"manual implementations of noop wakers can be simplified using Waker::noop()"
}

declare_lint_pass!(ManualNoopWaker => [MANUAL_NOOP_WAKER]);

impl<'tcx> LateLintPass<'tcx> for ManualNoopWaker {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if let ItemKind::Impl(imp) = item.kind
&& let Some(trait_ref) = imp.of_trait
&& let Some(trait_id) = trait_ref.trait_ref.trait_def_id()
&& cx.tcx.is_diagnostic_item(sym::Wake, trait_id)
{
for impl_item_ref in imp.items {
let impl_item = cx
.tcx
.hir_node_by_def_id(impl_item_ref.owner_id.def_id)
.expect_impl_item();

if let ImplItemKind::Fn(_, body_id) = &impl_item.kind {
let body = cx.tcx.hir_body(*body_id);
if !is_empty_block(body.value) {
return;
}
}
}

span_lint_and_help(
cx,
MANUAL_NOOP_WAKER,
trait_ref.trait_ref.path.span,
"manual implementation of a no-op waker",
None,
"use `std::task::Waker::noop()` instead",
);
}
}
}
Loading
Loading