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   * <p>
31   * Checks if unnecessary semicolon is used after type member declaration.
32   * </p>
33   * <p>
34   * This check is not applicable to empty statements (unnecessary semicolons inside methods or
35   * init blocks),
36   * <a href="https://checkstyle.org/checks/coding/emptystatement.html">EmptyStatement</a>
37   * is responsible for it.
38   * </p>
39   * <ul>
40   * <li>
41   * Property {@code tokens} - tokens to check
42   * Type is {@code java.lang.String[]}.
43   * Validation type is {@code tokenSet}.
44   * Default value is:
45   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF">
46   * CLASS_DEF</a>,
47   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF">
48   * INTERFACE_DEF</a>,
49   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF">
50   * ENUM_DEF</a>,
51   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_DEF">
52   * ANNOTATION_DEF</a>,
53   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#VARIABLE_DEF">
54   * VARIABLE_DEF</a>,
55   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_FIELD_DEF">
56   * ANNOTATION_FIELD_DEF</a>,
57   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STATIC_INIT">
58   * STATIC_INIT</a>,
59   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INSTANCE_INIT">
60   * INSTANCE_INIT</a>,
61   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CTOR_DEF">
62   * CTOR_DEF</a>,
63   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF">
64   * METHOD_DEF</a>,
65   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_CONSTANT_DEF">
66   * ENUM_CONSTANT_DEF</a>,
67   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#COMPACT_CTOR_DEF">
68   * COMPACT_CTOR_DEF</a>,
69   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#RECORD_DEF">
70   * RECORD_DEF</a>.
71   * </li>
72   * </ul>
73   * <p>
74   * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
75   * </p>
76   * <p>
77   * Violation Message Keys:
78   * </p>
79   * <ul>
80   * <li>
81   * {@code unnecessary.semicolon}
82   * </li>
83   * </ul>
84   *
85   * @since 8.24
86   */
87  @StatelessCheck
88  public final class UnnecessarySemicolonAfterTypeMemberDeclarationCheck extends AbstractCheck {
89  
90      /**
91       * A key is pointing to the warning message text in "messages.properties"
92       * file.
93       */
94      public static final String MSG_SEMI = "unnecessary.semicolon";
95  
96      @Override
97      public int[] getDefaultTokens() {
98          return getAcceptableTokens();
99      }
100 
101     @Override
102     public int[] getAcceptableTokens() {
103         return new int[] {
104             TokenTypes.CLASS_DEF,
105             TokenTypes.INTERFACE_DEF,
106             TokenTypes.ENUM_DEF,
107             TokenTypes.ANNOTATION_DEF,
108             TokenTypes.VARIABLE_DEF,
109             TokenTypes.ANNOTATION_FIELD_DEF,
110             TokenTypes.STATIC_INIT,
111             TokenTypes.INSTANCE_INIT,
112             TokenTypes.CTOR_DEF,
113             TokenTypes.METHOD_DEF,
114             TokenTypes.ENUM_CONSTANT_DEF,
115             TokenTypes.COMPACT_CTOR_DEF,
116             TokenTypes.RECORD_DEF,
117         };
118     }
119 
120     @Override
121     public int[] getRequiredTokens() {
122         return CommonUtil.EMPTY_INT_ARRAY;
123     }
124 
125     @Override
126     public void visitToken(DetailAST ast) {
127         switch (ast.getType()) {
128             case TokenTypes.CLASS_DEF:
129             case TokenTypes.INTERFACE_DEF:
130             case TokenTypes.ENUM_DEF:
131             case TokenTypes.ANNOTATION_DEF:
132             case TokenTypes.RECORD_DEF:
133                 checkTypeDefinition(ast);
134                 break;
135             case TokenTypes.VARIABLE_DEF:
136                 checkVariableDefinition(ast);
137                 break;
138             case TokenTypes.ENUM_CONSTANT_DEF:
139                 checkEnumConstant(ast);
140                 break;
141             default:
142                 checkTypeMember(ast);
143                 break;
144         }
145     }
146 
147     /**
148      * Checks if type member has unnecessary semicolon.
149      *
150      * @param ast type member
151      */
152     private void checkTypeMember(DetailAST ast) {
153         if (isSemicolon(ast.getNextSibling())) {
154             log(ast.getNextSibling(), MSG_SEMI);
155         }
156     }
157 
158     /**
159      * Checks if type definition has unnecessary semicolon.
160      *
161      * @param ast type definition
162      */
163     private void checkTypeDefinition(DetailAST ast) {
164         if (!ScopeUtil.isOuterMostType(ast) && isSemicolon(ast.getNextSibling())) {
165             log(ast.getNextSibling(), MSG_SEMI);
166         }
167         final DetailAST firstMember =
168             ast.findFirstToken(TokenTypes.OBJBLOCK).getFirstChild().getNextSibling();
169         if (isSemicolon(firstMember) && !ScopeUtil.isInEnumBlock(firstMember)) {
170             log(firstMember, MSG_SEMI);
171         }
172     }
173 
174     /**
175      * Checks if variable definition has unnecessary semicolon.
176      *
177      * @param variableDef variable definition
178      */
179     private void checkVariableDefinition(DetailAST variableDef) {
180         if (isSemicolon(variableDef.getLastChild()) && isSemicolon(variableDef.getNextSibling())) {
181             log(variableDef.getNextSibling(), MSG_SEMI);
182         }
183     }
184 
185     /**
186      * Checks if enum constant has unnecessary semicolon.
187      *
188      * @param ast enum constant
189      */
190     private void checkEnumConstant(DetailAST ast) {
191         final DetailAST next = ast.getNextSibling();
192         if (isSemicolon(next) && isSemicolon(next.getNextSibling())) {
193             log(next.getNextSibling(), MSG_SEMI);
194         }
195     }
196 
197     /**
198      * Checks that {@code ast} is a semicolon.
199      *
200      * @param ast token to check
201      * @return true if ast is semicolon, false otherwise
202      */
203     private static boolean isSemicolon(DetailAST ast) {
204         return ast != null && ast.getType() == TokenTypes.SEMI;
205     }
206 }