Skip to content

Commit 26c415a

Browse files
authored
Merge pull request #2381 from HMPerson1/remove_is_unit_expr
Replace `is_unit_expr`
2 parents 8a53d90 + e09805e commit 26c415a

File tree

7 files changed

+252
-334
lines changed

7 files changed

+252
-334
lines changed

clippy_lints/src/is_unit_expr.rs

Lines changed: 0 additions & 140 deletions
This file was deleted.

clippy_lints/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ pub mod if_not_else;
111111
pub mod infinite_iter;
112112
pub mod int_plus_one;
113113
pub mod invalid_ref;
114-
pub mod is_unit_expr;
115114
pub mod items_after_statements;
116115
pub mod large_enum_variant;
117116
pub mod len_zero;
@@ -248,6 +247,10 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
248247
"string_to_string",
249248
"using `string::to_string` is common even today and specialization will likely happen soon",
250249
);
250+
store.register_removed(
251+
"unit_expr",
252+
"superseded by `let_unit_value` and `unit_arg`",
253+
);
251254
// end deprecated lints, do not remove this comment, it’s used in `update_lints`
252255

253256
reg.register_late_lint_pass(box serde_api::Serde);
@@ -268,7 +271,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
268271
reg.register_late_lint_pass(box approx_const::Pass);
269272
reg.register_late_lint_pass(box misc::Pass);
270273
reg.register_early_lint_pass(box precedence::Precedence);
271-
reg.register_early_lint_pass(box is_unit_expr::UnitExpr);
272274
reg.register_early_lint_pass(box needless_continue::NeedlessContinue);
273275
reg.register_late_lint_pass(box eta_reduction::EtaPass);
274276
reg.register_late_lint_pass(box identity_op::IdentityOp);
@@ -365,6 +367,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
365367
reg.register_early_lint_pass(box const_static_lifetime::StaticConst);
366368
reg.register_late_lint_pass(box fallible_impl_from::FallibleImplFrom);
367369
reg.register_late_lint_pass(box replace_consts::ReplaceConsts);
370+
reg.register_late_lint_pass(box types::UnitArg);
368371

