Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lint for excess trailing semicolons #62984

Merged
merged 3 commits into from
Aug 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/librustc_lint/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ extern crate rustc;

mod error_codes;
mod nonstandard_style;
mod redundant_semicolon;
pub mod builtin;
mod types;
mod unused;
Expand Down Expand Up @@ -55,6 +56,7 @@ use session::Session;
use lint::LintId;
use lint::FutureIncompatibleInfo;

use redundant_semicolon::*;
use nonstandard_style::*;
use builtin::*;
use types::*;
Expand Down Expand Up @@ -98,6 +100,7 @@ macro_rules! early_lint_passes {
WhileTrue: WhileTrue,
NonAsciiIdents: NonAsciiIdents,
IncompleteFeatures: IncompleteFeatures,
RedundantSemicolon: RedundantSemicolon,
]);
)
}
Expand Down
52 changes: 52 additions & 0 deletions src/librustc_lint/redundant_semicolon.rs
Original file line number Diff line number Diff line change
@@ -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 == ';') {
nathanwhit marked this conversation as resolved.
Show resolved Hide resolved
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();
}
}
}
}
}
}
}
17 changes: 16 additions & 1 deletion src/libsyntax/parse/parser/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/block-expr-precedence.stderr
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
Expand Up @@ -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: `{ ; }`
nathanwhit marked this conversation as resolved.
Show resolved Hide resolved

error: unexpected `2` after identifier
--> $DIR/issue-46836-identifier-not-instead-of-negation.rs:26:24
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/parser/doc-before-semi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
8 changes: 8 additions & 0 deletions src/test/ui/parser/doc-before-semi.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
2 changes: 1 addition & 1 deletion src/test/ui/proc-macro/span-preservation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/proc-macro/span-preservation.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down