1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3 * SPDX-License-Identifier: MIT
4 */
5 package com.qulice.checkstyle;
6
7 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
8 import com.puppycrawl.tools.checkstyle.api.DetailAST;
9 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
10
11 /**
12 * Detects unnecessary semicolons placed after the closing brace
13 * of a class, interface, record, method or constructor declaration.
14 *
15 * <p>Such semicolons form empty declarations that carry no meaning and
16 * clutter the code, for example:
17 *
18 * <pre>
19 * class Semicolons {
20 * Semicolons() {
21 * };
22 * void act() {
23 * };
24 * };
25 * </pre>
26 *
27 * <p>This check flags every {@code SEMI} token that appears as a
28 * direct child of an {@code OBJBLOCK} (a class, interface or record
29 * body) or of the root {@code COMPILATION_UNIT}. Enum bodies are
30 * excluded because the {@code ;} separator between enum constants and
31 * member declarations is mandated by the Java grammar.
32 *
33 * @since 0.24
34 */
35 public final class ExtraSemicolonCheck extends AbstractCheck {
36
37 @Override
38 public int[] getDefaultTokens() {
39 return new int[] {
40 TokenTypes.OBJBLOCK,
41 TokenTypes.COMPILATION_UNIT,
42 };
43 }
44
45 @Override
46 public int[] getAcceptableTokens() {
47 return this.getDefaultTokens();
48 }
49
50 @Override
51 public int[] getRequiredTokens() {
52 return this.getDefaultTokens();
53 }
54
55 @Override
56 public void visitToken(final DetailAST ast) {
57 if (ast.getType() == TokenTypes.COMPILATION_UNIT
58 || ast.getParent() == null
59 || ast.getParent().getType() != TokenTypes.ENUM_DEF) {
60 this.reportSemis(ast);
61 }
62 }
63
64 /**
65 * Report every {@code SEMI} token that is a direct child of the node.
66 * @param node The parent node whose children are inspected
67 */
68 private void reportSemis(final DetailAST node) {
69 for (DetailAST child = node.getFirstChild(); child != null;
70 child = child.getNextSibling()) {
71 if (child.getType() == TokenTypes.SEMI) {
72 this.log(
73 child.getLineNo(),
74 child.getColumnNo(),
75 "Unnecessary semicolon"
76 );
77 }
78 }
79 }
80 }