rustc_lint/
redundant_semicolon.rs

1use rustc_ast::{Block, StmtKind};
2use rustc_session::{declare_lint, declare_lint_pass};
3use rustc_span::Span;
4
5use crate::lints::RedundantSemicolonsDiag;
6use crate::{EarlyContext, EarlyLintPass, LintContext};
7
8declare_lint! {
9    /// The `redundant_semicolons` lint detects unnecessary trailing
10    /// semicolons.
11    ///
12    /// ### Example
13    ///
14    /// ```rust
15    /// let _ = 123;;
16    /// ```
17    ///
18    /// {{produces}}
19    ///
20    /// ### Explanation
21    ///
22    /// Extra semicolons are not needed, and may be removed to avoid confusion
23    /// and visual clutter.
24    pub REDUNDANT_SEMICOLONS,
25    Warn,
26    "detects unnecessary trailing semicolons"
27}
28
29declare_lint_pass!(RedundantSemicolons => [REDUNDANT_SEMICOLONS]);
30
31impl EarlyLintPass for RedundantSemicolons {
32    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
33        let mut seq = None;
34        for stmt in block.stmts.iter() {
35            match (&stmt.kind, &mut seq) {
36                (StmtKind::Empty, None) => seq = Some((stmt.span, false)),
37                (StmtKind::Empty, Some(seq)) => *seq = (seq.0.to(stmt.span), true),
38                (_, seq) => maybe_lint_redundant_semis(cx, seq),
39            }
40        }
41        maybe_lint_redundant_semis(cx, &mut seq);
42    }
43}
44
45fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) {
46    if let Some((span, multiple)) = seq.take() {
47        // FIXME: Find a better way of ignoring the trailing
48        // semicolon from macro expansion
49        if span == rustc_span::DUMMY_SP {
50            return;
51        }
52
53        cx.emit_span_lint(
54            REDUNDANT_SEMICOLONS,
55            span,
56            RedundantSemicolonsDiag { multiple, suggestion: span },
57        );
58    }
59}