Merge commit 'f712eb5cdc' into clippy-subtree-update
This commit is contained in:
parent
4847c40c8b
commit
6ced8c33c0
248 changed files with 5023 additions and 900 deletions
|
|
@ -29,11 +29,7 @@ pub(super) fn check(
|
|||
if !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) {
|
||||
return;
|
||||
}
|
||||
} else if count
|
||||
.try_to_target_usize(cx.tcx)
|
||||
.map_or(true, |x| x > 32)
|
||||
&& !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN)
|
||||
{
|
||||
} else if count.try_to_target_usize(cx.tcx).map_or(true, |x| x > 32) && !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::{fn_def_id, is_from_proc_macro, is_lint_allowed};
|
||||
use hir::intravisit::{Visitor, walk_expr};
|
||||
use hir::{Expr, ExprKind, FnRetTy, FnSig, Node};
|
||||
use hir::{Expr, ExprKind, FnRetTy, FnSig, Node, TyKind};
|
||||
use rustc_ast::Label;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::INFINITE_LOOP;
|
||||
|
||||
|
|
@ -25,13 +26,7 @@ pub(super) fn check<'tcx>(
|
|||
return;
|
||||
};
|
||||
// Or, its parent function is already returning `Never`
|
||||
if matches!(
|
||||
parent_fn_ret,
|
||||
FnRetTy::Return(hir::Ty {
|
||||
kind: hir::TyKind::Never,
|
||||
..
|
||||
})
|
||||
) {
|
||||
if is_never_return(parent_fn_ret) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +64,16 @@ pub(super) fn check<'tcx>(
|
|||
fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<FnRetTy<'tcx>> {
|
||||
for (_, parent_node) in cx.tcx.hir().parent_iter(expr.hir_id) {
|
||||
match parent_node {
|
||||
// Skip `Coroutine` closures, these are the body of `async fn`, not async closures.
|
||||
// This is because we still need to backtrack one parent node to get the `OpaqueDef` ty.
|
||||
Node::Expr(Expr {
|
||||
kind:
|
||||
ExprKind::Closure(hir::Closure {
|
||||
kind: hir::ClosureKind::Coroutine(_),
|
||||
..
|
||||
}),
|
||||
..
|
||||
}) => (),
|
||||
Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Fn(FnSig { decl, .. }, _, _),
|
||||
..
|
||||
|
|
@ -143,3 +148,41 @@ impl<'hir> Visitor<'hir> for LoopVisitor<'hir, '_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `true` if the given [`FnRetTy`] is never (!).
|
||||
///
|
||||
/// Note: This function also take care of return type of async fn,
|
||||
/// as the actual type is behind an [`OpaqueDef`](TyKind::OpaqueDef).
|
||||
fn is_never_return(ret_ty: FnRetTy<'_>) -> bool {
|
||||
let FnRetTy::Return(hir_ty) = ret_ty else { return false };
|
||||
|
||||
match hir_ty.kind {
|
||||
TyKind::Never => true,
|
||||
TyKind::OpaqueDef(hir::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::AsyncFn { .. },
|
||||
bounds,
|
||||
..
|
||||
}) => {
|
||||
if let Some(trait_ref) = bounds.iter().find_map(|b| b.trait_ref())
|
||||
&& let Some(segment) = trait_ref
|
||||
.path
|
||||
.segments
|
||||
.iter()
|
||||
.find(|seg| seg.ident.name == sym::future_trait)
|
||||
&& let Some(args) = segment.args
|
||||
&& let Some(cst_kind) = args
|
||||
.constraints
|
||||
.iter()
|
||||
.find_map(|cst| (cst.ident.name == sym::Output).then_some(cst.kind))
|
||||
&& let hir::AssocItemConstraintKind::Equality {
|
||||
term: hir::Term::Ty(ty),
|
||||
} = cst_kind
|
||||
{
|
||||
matches!(ty.kind, TyKind::Never)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,10 +19,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'
|
|||
cx,
|
||||
ids: HirIdSet::default(),
|
||||
def_ids: DefIdMap::default(),
|
||||
skip: false,
|
||||
};
|
||||
var_visitor.visit_expr(cond);
|
||||
if var_visitor.skip {
|
||||
if var_visitor.visit_expr(cond).is_break() {
|
||||
return;
|
||||
}
|
||||
let used_in_condition = &var_visitor.ids;
|
||||
|
|
@ -81,7 +79,6 @@ struct VarCollectorVisitor<'a, 'tcx> {
|
|||
cx: &'a LateContext<'tcx>,
|
||||
ids: HirIdSet,
|
||||
def_ids: DefIdMap<bool>,
|
||||
skip: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> VarCollectorVisitor<'_, 'tcx> {
|
||||
|
|
@ -104,11 +101,15 @@ impl<'tcx> VarCollectorVisitor<'_, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for VarCollectorVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> Self::Result {
|
||||
match ex.kind {
|
||||
ExprKind::Path(_) => self.insert_def_id(ex),
|
||||
ExprKind::Path(_) => {
|
||||
self.insert_def_id(ex);
|
||||
ControlFlow::Continue(())
|
||||
},
|
||||
// If there is any function/method call… we just stop analysis
|
||||
ExprKind::Call(..) | ExprKind::MethodCall(..) => self.skip = true,
|
||||
ExprKind::Call(..) | ExprKind::MethodCall(..) => ControlFlow::Break(()),
|
||||
|
||||
_ => walk_expr(self, ex),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use super::WHILE_LET_ON_ITERATOR;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
|
|
@ -204,35 +206,32 @@ fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tc
|
|||
struct V<'a, 'b, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
iter_expr: &'b IterExpr,
|
||||
uses_iter: bool,
|
||||
}
|
||||
impl<'tcx> Visitor<'tcx> for V<'_, '_, 'tcx> {
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
if self.uses_iter {
|
||||
// return
|
||||
} else if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
|
||||
self.uses_iter = true;
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result {
|
||||
if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
|
||||
ControlFlow::Break(())
|
||||
} else if let (e, true) = skip_fields_and_path(e) {
|
||||
if let Some(e) = e {
|
||||
self.visit_expr(e);
|
||||
self.visit_expr(e)
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
} else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
|
||||
if is_res_used(self.cx, self.iter_expr.path, id) {
|
||||
self.uses_iter = true;
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
} else {
|
||||
walk_expr(self, e);
|
||||
walk_expr(self, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut v = V {
|
||||
cx,
|
||||
iter_expr,
|
||||
uses_iter: false,
|
||||
};
|
||||
v.visit_expr(container);
|
||||
v.uses_iter
|
||||
let mut v = V { cx, iter_expr };
|
||||
v.visit_expr(container).is_break()
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_lines)]
|
||||
|
|
@ -242,34 +241,38 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
|
|||
iter_expr: &'b IterExpr,
|
||||
loop_id: HirId,
|
||||
after_loop: bool,
|
||||
used_iter: bool,
|
||||
}
|
||||
impl<'tcx> Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
|
||||
type NestedFilter = OnlyBodies;
|
||||
type Result = ControlFlow<()>;
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.cx.tcx.hir()
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
if self.used_iter {
|
||||
return;
|
||||
}
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) -> Self::Result {
|
||||
if self.after_loop {
|
||||
if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
|
||||
self.used_iter = true;
|
||||
ControlFlow::Break(())
|
||||
} else if let (e, true) = skip_fields_and_path(e) {
|
||||
if let Some(e) = e {
|
||||
self.visit_expr(e);
|
||||
self.visit_expr(e)
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
} else if let ExprKind::Closure(&Closure { body: id, .. }) = e.kind {
|
||||
self.used_iter = is_res_used(self.cx, self.iter_expr.path, id);
|
||||
if is_res_used(self.cx, self.iter_expr.path, id) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
} else {
|
||||
walk_expr(self, e);
|
||||
walk_expr(self, e)
|
||||
}
|
||||
} else if self.loop_id == e.hir_id {
|
||||
self.after_loop = true;
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
walk_expr(self, e);
|
||||
walk_expr(self, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -347,9 +350,8 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
|
|||
iter_expr,
|
||||
loop_id: loop_expr.hir_id,
|
||||
after_loop: false,
|
||||
used_iter: false,
|
||||
};
|
||||
v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
|
||||
v.used_iter
|
||||
v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value)
|
||||
.is_break()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue