-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add allow-by-default lint for unit bindings
This lint is not triggered if any of the following conditions are met: - The user explicitly annotates the binding with the `()` type. - The binding is from a macro expansion. - The user explicitly wrote `let () = init;` - The user explicitly wrote `let pat = ();`. This is allowed for local lifetimes.
- Loading branch information
Showing
6 changed files
with
88 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
use crate::lints::UnitBindingsDiag; | ||
use crate::{LateLintPass, LintContext}; | ||
use rustc_hir as hir; | ||
use rustc_middle::ty::Ty; | ||
|
||
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::Local<'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.maybe_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 == Ty::new_unit(cx.tcx) | ||
&& local_ty == Ty::new_unit(cx.tcx) | ||
&& local.ty.is_none() | ||
&& !matches!(init.kind, hir::ExprKind::Tup([])) | ||
&& !matches!(local.pat.kind, hir::PatKind::Tuple([], ..)) | ||
{ | ||
cx.emit_spanned_lint( | ||
UNIT_BINDINGS, | ||
local.span, | ||
UnitBindingsDiag { label: local.pat.span }, | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters