001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2023 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 * Type is {@code boolean}. 100 * Default value is {@code true}. 101 * </li> 102 * <li> 103 * Property {@code violateImpliedStaticField} - Control whether to enforce that {@code static} 104 * is explicitly coded on interface fields. 105 * Type is {@code boolean}. 106 * Default value is {@code true}. 107 * </li> 108 * <li> 109 * Property {@code violateImpliedFinalField} - Control whether to enforce that {@code final} 110 * is explicitly coded on interface fields. 111 * Type is {@code boolean}. 112 * Default value is {@code true}. 113 * </li> 114 * <li> 115 * Property {@code violateImpliedPublicMethod} - Control whether to enforce that {@code public} 116 * is explicitly coded on interface methods. 117 * Type is {@code boolean}. 118 * Default value is {@code true}. 119 * </li> 120 * <li> 121 * Property {@code violateImpliedAbstractMethod} - Control whether to enforce that {@code abstract} 122 * is explicitly coded on interface methods. 123 * Type is {@code boolean}. 124 * Default value is {@code true}. 125 * </li> 126 * <li> 127 * Property {@code violateImpliedPublicNested} - Control whether to enforce that {@code public} 128 * is explicitly coded on interface nested types. 129 * Type is {@code boolean}. 130 * Default value is {@code true}. 131 * </li> 132 * <li> 133 * Property {@code violateImpliedStaticNested} - Control whether to enforce that {@code static} 134 * is explicitly coded on interface nested types. 135 * Type is {@code boolean}. 136 * Default value is {@code true}. 137 * </li> 138 * </ul> 139 * <p> 140 * To configure the check so that it checks that all implicit modifiers on methods, fields 141 * and nested types are explicitly specified in interfaces. 142 * </p> 143 * <p> 144 * Configuration: 145 * </p> 146 * <pre> 147 * <module name="InterfaceMemberImpliedModifier"/> 148 * </pre> 149 * <p> 150 * Code: 151 * </p> 152 * <pre> 153 * public interface AddressFactory { 154 * 155 * public static final String UNKNOWN = "Unknown"; // valid 156 * 157 * String OTHER = "Other"; // violation 158 * 159 * public static AddressFactory instance(); // valid 160 * 161 * public abstract Address createAddress(String addressLine, String city); // valid 162 * 163 * List<Address> findAddresses(String city); // violation 164 * 165 * interface Address { // violation 166 * 167 * String getCity(); // violation 168 * } 169 * } 170 * </pre> 171 * <p> 172 * This example checks that all implicit modifiers on methods and fields are 173 * explicitly specified, but nested types do not need to be. 174 * </p> 175 * <p> 176 * Configuration: 177 * </p> 178 * <pre> 179 * <module name="InterfaceMemberImpliedModifier"> 180 * <property name="violateImpliedPublicNested" value="false"/> 181 * <property name="violateImpliedStaticNested" value="false"/> 182 * </module> 183 * </pre> 184 * <p> 185 * Code: 186 * </p> 187 * <pre> 188 * public interface RoadFeature { 189 * 190 * String STOP = "Stop"; // violation 191 * 192 * enum Lights { // valid because of configured properties 193 * 194 * RED, YELLOW, GREEN; 195 * } 196 * } 197 * </pre> 198 * <p> 199 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} 200 * </p> 201 * <p> 202 * Violation Message Keys: 203 * </p> 204 * <ul> 205 * <li> 206 * {@code interface.implied.modifier} 207 * </li> 208 * </ul> 209 * 210 * @since 8.12 211 */ 212@StatelessCheck 213public class InterfaceMemberImpliedModifierCheck 214 extends AbstractCheck { 215 216 /** 217 * A key is pointing to the warning message text in "messages.properties" file. 218 */ 219 public static final String MSG_KEY = "interface.implied.modifier"; 220 221 /** Name for 'public' access modifier. */ 222 private static final String PUBLIC_ACCESS_MODIFIER = "public"; 223 224 /** Name for 'abstract' keyword. */ 225 private static final String ABSTRACT_KEYWORD = "abstract"; 226 227 /** Name for 'static' keyword. */ 228 private static final String STATIC_KEYWORD = "static"; 229 230 /** Name for 'final' keyword. */ 231 private static final String FINAL_KEYWORD = "final"; 232 233 /** 234 * Control whether to enforce that {@code public} is explicitly coded 235 * on interface fields. 236 */ 237 private boolean violateImpliedPublicField = true; 238 239 /** 240 * Control whether to enforce that {@code static} is explicitly coded 241 * on interface fields. 242 */ 243 private boolean violateImpliedStaticField = true; 244 245 /** 246 * Control whether to enforce that {@code final} is explicitly coded 247 * on interface fields. 248 */ 249 private boolean violateImpliedFinalField = true; 250 251 /** 252 * Control whether to enforce that {@code public} is explicitly coded 253 * on interface methods. 254 */ 255 private boolean violateImpliedPublicMethod = true; 256 257 /** 258 * Control whether to enforce that {@code abstract} is explicitly coded 259 * on interface methods. 260 */ 261 private boolean violateImpliedAbstractMethod = true; 262 263 /** 264 * Control whether to enforce that {@code public} is explicitly coded 265 * on interface nested types. 266 */ 267 private boolean violateImpliedPublicNested = true; 268 269 /** 270 * Control whether to enforce that {@code static} is explicitly coded 271 * on interface nested types. 272 */ 273 private boolean violateImpliedStaticNested = true; 274 275 /** 276 * Setter to control whether to enforce that {@code public} is explicitly coded 277 * on interface fields. 278 * 279 * @param violateImpliedPublicField 280 * True to perform the check, false to turn the check off. 281 */ 282 public void setViolateImpliedPublicField(boolean violateImpliedPublicField) { 283 this.violateImpliedPublicField = violateImpliedPublicField; 284 } 285 286 /** 287 * Setter to control whether to enforce that {@code static} is explicitly coded 288 * on interface fields. 289 * 290 * @param violateImpliedStaticField 291 * True to perform the check, false to turn the check off. 292 */ 293 public void setViolateImpliedStaticField(boolean violateImpliedStaticField) { 294 this.violateImpliedStaticField = violateImpliedStaticField; 295 } 296 297 /** 298 * Setter to control whether to enforce that {@code final} is explicitly coded 299 * on interface fields. 300 * 301 * @param violateImpliedFinalField 302 * True to perform the check, false to turn the check off. 303 */ 304 public void setViolateImpliedFinalField(boolean violateImpliedFinalField) { 305 this.violateImpliedFinalField = violateImpliedFinalField; 306 } 307 308 /** 309 * Setter to control whether to enforce that {@code public} is explicitly coded 310 * on interface methods. 311 * 312 * @param violateImpliedPublicMethod 313 * True to perform the check, false to turn the check off. 314 */ 315 public void setViolateImpliedPublicMethod(boolean violateImpliedPublicMethod) { 316 this.violateImpliedPublicMethod = violateImpliedPublicMethod; 317 } 318 319 /** 320 * Setter to control whether to enforce that {@code abstract} is explicitly coded 321 * on interface methods. 322 * 323 * @param violateImpliedAbstractMethod 324 * True to perform the check, false to turn the check off. 325 */ 326 public void setViolateImpliedAbstractMethod(boolean violateImpliedAbstractMethod) { 327 this.violateImpliedAbstractMethod = violateImpliedAbstractMethod; 328 } 329 330 /** 331 * Setter to control whether to enforce that {@code public} is explicitly coded 332 * on interface nested types. 333 * 334 * @param violateImpliedPublicNested 335 * True to perform the check, false to turn the check off. 336 */ 337 public void setViolateImpliedPublicNested(boolean violateImpliedPublicNested) { 338 this.violateImpliedPublicNested = violateImpliedPublicNested; 339 } 340 341 /** 342 * Setter to control whether to enforce that {@code static} is explicitly coded 343 * on interface nested types. 344 * 345 * @param violateImpliedStaticNested 346 * True to perform the check, false to turn the check off. 347 */ 348 public void setViolateImpliedStaticNested(boolean violateImpliedStaticNested) { 349 this.violateImpliedStaticNested = violateImpliedStaticNested; 350 } 351 352 @Override 353 public int[] getDefaultTokens() { 354 return getAcceptableTokens(); 355 } 356 357 @Override 358 public int[] getRequiredTokens() { 359 return getAcceptableTokens(); 360 } 361 362 @Override 363 public int[] getAcceptableTokens() { 364 return new int[] { 365 TokenTypes.METHOD_DEF, 366 TokenTypes.VARIABLE_DEF, 367 TokenTypes.INTERFACE_DEF, 368 TokenTypes.CLASS_DEF, 369 TokenTypes.ENUM_DEF, 370 }; 371 } 372 373 @Override 374 public void visitToken(DetailAST ast) { 375 if (ScopeUtil.isInInterfaceBlock(ast) && !ScopeUtil.isInCodeBlock(ast)) { 376 switch (ast.getType()) { 377 case TokenTypes.METHOD_DEF: 378 processMethod(ast); 379 break; 380 case TokenTypes.VARIABLE_DEF: 381 processField(ast); 382 break; 383 case TokenTypes.CLASS_DEF: 384 case TokenTypes.INTERFACE_DEF: 385 case TokenTypes.ENUM_DEF: 386 processNestedType(ast); 387 break; 388 default: 389 throw new IllegalStateException(ast.toString()); 390 } 391 } 392 } 393 394 /** 395 * Check method in interface. 396 * 397 * @param ast the method AST 398 */ 399 private void processMethod(DetailAST ast) { 400 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 401 if (violateImpliedPublicMethod 402 && modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null 403 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 404 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 405 } 406 if (violateImpliedAbstractMethod 407 && modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null 408 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null 409 && modifiers.findFirstToken(TokenTypes.LITERAL_DEFAULT) == null 410 && modifiers.findFirstToken(TokenTypes.ABSTRACT) == null) { 411 log(ast, MSG_KEY, ABSTRACT_KEYWORD); 412 } 413 } 414 415 /** 416 * Check field in interface. 417 * 418 * @param ast the field AST 419 */ 420 private void processField(DetailAST ast) { 421 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 422 if (violateImpliedPublicField 423 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 424 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 425 } 426 if (violateImpliedStaticField 427 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { 428 log(ast, MSG_KEY, STATIC_KEYWORD); 429 } 430 if (violateImpliedFinalField 431 && modifiers.findFirstToken(TokenTypes.FINAL) == null) { 432 log(ast, MSG_KEY, FINAL_KEYWORD); 433 } 434 } 435 436 /** 437 * Check nested types in interface. 438 * 439 * @param ast the nested type AST 440 */ 441 private void processNestedType(DetailAST ast) { 442 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 443 if (violateImpliedPublicNested 444 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 445 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 446 } 447 if (violateImpliedStaticNested 448 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { 449 log(ast, MSG_KEY, STATIC_KEYWORD); 450 } 451 } 452 453}