1 use clippy_utils::diagnostics::span_lint_and_then;
2 use clippy_utils::source::snippet_with_macro_callsite;
3 use clippy_utils::visitors::for_each_value_source;
4 use core::ops::ControlFlow;
5 use rustc_errors::Applicability;
6 use rustc_hir::def::{DefKind, Res};
7 use rustc_hir::{Expr, ExprKind, PatKind, Stmt, StmtKind};
8 use rustc_lint::{LateContext, LintContext};
9 use rustc_middle::lint::in_external_macro;
10 use rustc_middle::ty::{self, Ty, TypeVisitable, TypeSuperVisitable, TypeVisitor};
12 use super::LET_UNIT_VALUE;
14 pub(super) fn check(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
15 if let StmtKind::Local(local) = stmt.kind
16 && let Some(init) = local.init
17 && !local.pat.span.from_expansion()
18 && !in_external_macro(cx.sess(), stmt.span)
19 && cx.typeck_results().pat_ty(local.pat).is_unit()
21 let needs_inferred = for_each_value_source(init, &mut |e| if needs_inferred_result_ty(cx, e) {
22 ControlFlow::Continue(())
24 ControlFlow::Break(())
28 if !matches!(local.pat.kind, PatKind::Wild) {
33 "this let-binding has unit value",
37 "use a wild (`_`) binding",
39 Applicability::MaybeIncorrect, // snippet
49 "this let-binding has unit value",
51 if let Some(expr) = &local.init {
52 let snip = snippet_with_macro_callsite(cx, expr.span, "()");
55 "omit the `let` binding",
57 Applicability::MachineApplicable, // snippet
66 fn needs_inferred_result_ty(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
67 let id = match e.kind {
70 kind: ExprKind::Path(ref path),
75 ) => match cx.qpath_res(path, *hir_id) {
76 Res::Def(DefKind::AssocFn | DefKind::Fn, id) => id,
79 ExprKind::MethodCall(..) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
85 let sig = cx.tcx.fn_sig(id).skip_binder();
86 if let ty::Param(output_ty) = *sig.output().kind() {
87 sig.inputs().iter().all(|&ty| !ty_contains_param(ty, output_ty.index))
93 fn ty_contains_param(ty: Ty<'_>, index: u32) -> bool {
95 impl<'tcx> TypeVisitor<'tcx> for Visitor {
97 fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
98 if let ty::Param(ty) = *ty.kind() {
99 if ty.index == self.0 {
102 ControlFlow::CONTINUE
105 ty.super_visit_with(self)
109 ty.visit_with(&mut Visitor(index)).is_break()