Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion clippy_lints/src/assertions_on_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
_ => return,
}
&& let Some((condition, _)) = find_assert_args(cx, e, macro_call.expn)
&& let Some((Constant::Bool(assert_val), const_src)) = ConstEvalCtxt::new(cx).eval_with_source(condition)
&& let Some((Constant::Bool(assert_val), const_src)) =
ConstEvalCtxt::new(cx).eval_with_source(condition, macro_call.span.ctxt())
&& let in_const_context = is_inside_always_const_context(cx.tcx, e.hir_id)
&& (const_src.is_local() || !in_const_context)
&& !(is_debug && as_bool_lit(condition) == Some(false))
Expand Down
8 changes: 2 additions & 6 deletions clippy_lints/src/enum_clike.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,8 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
if let Some(anon_const) = &var.disr_expr {
let def_id = cx.tcx.hir_body_owner_def_id(anon_const.body);
let mut ty = cx.tcx.type_of(def_id.to_def_id()).instantiate_identity();
let constant = cx
.tcx
.const_eval_poly(def_id.to_def_id())
.ok()
.map(|val| rustc_middle::mir::Const::from_value(val, ty));
if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx.tcx, c)) {
let constant = cx.tcx.const_eval_poly(def_id.to_def_id()).ok();
if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx.tcx, c, ty)) {
if let ty::Adt(adt, _) = ty.kind()
&& adt.is_enum()
{
Expand Down
21 changes: 11 additions & 10 deletions clippy_lints/src/floating_point_arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::declare_lint_pass;
use rustc_span::SyntaxContext;
use rustc_span::source_map::Spanned;
use std::f32::consts as f32_consts;
use std::f64::consts as f64_consts;
Expand Down Expand Up @@ -110,8 +111,8 @@ declare_lint_pass!(FloatingPointArithmetic => [

// Returns the specialized log method for a given base if base is constant
// and is one of 2, 10 and e
fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<&'static str> {
if let Some(value) = ConstEvalCtxt::new(cx).eval(base) {
fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>, ctxt: SyntaxContext) -> Option<&'static str> {
if let Some(value) = ConstEvalCtxt::new(cx).eval_local(base, ctxt) {
if F32(2.0) == value || F64(2.0) == value {
return Some("log2");
} else if F32(10.0) == value || F64(10.0) == value {
Expand Down Expand Up @@ -157,7 +158,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
}

fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
if let Some(method) = get_specialized_log_method(cx, &args[0]) {
if let Some(method) = get_specialized_log_method(cx, &args[0], expr.span.ctxt()) {
span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
Expand Down Expand Up @@ -205,7 +206,7 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
// ranges [-16777215, 16777216) for type f32 as whole number floats outside
// this range are lossy and ambiguous.
#[expect(clippy::cast_possible_truncation)]
fn get_integer_from_float_constant(value: &Constant<'_>) -> Option<i32> {
fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
match value {
F32(num) if num.fract() == 0.0 => {
if (-16_777_215.0..16_777_216.0).contains(num) {
Expand Down Expand Up @@ -517,8 +518,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
fn is_testing_positive(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool {
if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind {
match op {
BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, right) && eq_expr_value(cx, left, test),
BinOpKind::Lt | BinOpKind::Le => is_zero(cx, left) && eq_expr_value(cx, right, test),
BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, right, expr.span.ctxt()) && eq_expr_value(cx, left, test),
BinOpKind::Lt | BinOpKind::Le => is_zero(cx, left, expr.span.ctxt()) && eq_expr_value(cx, right, test),
_ => false,
}
} else {
Expand All @@ -530,8 +531,8 @@ fn is_testing_positive(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -
fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -> bool {
if let ExprKind::Binary(Spanned { node: op, .. }, left, right) = expr.kind {
match op {
BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, left) && eq_expr_value(cx, right, test),
BinOpKind::Lt | BinOpKind::Le => is_zero(cx, right) && eq_expr_value(cx, left, test),
BinOpKind::Gt | BinOpKind::Ge => is_zero(cx, left, expr.span.ctxt()) && eq_expr_value(cx, right, test),
BinOpKind::Lt | BinOpKind::Le => is_zero(cx, right, expr.span.ctxt()) && eq_expr_value(cx, left, test),
_ => false,
}
} else {
Expand All @@ -540,8 +541,8 @@ fn is_testing_negative(cx: &LateContext<'_>, expr: &Expr<'_>, test: &Expr<'_>) -
}

/// Returns true iff expr is some zero literal
fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
match ConstEvalCtxt::new(cx).eval_simple(expr) {
fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>, ctxt: SyntaxContext) -> bool {
match ConstEvalCtxt::new(cx).eval_local(expr, ctxt) {
Some(Int(i)) => i == 0,
Some(F32(f)) => f == 0.0,
Some(F64(f)) => f == 0.0,
Expand Down
12 changes: 8 additions & 4 deletions clippy_lints/src/if_not_else.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,14 @@ impl LateLintPass<'_> for IfNotElse {
),
// Don't lint on `… != 0`, as these are likely to be bit tests.
// For example, `if foo & 0x0F00 != 0 { … } else { … }` is already in the "proper" order.
ExprKind::Binary(op, _, rhs) if op.node == BinOpKind::Ne && !is_zero_integer_const(cx, rhs) => (
"unnecessary `!=` operation",
"change to `==` and swap the blocks of the `if`/`else`",
),
ExprKind::Binary(op, _, rhs)
if op.node == BinOpKind::Ne && !is_zero_integer_const(cx, rhs, e.span.ctxt()) =>
{
(
"unnecessary `!=` operation",
"change to `==` and swap the blocks of the `if`/`else`",
)
},
_ => return,
};

Expand Down
5 changes: 3 additions & 2 deletions clippy_lints/src/implicit_saturating_add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,11 @@ fn get_int_max(ty: Ty<'_>) -> Option<u128> {
fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, BinOpKind, &'tcx Expr<'tcx>)> {
if let ExprKind::Binary(op, l, r) = expr.kind {
let ecx = ConstEvalCtxt::new(cx);
if let Some(Constant::Int(c)) = ecx.eval(r) {
let ctxt = expr.span.ctxt();
if let Some(Constant::Int(c)) = ecx.eval_local(r, ctxt) {
return Some((c, op.node, l));
}
if let Some(Constant::Int(c)) = ecx.eval(l) {
if let Some(Constant::Int(c)) = ecx.eval_local(l, ctxt) {
return Some((c, invert_op(op.node)?, r));
}
}
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/invalid_upcast_comparisons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ fn upcast_comparison_bounds_err<'tcx>(
invert: bool,
) {
if let Some((lb, ub)) = lhs_bounds
&& let Some(norm_rhs_val) = ConstEvalCtxt::new(cx).eval_full_int(rhs)
&& let Some(norm_rhs_val) = ConstEvalCtxt::new(cx).eval_full_int(rhs, span.ctxt())
{
if rel == Rel::Eq || rel == Rel::Ne {
if norm_rhs_val < lb || norm_rhs_val > ub {
Expand Down
29 changes: 6 additions & 23 deletions clippy_lints/src/manual_float_methods.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use clippy_config::Conf;
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::consts::ConstEvalCtxt;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::SpanRangeExt;
Expand Down Expand Up @@ -146,13 +146,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
)
&& let [first, second, const_1, const_2] = exprs
&& let ecx = ConstEvalCtxt::new(cx)
&& let Some(const_1) = ecx.eval(const_1)
&& let Some(const_2) = ecx.eval(const_2)
&& let ctxt = expr.span.ctxt()
&& let Some(const_1) = ecx.eval_local(const_1, ctxt)
&& let Some(const_2) = ecx.eval_local(const_2, ctxt)
&& path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
// The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
// case somebody does that for some reason
&& (is_infinity(&const_1) && is_neg_infinity(&const_2)
|| is_neg_infinity(&const_1) && is_infinity(&const_2))
&& (const_1.is_pos_infinity() && const_2.is_neg_infinity()
|| const_1.is_neg_infinity() && const_2.is_pos_infinity())
&& let Some(local_snippet) = first.span.get_source_text(cx)
{
let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
Expand Down Expand Up @@ -201,21 +202,3 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
}
}
}

fn is_infinity(constant: &Constant<'_>) -> bool {
match constant {
// FIXME(f16_f128): add f16 and f128 when constants are available
Constant::F32(float) => *float == f32::INFINITY,
Constant::F64(float) => *float == f64::INFINITY,
_ => false,
}
}

fn is_neg_infinity(constant: &Constant<'_>) -> bool {
match constant {
// FIXME(f16_f128): add f16 and f128 when constants are available
Constant::F32(float) => *float == f32::NEG_INFINITY,
Constant::F64(float) => *float == f64::NEG_INFINITY,
_ => false,
}
}
20 changes: 13 additions & 7 deletions clippy_lints/src/manual_rem_euclid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::impl_lint_pass;
use rustc_span::SyntaxContext;

declare_clippy_lint! {
/// ### What it does
Expand Down Expand Up @@ -58,13 +59,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
&& add_lhs.span.ctxt() == ctxt
&& add_rhs.span.ctxt() == ctxt
&& !expr.span.in_external_macro(cx.sess().source_map())
&& let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs)
&& let Some((const2, add_other)) = check_for_either_unsigned_int_constant(cx, add_lhs, add_rhs)
&& let Some(const1) = check_for_unsigned_int_constant(cx, ctxt, rem_rhs)
&& let Some((const2, add_other)) = check_for_either_unsigned_int_constant(cx, ctxt, add_lhs, add_rhs)
&& let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind
&& rem2_op.node == BinOpKind::Rem
&& const1 == const2
&& let Some(hir_id) = path_to_local(rem2_lhs)
&& let Some(const3) = check_for_unsigned_int_constant(cx, rem2_rhs)
&& let Some(const3) = check_for_unsigned_int_constant(cx, ctxt, rem2_rhs)
// Also ensures the const is nonzero since zero can't be a divisor
&& const2 == const3
&& rem2_lhs.span.ctxt() == ctxt
Expand Down Expand Up @@ -103,16 +104,21 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
// constant along with the other expression unchanged if so
fn check_for_either_unsigned_int_constant<'a>(
cx: &'a LateContext<'_>,
ctxt: SyntaxContext,
left: &'a Expr<'_>,
right: &'a Expr<'_>,
) -> Option<(u128, &'a Expr<'a>)> {
check_for_unsigned_int_constant(cx, left)
check_for_unsigned_int_constant(cx, ctxt, left)
.map(|int_const| (int_const, right))
.or_else(|| check_for_unsigned_int_constant(cx, right).map(|int_const| (int_const, left)))
.or_else(|| check_for_unsigned_int_constant(cx, ctxt, right).map(|int_const| (int_const, left)))
}

fn check_for_unsigned_int_constant<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<u128> {
let int_const = ConstEvalCtxt::new(cx).eval_full_int(expr)?;
fn check_for_unsigned_int_constant<'a>(
cx: &'a LateContext<'_>,
ctxt: SyntaxContext,
expr: &'a Expr<'_>,
) -> Option<u128> {
let int_const = ConstEvalCtxt::new(cx).eval_full_int(expr, ctxt)?;
match int_const {
FullInt::S(s) => s.try_into().ok(),
FullInt::U(u) => Some(u),
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/manual_rotate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn parse_shift<'tcx>(
BinOpKind::Shr => ShiftDirection::Right,
_ => return None,
};
let const_expr = ConstEvalCtxt::new(cx).eval(r)?;
let const_expr = ConstEvalCtxt::new(cx).eval_local(r, expr.span.ctxt())?;
if let Constant::Int(shift) = const_expr {
return Some((dir, shift, l));
}
Expand Down
24 changes: 16 additions & 8 deletions clippy_lints/src/manual_strip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext as _};
use rustc_middle::ty;
use rustc_session::impl_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::{Symbol, sym};
use rustc_span::{Symbol, SyntaxContext, sym};
use std::iter;

declare_clippy_lint! {
Expand Down Expand Up @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
return;
}

let (strippings, bindings) = find_stripping(cx, strip_kind, target_res, pattern, then);
let (strippings, bindings) = find_stripping(cx, strip_kind, target_res, pattern, then, expr.span.ctxt());
if !strippings.is_empty() && self.msrv.meets(cx, msrvs::STR_STRIP_PREFIX) {
let kind_word = match strip_kind {
StripKind::Prefix => "prefix",
Expand Down Expand Up @@ -166,8 +166,8 @@ fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx E
}

// Returns the length of the `expr` if it's a constant string or char.
fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
let value = ConstEvalCtxt::new(cx).eval(expr)?;
fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>, ctxt: SyntaxContext) -> Option<u128> {
let value = ConstEvalCtxt::new(cx).eval_local(expr, ctxt)?;
match value {
Constant::Str(value) => Some(value.len() as u128),
Constant::Char(value) => Some(value.len_utf8() as u128),
Expand All @@ -176,13 +176,18 @@ fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
}

// Tests if `expr` equals the length of the pattern.
fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
fn eq_pattern_length<'tcx>(
cx: &LateContext<'tcx>,
pattern: &Expr<'_>,
expr: &'tcx Expr<'_>,
ctxt: SyntaxContext,
) -> bool {
if let ExprKind::Lit(Spanned {
node: LitKind::Int(n, _),
..
}) = expr.kind
{
constant_length(cx, pattern).is_some_and(|length| n == length)
constant_length(cx, pattern, ctxt).is_some_and(|length| n == length)
} else {
len_arg(cx, expr).is_some_and(|arg| eq_expr_value(cx, pattern, arg))
}
Expand Down Expand Up @@ -215,6 +220,7 @@ fn find_stripping<'tcx>(
target: Res,
pattern: &'tcx Expr<'_>,
expr: &'tcx Expr<'tcx>,
ctxt: SyntaxContext,
) -> (Vec<&'tcx Expr<'tcx>>, FxHashMap<Symbol, usize>) {
struct StrippingFinder<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
Expand All @@ -223,6 +229,7 @@ fn find_stripping<'tcx>(
pattern: &'tcx Expr<'tcx>,
results: Vec<&'tcx Expr<'tcx>>,
bindings: FxHashMap<Symbol, usize>,
ctxt: SyntaxContext,
}

impl<'tcx> Visitor<'tcx> for StrippingFinder<'_, 'tcx> {
Expand All @@ -236,7 +243,7 @@ fn find_stripping<'tcx>(
{
match (self.strip_kind, start, end) {
(StripKind::Prefix, Some(start), None) => {
if eq_pattern_length(self.cx, self.pattern, start) {
if eq_pattern_length(self.cx, self.pattern, start, self.ctxt) {
self.results.push(ex);
return;
}
Expand All @@ -252,7 +259,7 @@ fn find_stripping<'tcx>(
&& let Some(left_arg) = len_arg(self.cx, left)
&& let ExprKind::Path(left_path) = &left_arg.kind
&& self.cx.qpath_res(left_path, left_arg.hir_id) == self.target
&& eq_pattern_length(self.cx, self.pattern, right)
&& eq_pattern_length(self.cx, self.pattern, right, self.ctxt)
{
self.results.push(ex);
return;
Expand Down Expand Up @@ -280,6 +287,7 @@ fn find_stripping<'tcx>(
pattern,
results: vec![],
bindings: FxHashMap::default(),
ctxt,
};
walk_expr(&mut finder, expr);
(finder.results, finder.bindings)
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/matches/manual_unwrap_or.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ fn handle(
&& cx.typeck_results().expr_adjustments(body_some).is_empty()
&& let Some(or_body_snippet) = peel_blocks(body_none).span.get_source_text(cx)
&& let Some(indent) = indent_of(cx, expr.span)
&& ConstEvalCtxt::new(cx).eval_simple(body_none).is_some()
&& ConstEvalCtxt::new(cx).eval_local(body_none, expr.span.ctxt()).is_some()
{
let reindented_or_body = reindent_multiline(&or_body_snippet, true, Some(indent));
let mut app = Applicability::MachineApplicable;
Expand Down
6 changes: 3 additions & 3 deletions clippy_lints/src/matches/overlapping_arms.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use clippy_utils::consts::{ConstEvalCtxt, FullInt, mir_to_const};
use clippy_utils::consts::{ConstEvalCtxt, Constant, FullInt};
use clippy_utils::diagnostics::span_lint_and_note;
use core::cmp::Ordering;
use rustc_hir::{Arm, Expr, PatKind, RangeEnd};
Expand Down Expand Up @@ -35,12 +35,12 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
let lhs_const = if let Some(lhs) = lhs {
ConstEvalCtxt::new(cx).eval_pat_expr(lhs)?
} else {
mir_to_const(cx.tcx, ty.numeric_min_val(cx.tcx)?)?
Constant::new_numeric_min(cx.tcx, ty)?
};
let rhs_const = if let Some(rhs) = rhs {
ConstEvalCtxt::new(cx).eval_pat_expr(rhs)?
} else {
mir_to_const(cx.tcx, ty.numeric_max_val(cx.tcx)?)?
Constant::new_numeric_max(cx.tcx, ty)?
};
let lhs_val = lhs_const.int_value(cx.tcx, ty)?;
let rhs_val = rhs_const.int_value(cx.tcx, ty)?;
Expand Down
4 changes: 3 additions & 1 deletion clippy_lints/src/methods/ip_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args
cx.tcx.get_diagnostic_name(func_def_id),
Some(sym::Ipv4Addr | sym::Ipv6Addr)
)
&& let ecx = ConstEvalCtxt::new(cx)
&& let ctxt = expr.span.ctxt()
&& let Some(args) = args
.iter()
.map(|arg| {
if let Some(Constant::Int(constant @ (0 | 1 | 127 | 255))) = ConstEvalCtxt::new(cx).eval(arg) {
if let Some(Constant::Int(constant @ (0 | 1 | 127 | 255))) = ecx.eval_local(arg, ctxt) {
u8::try_from(constant).ok()
} else {
None
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/is_digit_ascii_radix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
return;
}

if let Some(radix_val) = ConstEvalCtxt::new(cx).eval_full_int(radix) {
if let Some(radix_val) = ConstEvalCtxt::new(cx).eval_full_int(radix, expr.span.ctxt()) {
let (num, replacement) = match radix_val {
FullInt::S(10) | FullInt::U(10) => (10, "is_ascii_digit"),
FullInt::S(16) | FullInt::U(16) => (16, "is_ascii_hexdigit"),
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/iter_nth_zero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
if let OwnerNode::Item(item) = cx.tcx.hir_owner_node(cx.tcx.hir_get_parent_item(expr.hir_id))
&& let def_id = item.owner_id.to_def_id()
&& is_trait_method(cx, expr, sym::Iterator)
&& let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg)
&& let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval_local(arg, expr.span.ctxt())
&& !is_lang_item_or_ctor(cx, def_id, LangItem::IteratorNext)
{
let mut app = Applicability::MachineApplicable;
Expand Down
Loading