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;; | ^ ```
This commit is contained in:
commit
7178cf5f97
9 changed files with 95 additions and 4 deletions
|
|
@ -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,
|
||||
]);
|
||||
)
|
||||
}
|
||||
|
|
|
|||
52
src/librustc_lint/redundant_semicolon.rs
Normal file
52
src/librustc_lint/redundant_semicolon.rs
Normal file
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
8
src/test/ui/block-expr-precedence.stderr
Normal file
8
src/test/ui/block-expr-precedence.stderr
Normal file
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue