2019-12-22 16:42:04 -06:00
|
|
|
use crate::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
|
|
|
|
use syntax::ast::{ExprKind, Stmt, StmtKind};
|
2019-07-30 12:48:39 -05:00
|
|
|
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) {
|
2019-09-26 11:34:50 -05:00
|
|
|
if let StmtKind::Semi(expr) = &stmt.kind {
|
2019-09-26 08:39:48 -05:00
|
|
|
if let ExprKind::Tup(ref v) = &expr.kind {
|
2019-07-30 12:48:39 -05:00
|
|
|
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"
|
|
|
|
};
|
2019-12-22 16:42:04 -06:00
|
|
|
let mut err = cx.struct_span_lint(REDUNDANT_SEMICOLON, stmt.span, &msg);
|
2019-07-30 12:48:39 -05:00
|
|
|
let suggest_msg = if multiple {
|
|
|
|
"remove these semicolons"
|
|
|
|
} else {
|
|
|
|
"remove this semicolon"
|
|
|
|
};
|
|
|
|
err.span_suggestion(
|
|
|
|
stmt.span,
|
|
|
|
&suggest_msg,
|
|
|
|
String::new(),
|
2019-12-22 16:42:04 -06:00
|
|
|
Applicability::MaybeIncorrect,
|
2019-07-30 12:48:39 -05:00
|
|
|
);
|
|
|
|
err.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|