Skip to content

Commit af2af23

Browse files
committed
Bless clippy.
1 parent 1d7e1a2 commit af2af23

15 files changed

Lines changed: 116 additions & 159 deletions

src/tools/clippy/clippy_lints/src/dbg_macro.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_errors::Applicability;
88
use rustc_hir::{Closure, ClosureKind, CoroutineKind, Expr, ExprKind, LetStmt, LocalSource, Node, Stmt, StmtKind};
99
use rustc_lint::{LateContext, LateLintPass, LintContext};
1010
use rustc_session::impl_lint_pass;
11-
use rustc_span::{Span, SyntaxContext};
11+
use rustc_span::{DesugaringKind, Span, SyntaxContext};
1212

1313
declare_clippy_lint! {
1414
/// ### What it does
@@ -58,10 +58,11 @@ impl LateLintPass<'_> for DbgMacro {
5858
let cur_syntax_ctxt = expr.span.ctxt();
5959

6060
if cur_syntax_ctxt != self.prev_ctxt &&
61+
// avoids exprs generated by the desugaring of coroutines,
62+
// as they confuse `first_dbg_macro_in_expansion`
63+
!expr.span.is_desugaring(DesugaringKind::Async) && !is_coroutine_desugar(expr) &&
6164
let Some(macro_call) = first_dbg_macro_in_expansion(cx, expr.span) &&
6265
!macro_call.span.in_external_macro(cx.sess().source_map()) &&
63-
// avoids exprs generated by the desugaring of coroutines
64-
!is_coroutine_desugar(expr) &&
6566
self.checked_dbg_call_site.insert(macro_call.span) &&
6667
// allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
6768
!(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id))

src/tools/clippy/clippy_lints/src/doc/missing_headers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub fn check(
8383
Some(owner_id.def_id.to_def_id()),
8484
&[],
8585
)
86-
&& let ty::Coroutine(_, subs) = ret_ty.kind()
86+
&& let Some((_, subs)) = cx.tcx.try_unwrap_desugared_coroutine(ret_ty)
8787
&& subs.as_coroutine().return_ty().is_diag_item(cx, sym::Result)
8888
{
8989
span_lint(

src/tools/clippy/clippy_lints/src/implicit_return.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
229229
_: LocalDefId,
230230
) {
231231
if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_)))
232-
|| !span.eq_ctxt(body.value.span)
233232
|| span.in_external_macro(cx.sess().source_map())
234233
{
235234
return;
@@ -251,7 +250,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
251250
body.value
252251
};
253252

