Skip to content

Commit 8f1b4bb

Browse files
authored
New lint: unnecessary_semicolon (rust-lang#14032)
This lint detects and removes the unnecessary semicolon after a `match` or `if` statement returning `()`. It seems to be quite a common "mistake", given the number of hits (88) we had in the Clippy sources themselves. The lint doesn't bother about loops, as `rustfmt` already removes the extra semicolon. It doesn't handle blocks either, as an extra block level, followed or not by a semicolon, is likely intentional. I propose to put the lint in `pedantic`, as putting it in `style` seems quite hazardous given the number of hits. Note: there exists a `redundant-semicolon` lint in the compiler, but it is an early lint and cannot check that the expression evaluates to `()`, so it ignores the cases we're handling here. ---- changelog: [`unnecessary_semicolon`]: new lint
2 parents 2280b8a + 3a7f50f commit 8f1b4bb

File tree

83 files changed

+236
-88
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+236
-88
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6174,6 +6174,7 @@ Released 2018-09-13
61746174
[`unnecessary_safety_comment`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_comment
61756175
[`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc
61766176
[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
6177+
[`unnecessary_semicolon`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_semicolon
61776178
[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
61786179
[`unnecessary_struct_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_struct_initialization
61796180
[`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned

clippy_dev/src/setup/intellij.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ fn check_and_get_rustc_dir(rustc_path: &str) -> Result<PathBuf, ()> {
6262
eprintln!("error: unable to get the absolute path of rustc ({err})");
6363
return Err(());
6464
},
65-
};
65+
}
6666
}
6767

6868
let path = path.join("compiler");

clippy_dev/src/update_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
842842
Ok(file) => drop(file),
843843
Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false,
844844
Err(e) => panic_file(e, new_name, "create"),
845-
};
845+
}
846846
match fs::rename(old_name, new_name) {
847847
Ok(()) => true,
848848
Err(e) => {

clippy_lints/src/assigning_clones.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ fn build_sugg<'tcx>(
257257
// The receiver may have been a value type, so we need to add an `&` to
258258
// be sure the argument to clone_from will be a reference.
259259
arg_sugg = arg_sugg.addr();
260-
};
260+
}
261261

262262
format!("{receiver_sugg}.clone_from({arg_sugg})")
263263
},

clippy_lints/src/attrs/mixed_attributes_style.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute])
6060
}
6161
outer_attr_kind.insert(kind);
6262
},
63-
};
63+
}
6464
}
6565
}
6666

clippy_lints/src/casts/cast_possible_wrap.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
8484
diag
8585
.note("`usize` and `isize` may be as small as 16 bits on some platforms")
8686
.note("for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types");
87-
};
87+
}
8888
});
8989
}

clippy_lints/src/casts/cast_sign_loss.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ fn expr_muldiv_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign {
205205
// - uncertain if there are any uncertain values (because they could be negative or positive),
206206
Sign::Uncertain => return Sign::Uncertain,
207207
Sign::ZeroOrPositive => (),
208-
};
208+
}
209209
}
210210

211211
// A mul/div is:
@@ -236,7 +236,7 @@ fn expr_add_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign {
236236
// - uncertain if there are any uncertain values (because they could be negative or positive),
237237
Sign::Uncertain => return Sign::Uncertain,
238238
Sign::ZeroOrPositive => positive_count += 1,
239-
};
239+
}
240240
}
241241

242242
// A sum is:

clippy_lints/src/checked_conversions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ fn get_types_from_cast<'a>(
273273
},
274274
_ => {},
275275
}
276-
};
276+
}
277277
None
278278
}
279279

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
757757
crate::unnecessary_map_on_constructor::UNNECESSARY_MAP_ON_CONSTRUCTOR_INFO,
758758
crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
759759
crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO,
760+
crate::unnecessary_semicolon::UNNECESSARY_SEMICOLON_INFO,
760761
crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO,
761762
crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO,
762763
crate::unneeded_struct_pattern::UNNEEDED_STRUCT_PATTERN_INFO,

clippy_lints/src/default_constructed_unit_structs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,6 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs {
8080
String::new(),
8181
Applicability::MachineApplicable,
8282
);
83-
};
83+
}
8484
}
8585
}

clippy_lints/src/dereference.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
331331
deref_count += 1;
332332
},
333333
None => break None,
334-
};
334+
}
335335
};
336336

337337
let use_node = use_cx.use_node(cx);

clippy_lints/src/enum_clike.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
7070
var.span,
7171
"C-like enum variant discriminant is not portable to 32-bit targets",
7272
);
73-
};
73+
}
7474
}
7575
}
7676
}

clippy_lints/src/extra_unused_type_parameters.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
183183
.collect()
184184
};
185185
self.emit_sugg(spans, msg, help);
186-
};
186+
}
187187
}
188188
}
189189

clippy_lints/src/functions/impl_trait_in_params.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body:
4545
for param in generics.params {
4646
if param.is_impl_trait() {
4747
report(cx, param, generics);
48-
};
48+
}
4949
}
5050
}
5151
}

clippy_lints/src/functions/must_use.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ fn check_needless_must_use(
160160
&& !is_must_use_ty(cx, future_ty)
161161
{
162162
return;
163-
};
163+
}
164164
}
165165

166166
span_lint_and_help(

clippy_lints/src/implicit_saturating_add.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, B
120120
let ecx = ConstEvalCtxt::new(cx);
121121
if let Some(Constant::Int(c)) = ecx.eval(r) {
122122
return Some((c, op.node, l));
123-
};
123+
}
124124
if let Some(Constant::Int(c)) = ecx.eval(l) {
125125
return Some((c, invert_op(op.node)?, r));
126126
}

clippy_lints/src/implicit_saturating_sub.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ fn check_with_condition<'tcx>(
350350
if cx.typeck_results().expr_ty(cond_left).is_signed() {
351351
} else {
352352
print_lint_and_sugg(cx, var_name, expr);
353-
};
353+
}
354354
}
355355
},
356356
ExprKind::Path(QPath::TypeRelative(_, name)) => {

clippy_lints/src/iter_over_hash_type.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,6 @@ impl LateLintPass<'_> for IterOverHashType {
6565
expr.span,
6666
"iteration over unordered hash-based type",
6767
);
68-
};
68+
}
6969
}
7070
}

clippy_lints/src/let_with_type_underscore.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
4141
Some(ty.span.with_lo(local.pat.span.hi())),
4242
"remove the explicit type `_` declaration",
4343
);
44-
};
44+
}
4545
}
4646
}

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ mod unnecessary_literal_bound;
372372
mod unnecessary_map_on_constructor;
373373
mod unnecessary_owned_empty_strings;
374374
mod unnecessary_self_imports;
375+
mod unnecessary_semicolon;
375376
mod unnecessary_struct_initialization;
376377
mod unnecessary_wraps;
377378
mod unneeded_struct_pattern;
@@ -972,5 +973,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
972973
store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
973974
store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
974975
store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern));
976+
store.register_late_pass(|_| Box::new(unnecessary_semicolon::UnnecessarySemicolon));
975977
// add lints here, do not remove this comment, it's used in `new_lint`
976978
}

clippy_lints/src/lifetimes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ fn report_elidable_lifetimes(
784784
|diag| {
785785
if !include_suggestions {
786786
return;
787-
};
787+
}
788788

789789
if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) {
790790
diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable);

clippy_lints/src/literal_representation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ impl LiteralDigitGrouping {
251251
);
252252
if !consistent {
253253
return Err(WarningType::InconsistentDigitGrouping);
254-
};
254+
}
255255
}
256256

257257
Ok(())

clippy_lints/src/manual_let_else.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ impl<'tcx> QuestionMark {
106106
emit_manual_let_else(cx, stmt.span, match_expr, &ident_map, pat_arm.pat, diverging_arm.body);
107107
},
108108
}
109-
};
109+
}
110110
}
111111
}
112112

@@ -295,7 +295,7 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo
295295
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..)
296296
) {
297297
return;
298-
};
298+
}
299299
let ty = typeck_results.pat_ty(pat);
300300
// Option and Result are allowed, everything else isn't.
301301
if !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) {

clippy_lints/src/manual_rem_euclid.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
8585
}
8686
},
8787
_ => return,
88-
};
88+
}
8989

9090
let mut app = Applicability::MachineApplicable;
9191
let rem_of = snippet_with_context(cx, rem2_lhs.span, ctxt, "_", &mut app).0;

clippy_lints/src/manual_strip.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
8686
let target_res = cx.qpath_res(target_path, target_arg.hir_id);
8787
if target_res == Res::Err {
8888
return;
89-
};
89+
}
9090

9191
if let Res::Local(hir_id) = target_res
9292
&& let Some(used_mutably) = mutated_variables(then, cx)

clippy_lints/src/matches/manual_filter.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ fn get_cond_expr<'tcx>(
3434
needs_negated: is_none_expr(cx, then_expr), /* if the `then_expr` resolves to `None`, need to negate the
3535
* cond */
3636
});
37-
};
37+
}
3838
None
3939
}
4040

@@ -45,7 +45,7 @@ fn peels_blocks_incl_unsafe_opt<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>>
4545
if block.stmts.is_empty() {
4646
return block.expr;
4747
}
48-
};
48+
}
4949
None
5050
}
5151

@@ -68,14 +68,14 @@ fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr:
6868
&& is_res_lang_ctor(cx, path_res(cx, callee), OptionSome)
6969
&& path_to_local_id(arg, target);
7070
}
71-
};
71+
}
7272
false
7373
}
7474

7575
fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
7676
if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
7777
return is_res_lang_ctor(cx, path_res(cx, inner_expr), OptionNone);
78-
};
78+
}
7979
false
8080
}
8181

clippy_lints/src/matches/manual_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ where
109109
}
110110
},
111111
None => return None,
112-
};
112+
}
113113

114114
let mut app = Applicability::MachineApplicable;
115115

clippy_lints/src/matches/match_like_matches.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ where
117117
if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() {
118118
ex_new = ex_inner;
119119
}
120-
};
120+
}
121121
span_lint_and_sugg(
122122
cx,
123123
MATCH_LIKE_MATCHES_MACRO,

clippy_lints/src/matches/match_wild_enum.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
170170
);
171171
});
172172
},
173-
};
173+
}
174174
}
175175

176176
enum CommonPrefixSearcher<'a> {

clippy_lints/src/matches/try_err.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
4646
err_ty = ty;
4747
} else {
4848
return;
49-
};
49+
}
5050

5151
span_lint_and_then(
5252
cx,

clippy_lints/src/matches/wild_in_or_pats.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arms: &[Arm<'_>]) {
1313
&& has_non_exhaustive_attr(cx.tcx, *adt_def)
1414
{
1515
return;
16-
};
16+
}
1717
for arm in arms {
1818
if let PatKind::Or(fields) = arm.pat.kind {
1919
// look for multiple fields in this arm that contains at least one Wild pattern

clippy_lints/src/methods/bytecount.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,5 @@ pub(super) fn check<'tcx>(
6262
),
6363
applicability,
6464
);
65-
};
65+
}
6666
}

clippy_lints/src/methods/bytes_count_to_len.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ pub(super) fn check<'tcx>(
3232
),
3333
applicability,
3434
);
35-
};
35+
}
3636
}

clippy_lints/src/methods/bytes_nth.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
4646
format!("{receiver}.as_bytes().get({n}).copied()"),
4747
applicability,
4848
);
49-
};
49+
}
5050
}

clippy_lints/src/methods/cloned_instead_of_copied.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span,
3232
// &T where T: Copy
3333
ty::Ref(_, ty, _) if is_copy(cx, *ty) => {},
3434
_ => return,
35-
};
35+
}
3636
span_lint_and_sugg(
3737
cx,
3838
CLONED_INSTEAD_OF_COPIED,

clippy_lints/src/methods/err_expect.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub(super) fn check(
3737
"expect_err".to_string(),
3838
Applicability::MachineApplicable,
3939
);
40-
};
40+
}
4141
}
4242

4343
/// Given a `Result<T, E>` type, return its data (`T`).

clippy_lints/src/methods/expect_fun_call.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub(super) fn check<'tcx>(
5858
if ty.is_str() && can_be_static_str(cx, arg) {
5959
return false;
6060
}
61-
};
61+
}
6262
true
6363
}
6464

clippy_lints/src/methods/iter_with_drain.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span
2525
"into_iter()".to_string(),
2626
Applicability::MaybeIncorrect,
2727
);
28-
};
28+
}
2929
}

clippy_lints/src/methods/path_ends_with_ext.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub(super) fn check(
3737
let _ = write!(sugg, r#".extension().is_some_and(|ext| ext == "{path}")"#);
3838
} else {
3939
let _ = write!(sugg, r#".extension().map_or(false, |ext| ext == "{path}")"#);
40-
};
40+
}
4141

4242
span_lint_and_sugg(
4343
cx,

clippy_lints/src/methods/unnecessary_iter_cloned.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ pub fn check_for_loop_iter(
8787
// skip lint
8888
return true;
8989
}
90-
};
90+
}
9191

9292
// the lint should not be executed if no violation happens
9393
let snippet = if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind

0 commit comments

Comments
 (0)