mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-08 01:28:18 +03:00
New lint: unnecessary_semicolon (#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
This commit is contained in:
@@ -6174,6 +6174,7 @@ Released 2018-09-13
|
||||
[`unnecessary_safety_comment`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_comment
|
||||
[`unnecessary_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_safety_doc
|
||||
[`unnecessary_self_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_self_imports
|
||||
[`unnecessary_semicolon`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_semicolon
|
||||
[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
|
||||
[`unnecessary_struct_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_struct_initialization
|
||||
[`unnecessary_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_to_owned
|
||||
|
||||
@@ -62,7 +62,7 @@ fn check_and_get_rustc_dir(rustc_path: &str) -> Result<PathBuf, ()> {
|
||||
eprintln!("error: unable to get the absolute path of rustc ({err})");
|
||||
return Err(());
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let path = path.join("compiler");
|
||||
|
||||
@@ -842,7 +842,7 @@ fn try_rename_file(old_name: &Path, new_name: &Path) -> bool {
|
||||
Ok(file) => drop(file),
|
||||
Err(e) if matches!(e.kind(), io::ErrorKind::AlreadyExists | io::ErrorKind::NotFound) => return false,
|
||||
Err(e) => panic_file(e, new_name, "create"),
|
||||
};
|
||||
}
|
||||
match fs::rename(old_name, new_name) {
|
||||
Ok(()) => true,
|
||||
Err(e) => {
|
||||
|
||||
@@ -257,7 +257,7 @@ fn build_sugg<'tcx>(
|
||||
// The receiver may have been a value type, so we need to add an `&` to
|
||||
// be sure the argument to clone_from will be a reference.
|
||||
arg_sugg = arg_sugg.addr();
|
||||
};
|
||||
}
|
||||
|
||||
format!("{receiver_sugg}.clone_from({arg_sugg})")
|
||||
},
|
||||
|
||||
@@ -60,7 +60,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute])
|
||||
}
|
||||
outer_attr_kind.insert(kind);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
|
||||
diag
|
||||
.note("`usize` and `isize` may be as small as 16 bits on some platforms")
|
||||
.note("for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types");
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ fn expr_muldiv_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign {
|
||||
// - uncertain if there are any uncertain values (because they could be negative or positive),
|
||||
Sign::Uncertain => return Sign::Uncertain,
|
||||
Sign::ZeroOrPositive => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// A mul/div is:
|
||||
@@ -236,7 +236,7 @@ fn expr_add_sign(cx: &LateContext<'_>, expr: &Expr<'_>) -> Sign {
|
||||
// - uncertain if there are any uncertain values (because they could be negative or positive),
|
||||
Sign::Uncertain => return Sign::Uncertain,
|
||||
Sign::ZeroOrPositive => positive_count += 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// A sum is:
|
||||
|
||||
@@ -273,7 +273,7 @@ fn get_types_from_cast<'a>(
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
@@ -757,6 +757,7 @@
|
||||
crate::unnecessary_map_on_constructor::UNNECESSARY_MAP_ON_CONSTRUCTOR_INFO,
|
||||
crate::unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS_INFO,
|
||||
crate::unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS_INFO,
|
||||
crate::unnecessary_semicolon::UNNECESSARY_SEMICOLON_INFO,
|
||||
crate::unnecessary_struct_initialization::UNNECESSARY_STRUCT_INITIALIZATION_INFO,
|
||||
crate::unnecessary_wraps::UNNECESSARY_WRAPS_INFO,
|
||||
crate::unneeded_struct_pattern::UNNEEDED_STRUCT_PATTERN_INFO,
|
||||
|
||||
@@ -80,6 +80,6 @@ fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tc
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +331,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
deref_count += 1;
|
||||
},
|
||||
None => break None,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let use_node = use_cx.use_node(cx);
|
||||
|
||||
@@ -70,7 +70,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
var.span,
|
||||
"C-like enum variant discriminant is not portable to 32-bit targets",
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ fn emit_lint(&self) {
|
||||
.collect()
|
||||
};
|
||||
self.emit_sugg(spans, msg, help);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body:
|
||||
for param in generics.params {
|
||||
if param.is_impl_trait() {
|
||||
report(cx, param, generics);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ fn check_needless_must_use(
|
||||
&& !is_must_use_ty(cx, future_ty)
|
||||
{
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
span_lint_and_help(
|
||||
|
||||
@@ -120,7 +120,7 @@ fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, B
|
||||
let ecx = ConstEvalCtxt::new(cx);
|
||||
if let Some(Constant::Int(c)) = ecx.eval(r) {
|
||||
return Some((c, op.node, l));
|
||||
};
|
||||
}
|
||||
if let Some(Constant::Int(c)) = ecx.eval(l) {
|
||||
return Some((c, invert_op(op.node)?, r));
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ fn check_with_condition<'tcx>(
|
||||
if cx.typeck_results().expr_ty(cond_left).is_signed() {
|
||||
} else {
|
||||
print_lint_and_sugg(cx, var_name, expr);
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
ExprKind::Path(QPath::TypeRelative(_, name)) => {
|
||||
|
||||
@@ -65,6 +65,6 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>) {
|
||||
expr.span,
|
||||
"iteration over unordered hash-based type",
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,6 @@ fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
|
||||
Some(ty.span.with_lo(local.pat.span.hi())),
|
||||
"remove the explicit type `_` declaration",
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,6 +372,7 @@
|
||||
mod unnecessary_map_on_constructor;
|
||||
mod unnecessary_owned_empty_strings;
|
||||
mod unnecessary_self_imports;
|
||||
mod unnecessary_semicolon;
|
||||
mod unnecessary_struct_initialization;
|
||||
mod unnecessary_wraps;
|
||||
mod unneeded_struct_pattern;
|
||||
@@ -972,5 +973,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
||||
store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
|
||||
store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern));
|
||||
store.register_late_pass(|_| Box::new(unnecessary_semicolon::UnnecessarySemicolon));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
@@ -784,7 +784,7 @@ fn report_elidable_lifetimes(
|
||||
|diag| {
|
||||
if !include_suggestions {
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) {
|
||||
diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable);
|
||||
|
||||
@@ -251,7 +251,7 @@ fn check_lit(&self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
|
||||
);
|
||||
if !consistent {
|
||||
return Err(WarningType::InconsistentDigitGrouping);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -106,7 +106,7 @@ pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'t
|
||||
emit_manual_let_else(cx, stmt.span, match_expr, &ident_map, pat_arm.pat, diverging_arm.body);
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo
|
||||
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..)
|
||||
) {
|
||||
return;
|
||||
};
|
||||
}
|
||||
let ty = typeck_results.pat_ty(pat);
|
||||
// Option and Result are allowed, everything else isn't.
|
||||
if !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) {
|
||||
|
||||
@@ -85,7 +85,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
}
|
||||
},
|
||||
_ => return,
|
||||
};
|
||||
}
|
||||
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let rem_of = snippet_with_context(cx, rem2_lhs.span, ctxt, "_", &mut app).0;
|
||||
|
||||
@@ -86,7 +86,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let target_res = cx.qpath_res(target_path, target_arg.hir_id);
|
||||
if target_res == Res::Err {
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
if let Res::Local(hir_id) = target_res
|
||||
&& let Some(used_mutably) = mutated_variables(then, cx)
|
||||
|
||||
@@ -34,7 +34,7 @@ fn get_cond_expr<'tcx>(
|
||||
needs_negated: is_none_expr(cx, then_expr), /* if the `then_expr` resolves to `None`, need to negate the
|
||||
* cond */
|
||||
});
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ fn peels_blocks_incl_unsafe_opt<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>>
|
||||
if block.stmts.is_empty() {
|
||||
return block.expr;
|
||||
}
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -68,14 +68,14 @@ fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr:
|
||||
&& is_res_lang_ctor(cx, path_res(cx, callee), OptionSome)
|
||||
&& path_to_local_id(arg, target);
|
||||
}
|
||||
};
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
|
||||
return is_res_lang_ctor(cx, path_res(cx, inner_expr), OptionNone);
|
||||
};
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ pub(super) fn check_with<'tcx, F>(
|
||||
}
|
||||
},
|
||||
None => return None,
|
||||
};
|
||||
}
|
||||
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ fn find_matches_sugg<'a, 'b, I>(
|
||||
if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() {
|
||||
ex_new = ex_inner;
|
||||
}
|
||||
};
|
||||
}
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MATCH_LIKE_MATCHES_MACRO,
|
||||
|
||||
@@ -170,7 +170,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
enum CommonPrefixSearcher<'a> {
|
||||
|
||||
@@ -46,7 +46,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
|
||||
err_ty = ty;
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
||||
@@ -13,7 +13,7 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arms: &[Arm<'_>]) {
|
||||
&& has_non_exhaustive_attr(cx.tcx, *adt_def)
|
||||
{
|
||||
return;
|
||||
};
|
||||
}
|
||||
for arm in arms {
|
||||
if let PatKind::Or(fields) = arm.pat.kind {
|
||||
// look for multiple fields in this arm that contains at least one Wild pattern
|
||||
|
||||
@@ -62,5 +62,5 @@ pub(super) fn check<'tcx>(
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@ pub(super) fn check<'tcx>(
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,5 +46,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
|
||||
format!("{receiver}.as_bytes().get({n}).copied()"),
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span,
|
||||
// &T where T: Copy
|
||||
ty::Ref(_, ty, _) if is_copy(cx, *ty) => {},
|
||||
_ => return,
|
||||
};
|
||||
}
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
CLONED_INSTEAD_OF_COPIED,
|
||||
|
||||
@@ -37,7 +37,7 @@ pub(super) fn check(
|
||||
"expect_err".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a `Result<T, E>` type, return its data (`T`).
|
||||
|
||||
@@ -58,7 +58,7 @@ fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
|
||||
if ty.is_str() && can_be_static_str(cx, arg) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
@@ -25,5 +25,5 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span
|
||||
"into_iter()".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ pub(super) fn check(
|
||||
let _ = write!(sugg, r#".extension().is_some_and(|ext| ext == "{path}")"#);
|
||||
} else {
|
||||
let _ = write!(sugg, r#".extension().map_or(false, |ext| ext == "{path}")"#);
|
||||
};
|
||||
}
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
||||
@@ -87,7 +87,7 @@ fn is_caller_or_fields_change(cx: &LateContext<'_>, body: &Expr<'_>, caller: &Ex
|
||||
// skip lint
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// the lint should not be executed if no violation happens
|
||||
let snippet = if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind
|
||||
|
||||
@@ -214,7 +214,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
if let StmtKind::Semi(expr) = stmt.kind
|
||||
&& let ExprKind::Binary(ref binop, a, b) = expr.kind
|
||||
&& (binop.node == BinOpKind::And || binop.node == BinOpKind::Or)
|
||||
@@ -236,7 +236,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
|
||||
);
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
|
||||
@@ -66,7 +66,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
}) => impl_params.push((path.segments[0].ident.to_string(), path.span)),
|
||||
GenericArg::Type(_) => return,
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// find the type that the Impl is for
|
||||
|
||||
@@ -220,7 +220,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
|
||||
| hir::ItemKind::GlobalAsm(..)
|
||||
| hir::ItemKind::Impl { .. }
|
||||
| hir::ItemKind::Use(..) => note_prev_span_then_ret!(self.prev_span, it.span),
|
||||
};
|
||||
}
|
||||
|
||||
let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
|
||||
| hir::ItemKind::ForeignMod { .. }
|
||||
| hir::ItemKind::Impl { .. }
|
||||
| hir::ItemKind::Use(..) => {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
|
||||
|
||||
@@ -56,10 +56,10 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if let ExprKind::Assign(target, source, _) = &expr.kind {
|
||||
if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(target).kind {
|
||||
span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively");
|
||||
};
|
||||
}
|
||||
if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(source).kind {
|
||||
span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ fn collect_unsafe_exprs<'tcx>(
|
||||
},
|
||||
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
|
||||
Continue::<(), _>(Descend::Yes)
|
||||
});
|
||||
|
||||
@@ -91,7 +91,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, msg),
|
||||
ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, msg),
|
||||
_ => span_lint(cx, MUTEX_ATOMIC, expr.span, msg),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +336,7 @@ fn check<'tcx>(
|
||||
);
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ fn has_specific_allowed_type_and_operation<'tcx>(
|
||||
|
||||
if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
let int_type = substs.type_at(0);
|
||||
let unsigned_int_types = [
|
||||
@@ -214,7 +214,7 @@ fn manage_bin_ops<'tcx>(
|
||||
| hir::BinOpKind::Sub
|
||||
) {
|
||||
return;
|
||||
};
|
||||
}
|
||||
let (mut actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
|
||||
let (mut actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
|
||||
actual_lhs = expr_or_init(cx, actual_lhs);
|
||||
|
||||
@@ -104,7 +104,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
|
||||
} else {
|
||||
expr_snip = arg_snip.to_string();
|
||||
eq_impl = without_deref;
|
||||
};
|
||||
}
|
||||
|
||||
let span;
|
||||
let hint;
|
||||
|
||||
@@ -127,7 +127,7 @@ pub(super) fn check<'tcx>(
|
||||
None,
|
||||
note,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,5 +49,5 @@ macro_rules! lint_double_comparison {
|
||||
lint_double_comparison!(==);
|
||||
},
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ fn is_float(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
|
||||
if let ty::Array(arr_ty, _) = value {
|
||||
return matches!(arr_ty.kind(), ty::Float(_));
|
||||
};
|
||||
}
|
||||
|
||||
matches!(value, ty::Float(_))
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
|
||||
} else {
|
||||
check_non_const_operands(cx, e, lhs);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
|
||||
@@ -21,6 +21,6 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, op: BinOpKind, right:
|
||||
"any number modulo -1 will panic/overflow or result in 0",
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,6 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||
// avoid clippy::double_parens
|
||||
if !is_in_fn_call_arg {
|
||||
hint = hint.maybe_par();
|
||||
};
|
||||
}
|
||||
|
||||
diag.span_suggestion(full_expr.span, "try doing something like", hint, applicability);
|
||||
}
|
||||
|
||||
@@ -215,6 +215,6 @@ fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
|
||||
&& let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next()
|
||||
{
|
||||
return Some((pointee_ty, count));
|
||||
};
|
||||
}
|
||||
if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind
|
||||
// Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods
|
||||
&& let method_ident = method_path.ident.as_str()
|
||||
@@ -108,7 +108,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
|
||||
cx.typeck_results().expr_ty(ptr_self).kind()
|
||||
{
|
||||
return Some((*pointee_ty, count));
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@@ -130,6 +130,6 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
&& pointee_ty == ty_used_for_size_of
|
||||
{
|
||||
span_lint_and_help(cx, SIZE_OF_IN_ELEMENT_COUNT, count_expr.span, LINT_MSG, None, HELP_MSG);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ fn lint_initialization<'tcx>(
|
||||
InitializationType::Extend(e) | InitializationType::Resize(e) => {
|
||||
Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization");
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &'static str) {
|
||||
|
||||
@@ -296,7 +296,7 @@ fn check_xor_swap<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
|
||||
{
|
||||
let span = s1.span.to(s3.span);
|
||||
generate_swap_warning(block, cx, lhs0, rhs0, rhs1, rhs2, span, true);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
|
||||
|
||||
if !tcx.is_diagnostic_item(sym::NonZero, adt.did()) {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
let int_ty = substs.type_at(0);
|
||||
if from_ty != int_ty {
|
||||
|
||||
@@ -119,7 +119,7 @@ fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &
|
||||
&& let LitKind::Int(val, _) = lit.node
|
||||
{
|
||||
return (val == i as u128).then_some(lhs);
|
||||
};
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
|
||||
@@ -71,7 +71,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
|
||||
Applicability::Unspecified,
|
||||
);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
false
|
||||
},
|
||||
_ => false,
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{ExprKind, MatchSource, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for the presence of a semicolon at the end of
|
||||
/// a `match` or `if` statement evaluating to `()`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// The semicolon is not needed, and may be removed to
|
||||
/// avoid confusion and visual clutter.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// # let a: u32 = 42;
|
||||
/// if a > 10 {
|
||||
/// println!("a is greater than 10");
|
||||
/// };
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// # let a: u32 = 42;
|
||||
/// if a > 10 {
|
||||
/// println!("a is greater than 10");
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.86.0"]
|
||||
pub UNNECESSARY_SEMICOLON,
|
||||
pedantic,
|
||||
"unnecessary semicolon after expression returning `()`"
|
||||
}
|
||||
|
||||
declare_lint_pass!(UnnecessarySemicolon => [UNNECESSARY_SEMICOLON]);
|
||||
|
||||
impl LateLintPass<'_> for UnnecessarySemicolon {
|
||||
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
|
||||
// rustfmt already takes care of removing semicolons at the end
|
||||
// of loops.
|
||||
if let StmtKind::Semi(expr) = stmt.kind
|
||||
&& !stmt.span.from_expansion()
|
||||
&& !expr.span.from_expansion()
|
||||
&& matches!(
|
||||
expr.kind,
|
||||
ExprKind::If(..) | ExprKind::Match(_, _, MatchSource::Normal | MatchSource::Postfix)
|
||||
)
|
||||
&& cx.typeck_results().expr_ty(expr) == cx.tcx.types.unit
|
||||
{
|
||||
let semi_span = expr.span.shrink_to_hi().to(stmt.span.shrink_to_hi());
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UNNECESSARY_SEMICOLON,
|
||||
semi_span,
|
||||
"unnecessary semicolon",
|
||||
"remove",
|
||||
String::new(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,7 +182,7 @@ fn check_expr<'a>(cx: &LateContext<'a>, expr: &'a hir::Expr<'a>) {
|
||||
emit_lint(cx, expr.span, expr.hir_id, op, &[]);
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn should_lint<'a>(cx: &LateContext<'a>, mut inner: &'a hir::Expr<'a>) -> Option<IoOp> {
|
||||
|
||||
@@ -69,6 +69,6 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
};
|
||||
if self.allow_in_test && is_in_test(cx.tcx, expr.hir_id) {
|
||||
return;
|
||||
};
|
||||
}
|
||||
// the parent callsite of this `vec!` expression, or span to the borrowed one such as `&vec!`
|
||||
let callsite = expr.span.parent_callsite().unwrap_or(expr.span);
|
||||
|
||||
|
||||
@@ -475,7 +475,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
|
||||
Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),
|
||||
_ => Some(VecInitKind::WithExprCapacity(arg.hir_id)),
|
||||
};
|
||||
};
|
||||
}
|
||||
},
|
||||
ExprKind::Path(QPath::Resolved(_, path))
|
||||
if cx.tcx.is_diagnostic_item(sym::default_fn, path.res.opt_def_id()?)
|
||||
|
||||
@@ -815,7 +815,7 @@ fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'
|
||||
e = ep;
|
||||
},
|
||||
_ => break e,
|
||||
};
|
||||
}
|
||||
};
|
||||
result.reverse();
|
||||
(result, root)
|
||||
@@ -2045,7 +2045,7 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t
|
||||
{
|
||||
return Some(expr);
|
||||
}
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ pub fn parse(expr: &'a Expr<'a>) -> Option<Self> {
|
||||
// This has no argument
|
||||
if name == "panic_cold_explicit" {
|
||||
return Some(Self::Empty);
|
||||
};
|
||||
}
|
||||
|
||||
let [arg, rest @ ..] = args else {
|
||||
return None;
|
||||
|
||||
@@ -125,7 +125,7 @@ pub fn split_digit_parts(digits: &str, float: bool) -> (&str, Option<&str>, Opti
|
||||
integer = &digits[..exp_start];
|
||||
} else {
|
||||
fraction = Some(&digits[integer.len() + 1..exp_start]);
|
||||
};
|
||||
}
|
||||
exponent = Some((&digits[exp_start..=i], &digits[i + 1..]));
|
||||
break;
|
||||
},
|
||||
|
||||
@@ -118,7 +118,7 @@ fn contains_ty_adt_constructor_opaque_inner<'tcx>(
|
||||
if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
|
||||
&& let Some(self_ty_def_id) = adt_def_id(self_ty(cx, method_def_id))
|
||||
{
|
||||
receiver_type_certainty = receiver_type_certainty.with_def_id(self_ty_def_id);
|
||||
};
|
||||
}
|
||||
let lhs = path_segment_certainty(cx, receiver_type_certainty, method, false);
|
||||
let rhs = if type_is_inferable_from_arguments(cx, expr) {
|
||||
meet(
|
||||
|
||||
@@ -107,7 +107,7 @@ pub fn new() -> Self {
|
||||
} else {
|
||||
std::thread::available_parallelism().map_or(1, NonZero::get)
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
for lint_name in &mut config.lint_filter {
|
||||
*lint_name = format!(
|
||||
|
||||
@@ -145,7 +145,7 @@ fn run_clippy_lints(
|
||||
assert_eq!(status.code(), Some(0));
|
||||
|
||||
return Vec::new();
|
||||
};
|
||||
}
|
||||
|
||||
if !config.fix {
|
||||
cmd.arg("--message-format=json");
|
||||
@@ -313,7 +313,7 @@ fn lintcheck(config: LintcheckConfig) {
|
||||
filter
|
||||
})
|
||||
.collect_into(&mut lint_level_args);
|
||||
};
|
||||
}
|
||||
|
||||
let crates: Vec<Crate> = crates
|
||||
.into_iter()
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ pub fn main() {
|
||||
if !has_sysroot_arg(args) {
|
||||
args.extend(vec!["--sysroot".into(), sys_root]);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// make "clippy-driver --rustc" work like a subcommand that passes further args to "rustc"
|
||||
|
||||
@@ -60,7 +60,7 @@ fn explore_directory(dir: &Path) -> Vec<String> {
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#![warn(clippy::unnecessary_semicolon)]
|
||||
#![feature(postfix_match)]
|
||||
|
||||
fn no_lint(mut x: u32) -> Option<u32> {
|
||||
Some(())?;
|
||||
|
||||
{
|
||||
let y = 3;
|
||||
dbg!(x + y)
|
||||
};
|
||||
|
||||
{
|
||||
let (mut a, mut b) = (10, 20);
|
||||
(a, b) = (b + 1, a + 1);
|
||||
}
|
||||
|
||||
Some(0)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut a = 3;
|
||||
if a == 2 {
|
||||
println!("This is weird");
|
||||
}
|
||||
//~^ ERROR: unnecessary semicolon
|
||||
|
||||
a.match {
|
||||
3 => println!("three"),
|
||||
_ => println!("not three"),
|
||||
}
|
||||
//~^ ERROR: unnecessary semicolon
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#![warn(clippy::unnecessary_semicolon)]
|
||||
#![feature(postfix_match)]
|
||||
|
||||
fn no_lint(mut x: u32) -> Option<u32> {
|
||||
Some(())?;
|
||||
|
||||
{
|
||||
let y = 3;
|
||||
dbg!(x + y)
|
||||
};
|
||||
|
||||
{
|
||||
let (mut a, mut b) = (10, 20);
|
||||
(a, b) = (b + 1, a + 1);
|
||||
}
|
||||
|
||||
Some(0)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut a = 3;
|
||||
if a == 2 {
|
||||
println!("This is weird");
|
||||
};
|
||||
//~^ ERROR: unnecessary semicolon
|
||||
|
||||
a.match {
|
||||
3 => println!("three"),
|
||||
_ => println!("not three"),
|
||||
};
|
||||
//~^ ERROR: unnecessary semicolon
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
error: unnecessary semicolon
|
||||
--> tests/ui/unnecessary_semicolon.rs:24:6
|
||||
|
|
||||
LL | };
|
||||
| ^ help: remove
|
||||
|
|
||||
= note: `-D clippy::unnecessary-semicolon` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_semicolon)]`
|
||||
|
||||
error: unnecessary semicolon
|
||||
--> tests/ui/unnecessary_semicolon.rs:30:6
|
||||
|
|
||||
LL | };
|
||||
| ^ help: remove
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
@@ -88,5 +88,5 @@ fn check_that_clippy_has_the_same_major_version_as_rustc() {
|
||||
_ => {
|
||||
panic!("Failed to parse rustc version: {vsplit:?}");
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user