254-
if is_from_proc_macro(cx, expr) {
253+
if !span.eq_ctxt(expr.span) || is_from_proc_macro(cx, expr) {
255254
return;
256255
}
257256
lint_implicit_returns(cx, expr, expr.span.ctxt(), None);

src/tools/clippy/clippy_lints/src/manual_async_fn.rs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
2+
use clippy_utils::desugared_async_block;
23
use clippy_utils::source::{SpanRangeExt, position_before_rarrow, snippet_block};
34
use rustc_errors::Applicability;
45
use rustc_hir::intravisit::FnKind;
5-
use rustc_hir::{
6-
Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl,
7-
FnRetTy, GenericBound, Node, OpaqueTy, TraitRef, Ty, TyKind,
8-
};
6+
use rustc_hir::{Body, ExprKind, FnDecl, FnRetTy, GenericBound, Node, OpaqueTy, TraitRef, Ty, TyKind};
97
use rustc_lint::{LateContext, LateLintPass};
108
use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
119
use rustc_middle::ty;
@@ -59,7 +57,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
5957
// Check that the body of the function consists of one async block
6058
&& let ExprKind::Block(block, _) = body.value.kind
6159
&& block.stmts.is_empty()
62-
&& let Some(closure_body) = desugared_async_block(cx, block)
60+
&& let Some(body_expr) = block.expr
61+
&& let Some((_, closure_body)) = desugared_async_block(cx, body_expr)
6362
&& let Some(vis_span_opt) = match cx.tcx.hir_node_by_def_id(fn_def_id) {
6463
Node::Item(item) => Some(Some(item.vis_span)),
6564
Node::ImplItem(impl_item) => Some(impl_item.vis_span()),
@@ -165,20 +164,6 @@ fn captures_all_lifetimes(cx: &LateContext<'_>, fn_def_id: LocalDefId, opaque_de
165164
num_captured_lifetimes == num_early_lifetimes + num_late_lifetimes
166165
}
167166

168-
fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
169-
if let Some(&Expr {
170-
kind: ExprKind::Closure(&Closure { kind, body, .. }),
171-
..
172-
}) = block.expr
173-
&& let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) =
174-
kind
175-
{
176-
return Some(cx.tcx.hir_body(body));
177-
}
178-
179-
None
180-
}
181-
182167
fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, String)> {
183168
if let TyKind::Tup([]) = output.kind {
184169
let sugg = "remove the return type";

src/tools/clippy/clippy_lints/src/redundant_async_block.rs

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::source::{snippet, walk_span_to_context};
2+
use clippy_utils::source::snippet;
33
use clippy_utils::ty::implements_trait;
4-
use clippy_utils::{desugar_await, peel_blocks};
4+
use clippy_utils::{desugar_await, desugared_async_block, peel_blocks};
55
use rustc_errors::Applicability;
6-
use rustc_hir::{Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind};
6+
use rustc_hir::Expr;
77
use rustc_lint::{LateContext, LateLintPass};
88
use rustc_middle::ty::UpvarCapture;
99
use rustc_session::declare_lint_pass;
10+
use rustc_span::{ExpnKind, Span};
1011

1112
declare_clippy_lint! {
1213
/// ### What it does
@@ -41,26 +42,24 @@ declare_lint_pass!(RedundantAsyncBlock => [REDUNDANT_ASYNC_BLOCK]);
4142

4243
impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
4344
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
44-
let span = expr.span;
45-
if !span.in_external_macro(cx.tcx.sess.source_map()) &&
45+
if !expr.span.in_external_macro(cx.tcx.sess.source_map()) &&
4646
let Some(body_expr) = desugar_async_block(cx, expr) &&
47-
let Some(expr) = desugar_await(peel_blocks(body_expr)) &&
47+
let Some(inner_expr) = desugar_await(peel_blocks(body_expr)) &&
4848
// The await prefix must not come from a macro as its content could change in the future.
49-
expr.span.eq_ctxt(body_expr.span) &&
49+
!is_from_macro_within(inner_expr.span, body_expr.span) &&
5050
// The await prefix must implement Future, as implementing IntoFuture is not enough.
5151
let Some(future_trait) = cx.tcx.lang_items().future_trait() &&
52-
implements_trait(cx, cx.typeck_results().expr_ty(expr), future_trait, &[]) &&
52+
implements_trait(cx, cx.typeck_results().expr_ty(inner_expr), future_trait, &[]) &&
5353
// An async block does not have immediate side-effects from a `.await` point-of-view.
54-
(!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) &&
55-
let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt())
54+
(!inner_expr.can_have_side_effects() || desugar_async_block(cx, inner_expr).is_some())
5655
{
5756
span_lint_and_sugg(
5857
cx,
5958
REDUNDANT_ASYNC_BLOCK,
60-
span,
59+
expr.span,
6160
"this async expression only awaits a single future",
6261
"you can reduce it to",
63-
snippet(cx, shortened_span, "..").into_owned(),
62+
snippet(cx, inner_expr.span, "..").into_owned(),
6463
Applicability::MachineApplicable,
6564
);
6665
}
@@ -70,28 +69,41 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
7069
/// If `expr` is a desugared `async` block, return the original expression if it does not capture
7170
/// any variable by ref.
7271
fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
73-
if let ExprKind::Closure(Closure { body, def_id, kind, .. }) = expr.kind
74-
&& let body = cx.tcx.hir_body(*body)
75-
&& matches!(
76-
kind,
77-
ClosureKind::Coroutine(CoroutineKind::Desugared(
78-
CoroutineDesugaring::Async,
79-
CoroutineSource::Block
80-
))
81-
)
82-
{
83-
cx.typeck_results()
72+
let (def_id, body) = desugared_async_block(cx, expr)?;
73+
if cx.typeck_results()
8474
.closure_min_captures
85-
.get(def_id)
75+
.get(&def_id)
8676
.is_none_or(|m| {
8777
m.values().all(|places| {
8878
places
8979
.iter()
9080
.all(|place| matches!(place.info.capture_kind, UpvarCapture::ByValue))
9181
})
9282
})
93-
.then_some(body.value)
83+
{
84+
Some(body.value)
9485
} else {
9586
None
9687
}
9788
}
89+
90+
fn is_from_macro_within(mut span: Span, outer_span: Span) -> bool {
91+
let outer_ctxt = outer_span.ctxt();
92+
loop {
93+
let ctxt = span.ctxt();
94+
if ctxt.is_root() || ctxt == outer_ctxt {
95+
break
96+
}
97+
98+
let expn_data = ctxt.outer_expn_data();
99+
match expn_data.kind {
100+
ExpnKind::Macro { .. } => return true,
101+
ExpnKind::Root
102+
| ExpnKind::AstPass(_)
103+
| ExpnKind::Desugaring(_) => {}
104+
}
105+
span = expn_data.call_site;
106+
}
107+
108+
false
109+
}

src/tools/clippy/clippy_lints/src/redundant_closure_call.rs

Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir};
2-
use clippy_utils::get_parent_expr;
2+
use clippy_utils::{get_async_closure_expr, get_parent_expr};
33
use clippy_utils::sugg::Sugg;
44
use hir::Param;
55
use rustc_errors::Applicability;
66
use rustc_hir as hir;
77
use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor};
8-
use rustc_hir::{ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, intravisit as hir_visit};
8+
use rustc_hir::{ClosureKind, CoroutineDesugaring, ExprKind, intravisit as hir_visit};
99
use rustc_lint::{LateContext, LateLintPass, LintContext};
1010
use rustc_middle::hir::nested_filter;
11-
use rustc_middle::ty;
1211
use rustc_session::declare_lint_pass;
1312
use rustc_span::ExpnKind;
1413
use std::ops::ControlFlow;
@@ -52,21 +51,6 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor {
5251
}
5352
}
5453

55-
/// Checks if the body is owned by an async closure.
56-
/// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression
57-
/// }`.
58-
fn is_async_closure(body: &hir::Body<'_>) -> bool {
59-
if let ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind
60-
// checks whether it is `async || whatever_expression`
61-
&& let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure))
62-
= innermost_closure_generated_by_desugar.kind
63-
{
64-
true
65-
} else {
66-
false
67-
}
68-
}
69-
7054
/// Tries to find the innermost closure:
7155
/// ```rust,ignore
7256
/// (|| || || || 42)()()()()
@@ -82,7 +66,7 @@ fn find_innermost_closure<'tcx>(
8266
) -> Option<(
8367
&'tcx hir::Expr<'tcx>,
8468
&'tcx hir::FnDecl<'tcx>,
85-
ty::Asyncness,
69+
ClosureKind,
8670
&'tcx [Param<'tcx>],
8771
)> {
8872
let mut data = None;
@@ -99,11 +83,7 @@ fn find_innermost_closure<'tcx>(
9983
data = Some((
10084
body.value,
10185
closure.fn_decl,
102-
if is_async_closure(body) {
103-
ty::Asyncness::Yes
104-
} else {
105-
ty::Asyncness::No
106-
},
86+
closure.kind,
10787
body.params,
10888
));
10989
steps -= 1;
@@ -171,23 +151,12 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
171151
let mut hint =
172152
Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability);
173153

