Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
commit
cc63143bbf
213 changed files with 3146 additions and 1693 deletions
|
|
@ -412,7 +412,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||
/// Simple constant folding: Insert an expression, get a constant or none.
|
||||
pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
||||
match e.kind {
|
||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr(e),
|
||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value),
|
||||
ExprKind::DropTemps(e) => self.expr(e),
|
||||
ExprKind::Path(ref qpath) => {
|
||||
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
|
||||
let result = mir_to_const(this.lcx, result)?;
|
||||
|
|
@ -490,7 +491,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||
/// leaves the local crate.
|
||||
pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
|
||||
match e.kind {
|
||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr_is_empty(e),
|
||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value),
|
||||
ExprKind::DropTemps(e) => self.expr_is_empty(e),
|
||||
ExprKind::Path(ref qpath) => {
|
||||
if !self
|
||||
.typeck_results
|
||||
|
|
@ -811,12 +813,8 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
|
|||
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
||||
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
|
||||
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.to_bits(int.size()))),
|
||||
ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
|
||||
int.try_into().expect("invalid f32 bit representation"),
|
||||
))),
|
||||
ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(
|
||||
int.try_into().expect("invalid f64 bit representation"),
|
||||
))),
|
||||
ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(int.into()))),
|
||||
ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(int.into()))),
|
||||
ty::RawPtr(_, _) => Some(Constant::RawPtr(int.to_bits(int.size()))),
|
||||
_ => None,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ use rustc_data_structures::fx::FxHasher;
|
|||
use rustc_hir::def::Res;
|
||||
use rustc_hir::MatchSource::TryDesugar;
|
||||
use rustc_hir::{
|
||||
ArrayLen, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
|
||||
GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, PatKind, Path,
|
||||
PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind, AssocItemConstraint,
|
||||
ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy,
|
||||
GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField,
|
||||
PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind,
|
||||
};
|
||||
use rustc_lexer::{tokenize, TokenKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
@ -519,7 +519,11 @@ impl HirEqInterExpr<'_, '_, '_> {
|
|||
}
|
||||
|
||||
fn eq_assoc_type_binding(&mut self, left: &AssocItemConstraint<'_>, right: &AssocItemConstraint<'_>) -> bool {
|
||||
left.ident.name == right.ident.name && self.eq_ty(left.ty().expect("expected assoc type binding"), right.ty().expect("expected assoc type binding"))
|
||||
left.ident.name == right.ident.name
|
||||
&& self.eq_ty(
|
||||
left.ty().expect("expected assoc type binding"),
|
||||
right.ty().expect("expected assoc type binding"),
|
||||
)
|
||||
}
|
||||
|
||||
fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool {
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ use visitors::Visitable;
|
|||
use crate::consts::{constant, mir_to_const, Constant};
|
||||
use crate::higher::Range;
|
||||
use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
|
||||
use crate::visitors::for_each_expr;
|
||||
use crate::visitors::for_each_expr_without_closures;
|
||||
|
||||
use rustc_middle::hir::nested_filter;
|
||||
|
||||
|
|
@ -321,6 +321,15 @@ pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str])
|
|||
.map_or(false, |trt_id| match_def_path(cx, trt_id, path))
|
||||
}
|
||||
|
||||
/// Checks if the given method call expression calls an inherent method.
|
||||
pub fn is_inherent_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
|
||||
cx.tcx.trait_of_item(method_id).is_none()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if a method is defined in an impl of a diagnostic item
|
||||
pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
|
||||
if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
|
||||
|
|
@ -1313,7 +1322,7 @@ pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<
|
|||
|
||||
/// Returns `true` if `expr` contains a return expression
|
||||
pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool {
|
||||
for_each_expr(expr, |e| {
|
||||
for_each_expr_without_closures(expr, |e| {
|
||||
if matches!(e.kind, ExprKind::Ret(..)) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
|
|
@ -3392,3 +3401,14 @@ pub fn binary_expr_needs_parentheses(expr: &Expr<'_>) -> bool {
|
|||
|
||||
contains_block(expr, false)
|
||||
}
|
||||
|
||||
/// Returns true if the specified expression is in a receiver position.
|
||||
pub fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
if let Some(parent_expr) = get_parent_expr(cx, expr)
|
||||
&& let ExprKind::MethodCall(_, receiver, ..) = parent_expr.kind
|
||||
&& receiver.hir_id == expr.hir_id
|
||||
{
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(clippy::similar_names)] // `expr` and `expn`
|
||||
|
||||
use crate::visitors::{for_each_expr, Descend};
|
||||
use crate::visitors::{for_each_expr_without_closures, Descend};
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder};
|
||||
|
|
@ -323,7 +323,7 @@ fn find_assert_args_inner<'a, const N: usize>(
|
|||
Some(inner_name) => find_assert_within_debug_assert(cx, expr, expn, Symbol::intern(inner_name))?,
|
||||
};
|
||||
let mut args = ArrayVec::new();
|
||||
let panic_expn = for_each_expr(expr, |e| {
|
||||
let panic_expn = for_each_expr_without_closures(expr, |e| {
|
||||
if args.is_full() {
|
||||
match PanicExpn::parse(e) {
|
||||
Some(expn) => ControlFlow::Break(expn),
|
||||
|
|
@ -349,7 +349,7 @@ fn find_assert_within_debug_assert<'a>(
|
|||
expn: ExpnId,
|
||||
assert_name: Symbol,
|
||||
) -> Option<(&'a Expr<'a>, ExpnId)> {
|
||||
for_each_expr(expr, |e| {
|
||||
for_each_expr_without_closures(expr, |e| {
|
||||
if !e.span.from_expansion() {
|
||||
return ControlFlow::Continue(Descend::No);
|
||||
}
|
||||
|
|
@ -397,7 +397,7 @@ impl FormatArgsStorage {
|
|||
///
|
||||
/// See also [`find_format_arg_expr`]
|
||||
pub fn get(&self, cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<&FormatArgs> {
|
||||
let format_args_expr = for_each_expr(start, |expr| {
|
||||
let format_args_expr = for_each_expr_without_closures(start, |expr| {
|
||||
let ctxt = expr.span.ctxt();
|
||||
if ctxt.outer_expn().is_descendant_of(expn_id) {
|
||||
if macro_backtrace(expr.span)
|
||||
|
|
@ -439,7 +439,7 @@ pub fn find_format_arg_expr<'hir, 'ast>(
|
|||
parent: _,
|
||||
} = target.expr.span.data();
|
||||
|
||||
for_each_expr(start, |expr| {
|
||||
for_each_expr_without_closures(start, |expr| {
|
||||
// When incremental compilation is enabled spans gain a parent during AST to HIR lowering,
|
||||
// since we're comparing an AST span to a HIR one we need to ignore the parent field
|
||||
let data = expr.span.data();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::source::snippet;
|
||||
use crate::visitors::{for_each_expr, Descend};
|
||||
use crate::visitors::{for_each_expr_without_closures, Descend};
|
||||
use crate::{path_to_local_id, strip_pat_refs};
|
||||
use core::ops::ControlFlow;
|
||||
use rustc_hir::{Body, BodyId, ExprKind, HirId, PatKind};
|
||||
|
|
@ -31,7 +31,7 @@ fn extract_clone_suggestions<'tcx>(
|
|||
body: &'tcx Body<'_>,
|
||||
) -> Option<Vec<(Span, Cow<'static, str>)>> {
|
||||
let mut spans = Vec::new();
|
||||
for_each_expr(body, |e| {
|
||||
for_each_expr_without_closures(body, |e| {
|
||||
if let ExprKind::MethodCall(seg, recv, [], _) = e.kind
|
||||
&& path_to_local_id(recv, id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,9 +40,13 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
|
|||
)?;
|
||||
|
||||
for bb in &*body.basic_blocks {
|
||||
check_terminator(tcx, body, bb.terminator(), msrv)?;
|
||||
for stmt in &bb.statements {
|
||||
check_statement(tcx, body, def_id, stmt, msrv)?;
|
||||
// Cleanup blocks are ignored entirely by const eval, so we can too:
|
||||
// https://github.com/rust-lang/rust/blob/1dea922ea6e74f99a0e97de5cdb8174e4dea0444/compiler/rustc_const_eval/src/transform/check_consts/check.rs#L382
|
||||
if !bb.is_cleanup {
|
||||
check_terminator(tcx, body, bb.terminator(), msrv)?;
|
||||
for stmt in &bb.statements {
|
||||
check_statement(tcx, body, def_id, stmt, msrv)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
|
||||
use rustc_ast::{LitKind, StrStyle};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::{original_sp, SourceMap};
|
||||
use rustc_span::{hygiene, BytePos, SourceFileAndLine, Pos, SourceFile, Span, SpanData, SyntaxContext, DUMMY_SP};
|
||||
use rustc_span::{hygiene, BytePos, Pos, SourceFile, SourceFileAndLine, Span, SpanData, SyntaxContext, DUMMY_SP};
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Range;
|
||||
|
||||
|
|
@ -500,6 +501,50 @@ pub fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span {
|
|||
extended.with_lo(extended.lo() - BytePos(1))
|
||||
}
|
||||
|
||||
/// Converts `expr` to a `char` literal if it's a `str` literal containing a single
|
||||
/// character (or a single byte with `ascii_only`)
|
||||
pub fn str_literal_to_char_literal(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
applicability: &mut Applicability,
|
||||
ascii_only: bool,
|
||||
) -> Option<String> {
|
||||
if let ExprKind::Lit(lit) = &expr.kind
|
||||
&& let LitKind::Str(r, style) = lit.node
|
||||
&& let string = r.as_str()
|
||||
&& let len = if ascii_only {
|
||||
string.len()
|
||||
} else {
|
||||
string.chars().count()
|
||||
}
|
||||
&& len == 1
|
||||
{
|
||||
let snip = snippet_with_applicability(cx, expr.span, string, applicability);
|
||||
let ch = if let StrStyle::Raw(nhash) = style {
|
||||
let nhash = nhash as usize;
|
||||
// for raw string: r##"a"##
|
||||
&snip[(nhash + 2)..(snip.len() - 1 - nhash)]
|
||||
} else {
|
||||
// for regular string: "a"
|
||||
&snip[1..(snip.len() - 1)]
|
||||
};
|
||||
|
||||
let hint = format!(
|
||||
"'{}'",
|
||||
match ch {
|
||||
"'" => "\\'",
|
||||
r"\" => "\\\\",
|
||||
"\\\"" => "\"", // no need to escape `"` in `'"'`
|
||||
_ => ch,
|
||||
}
|
||||
);
|
||||
|
||||
Some(hint)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{reindent_multiline, without_block_comments};
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ use rustc_middle::mir::ConstValue;
|
|||
use rustc_middle::traits::EvaluationResult;
|
||||
use rustc_middle::ty::layout::ValidityRequirement;
|
||||
use rustc_middle::ty::{
|
||||
self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
|
||||
GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
|
||||
self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind,
|
||||
GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
|
||||
};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
|
||||
|
|
@ -861,7 +861,6 @@ impl core::ops::Add<u32> for EnumValue {
|
|||
}
|
||||
|
||||
/// Attempts to read the given constant as though it were an enum value.
|
||||
#[expect(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
|
||||
pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> {
|
||||
if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) {
|
||||
match tcx.type_of(id).instantiate_identity().kind() {
|
||||
|
|
@ -1314,3 +1313,39 @@ pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>
|
|||
pub fn is_manually_drop(ty: Ty<'_>) -> bool {
|
||||
ty.ty_adt_def().map_or(false, AdtDef::is_manually_drop)
|
||||
}
|
||||
|
||||
/// Returns the deref chain of a type, starting with the type itself.
|
||||
pub fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'cx {
|
||||
iter::successors(Some(ty), |&ty| {
|
||||
if let Some(deref_did) = cx.tcx.lang_items().deref_trait()
|
||||
&& implements_trait(cx, ty, deref_did, &[])
|
||||
{
|
||||
make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if a Ty<'_> has some inherent method Symbol.
|
||||
/// This does not look for impls in the type's `Deref::Target` type.
|
||||
/// If you need this, you should wrap this call in `clippy_utils::ty::deref_chain().any(...)`.
|
||||
pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> Option<&'a AssocItem> {
|
||||
if let Some(ty_did) = ty.ty_adt_def().map(AdtDef::did) {
|
||||
cx.tcx
|
||||
.inherent_impls(ty_did)
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.map(|&did| {
|
||||
cx.tcx
|
||||
.associated_items(did)
|
||||
.filter_by_name_unhygienic(method_name)
|
||||
.next()
|
||||
.filter(|item| item.kind == AssocKind::Fn)
|
||||
})
|
||||
.next()
|
||||
.flatten()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,8 +206,18 @@ fn path_segment_certainty(
|
|||
// Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE.
|
||||
if cx.tcx.res_generics_def_id(path_segment.res).is_some() {
|
||||
let generics = cx.tcx.generics_of(def_id);
|
||||
let count = generics.own_params.len() - usize::from(generics.host_effect_index.is_some());
|
||||
let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && count == 0 {
|
||||
|
||||
let own_count = generics.own_params.len()
|
||||
- usize::from(generics.host_effect_index.is_some_and(|index| {
|
||||
// Check that the host index actually belongs to this resolution.
|
||||
// E.g. for `Add::add`, host_effect_index is `Some(2)`, but it's part of the parent `Add`
|
||||
// trait's generics.
|
||||
// Add params: [Self#0, Rhs#1, host#2] parent_count=0, count=3
|
||||
// Add::add params: [] parent_count=3, count=3
|
||||
// (3..3).contains(&host_effect_index) => false
|
||||
(generics.parent_count..generics.count()).contains(&index)
|
||||
}));
|
||||
let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && own_count == 0 {
|
||||
Certainty::Certain(None)
|
||||
} else {
|
||||
Certainty::Uncertain
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend, Visitable};
|
||||
use crate::visitors::{for_each_expr, for_each_expr_without_closures, Descend, Visitable};
|
||||
use crate::{self as utils, get_enclosing_loop_or_multi_call_closure};
|
||||
use core::ops::ControlFlow;
|
||||
use hir::def::Res;
|
||||
|
|
@ -145,7 +145,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
|
||||
for_each_expr(expression, |e| {
|
||||
for_each_expr_without_closures(expression, |e| {
|
||||
match e.kind {
|
||||
ExprKind::Ret(..) | ExprKind::Break(..) | ExprKind::Continue(..) => ControlFlow::Break(()),
|
||||
// Something special could be done here to handle while or for loop
|
||||
|
|
@ -159,7 +159,7 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
|
|||
}
|
||||
|
||||
pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool {
|
||||
for_each_expr_with_closures(cx, v, |e| {
|
||||
for_each_expr(cx, v, |e| {
|
||||
if utils::path_to_local_id(e, local_id) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
|
|
@ -184,7 +184,7 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr
|
|||
let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id);
|
||||
|
||||
let mut past_expr = false;
|
||||
for_each_expr_with_closures(cx, block, |e| {
|
||||
for_each_expr(cx, block, |e| {
|
||||
if past_expr {
|
||||
if utils::path_to_local_id(e, local_id) {
|
||||
ControlFlow::Break(())
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ visitable_ref!(Stmt, visit_stmt);
|
|||
|
||||
/// Calls the given function once for each expression contained. This does not enter any bodies or
|
||||
/// nested items.
|
||||
pub fn for_each_expr<'tcx, B, C: Continue>(
|
||||
pub fn for_each_expr_without_closures<'tcx, B, C: Continue>(
|
||||
node: impl Visitable<'tcx>,
|
||||
f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>,
|
||||
) -> Option<B> {
|
||||
|
|
@ -134,7 +134,7 @@ pub fn for_each_expr<'tcx, B, C: Continue>(
|
|||
|
||||
/// Calls the given function once for each expression contained. This will enter bodies, but not
|
||||
/// nested items.
|
||||
pub fn for_each_expr_with_closures<'tcx, B, C: Continue>(
|
||||
pub fn for_each_expr<'tcx, B, C: Continue>(
|
||||
cx: &LateContext<'tcx>,
|
||||
node: impl Visitable<'tcx>,
|
||||
f: impl FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>,
|
||||
|
|
@ -181,7 +181,7 @@ pub fn for_each_expr_with_closures<'tcx, B, C: Continue>(
|
|||
|
||||
/// returns `true` if expr contains match expr desugared from try
|
||||
fn contains_try(expr: &Expr<'_>) -> bool {
|
||||
for_each_expr(expr, |e| {
|
||||
for_each_expr_without_closures(expr, |e| {
|
||||
if matches!(e.kind, ExprKind::Match(_, _, hir::MatchSource::TryDesugar(_))) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
|
|
@ -286,7 +286,7 @@ where
|
|||
|
||||
/// Checks if the given resolved path is used in the given body.
|
||||
pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
|
||||
for_each_expr_with_closures(cx, cx.tcx.hir().body(body).value, |e| {
|
||||
for_each_expr(cx, cx.tcx.hir().body(body).value, |e| {
|
||||
if let ExprKind::Path(p) = &e.kind {
|
||||
if cx.qpath_res(p, e.hir_id) == res {
|
||||
return ControlFlow::Break(());
|
||||
|
|
@ -299,7 +299,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
|
|||
|
||||
/// Checks if the given local is used.
|
||||
pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool {
|
||||
for_each_expr_with_closures(cx, visitable, |e| {
|
||||
for_each_expr(cx, visitable, |e| {
|
||||
if path_to_local_id(e, id) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
|
|
@ -757,7 +757,7 @@ pub fn for_each_local_assignment<'tcx, B>(
|
|||
}
|
||||
|
||||
pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool {
|
||||
for_each_expr(expr, |e| {
|
||||
for_each_expr_without_closures(expr, |e| {
|
||||
if matches!(e.kind, ExprKind::Break(..) | ExprKind::Continue(..)) {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
|
|
@ -776,7 +776,7 @@ pub fn local_used_once<'tcx>(
|
|||
) -> Option<&'tcx Expr<'tcx>> {
|
||||
let mut expr = None;
|
||||
|
||||
let cf = for_each_expr_with_closures(cx, visitable, |e| {
|
||||
let cf = for_each_expr(cx, visitable, |e| {
|
||||
if path_to_local_id(e, id) && expr.replace(e).is_some() {
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue