Skip to content
4 changes: 3 additions & 1 deletion clippy_lints/src/assertions_on_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
_ => return,
}
&& let Some((condition, _)) = find_assert_args(cx, e, macro_call.expn)
&& is_const_evaluatable(cx, condition)
// Check if the whole expression can be moved into a const context.
// Note that const eval can evaluate things which cannot be moved (e.g. `false && x`).
&& is_const_evaluatable(cx.tcx, cx.typeck_results(), 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)
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/casts/needless_type_cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ fn can_coerce_to_target_type(expr: &Expr<'_>) -> bool {
fn check_binding_usages<'a>(cx: &LateContext<'a>, body: &Body<'a>, hir_id: HirId, binding_info: &BindingInfo<'a>) {
let mut usages = Vec::new();

for_each_expr(cx, body.value, |expr| {
for_each_expr(cx.tcx, body.value, |expr| {
if let ExprKind::Path(ref qpath) = expr.kind
&& !expr.span.from_expansion()
&& let Res::Local(id) = cx.qpath_res(qpath, expr.hir_id)
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/cloned_ref_to_slice_refs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> {
&& let Some(adjustment) = is_needless_clone_or_equivalent(cx, recv, path.ident.name, item.hir_id)

// check for immutability or purity
&& (!is_mutable(cx, recv) || is_const_evaluatable(cx, recv))
&& (!is_mutable(cx, recv) || is_const_evaluatable(cx.tcx, cx.typeck_results(), recv))

// get appropriate crate for `slice::from_ref`
&& let Some(builtin_crate) = clippy_utils::std_or_core(cx)
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/collection_is_never_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
let mut has_read_access = false;

// Inspect all expressions and sub-expressions in the block.
for_each_expr(cx, block, |expr| {
for_each_expr(cx.tcx, block, |expr| {
// Ignore expressions that are not simply `id`.
if expr.res_local_id() != Some(id) {
return ControlFlow::Continue(());
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/doc/missing_headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ pub fn check(
fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option<Span> {
let mut panic_span = None;
let typeck = cx.tcx.typeck_body(body_id);
for_each_expr(cx, cx.tcx.hir_body(body_id), |expr| {
for_each_expr(cx.tcx, cx.tcx.hir_body(body_id), |expr| {
if is_inside_always_const_context(cx.tcx, expr.hir_id) {
return ControlFlow::<!>::Continue(());
}
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ fn is_any_expr_in_map_used<'tcx>(
map: &'tcx Expr<'tcx>,
expr: &'tcx Expr<'tcx>,
) -> bool {
for_each_expr(cx, map, |e| {
for_each_expr(cx.tcx, map, |e| {
if spanless_eq.eq_expr(ctxt, e, expr) {
return ControlFlow::Break(());
}
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fn check_raw_ptr<'tcx>(

if !raw_ptrs.is_empty() {
let typeck = cx.tcx.typeck_body(body.id());
let _: Option<!> = for_each_expr(cx, body.value, |e| {
let _: Option<!> = for_each_expr(cx.tcx, body.value, |e| {
match e.kind {
hir::ExprKind::Call(f, args) if is_unsafe_fn(cx, typeck.expr_ty(f)) => {
for arg in args {
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/loops/char_indices_as_byte_indices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr
&& let PatKind::Binding(_, binding_id, ..) = pat.kind
{
// Destructured iterator element `(idx, _)`, look for uses of the binding
for_each_expr(cx, body, |expr| {
for_each_expr(cx.tcx, body, |expr| {
if expr.res_local_id() == Some(binding_id) {
check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv);
}
CONTINUE
});
} else if let PatKind::Binding(_, binding_id, ..) = pat.kind {
// Bound as a tuple, look for `tup.0`
for_each_expr(cx, body, |expr| {
for_each_expr(cx.tcx, body, |expr| {
if let ExprKind::Field(e, field) = expr.kind
&& e.res_local_id() == Some(binding_id)
&& field.name == sym::integer(0)
Expand Down
8 changes: 6 additions & 2 deletions clippy_lints/src/manual_clamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,12 +367,16 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
&& let Some(inner_seg) = segment(cx, inner_fn)
&& let Some(outer_seg) = segment(cx, outer_fn)
{
let (input, inner_arg) = match (is_const_evaluatable(cx, first), is_const_evaluatable(cx, second)) {
let typeck = cx.typeck_results();
let (input, inner_arg) = match (
is_const_evaluatable(cx.tcx, typeck, first),
is_const_evaluatable(cx.tcx, typeck, second),
) {
(true, false) => (second, first),
(false, true) => (first, second),
_ => return None,
};
let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point();
let is_float = typeck.expr_ty_adjusted(input).is_floating_point();
let (min, max) = match (inner_seg, outer_seg) {
(FunctionType::CmpMin, FunctionType::CmpMax) => (outer_arg, inner_arg),
(FunctionType::CmpMax, FunctionType::CmpMin) => (inner_arg, outer_arg),
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/chunks_exact_to_as_chunks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(
return;
}

if is_const_evaluatable(cx, arg) {
if is_const_evaluatable(cx.tcx, cx.typeck_results(), arg) {
if !msrv.meets(cx, msrvs::AS_CHUNKS) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/expect_fun_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Ex
}

fn contains_call<'a>(cx: &LateContext<'a>, arg: &'a hir::Expr<'a>) -> bool {
for_each_expr(cx, arg, |expr| {
for_each_expr(cx.tcx, arg, |expr| {
if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. })
&& !is_inside_always_const_context(cx.tcx, expr.hir_id)
{
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/manual_inspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
let can_lint = for_each_expr_without_closures(block.stmts, |e| {
if let ExprKind::Closure(c) = e.kind {
// Nested closures don't need to treat returns specially.
let _: Option<!> = for_each_expr(cx, cx.tcx.hir_body(c.body).value, |e| {
let _: Option<!> = for_each_expr(cx.tcx, cx.tcx.hir_body(c.body).value, |e| {
if e.res_local_id() == Some(arg_id) {
let (kind, same_ctxt) = check_use(cx, ctxt, e);
match (kind, same_ctxt && e.span.ctxt() == ctxt) {
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/methods/or_fun_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub(super) fn check<'tcx>(
) {
if let [arg] = args {
let inner_arg = peel_blocks(arg);
for_each_expr(cx, inner_arg, |ex| {
for_each_expr(cx.tcx, inner_arg, |ex| {
// `or_fun_call` lint needs to take nested expr into account,
// but `unwrap_or_default` lint doesn't, we don't want something like:
// `opt.unwrap_or(Foo { inner: String::default(), other: 1 })` to get replaced by
Expand Down Expand Up @@ -72,7 +72,7 @@ pub(super) fn check<'tcx>(
// `map_or` takes two arguments
if let [arg, lambda] = args {
let inner_arg = peel_blocks(arg);
for_each_expr(cx, inner_arg, |ex| {
for_each_expr(cx.tcx, inner_arg, |ex| {
let is_top_most_expr = ex.hir_id == inner_arg.hir_id;
match ex.kind {
hir::ExprKind::Call(fun, fun_args) => {
Expand Down
5 changes: 3 additions & 2 deletions clippy_lints/src/methods/str_split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ pub(super) fn check<'a>(
// basic ones: a `'\n'`, `"\n"`, and `"\r\n"`.
if let ExprKind::MethodCall(trim_method_name, trim_recv, [], trim_span) = split_recv.kind
&& trim_method_name.ident.name == sym::trim
&& cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str()
&& !is_const_evaluatable(cx, trim_recv)
&& let typeck = cx.typeck_results()
&& typeck.expr_ty_adjusted(trim_recv).peel_refs().is_str()
&& !is_const_evaluatable(cx.tcx, typeck, trim_recv)
&& let ExprKind::Lit(split_lit) = split_arg.kind
&& matches!(
split_lit.node,
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/methods/str_splitn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ fn indirect_usage<'tcx>(
}) = stmt.kind
{
let mut path_to_binding = None;
let _: Option<!> = for_each_expr(cx, init_expr, |e| {
let _: Option<!> = for_each_expr(cx.tcx, init_expr, |e| {
if e.res_local_id() == Some(binding) {
path_to_binding = Some(e);
}
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints/src/missing_fields_in_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ fn should_lint<'tcx>(
// Is there a call to `DebugStruct::debug_struct`? Do lint if there is.
let mut has_debug_struct = false;

for_each_expr(cx, block, |expr| {
for_each_expr(cx.tcx, block, |expr| {
if let ExprKind::MethodCall(path, recv, ..) = &expr.kind {
let recv_ty = typeck_results.expr_ty(recv).peel_refs();

Expand Down Expand Up @@ -166,7 +166,7 @@ fn check_struct<'tcx>(
let mut has_direct_field_access = false;
let mut field_accesses = FxHashSet::default();

for_each_expr(cx, block, |expr| {
for_each_expr(cx.tcx, block, |expr| {
if let ExprKind::Field(target, ident) = expr.kind
&& let target_ty = typeck_results.expr_ty_adjusted(target).peel_refs()
&& target_ty == self_ty
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/needless_late_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ declare_clippy_lint! {
declare_lint_pass!(NeedlessLateInit => [NEEDLESS_LATE_INIT]);

fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> bool {
for_each_expr(cx, stmt, |e| {
for_each_expr(cx.tcx, stmt, |e| {
if matches!(e.kind, ExprKind::Assign(..)) {
ControlFlow::Break(())
} else {
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/needless_pass_by_ref_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
// We retrieve all the closures declared in the function because they will not be found
// by `euv::Delegate`.
let mut closures: FxIndexSet<LocalDefId> = FxIndexSet::default();
for_each_expr(cx, body, |expr| {
for_each_expr(cx.tcx, body, |expr| {
if let ExprKind::Closure(closure) = expr.kind {
closures.insert(closure.def_id);
}
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/non_std_lazy_statics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ impl LazyInfo {

// visit body to collect `Lazy::new` calls
let mut new_fn_calls = FxIndexMap::default();
for_each_expr::<(), ()>(cx, body, |ex| {
for_each_expr::<(), ()>(cx.tcx, body, |ex| {
if let Some((fn_did, call_span)) = fn_def_id_and_span_from_body(cx, ex, body_id)
&& paths::ONCE_CELL_SYNC_LAZY_NEW.matches(cx, fn_did)
{
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/panic_in_result_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn {

fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) {
let mut panics = Vec::new();
let _: Option<!> = for_each_expr(cx, body.value, |e| {
let _: Option<!> = for_each_expr(cx.tcx, body.value, |e| {
let Some(macro_call) = root_macro_call_first_node(cx, e) else {
return ControlFlow::Continue(Descend::Yes);
};
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/redundant_test_prefix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ fn name_conflicts<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, fn_name: S

// Also check that within the body of the function there is also no function call
// with the same name (since it will result in recursion)
for_each_expr(cx, body, |expr| {
for_each_expr(cx.tcx, body, |expr| {
if let ExprKind::Path(qpath) = &expr.kind
&& let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id()
&& let Some(name) = tcx.opt_item_name(def_id)
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/returns/let_and_return.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub(super) fn check_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'_>)
}
}
fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
for_each_expr(cx, expr, |e| {
for_each_expr(cx.tcx, expr, |e| {
if let Some(def_id) = fn_def_id(cx, e)
&& cx
.tcx
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/set_contains_or_insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ fn find_insert_calls<'tcx>(
contains_expr: &OpExpr<'tcx>,
expr: &'tcx Expr<'_>,
) -> Option<OpExpr<'tcx>> {
for_each_expr(cx, expr, |e| {
for_each_expr(cx.tcx, expr, |e| {
if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym::insert)
&& SpanlessEq::new(cx).eq_expr(SyntaxContext::root(), contains_expr.receiver, insert_expr.receiver)
&& SpanlessEq::new(cx).eq_expr(SyntaxContext::root(), contains_expr.value, insert_expr.value)
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ pub fn is_local_used_except<'tcx>(
id: HirId,
except: Option<HirId>,
) -> bool {
for_each_expr(cx, visitable, |e| {
for_each_expr(cx.tcx, visitable, |e| {
if except.is_some_and(|it| it == e.hir_id) {
ControlFlow::Continue(Descend::No)
} else if e.res_local_id() == Some(id) {
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/string_patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<

// We want to retrieve all the comparisons done.
// They are ordered in a nested way and so we need to traverse the AST to collect them all.
if for_each_expr(cx, body.value, |sub_expr| -> ControlFlow<(), Descend> {
if for_each_expr(cx.tcx, body.value, |sub_expr| -> ControlFlow<(), Descend> {
match sub_expr.kind {
ExprKind::Binary(op, left, right) if op.node == BinOpKind::Eq => {
if left.res_local_id() == Some(binding)
Expand Down
2 changes: 1 addition & 1 deletion clippy_lints/src/undocumented_unsafe_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ fn expr_has_unnecessary_safety_comment<'tcx>(
}

// this should roughly be the reverse of `block_parents_have_safety_comment`
if for_each_expr(cx, expr, |expr| match expr.kind {
if for_each_expr(cx.tcx, expr, |expr| match expr.kind {
hir::ExprKind::Block(
Block {
rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
Expand Down
4 changes: 2 additions & 2 deletions clippy_lints_internal/src/repeated_is_diagnostic_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ fn extract_nested_is_diag_item<'tcx>(
cx: &LateContext<'tcx>,
cond: &'tcx Expr<'_>,
) -> Option<(Span, (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>))> {
for_each_expr(cx, cond, |cond_part| {
for_each_expr(cx.tcx, cond, |cond_part| {
if let Some(res) = extract_is_diag_item(cx, cond_part) {
ControlFlow::Break((cond_part.span, res))
} else {
Expand All @@ -554,7 +554,7 @@ fn extract_nested_is_diagnostic_item<'tcx>(
cx: &LateContext<'tcx>,
cond: &'tcx Expr<'_>,
) -> Option<(Span, (&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>))> {
for_each_expr(cx, cond, |cond_part| {
for_each_expr(cx.tcx, cond, |cond_part| {
if let Some(res) = extract_is_diagnostic_item(cx, cond_part) {
ControlFlow::Break((cond_part.span, res))
} else {
Expand Down
22 changes: 19 additions & 3 deletions clippy_utils/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,13 @@ impl Constant {
_ => false,
}
}

pub fn to_int(&self, tcx: TyCtxt<'_>, ty: IntTy) -> Option<i128> {
match *self {
Self::Int(x) => Some(sext(tcx, x, ty)),
_ => None,
}
}
}

/// Parses a `LitKind` to a `Constant`.
Expand Down Expand Up @@ -522,9 +529,9 @@ pub fn eval_int(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<FullInt> {
///
/// See the module level documentation for some context.
pub struct ConstEvalCtxt<'tcx> {
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
typeck: &'tcx TypeckResults<'tcx>,
pub tcx: TyCtxt<'tcx>,
pub typing_env: ty::TypingEnv<'tcx>,
pub typeck: &'tcx TypeckResults<'tcx>,
source: Cell<ConstantSource>,
ctxt: Cell<SyntaxContext>,
}
Expand Down Expand Up @@ -566,6 +573,15 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
self.expr(e)
}

/// Attempts to evaluate the expression and optionally dereference the result.
pub fn eval_deref(&self, e: &Expr<'_>, deref: bool) -> Option<Constant> {
match (self.eval(e), deref) {
(Some(c), false) => Some(c),
(Some(Constant::Ref(c)), true) => Some(*c),
_ => None,
}
}

/// Attempts to evaluate the expression without accessing other items.
///
/// The context argument is the context used to view the evaluated expression. e.g. when
Expand Down
Loading
Loading