174-
if coroutine_kind.is_async()
175-
&& let ExprKind::Closure(closure) = body.kind
154+
if let ClosureKind::CoroutineClosure(CoroutineDesugaring::Async) = coroutine_kind
155+
&& let Some(body_expr) = get_async_closure_expr(cx.tcx, body)
176156
{
177157
// Like `async fn`, async closures are wrapped in an additional block
178158
// to move all of the closure's arguments into the future.
179159

180-
let async_closure_body = cx.tcx.hir_body(closure.body).value;
181-
let ExprKind::Block(block, _) = async_closure_body.kind else {
182-
return;
183-
};
184-
let Some(block_expr) = block.expr else {
185-
return;
186-
};
187-
let ExprKind::DropTemps(body_expr) = block_expr.kind else {
188-
return;
189-
};
190-
191160
// `async x` is a syntax error, so it becomes `async { x }`
192161
if !matches!(body_expr.kind, ExprKind::Block(_, _)) {
193162
hint = hint.blockify();

src/tools/clippy/clippy_lints/src/unused_async.rs

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
2-
use clippy_utils::is_def_id_trait_method;
2+
use clippy_utils::{get_async_closure_expr, is_def_id_trait_method};
33
use clippy_utils::source::{HasSession, snippet_with_applicability, walk_span_to_context};
44
use clippy_utils::usage::is_todo_unimplemented_stub;
55
use rustc_errors::Applicability;
@@ -258,7 +258,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
258258

259259
if !visitor.found_await
260260
&& let Some(builtin_crate) = clippy_utils::std_or_core(cx)
261-
&& let Some(inner) = unpack_async_fn_body(cx, body)
261+
&& let Some(inner) = get_async_closure_expr(cx.tcx, body.value)
262262
// Find the tail expression contained in the async fn (if any),
263263
// which will be wrapped in std::future::ready.
264264
&& let ExprKind::Block(block, _) = inner.kind
@@ -319,47 +319,6 @@ fn is_default_trait_impl(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
319319
)
320320
}
321321

322-
/// Get the inner expression of the body of an async function.
323-
///
324-
/// If it is not an async function, returns `None`.
325-
///
326-
/// An async function like
327-
/// ```rs
328-
/// async fn get_random_number() -> i64 {
329-
/// do_something();
330-
/// 4
331-
/// }
332-
/// ```
333-
/// (roughly) desugars to
334-
/// ```rs
335-
/// fn get_random_number() -> impl Future<Output = i64> {
336-
/// async move {
337-
/// do_something();
338-
/// 4
339-
/// }
340-
/// }
341-
/// ```
342-
///
343-
/// We first get to the `async move {}` block,
344-
/// which is the one and only expression in the body of the function.
345-
/// This block is a coroutine wrapped in a closure.
346-
/// The expression in this block is contained in a terminating scope.
347-
///
348-
/// This function returns that expression in `Some(...)` if this body indeed is an async function.
349-
fn unpack_async_fn_body<'hir>(cx: &LateContext<'hir>, body: &Body<'hir>) -> Option<&'hir Expr<'hir>> {
350-
if let ExprKind::Closure(closure) = body.value.kind
351-
&& let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) = closure.kind
352-
&& let body = cx.tcx.hir_body(closure.body)
353-
&& let ExprKind::Block(block, _) = body.value.kind
354-
&& let Some(expr) = block.expr
355-
&& let ExprKind::DropTemps(inner) = expr.kind
356-
{
357-
Some(inner)
358-
} else {
359-
None
360-
}
361-
}
362-
363322
fn async_fn_contains_todo_unimplemented_macro<'hir>(cx: &LateContext<'hir>, body: &Body<'hir>) -> bool {
364-
unpack_async_fn_body(cx, body).is_some_and(|inner| is_todo_unimplemented_stub(cx, inner))
323+
get_async_closure_expr(cx.tcx, body.value).is_some_and(|inner| is_todo_unimplemented_stub(cx, inner))
365324
}

src/tools/clippy/clippy_lints/src/utils/author.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
295295
&& !id.is_local()
296296
{
297297
if let Some(lang) = self.cx.tcx.lang_items().from_def_id(id) {
298-
chain!(self, "{path}.res(cx).is_lang_item(cx, LangItem::{}", lang.name());
298+
chain!(self, "{path}.res(cx).is_lang_item(cx, LangItem::{})", lang.name());
299299
} else if let Some(name) = self.cx.tcx.get_diagnostic_name(id) {
300300
chain!(self, "{path}.res(cx).is_diag_item(cx, sym::{name})");
301301
} else {

0 commit comments

Comments
 (0)