001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2019 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.modifier; 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.ScopeUtil; 027 028/** 029 * <p> 030 * Checks for implicit modifiers on interface members and nested types. 031 * </p> 032 * <p> 033 * This check is effectively the opposite of 034 * <a href="https://checkstyle.org/config_modifier.html#RedundantModifier">RedundantModifier</a>. 035 * It checks the modifiers on interface members, ensuring that certain modifiers are explicitly 036 * specified even though they are actually redundant. 037 * </p> 038 * <p> 039 * Methods in interfaces are {@code public} by default, however from Java 9 they can also be 040 * {@code private}. This check provides the ability to enforce that {@code public} is explicitly 041 * coded and not implicitly added by the compiler. 042 * </p> 043 * <p> 044 * From Java 8, there are three types of methods in interfaces - static methods marked with 045 * {@code static}, default methods marked with {@code default} and abstract methods which do not 046 * have to be marked with anything. From Java 9, there are also private methods marked with 047 * {@code private}. This check provides the ability to enforce that {@code abstract} is 048 * explicitly coded and not implicitly added by the compiler. 049 * </p> 050 * <p> 051 * Fields in interfaces are always {@code public static final} and as such the compiler does not 052 * require these modifiers. This check provides the ability to enforce that these modifiers are 053 * explicitly coded and not implicitly added by the compiler. 054 * </p> 055 * <p> 056 * Nested types within an interface are always {@code public static} and as such the compiler 057 * does not require the {@code public static} modifiers. This check provides the ability to 058 * enforce that the {@code public} and {@code static} modifiers are explicitly coded and not 059 * implicitly added by the compiler. 060 * </p> 061 * <pre> 062 * public interface AddressFactory { 063 * // check enforces code contains "public static final" 064 * public static final String UNKNOWN = "Unknown"; 065 * 066 * String OTHER = "Other"; // violation 067 * 068 * // check enforces code contains "public" or "private" 069 * public static AddressFactory instance(); 070 * 071 * // check enforces code contains "public abstract" 072 * public abstract Address createAddress(String addressLine, String city); 073 * 074 * List<Address> findAddresses(String city); // violation 075 * 076 * // check enforces default methods are explicitly declared "public" 077 * public default Address createAddress(String city) { 078 * return createAddress(UNKNOWN, city); 079 * } 080 * 081 * default Address createOtherAddress() { // violation 082 * return createAddress(OTHER, OTHER); 083 * } 084 * } 085 * </pre> 086 * <p> 087 * Rationale for this check: Methods, fields and nested types are treated differently 088 * depending on whether they are part of an interface or part of a class. For example, by 089 * default methods are package-scoped on classes, but public in interfaces. However, from 090 * Java 8 onwards, interfaces have changed to be much more like abstract classes. 091 * Interfaces now have static and instance methods with code. Developers should not have to 092 * remember which modifiers are required and which are implied. This check allows the simpler 093 * alternative approach to be adopted where the implied modifiers must always be coded explicitly. 094 * </p> 095 * <ul> 096 * <li> 097 * Property {@code violateImpliedPublicField} - Control whether to enforce that {@code public} 098 * is explicitly coded on interface fields. 099 * Default value is {@code true}. 100 * </li> 101 * <li> 102 * Property {@code violateImpliedStaticField} - Control whether to enforce that {@code static} 103 * is explicitly coded on interface fields. 104 * Default value is {@code true}. 105 * </li> 106 * <li> 107 * Property {@code violateImpliedFinalField} - Control whether to enforce that {@code final} 108 * is explicitly coded on interface fields. 109 * Default value is {@code true}. 110 * </li> 111 * <li> 112 * Property {@code violateImpliedPublicMethod} - Control whether to enforce that {@code public} 113 * is explicitly coded on interface methods. 114 * Default value is {@code true}. 115 * </li> 116 * <li> 117 * Property {@code violateImpliedAbstractMethod} - Control whether to enforce that {@code abstract} 118 * is explicitly coded on interface methods. 119 * Default value is {@code true}. 120 * </li> 121 * <li> 122 * Property {@code violateImpliedPublicNested} - Control whether to enforce that {@code public} 123 * is explicitly coded on interface nested types. 124 * Default value is {@code true}. 125 * </li> 126 * <li> 127 * Property {@code violateImpliedStaticNested} - Control whether to enforce that {@code static} 128 * is explicitly coded on interface nested types. 129 * Default value is {@code true}. 130 * </li> 131 * </ul> 132 * <p> 133 * This example checks that all implicit modifiers on methods, fields and nested 134 * types are explicitly specified in interfaces. 135 * </p> 136 * <p> 137 * Configuration: 138 * </p> 139 * <pre> 140 * <module name="InterfaceMemberImpliedModifier"/> 141 * </pre> 142 * <p> 143 * Code: 144 * </p> 145 * <pre> 146 * public interface AddressFactory { 147 * 148 * public static final String UNKNOWN = "Unknown"; // valid 149 * 150 * String OTHER = "Other"; // violation 151 * 152 * public static AddressFactory instance(); // valid 153 * 154 * public abstract Address createAddress(String addressLine, String city); // valid 155 * 156 * List<Address> findAddresses(String city); // violation 157 * 158 * interface Address { // violation 159 * 160 * String getCity(); // violation 161 * } 162 * } 163 * </pre> 164 * <p> 165 * This example checks that all implicit modifiers on methods and fields are 166 * explicitly specified, but nested types do not need to be. 167 * </p> 168 * <p> 169 * Configuration: 170 * </p> 171 * <pre> 172 * <module name="InterfaceMemberImpliedModifier"> 173 * <property name="violateImpliedPublicNested" value="false"/> 174 * <property name="violateImpliedStaticNested" value="false"/> 175 * </module> 176 * </pre> 177 * <p> 178 * Code: 179 * </p> 180 * <pre> 181 * public interface RoadFeature { 182 * 183 * String STOP = "Stop"; // violation 184 * 185 * enum Lights { // valid because of configured properties 186 * 187 * RED, YELLOW, GREEN; 188 * } 189 * } 190 * </pre> 191 * @since 8.12 192 */ 193@StatelessCheck 194public class InterfaceMemberImpliedModifierCheck 195 extends AbstractCheck { 196 197 /** 198 * A key is pointing to the warning message text in "messages.properties" file. 199 */ 200 public static final String MSG_KEY = "interface.implied.modifier"; 201 202 /** Name for 'public' access modifier. */ 203 private static final String PUBLIC_ACCESS_MODIFIER = "public"; 204 205 /** Name for 'abstract' keyword. */ 206 private static final String ABSTRACT_KEYWORD = "abstract"; 207 208 /** Name for 'static' keyword. */ 209 private static final String STATIC_KEYWORD = "static"; 210 211 /** Name for 'final' keyword. */ 212 private static final String FINAL_KEYWORD = "final"; 213 214 /** 215 * Control whether to enforce that {@code public} is explicitly coded 216 * on interface fields. 217 */ 218 private boolean violateImpliedPublicField = true; 219 220 /** 221 * Control whether to enforce that {@code static} is explicitly coded 222 * on interface fields. 223 */ 224 private boolean violateImpliedStaticField = true; 225 226 /** 227 * Control whether to enforce that {@code final} is explicitly coded 228 * on interface fields. 229 */ 230 private boolean violateImpliedFinalField = true; 231 232 /** 233 * Control whether to enforce that {@code public} is explicitly coded 234 * on interface methods. 235 */ 236 private boolean violateImpliedPublicMethod = true; 237 238 /** 239 * Control whether to enforce that {@code abstract} is explicitly coded 240 * on interface methods. 241 */ 242 private boolean violateImpliedAbstractMethod = true; 243 244 /** 245 * Control whether to enforce that {@code public} is explicitly coded 246 * on interface nested types. 247 */ 248 private boolean violateImpliedPublicNested = true; 249 250 /** 251 * Control whether to enforce that {@code static} is explicitly coded 252 * on interface nested types. 253 */ 254 private boolean violateImpliedStaticNested = true; 255 256 /** 257 * Setter to control whether to enforce that {@code public} is explicitly coded 258 * on interface fields. 259 * @param violateImpliedPublicField 260 * True to perform the check, false to turn the check off. 261 */ 262 public void setViolateImpliedPublicField(boolean violateImpliedPublicField) { 263 this.violateImpliedPublicField = violateImpliedPublicField; 264 } 265 266 /** 267 * Setter to control whether to enforce that {@code static} is explicitly coded 268 * on interface fields. 269 * @param violateImpliedStaticField 270 * True to perform the check, false to turn the check off. 271 */ 272 public void setViolateImpliedStaticField(boolean violateImpliedStaticField) { 273 this.violateImpliedStaticField = violateImpliedStaticField; 274 } 275 276 /** 277 * Setter to control whether to enforce that {@code final} is explicitly coded 278 * on interface fields. 279 * @param violateImpliedFinalField 280 * True to perform the check, false to turn the check off. 281 */ 282 public void setViolateImpliedFinalField(boolean violateImpliedFinalField) { 283 this.violateImpliedFinalField = violateImpliedFinalField; 284 } 285 286 /** 287 * Setter to control whether to enforce that {@code public} is explicitly coded 288 * on interface methods. 289 * @param violateImpliedPublicMethod 290 * True to perform the check, false to turn the check off. 291 */ 292 public void setViolateImpliedPublicMethod(boolean violateImpliedPublicMethod) { 293 this.violateImpliedPublicMethod = violateImpliedPublicMethod; 294 } 295 296 /** 297 * Setter to control whether to enforce that {@code abstract} is explicitly coded 298 * on interface methods. 299 * @param violateImpliedAbstractMethod 300 * True to perform the check, false to turn the check off. 301 */ 302 public void setViolateImpliedAbstractMethod(boolean violateImpliedAbstractMethod) { 303 this.violateImpliedAbstractMethod = violateImpliedAbstractMethod; 304 } 305 306 /** 307 * Setter to control whether to enforce that {@code public} is explicitly coded 308 * on interface nested types. 309 * @param violateImpliedPublicNested 310 * True to perform the check, false to turn the check off. 311 */ 312 public void setViolateImpliedPublicNested(boolean violateImpliedPublicNested) { 313 this.violateImpliedPublicNested = violateImpliedPublicNested; 314 } 315 316 /** 317 * Setter to control whether to enforce that {@code static} is explicitly coded 318 * on interface nested types. 319 * @param violateImpliedStaticNested 320 * True to perform the check, false to turn the check off. 321 */ 322 public void setViolateImpliedStaticNested(boolean violateImpliedStaticNested) { 323 this.violateImpliedStaticNested = violateImpliedStaticNested; 324 } 325 326 @Override 327 public int[] getDefaultTokens() { 328 return getAcceptableTokens(); 329 } 330 331 @Override 332 public int[] getRequiredTokens() { 333 return getAcceptableTokens(); 334 } 335 336 @Override 337 public int[] getAcceptableTokens() { 338 return new int[] { 339 TokenTypes.METHOD_DEF, 340 TokenTypes.VARIABLE_DEF, 341 TokenTypes.INTERFACE_DEF, 342 TokenTypes.CLASS_DEF, 343 TokenTypes.ENUM_DEF, 344 }; 345 } 346 347 @Override 348 public void visitToken(DetailAST ast) { 349 if (ScopeUtil.isInInterfaceBlock(ast) && !ScopeUtil.isInCodeBlock(ast)) { 350 switch (ast.getType()) { 351 case TokenTypes.METHOD_DEF: 352 processMethod(ast); 353 break; 354 case TokenTypes.VARIABLE_DEF: 355 processField(ast); 356 break; 357 case TokenTypes.CLASS_DEF: 358 case TokenTypes.INTERFACE_DEF: 359 case TokenTypes.ENUM_DEF: 360 processNestedType(ast); 361 break; 362 default: 363 throw new IllegalStateException(ast.toString()); 364 } 365 } 366 } 367 368 /** 369 * Check method in interface. 370 * @param ast the method AST 371 */ 372 private void processMethod(DetailAST ast) { 373 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 374 if (violateImpliedPublicMethod 375 && modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null 376 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 377 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 378 } 379 if (violateImpliedAbstractMethod 380 && modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null 381 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null 382 && modifiers.findFirstToken(TokenTypes.LITERAL_DEFAULT) == null 383 && modifiers.findFirstToken(TokenTypes.ABSTRACT) == null) { 384 log(ast, MSG_KEY, ABSTRACT_KEYWORD); 385 } 386 } 387 388 /** 389 * Check field in interface. 390 * @param ast the field AST 391 */ 392 private void processField(DetailAST ast) { 393 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 394 if (violateImpliedPublicField 395 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 396 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 397 } 398 if (violateImpliedStaticField 399 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { 400 log(ast, MSG_KEY, STATIC_KEYWORD); 401 } 402 if (violateImpliedFinalField 403 && modifiers.findFirstToken(TokenTypes.FINAL) == null) { 404 log(ast, MSG_KEY, FINAL_KEYWORD); 405 } 406 } 407 408 /** 409 * Check nested types in interface. 410 * @param ast the nested type AST 411 */ 412 private void processNestedType(DetailAST ast) { 413 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 414 if (violateImpliedPublicNested 415 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 416 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 417 } 418 if (violateImpliedStaticNested 419 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { 420 log(ast, MSG_KEY, STATIC_KEYWORD); 421 } 422 } 423 424}