1use rustc_hiras hir;
2use rustc_session::{declare_lint, declare_lint_pass};
34use crate::lints::UnitBindingsDiag;
5use crate::{LateLintPass, LintContext};
67#[doc =
r" The `unit_bindings` lint detects cases where bindings are useless because they have"]
#[doc =
r" the unit type `()` as their inferred type. The lint is suppressed if the user explicitly"]
#[doc =
r" annotates the let binding with the unit type `()`, or if the let binding uses an underscore"]
#[doc =
r" wildcard pattern, i.e. `let _ = expr`, or if the binding is produced from macro expansions."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust,compile_fail"]
#[doc = r" #![deny(unit_bindings)]"]
#[doc = r""]
#[doc = r" fn foo() {"]
#[doc = r#" println!("do work");"#]
#[doc = r" }"]
#[doc = r""]
#[doc = r" pub fn main() {"]
#[doc = r" let x = foo(); // useless binding"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" Creating a local binding with the unit type `()` does not do much and can be a sign of a"]
#[doc = r" user error, such as in this example:"]
#[doc = r""]
#[doc = r" ```rust,no_run"]
#[doc = r" fn main() {"]
#[doc = r" let mut x = [1, 2, 3];"]
#[doc = r" x[0] = 5;"]
#[doc =
r" let y = x.sort(); // useless binding as `sort` returns `()` and not the sorted array."]
#[doc = r#" println!("{:?}", y); // prints "()""#]
#[doc = r" }"]
#[doc = r" ```"]
pub static UNIT_BINDINGS: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "UNIT_BINDINGS",
default_level: ::rustc_lint_defs::Allow,
desc: "binding is useless because it has the unit `()` type",
is_externally_loaded: false,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
8/// The `unit_bindings` lint detects cases where bindings are useless because they have
9 /// the unit type `()` as their inferred type. The lint is suppressed if the user explicitly
10 /// annotates the let binding with the unit type `()`, or if the let binding uses an underscore
11 /// wildcard pattern, i.e. `let _ = expr`, or if the binding is produced from macro expansions.
12 ///
13 /// ### Example
14 ///
15 /// ```rust,compile_fail
16 /// #![deny(unit_bindings)]
17 ///
18 /// fn foo() {
19 /// println!("do work");
20 /// }
21 ///
22 /// pub fn main() {
23 /// let x = foo(); // useless binding
24 /// }
25 /// ```
26 ///
27 /// {{produces}}
28 ///
29 /// ### Explanation
30 ///
31 /// Creating a local binding with the unit type `()` does not do much and can be a sign of a
32 /// user error, such as in this example:
33 ///
34 /// ```rust,no_run
35 /// fn main() {
36 /// let mut x = [1, 2, 3];
37 /// x[0] = 5;
38 /// let y = x.sort(); // useless binding as `sort` returns `()` and not the sorted array.
39 /// println!("{:?}", y); // prints "()"
40 /// }
41 /// ```
42pub UNIT_BINDINGS,
43 Allow,
44"binding is useless because it has the unit `()` type"
45}4647pub struct UnitBindings;
#[automatically_derived]
impl ::core::marker::Copy for UnitBindings { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for UnitBindings { }
#[automatically_derived]
impl ::core::clone::Clone for UnitBindings {
#[inline]
fn clone(&self) -> UnitBindings { *self }
}
impl ::rustc_lint_defs::LintPass for UnitBindings {
fn name(&self) -> &'static str { "UnitBindings" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([UNIT_BINDINGS]))
}
}
impl UnitBindings {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([UNIT_BINDINGS]))
}
}declare_lint_pass!(UnitBindings => [UNIT_BINDINGS]);
4849impl<'tcx> LateLintPass<'tcx> for UnitBindings {
50fn check_local(&mut self, cx: &crate::LateContext<'tcx>, local: &'tcx hir::LetStmt<'tcx>) {
51// Suppress warning if user:
52 // - explicitly ascribes a type to the pattern
53 // - explicitly wrote `let pat = ();`
54 // - explicitly wrote `let () = init;`.
55if !local.span.from_expansion()
56 && let Some(tyck_results) = cx.maybe_typeck_results()
57 && let Some(init) = local.init
58 && let init_ty = tyck_results.expr_ty(init)
59 && let local_ty = tyck_results.node_type(local.hir_id)
60 && init_ty == cx.tcx.types.unit
61 && local_ty == cx.tcx.types.unit
62 && local.ty.is_none()
63 && !#[allow(non_exhaustive_omitted_patterns)] match init.kind {
hir::ExprKind::Tup([]) => true,
_ => false,
}matches!(init.kind, hir::ExprKind::Tup([]))64 && !#[allow(non_exhaustive_omitted_patterns)] match local.pat.kind {
hir::PatKind::Tuple([], ..) => true,
_ => false,
}matches!(local.pat.kind, hir::PatKind::Tuple([], ..))65 {
66cx.emit_span_lint(
67UNIT_BINDINGS,
68local.span,
69UnitBindingsDiag { label: local.pat.span },
70 );
71 }
72 }
73}