View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.coding;
21  
22  import com.puppycrawl.tools.checkstyle.StatelessCheck;
23  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
24  import com.puppycrawl.tools.checkstyle.api.DetailAST;
25  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
26  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
27  import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;
28  
29  /**
30   * <div>
31   * Checks if unnecessary semicolon is used after type member declaration.
32   * </div>
33   *
34   * <p>
35   * This check is not applicable to empty statements (unnecessary semicolons inside methods or
36   * init blocks),
37   * <a href="https://checkstyle.org/checks/coding/emptystatement.html">EmptyStatement</a>
38   * is responsible for it.
39   * </p>
40   * <ul>
41   * <li>
42   * Property {@code tokens} - tokens to check
43   * Type is {@code java.lang.String[]}.
44   * Validation type is {@code tokenSet}.
45   * Default value is:
46   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF">
47   * CLASS_DEF</a>,
48   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF">
49   * INTERFACE_DEF</a>,
50   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF">
51   * ENUM_DEF</a>,
52   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_DEF">
53   * ANNOTATION_DEF</a>,
54   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#VARIABLE_DEF">
55   * VARIABLE_DEF</a>,
56   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_FIELD_DEF">
57   * ANNOTATION_FIELD_DEF</a>,
58   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STATIC_INIT">
59   * STATIC_INIT</a>,
60   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INSTANCE_INIT">
61   * INSTANCE_INIT</a>,
62   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CTOR_DEF">
63   * CTOR_DEF</a>,
64   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF">
65   * METHOD_DEF</a>,
66   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_CONSTANT_DEF">
67   * ENUM_CONSTANT_DEF</a>,
68   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#COMPACT_CTOR_DEF">
69   * COMPACT_CTOR_DEF</a>,
70   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_DEF">
71   * RECORD_DEF</a>.
72   * </li>
73   * </ul>
74   *
75   * <p>
76   * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
77   * </p>
78   *
79   * <p>
80   * Violation Message Keys:
81   * </p>
82   * <ul>
83   * <li>
84   * {@code unnecessary.semicolon}
85   * </li>
86   * </ul>
87   *
88   * @since 8.24
89   */
90  @StatelessCheck
91  public final class UnnecessarySemicolonAfterTypeMemberDeclarationCheck extends AbstractCheck {
92  
93      /**
94       * A key is pointing to the warning message text in "messages.properties"
95       * file.
96       */
97      public static final String MSG_SEMI = "unnecessary.semicolon";
98  
99      @Override
100     public int[] getDefaultTokens() {
101         return getAcceptableTokens();
102     }
103 
104     @Override
105     public int[] getAcceptableTokens() {
106         return new int[] {
107             TokenTypes.CLASS_DEF,
108             TokenTypes.INTERFACE_DEF,
109             TokenTypes.ENUM_DEF,
110             TokenTypes.ANNOTATION_DEF,
111             TokenTypes.VARIABLE_DEF,
112             TokenTypes.ANNOTATION_FIELD_DEF,
113             TokenTypes.STATIC_INIT,
114             TokenTypes.INSTANCE_INIT,
115             TokenTypes.CTOR_DEF,
116             TokenTypes.METHOD_DEF,
117             TokenTypes.ENUM_CONSTANT_DEF,
118             TokenTypes.COMPACT_CTOR_DEF,
119             TokenTypes.RECORD_DEF,
120         };
121     }
122 
123     @Override
124     public int[] getRequiredTokens() {
125         return CommonUtil.EMPTY_INT_ARRAY;
126     }
127 
128     @Override
129     public void visitToken(DetailAST ast) {
130         switch (ast.getType()) {
131             case TokenTypes.CLASS_DEF:
132             case TokenTypes.INTERFACE_DEF:
133             case TokenTypes.ENUM_DEF:
134             case TokenTypes.ANNOTATION_DEF:
135             case TokenTypes.RECORD_DEF:
136                 checkTypeDefinition(ast);
137                 break;
138             case TokenTypes.VARIABLE_DEF:
139                 checkVariableDefinition(ast);
140                 break;
141             case TokenTypes.ENUM_CONSTANT_DEF:
142                 checkEnumConstant(ast);
143                 break;
144             default:
145                 checkTypeMember(ast);
146                 break;
147         }
148     }
149 
150     /**
151      * Checks if type member has unnecessary semicolon.
152      *
153      * @param ast type member
154      */
155     private void checkTypeMember(DetailAST ast) {
156         if (isSemicolon(ast.getNextSibling())) {
157             log(ast.getNextSibling(), MSG_SEMI);
158         }
159     }
160 
161     /**
162      * Checks if type definition has unnecessary semicolon.
163      *
164      * @param ast type definition
165      */
166     private void checkTypeDefinition(DetailAST ast) {
167         if (!ScopeUtil.isOuterMostType(ast) && isSemicolon(ast.getNextSibling())) {
168             log(ast.getNextSibling(), MSG_SEMI);
169         }
170         final DetailAST firstMember =
171             ast.findFirstToken(TokenTypes.OBJBLOCK).getFirstChild().getNextSibling();
172         if (isSemicolon(firstMember) && !ScopeUtil.isInEnumBlock(firstMember)) {
173             log(firstMember, MSG_SEMI);
174         }
175     }
176 
177     /**
178      * Checks if variable definition has unnecessary semicolon.
179      *
180      * @param variableDef variable definition
181      */
182     private void checkVariableDefinition(DetailAST variableDef) {
183         if (isSemicolon(variableDef.getLastChild()) && isSemicolon(variableDef.getNextSibling())) {
184             log(variableDef.getNextSibling(), MSG_SEMI);
185         }
186     }
187 
188     /**
189      * Checks if enum constant has unnecessary semicolon.
190      *
191      * @param ast enum constant
192      */
193     private void checkEnumConstant(DetailAST ast) {
194         final DetailAST next = ast.getNextSibling();
195         if (isSemicolon(next) && isSemicolon(next.getNextSibling())) {
196             log(next.getNextSibling(), MSG_SEMI);
197         }
198     }
199 
200     /**
201      * Checks that {@code ast} is a semicolon.
202      *
203      * @param ast token to check
204      * @return true if ast is semicolon, false otherwise
205      */
206     private static boolean isSemicolon(DetailAST ast) {
207         return ast != null && ast.getType() == TokenTypes.SEMI;
208     }
209 }