001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks.coding; 021 022import com.puppycrawl.tools.checkstyle.StatelessCheck; 023import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 024import com.puppycrawl.tools.checkstyle.api.DetailAST; 025import com.puppycrawl.tools.checkstyle.api.TokenTypes; 026import com.puppycrawl.tools.checkstyle.utils.CommonUtil; 027import com.puppycrawl.tools.checkstyle.utils.ScopeUtil; 028 029/** 030 * <p> 031 * Checks if unnecessary semicolon is used after type member declaration. 032 * </p> 033 * <p> 034 * This check is not applicable to empty statements (unnecessary semicolons inside methods or 035 * init blocks), 036 * <a href="https://checkstyle.org/config_coding.html#EmptyStatement">EmptyStatement</a> 037 * is responsible for it. 038 * </p> 039 * <ul> 040 * <li> 041 * Property {@code tokens} - tokens to check 042 * Default value is: 043 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CLASS_DEF"> 044 * CLASS_DEF</a>, 045 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INTERFACE_DEF"> 046 * INTERFACE_DEF</a>, 047 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_DEF"> 048 * ENUM_DEF</a>, 049 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_DEF"> 050 * ANNOTATION_DEF</a>, 051 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#VARIABLE_DEF"> 052 * VARIABLE_DEF</a>, 053 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ANNOTATION_FIELD_DEF"> 054 * ANNOTATION_FIELD_DEF</a>, 055 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#STATIC_INIT"> 056 * STATIC_INIT</a>, 057 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#INSTANCE_INIT"> 058 * INSTANCE_INIT</a>, 059 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#CTOR_DEF"> 060 * CTOR_DEF</a>, 061 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#METHOD_DEF"> 062 * METHOD_DEF</a>, 063 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_CONSTANT_DEF"> 064 * ENUM_CONSTANT_DEF</a>. 065 * </li> 066 * </ul> 067 * <p> 068 * To configure the check: 069 * </p> 070 * <pre> 071 * <module name="UnnecessarySemicolonAfterTypeMemberDeclaration"/> 072 * </pre> 073 * <p> 074 * Results in following: 075 * </p> 076 * <pre> 077 * class A { 078 * ; // violation, standalone semicolon 079 * {}; // violation, extra semicolon after init block 080 * static {}; // violation, extra semicolon after static init block 081 * A(){}; // violation, extra semicolon after constructor definition 082 * void method() {}; // violation, extra semicolon after method definition 083 * int field = 10;; // violation, extra semicolon after field declaration 084 * 085 * { 086 * ; // no violation, it is empty statement inside init block 087 * } 088 * 089 * static { 090 * ; // no violation, it is empty statement inside static init block 091 * } 092 * 093 * void anotherMethod() { 094 * ; // no violation, it is empty statement 095 * if(true); // no violation, it is empty statement 096 * } 097 * } 098 * </pre> 099 * 100 * @since 8.24 101 */ 102@StatelessCheck 103public final class UnnecessarySemicolonAfterTypeMemberDeclarationCheck extends AbstractCheck { 104 105 /** 106 * A key is pointing to the warning message text in "messages.properties" 107 * file. 108 */ 109 public static final String MSG_SEMI = "unnecessary.semicolon"; 110 111 @Override 112 public int[] getDefaultTokens() { 113 return getAcceptableTokens(); 114 } 115 116 @Override 117 public int[] getAcceptableTokens() { 118 return new int[] { 119 TokenTypes.CLASS_DEF, 120 TokenTypes.INTERFACE_DEF, 121 TokenTypes.ENUM_DEF, 122 TokenTypes.ANNOTATION_DEF, 123 TokenTypes.VARIABLE_DEF, 124 TokenTypes.ANNOTATION_FIELD_DEF, 125 TokenTypes.STATIC_INIT, 126 TokenTypes.INSTANCE_INIT, 127 TokenTypes.CTOR_DEF, 128 TokenTypes.METHOD_DEF, 129 TokenTypes.ENUM_CONSTANT_DEF, 130 }; 131 } 132 133 @Override 134 public int[] getRequiredTokens() { 135 return CommonUtil.EMPTY_INT_ARRAY; 136 } 137 138 @Override 139 public void visitToken(DetailAST ast) { 140 switch (ast.getType()) { 141 case TokenTypes.CLASS_DEF: 142 case TokenTypes.INTERFACE_DEF: 143 case TokenTypes.ENUM_DEF: 144 case TokenTypes.ANNOTATION_DEF: 145 checkTypeDefinition(ast); 146 break; 147 case TokenTypes.VARIABLE_DEF: 148 checkVariableDefinition(ast); 149 break; 150 case TokenTypes.ENUM_CONSTANT_DEF: 151 checkEnumConstant(ast); 152 break; 153 default: 154 checkTypeMember(ast); 155 break; 156 } 157 } 158 159 /** 160 * Checks if type member has unnecessary semicolon. 161 * 162 * @param ast type member 163 */ 164 private void checkTypeMember(DetailAST ast) { 165 if (isSemicolon(ast.getNextSibling())) { 166 log(ast.getNextSibling(), MSG_SEMI); 167 } 168 } 169 170 /** 171 * Checks if type definition has unnecessary semicolon. 172 * 173 * @param ast type definition 174 */ 175 private void checkTypeDefinition(DetailAST ast) { 176 if (!ScopeUtil.isOuterMostType(ast) && isSemicolon(ast.getNextSibling())) { 177 log(ast.getNextSibling(), MSG_SEMI); 178 } 179 final DetailAST firstMember = 180 ast.findFirstToken(TokenTypes.OBJBLOCK).getFirstChild().getNextSibling(); 181 if (isSemicolon(firstMember) && !ScopeUtil.isInEnumBlock(firstMember)) { 182 log(firstMember, MSG_SEMI); 183 } 184 } 185 186 /** 187 * Checks if variable definition has unnecessary semicolon. 188 * 189 * @param variableDef variable definition 190 */ 191 private void checkVariableDefinition(DetailAST variableDef) { 192 if (isSemicolon(variableDef.getLastChild()) && isSemicolon(variableDef.getNextSibling())) { 193 log(variableDef.getNextSibling(), MSG_SEMI); 194 } 195 } 196 197 /** 198 * Checks if enum constant has unnecessary semicolon. 199 * 200 * @param ast enum constant 201 */ 202 private void checkEnumConstant(DetailAST ast) { 203 final DetailAST next = ast.getNextSibling(); 204 if (isSemicolon(next) && isSemicolon(next.getNextSibling())) { 205 log(next.getNextSibling(), MSG_SEMI); 206 } 207 } 208 209 /** 210 * Checks that {@code ast} is a semicolon. 211 * 212 * @param ast token to check 213 * @return true if ast is semicolon, false otherwise 214 */ 215 private static boolean isSemicolon(DetailAST ast) { 216 return ast.getType() == TokenTypes.SEMI; 217 } 218}