| use rustc_hir as hir; | |
| use rustc_lint_defs::{declare_lint, declare_lint_pass}; | |
| use crate::diagnostics::UnitBindingsDiag; | |
| use crate::{LateLintPass, LintContext}; | |
| declare_lint! { | |
| /// The `unit_bindings` lint detects cases where bindings are useless because they have | |
| /// the unit type `()` as their inferred type. The lint is suppressed if the user explicitly | |
| /// annotates the let binding with the unit type `()`, or if the let binding uses an underscore | |
| /// wildcard pattern, i.e. `let _ = expr`, or if the binding is produced from macro expansions. | |
| /// | |
| /// ### Example | |
| /// | |
| /// ```rust,compile_fail | |
| /// #![deny(unit_bindings)] | |
| /// | |
| /// fn foo() { | |
| /// println!("do work"); | |
| /// } | |
| /// | |
| /// pub fn main() { | |
| /// let x = foo(); // useless binding | |
| /// } | |
| /// ``` | |
| /// | |
| /// {{produces}} | |
| /// | |
| /// ### Explanation | |
| /// | |
| /// Creating a local binding with the unit type `()` does not do much and can be a sign of a | |
| /// user error, such as in this example: | |
| /// | |
| /// ```rust,no_run | |
| /// fn main() { | |
| /// let mut x = [1, 2, 3]; | |
| /// x[0] = 5; | |
| /// let y = x.sort(); // useless binding as `sort` returns `()` and not the sorted array. | |
| /// println!("{:?}", y); // prints "()" | |
| /// } | |
| /// ``` | |
| pub UNIT_BINDINGS, | |
| Allow, | |
| "binding is useless because it has the unit `()` type" | |
| } | |
| declare_lint_pass!(UnitBindings => [UNIT_BINDINGS]); | |
| impl<'tcx> LateLintPass<'tcx> for UnitBindings { | |
| fn check_local(&mut self, cx: &crate::LateContext<'tcx>, local: &'tcx hir::LetStmt<'tcx>) { | |
| // Suppress warning if user: | |
| // - explicitly ascribes a type to the pattern | |
| // - explicitly wrote `let pat = ();` | |
| // - explicitly wrote `let () = init;`. | |
| if !local.span.from_expansion() | |
| && let Some(tyck_results) = cx.typeck_results | |
| && let Some(init) = local.init | |
| && let init_ty = tyck_results.expr_ty(init) | |
| && let local_ty = tyck_results.node_type(local.hir_id) | |
| && init_ty == cx.tcx.types.unit | |
| && local_ty == cx.tcx.types.unit | |
| && local.ty.is_none() | |
| && !matches!(init.kind, hir::ExprKind::Tup([])) | |
| && !matches!(local.pat.kind, hir::PatKind::Tuple([], ..)) | |
| { | |
| cx.emit_span_lint( | |
| UNIT_BINDINGS, | |
| local.span, | |
| UnitBindingsDiag { label: local.pat.span }, | |
| ); | |
| } | |
| } | |
| } |