diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-08-14 22:56:18 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-08-14 22:56:18 +0200 |
| commit | 7178cf5f970a4f32afd260dda4f87223d8a9ba96 (patch) | |
| tree | 1663a71b9c9cf82ff994b7ce35eaf1d52d170c27 /src | |
| parent | c43d03a19f326f4a323569328cc501e86eb6d22e (diff) | |
| parent | 76a134524295a04ed5f336265239ef5f39d089de (diff) | |
| download | rust-7178cf5f970a4f32afd260dda4f87223d8a9ba96.tar.gz rust-7178cf5f970a4f32afd260dda4f87223d8a9ba96.zip | |
Rollup merge of #62984 - nathanwhit:extra_semi_lint, r=varkor
Add lint for excess trailing semicolons
Closes #60876.
A caveat (not necessarily a negative, but something to consider) with this implementation is that excess semicolons after return/continue/break now also cause an 'unreachable statement' warning.
For the following example:
```
fn main() {
extra_semis();
}
fn extra_semis() -> i32 {
let mut sum = 0;;;
for i in 0..10 {
if i == 5 {
continue;;
} else if i == 9 {
break;;
} else {
sum += i;;
}
}
return sum;;
}
```
The output is:
```
warning: unnecessary trailing semicolons
--> src/main.rs:5:21
|
5 | let mut sum = 0;;;
| ^^ help: remove these semicolons
|
= note: `#[warn(redundant_semicolon)]` on by default
warning: unnecessary trailing semicolon
--> src/main.rs:8:22
|
8 | continue;;
| ^ help: remove this semicolon
warning: unnecessary trailing semicolon
--> src/main.rs:10:19
|
10 | break;;
| ^ help: remove this semicolon
warning: unnecessary trailing semicolon
--> src/main.rs:12:22
|
12 | sum += i;;
| ^ help: remove this semicolon
warning: unnecessary trailing semicolon
--> src/main.rs:15:16
|
15 | return sum;;
| ^ help: remove this semicolon
warning: unreachable statement
--> src/main.rs:8:22
|
8 | continue;;
| ^
|
= note: `#[warn(unreachable_code)]` on by default
warning: unreachable statement
--> src/main.rs:10:19
|
10 | break;;
| ^
warning: unreachable statement
--> src/main.rs:15:16
|
15 | return sum;;
| ^
```
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc_lint/lib.rs | 3 | ||||
| -rw-r--r-- | src/librustc_lint/redundant_semicolon.rs | 52 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser/stmt.rs | 17 | ||||
| -rw-r--r-- | src/test/ui/block-expr-precedence.stderr | 8 | ||||
| -rw-r--r-- | src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr | 5 | ||||
| -rw-r--r-- | src/test/ui/parser/doc-before-semi.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/parser/doc-before-semi.stderr | 8 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/span-preservation.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/proc-macro/span-preservation.stderr | 2 |
9 files changed, 95 insertions, 4 deletions
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 3a540fdf4b9..fc416be8eeb 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -24,6 +24,7 @@ extern crate rustc; mod error_codes; mod nonstandard_style; +mod redundant_semicolon; pub mod builtin; mod types; mod unused; @@ -55,6 +56,7 @@ use session::Session; use lint::LintId; use lint::FutureIncompatibleInfo; +use redundant_semicolon::*; use nonstandard_style::*; use builtin::*; use types::*; @@ -98,6 +100,7 @@ macro_rules! early_lint_passes { WhileTrue: WhileTrue, NonAsciiIdents: NonAsciiIdents, IncompleteFeatures: IncompleteFeatures, + RedundantSemicolon: RedundantSemicolon, ]); ) } diff --git a/src/librustc_lint/redundant_semicolon.rs b/src/librustc_lint/redundant_semicolon.rs new file mode 100644 index 00000000000..7c9df3578b5 --- /dev/null +++ b/src/librustc_lint/redundant_semicolon.rs @@ -0,0 +1,52 @@ +use crate::lint::{EarlyLintPass, LintPass, EarlyContext, LintArray, LintContext}; +use syntax::ast::{Stmt, StmtKind, ExprKind}; +use syntax::errors::Applicability; + +declare_lint! { + pub REDUNDANT_SEMICOLON, + Warn, + "detects unnecessary trailing semicolons" +} + +declare_lint_pass!(RedundantSemicolon => [REDUNDANT_SEMICOLON]); + +impl EarlyLintPass for RedundantSemicolon { + fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) { + if let StmtKind::Semi(expr) = &stmt.node { + if let ExprKind::Tup(ref v) = &expr.node { + if v.is_empty() { + // Strings of excess semicolons are encoded as empty tuple expressions + // during the parsing stage, so we check for empty tuple expressions + // which span only semicolons + if let Ok(source_str) = cx.sess().source_map().span_to_snippet(stmt.span) { + if source_str.chars().all(|c| c == ';') { + let multiple = (stmt.span.hi() - stmt.span.lo()).0 > 1; + let msg = if multiple { + "unnecessary trailing semicolons" + } else { + "unnecessary trailing semicolon" + }; + let mut err = cx.struct_span_lint( + REDUNDANT_SEMICOLON, + stmt.span, + &msg + ); + let suggest_msg = if multiple { + "remove these semicolons" + } else { + "remove this semicolon" + }; + err.span_suggestion( + stmt.span, + &suggest_msg, + String::new(), + Applicability::MaybeIncorrect + ); + err.emit(); + } + } + } + } + } + } +} diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index f182edcbff4..750d8fbbddc 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -167,7 +167,22 @@ impl<'a> Parser<'a> { if self.token == token::Semi { unused_attrs(&attrs, self); self.bump(); - return Ok(None); + let mut last_semi = lo; + while self.token == token::Semi { + last_semi = self.token.span; + self.bump(); + } + // We are encoding a string of semicolons as an + // an empty tuple that spans the excess semicolons + // to preserve this info until the lint stage + return Ok(Some(Stmt { + id: ast::DUMMY_NODE_ID, + span: lo.to(last_semi), + node: StmtKind::Semi(self.mk_expr(lo.to(last_semi), + ExprKind::Tup(Vec::new()), + ThinVec::new() + )), + })); } if self.token == token::CloseDelim(token::Brace) { diff --git a/src/test/ui/block-expr-precedence.stderr b/src/test/ui/block-expr-precedence.stderr new file mode 100644 index 00000000000..1307b5d6ddd --- /dev/null +++ b/src/test/ui/block-expr-precedence.stderr @@ -0,0 +1,8 @@ +warning: unnecessary trailing semicolons + --> $DIR/block-expr-precedence.rs:60:21 + | +LL | if (true) { 12; };;; -num; + | ^^ help: remove these semicolons + | + = note: `#[warn(redundant_semicolon)]` on by default + diff --git a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr index f1c93d54637..f5edbe2a3af 100644 --- a/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr +++ b/src/test/ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.stderr @@ -28,7 +28,10 @@ error: expected `{`, found `;` LL | if not // lack of braces is [sic] | -- this `if` statement has a condition, but no block LL | println!("Then when?"); - | ^ expected `{` + | ^ + | | + | expected `{` + | help: try placing this code inside a block: `{ ; }` error: unexpected `2` after identifier --> $DIR/issue-46836-identifier-not-instead-of-negation.rs:26:24 diff --git a/src/test/ui/parser/doc-before-semi.rs b/src/test/ui/parser/doc-before-semi.rs index 405a7e1e2a3..c3f478fe420 100644 --- a/src/test/ui/parser/doc-before-semi.rs +++ b/src/test/ui/parser/doc-before-semi.rs @@ -3,4 +3,6 @@ fn main() { //~^ ERROR found a documentation comment that doesn't document anything //~| HELP maybe a comment was intended ; + //~^ WARNING unnecessary trailing semicolon + //~| HELP remove this semicolon } diff --git a/src/test/ui/parser/doc-before-semi.stderr b/src/test/ui/parser/doc-before-semi.stderr index e6bade18d0a..b9ac30b09b2 100644 --- a/src/test/ui/parser/doc-before-semi.stderr +++ b/src/test/ui/parser/doc-before-semi.stderr @@ -6,6 +6,14 @@ LL | /// hi | = help: doc comments must come before what they document, maybe a comment was intended with `//`? +warning: unnecessary trailing semicolon + --> $DIR/doc-before-semi.rs:5:5 + | +LL | ; + | ^ help: remove this semicolon + | + = note: `#[warn(redundant_semicolon)]` on by default + error: aborting due to previous error For more information about this error, try `rustc --explain E0585`. diff --git a/src/test/ui/proc-macro/span-preservation.rs b/src/test/ui/proc-macro/span-preservation.rs index 0a82d28e9e5..55835cb88f4 100644 --- a/src/test/ui/proc-macro/span-preservation.rs +++ b/src/test/ui/proc-macro/span-preservation.rs @@ -9,7 +9,7 @@ extern crate test_macros; #[recollect_attr] fn a() { - let x: usize = "hello";;;;; //~ ERROR mismatched types + let x: usize = "hello"; //~ ERROR mismatched types } #[recollect_attr] diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index cf03deee7e4..0290f4b2cc9 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -6,7 +6,7 @@ error[E0308]: mismatched types error[E0308]: mismatched types --> $DIR/span-preservation.rs:12:20 | -LL | let x: usize = "hello";;;;; +LL | let x: usize = "hello"; | ^^^^^^^ expected usize, found reference | = note: expected type `usize` |
