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.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 * 192 * @since 8.12 193 */ 194@StatelessCheck 195public class InterfaceMemberImpliedModifierCheck 196 extends AbstractCheck { 197 198 /** 199 * A key is pointing to the warning message text in "messages.properties" file. 200 */ 201 public static final String MSG_KEY = "interface.implied.modifier"; 202 203 /** Name for 'public' access modifier. */ 204 private static final String PUBLIC_ACCESS_MODIFIER = "public"; 205 206 /** Name for 'abstract' keyword. */ 207 private static final String ABSTRACT_KEYWORD = "abstract"; 208 209 /** Name for 'static' keyword. */ 210 private static final String STATIC_KEYWORD = "static"; 211 212 /** Name for 'final' keyword. */ 213 private static final String FINAL_KEYWORD = "final"; 214 215 /** 216 * Control whether to enforce that {@code public} is explicitly coded 217 * on interface fields. 218 */ 219 private boolean violateImpliedPublicField = true; 220 221 /** 222 * Control whether to enforce that {@code static} is explicitly coded 223 * on interface fields. 224 */ 225 private boolean violateImpliedStaticField = true; 226 227 /** 228 * Control whether to enforce that {@code final} is explicitly coded 229 * on interface fields. 230 */ 231 private boolean violateImpliedFinalField = true; 232 233 /** 234 * Control whether to enforce that {@code public} is explicitly coded 235 * on interface methods. 236 */ 237 private boolean violateImpliedPublicMethod = true; 238 239 /** 240 * Control whether to enforce that {@code abstract} is explicitly coded 241 * on interface methods. 242 */ 243 private boolean violateImpliedAbstractMethod = true; 244 245 /** 246 * Control whether to enforce that {@code public} is explicitly coded 247 * on interface nested types. 248 */ 249 private boolean violateImpliedPublicNested = true; 250 251 /** 252 * Control whether to enforce that {@code static} is explicitly coded 253 * on interface nested types. 254 */ 255 private boolean violateImpliedStaticNested = true; 256 257 /** 258 * Setter to control whether to enforce that {@code public} is explicitly coded 259 * on interface fields. 260 * 261 * @param violateImpliedPublicField 262 * True to perform the check, false to turn the check off. 263 */ 264 public void setViolateImpliedPublicField(boolean violateImpliedPublicField) { 265 this.violateImpliedPublicField = violateImpliedPublicField; 266 } 267 268 /** 269 * Setter to control whether to enforce that {@code static} is explicitly coded 270 * on interface fields. 271 * 272 * @param violateImpliedStaticField 273 * True to perform the check, false to turn the check off. 274 */ 275 public void setViolateImpliedStaticField(boolean violateImpliedStaticField) { 276 this.violateImpliedStaticField = violateImpliedStaticField; 277 } 278 279 /** 280 * Setter to control whether to enforce that {@code final} is explicitly coded 281 * on interface fields. 282 * 283 * @param violateImpliedFinalField 284 * True to perform the check, false to turn the check off. 285 */ 286 public void setViolateImpliedFinalField(boolean violateImpliedFinalField) { 287 this.violateImpliedFinalField = violateImpliedFinalField; 288 } 289 290 /** 291 * Setter to control whether to enforce that {@code public} is explicitly coded 292 * on interface methods. 293 * 294 * @param violateImpliedPublicMethod 295 * True to perform the check, false to turn the check off. 296 */ 297 public void setViolateImpliedPublicMethod(boolean violateImpliedPublicMethod) { 298 this.violateImpliedPublicMethod = violateImpliedPublicMethod; 299 } 300 301 /** 302 * Setter to control whether to enforce that {@code abstract} is explicitly coded 303 * on interface methods. 304 * 305 * @param violateImpliedAbstractMethod 306 * True to perform the check, false to turn the check off. 307 */ 308 public void setViolateImpliedAbstractMethod(boolean violateImpliedAbstractMethod) { 309 this.violateImpliedAbstractMethod = violateImpliedAbstractMethod; 310 } 311 312 /** 313 * Setter to control whether to enforce that {@code public} is explicitly coded 314 * on interface nested types. 315 * 316 * @param violateImpliedPublicNested 317 * True to perform the check, false to turn the check off. 318 */ 319 public void setViolateImpliedPublicNested(boolean violateImpliedPublicNested) { 320 this.violateImpliedPublicNested = violateImpliedPublicNested; 321 } 322 323 /** 324 * Setter to control whether to enforce that {@code static} is explicitly coded 325 * on interface nested types. 326 * 327 * @param violateImpliedStaticNested 328 * True to perform the check, false to turn the check off. 329 */ 330 public void setViolateImpliedStaticNested(boolean violateImpliedStaticNested) { 331 this.violateImpliedStaticNested = violateImpliedStaticNested; 332 } 333 334 @Override 335 public int[] getDefaultTokens() { 336 return getAcceptableTokens(); 337 } 338 339 @Override 340 public int[] getRequiredTokens() { 341 return getAcceptableTokens(); 342 } 343 344 @Override 345 public int[] getAcceptableTokens() { 346 return new int[] { 347 TokenTypes.METHOD_DEF, 348 TokenTypes.VARIABLE_DEF, 349 TokenTypes.INTERFACE_DEF, 350 TokenTypes.CLASS_DEF, 351 TokenTypes.ENUM_DEF, 352 }; 353 } 354 355 @Override 356 public void visitToken(DetailAST ast) { 357 if (ScopeUtil.isInInterfaceBlock(ast) && !ScopeUtil.isInCodeBlock(ast)) { 358 switch (ast.getType()) { 359 case TokenTypes.METHOD_DEF: 360 processMethod(ast); 361 break; 362 case TokenTypes.VARIABLE_DEF: 363 processField(ast); 364 break; 365 case TokenTypes.CLASS_DEF: 366 case TokenTypes.INTERFACE_DEF: 367 case TokenTypes.ENUM_DEF: 368 processNestedType(ast); 369 break; 370 default: 371 throw new IllegalStateException(ast.toString()); 372 } 373 } 374 } 375 376 /** 377 * Check method in interface. 378 * 379 * @param ast the method AST 380 */ 381 private void processMethod(DetailAST ast) { 382 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 383 if (violateImpliedPublicMethod 384 && modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null 385 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 386 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 387 } 388 if (violateImpliedAbstractMethod 389 && modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null 390 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null 391 && modifiers.findFirstToken(TokenTypes.LITERAL_DEFAULT) == null 392 && modifiers.findFirstToken(TokenTypes.ABSTRACT) == null) { 393 log(ast, MSG_KEY, ABSTRACT_KEYWORD); 394 } 395 } 396 397 /** 398 * Check field in interface. 399 * 400 * @param ast the field AST 401 */ 402 private void processField(DetailAST ast) { 403 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 404 if (violateImpliedPublicField 405 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 406 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 407 } 408 if (violateImpliedStaticField 409 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { 410 log(ast, MSG_KEY, STATIC_KEYWORD); 411 } 412 if (violateImpliedFinalField 413 && modifiers.findFirstToken(TokenTypes.FINAL) == null) { 414 log(ast, MSG_KEY, FINAL_KEYWORD); 415 } 416 } 417 418 /** 419 * Check nested types in interface. 420 * 421 * @param ast the nested type AST 422 */ 423 private void processNestedType(DetailAST ast) { 424 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 425 if (violateImpliedPublicNested 426 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 427 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 428 } 429 if (violateImpliedStaticNested 430 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { 431 log(ast, MSG_KEY, STATIC_KEYWORD); 432 } 433 } 434 435}