369372
reg.register_lint_group("clippy_restrictions", vec![
370373
arithmetic::FLOAT_ARITHMETIC,
@@ -478,7 +481,6 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
478481
if_let_redundant_pattern_matching::IF_LET_REDUNDANT_PATTERN_MATCHING,
479482
infinite_iter::INFINITE_ITER,
480483
invalid_ref::INVALID_REF,
481-
is_unit_expr::UNIT_EXPR,
482484
large_enum_variant::LARGE_ENUM_VARIANT,
483485
len_zero::LEN_WITHOUT_IS_EMPTY,
484486
len_zero::LEN_ZERO,
@@ -608,6 +610,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
608610
types::OPTION_OPTION,
609611
types::TYPE_COMPLEXITY,
610612
types::UNIT_CMP,
613+
types::UNIT_ARG,
611614
types::UNNECESSARY_CAST,
612615
unicode::ZERO_WIDTH_SPACE,
613616
unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,

clippy_lints/src/types.rs

Lines changed: 123 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -361,25 +361,22 @@ declare_lint! {
361361

362362
fn check_let_unit(cx: &LateContext, decl: &Decl) {
363363
if let DeclLocal(ref local) = decl.node {
364-
match cx.tables.pat_ty(&local.pat).sty {
365-
ty::TyTuple(slice, _) if slice.is_empty() => {
366-
if in_external_macro(cx, decl.span) || in_macro(local.pat.span) {
367-
return;
368-
}
369-
if higher::is_from_for_desugar(decl) {
370-
return;
371-
}
372-
span_lint(
373-
cx,
374-
LET_UNIT_VALUE,
375-
decl.span,
376-
&format!(
377-
"this let-binding has unit value. Consider omitting `let {} =`",
378-
snippet(cx, local.pat.span, "..")
379-
),
380-
);
381-
},
382-
_ => (),
364+
if is_unit(cx.tables.pat_ty(&local.pat)) {
365+
if in_external_macro(cx, decl.span) || in_macro(local.pat.span) {
366+
return;
367+
}
368+
if higher::is_from_for_desugar(decl) {
369+
return;
370+
}
371+
span_lint(
372+
cx,
373+
LET_UNIT_VALUE,
374+
decl.span,
375+
&format!(
376+
"this let-binding has unit value. Consider omitting `let {} =`",
377+
snippet(cx, local.pat.span, "..")
378+
),
379+
);
383380
}
384381
}
385382
}
@@ -434,31 +431,118 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitCmp {
434431
}
435432
if let ExprBinary(ref cmp, ref left, _) = expr.node {
436433
let op = cmp.node;
437-
if op.is_comparison() {
438-
match cx.tables.expr_ty(left).sty {
439-
ty::TyTuple(slice, _) if slice.is_empty() => {
440-
let result = match op {
441-
BiEq | BiLe | BiGe => "true",
442-
_ => "false",
443-
};
444-
span_lint(
445-
cx,
446-
UNIT_CMP,
447-
expr.span,
448-
&format!(
449-
"{}-comparison of unit values detected. This will always be {}",
450-
op.as_str(),
451-
result
452-
),
453-
);
454-
},
455-
_ => (),
456-
}
434+
if op.is_comparison() && is_unit(cx.tables.expr_ty(left)) {
435+
let result = match op {
436+
BiEq | BiLe | BiGe => "true",
437+
_ => "false",
438+
};
439+
span_lint(
440+
cx,
441+
UNIT_CMP,
442+
expr.span,
443+
&format!(
444+
"{}-comparison of unit values detected. This will always be {}",
445+
op.as_str(),
446+
result
447+
),
448+
);
457449
}
458450
}
459451
}
460452
}
461453

454+
/// **What it does:** Checks for passing a unit value as an argument to a function without using a unit literal (`()`).
455+
///
456+
/// **Why is this bad?** This is likely the result of an accidental semicolon.
457+
///
458+
/// **Known problems:** None.
459+
///
460+
/// **Example:**
461+
/// ```rust
462+
/// foo({
463+
/// let a = bar();
464+
/// baz(a);
465+
/// })
466+
/// ```
467+
declare_lint! {
468+
pub UNIT_ARG,
469+
Warn,
470+
"passing unit to a function"
471+
}
472+
473+
pub struct UnitArg;
474+
475+
impl LintPass for UnitArg {
476+
fn get_lints(&self) -> LintArray {
477+
lint_array!(UNIT_ARG)
478+
}
479+
}
480+
481+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg {
482+
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
483+
if in_macro(expr.span) {
484+
return;
485+
}
486+
match expr.node {
487+
ExprCall(_, ref args) | ExprMethodCall(_, _, ref args) => {
488+
for arg in args {
489+
if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) {
490+
let map = &cx.tcx.hir;
491+
// apparently stuff in the desugaring of `?` can trigger this
492+
// so check for that here
493+
// only the calls to `Try::from_error` is marked as desugared,
494+
// so we need to check both the current Expr and its parent.
495+
if !is_questionmark_desugar_marked_call(expr) {
496+
if_chain!{
497+
let opt_parent_node = map.find(map.get_parent_node(expr.id));
498+
if let Some(hir::map::NodeExpr(parent_expr)) = opt_parent_node;
499+
if is_questionmark_desugar_marked_call(parent_expr);
500+
then {}
501+
else {
502+
// `expr` and `parent_expr` where _both_ not from
503+
// desugaring `?`, so lint
504+
span_lint_and_sugg(
505+
cx,
506+
UNIT_ARG,
507+
arg.span,
508+
"passing a unit value to a function",
509+
"if you intended to pass a unit value, use a unit literal instead",
510+
"()".to_string(),
511+
);
512+
}
513+
}
514+
}
515+
}
516+
}
517+
},
518+
_ => (),
519+
}
520+
}
521+
}
522+
523+
fn is_questionmark_desugar_marked_call(expr: &Expr) -> bool {
524+
use syntax_pos::hygiene::CompilerDesugaringKind;
525+
if let ExprCall(ref callee, _) = expr.node {
526+
callee.span.is_compiler_desugaring(CompilerDesugaringKind::QuestionMark)
527+
} else {
528+
false
529+
}
530+
}
531+
532+
fn is_unit(ty: Ty) -> bool {
533+
match ty.sty {
534+
ty::TyTuple(slice, _) if slice.is_empty() => true,
535+
_ => false,
536+
}
537+
}
538+
539+
fn is_unit_literal(expr: &Expr) -> bool {
540+
match expr.node {
541+
ExprTup(ref slice) if slice.is_empty() => true,
542+
_ => false,
543+
}
544+
}
545+
462546
pub struct CastPass;
463547

464548
/// **What it does:** Checks for casts from any numerical to a float type where

0 commit comments

Comments
 (0)