Skip to content

Commit 001185d

Browse files
committed
Auto merge of #6681 - 1c3t3a:1c3t3a-issue-6467, r=xFrednet,flip1995,phansch
Adds a new lint that checks if there is a semicolon on the last block statement if it returns nothing changelog: Added a new lint: `SEMICOLON_IF_NOTHING_RETURNED` fixes #6467 Adds the `SEMICOLON_IF_NOTHING_RETURNED` lint and therefore closes #6467.
2 parents d51db24 + 6b4789d commit 001185d

File tree

5 files changed

+148
-0
lines changed

5 files changed

+148
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -2185,6 +2185,7 @@ Released 2018-09-13
21852185
[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
21862186
[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
21872187
[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
2188+
[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
21882189
[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
21892190
[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
21902191
[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same

clippy_lints/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ mod regex;
310310
mod repeat_once;
311311
mod returns;
312312
mod self_assignment;
313+
mod semicolon_if_nothing_returned;
313314
mod serde_api;
314315
mod shadow;
315316
mod single_component_path_imports;
@@ -876,6 +877,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
876877
&returns::LET_AND_RETURN,
877878
&returns::NEEDLESS_RETURN,
878879
&self_assignment::SELF_ASSIGNMENT,
880+
&semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
879881
&serde_api::SERDE_API_MISUSE,
880882
&shadow::SHADOW_REUSE,
881883
&shadow::SHADOW_SAME,
@@ -1237,6 +1239,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12371239
store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
12381240
store.register_late_pass(|| box manual_ok_or::ManualOkOr);
12391241
store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
1242+
store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
12401243
store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
12411244
let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
12421245
store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
@@ -1291,6 +1294,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12911294
LintId::of(&panic_unimplemented::UNIMPLEMENTED),
12921295
LintId::of(&panic_unimplemented::UNREACHABLE),
12931296
LintId::of(&pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
1297+
LintId::of(&semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
12941298
LintId::of(&shadow::SHADOW_REUSE),
12951299
LintId::of(&shadow::SHADOW_SAME),
12961300
LintId::of(&strings::STRING_ADD),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use crate::utils::{in_macro, snippet_with_macro_callsite, span_lint_and_sugg, sugg};
2+
use if_chain::if_chain;
3+
use rustc_errors::Applicability;
4+
use rustc_hir::{Block, ExprKind};
5+
use rustc_lint::{LateContext, LateLintPass};
6+
use rustc_session::{declare_lint_pass, declare_tool_lint};
7+
8+
declare_clippy_lint! {
9+
/// **What it does:** Looks for blocks of expressions and fires if the last expression returns `()`
10+
/// but is not followed by a semicolon.
11+
///
12+
/// **Why is this bad?** The semicolon might be optional but when
13+
/// extending the block with new code, it doesn't require a change in previous last line.
14+
///
15+
/// **Known problems:** None.
16+
///
17+
/// **Example:**
18+
///
19+
/// ```rust
20+
/// fn main() {
21+
/// println!("Hello world")
22+
/// }
23+
/// ```
24+
/// Use instead:
25+
/// ```rust
26+
/// fn main() {
27+
/// println!("Hello world");
28+
/// }
29+
/// ```
30+
pub SEMICOLON_IF_NOTHING_RETURNED,
31+
restriction,
32+
"add a semicolon if nothing is returned"
33+
}
34+
35+
declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED]);
36+
37+
impl LateLintPass<'_> for SemicolonIfNothingReturned {
38+
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
39+
if_chain! {
40+
if !in_macro(block.span);
41+
if let Some(expr) = block.expr;
42+
let t_expr = cx.typeck_results().expr_ty(expr);
43+
if t_expr.is_unit();
44+
if let snippet = snippet_with_macro_callsite(cx, expr.span, "}");
45+
if !snippet.ends_with('}');
46+
then {
47+
// filter out the desugared `for` loop
48+
if let ExprKind::DropTemps(..) = &expr.kind {
49+
return;
50+
}
51+
52+
let sugg = sugg::Sugg::hir_with_macro_callsite(cx, &expr, "..");
53+
let suggestion = format!("{0};", sugg);
54+
span_lint_and_sugg(
55+
cx,
56+
SEMICOLON_IF_NOTHING_RETURNED,
57+
expr.span.source_callsite(),
58+
"consider adding a `;` to the last statement for consistent formatting",
59+
"add a `;` here",
60+
suggestion,
61+
Applicability::MaybeIncorrect,
62+
);
63+
}
64+
}
65+
}
66+
}
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#![warn(clippy::semicolon_if_nothing_returned)]
2+
#![feature(label_break_value)]
3+
4+
fn get_unit() {}
5+
6+
// the functions below trigger the lint
7+
fn main() {
8+
println!("Hello")
9+
}
10+
11+
fn hello() {
12+
get_unit()
13+
}
14+
15+
fn basic101(x: i32) {
16+
let y: i32;
17+
y = x + 1
18+
}
19+
20+
// this is fine
21+
fn print_sum(a: i32, b: i32) {
22+
println!("{}", a + b);
23+
assert_eq!(true, false);
24+
}
25+
26+
fn foo(x: i32) {
27+
let y: i32;
28+
if x < 1 {
29+
y = 4;
30+
} else {
31+
y = 5;
32+
}
33+
}
34+
35+
fn bar(x: i32) {
36+
let y: i32;
37+
match x {
38+
1 => y = 4,
39+
_ => y = 32,
40+
}
41+
}
42+
43+
fn foobar(x: i32) {
44+
let y: i32;
45+
'label: {
46+
y = x + 1;
47+
}
48+
}
49+
50+
fn loop_test(x: i32) {
51+
let y: i32;
52+
for &ext in &["stdout", "stderr", "fixed"] {
53+
println!("{}", ext);
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: consider adding a `;` to the last statement for consistent formatting
2+
--> $DIR/semicolon_if_nothing_returned.rs:8:5
3+
|
4+
LL | println!("Hello")
5+
| ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");`
6+
|
7+
= note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings`
8+
9+
error: consider adding a `;` to the last statement for consistent formatting
10+
--> $DIR/semicolon_if_nothing_returned.rs:12:5
11+
|
12+
LL | get_unit()
13+
| ^^^^^^^^^^ help: add a `;` here: `get_unit();`
14+
15+
error: consider adding a `;` to the last statement for consistent formatting
16+
--> $DIR/semicolon_if_nothing_returned.rs:17:5
17+
|
18+
LL | y = x + 1
19+
| ^^^^^^^^^ help: add a `;` here: `y = x + 1;`
20+
21+
error: aborting due to 3 previous errors
22+

0 commit comments

Comments
 (0)