1 //////////////////////////////////////////////////////////////////////////////// 2 // checkstyle: Checks Java source code for adherence to a set of rules. 3 // Copyright (C) 2001-2019 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.modifier; 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.ScopeUtil; 27 28 /** 29 * <p> 30 * Checks for implicit modifiers on interface members and nested types. 31 * </p> 32 * <p> 33 * This check is effectively the opposite of <a href="#RedundantModifier">RedundantModifier</a>. 34 * It checks the modifiers on interface members, ensuring that certain modifiers are explicitly 35 * specified even though they are actually redundant. 36 * </p> 37 * <p> 38 * Methods in interfaces are {@code public} by default, however from Java 9 they can also be 39 * {@code private}. This check provides the ability to enforce that {@code public} is explicitly 40 * coded and not implicitly added by the compiler. 41 * </p> 42 * <p> 43 * From Java 8, there are three types of methods in interfaces - static methods marked with 44 * {@code static}, default methods marked with {@code default} and abstract methods which do not 45 * have to be marked with anything. From Java 9, there are also private methods marked with 46 * {@code private}. This check provides the ability to enforce that {@code abstract} is 47 * explicitly coded and not implicitly added by the compiler. 48 * </p> 49 * <p> 50 * Fields in interfaces are always {@code public static final} and as such the compiler does not 51 * require these modifiers. This check provides the ability to enforce that these modifiers are 52 * explicitly coded and not implicitly added by the compiler. 53 * </p> 54 * <p> 55 * Nested types within an interface are always {@code public static} and as such the compiler 56 * does not require the {@code public static} modifiers. This check provides the ability to 57 * enforce that the {@code public} and {@code static} modifiers are explicitly coded and not 58 * implicitly added by the compiler. 59 * </p> 60 * <pre> 61 * public interface AddressFactory { 62 * // check enforces code contains "public static final" 63 * public static final String UNKNOWN = "Unknown"; 64 * 65 * String OTHER = "Other"; // violation 66 * 67 * // check enforces code contains "public" or "private" 68 * public static AddressFactory instance(); 69 * 70 * // check enforces code contains "public abstract" 71 * public abstract Address createAddress(String addressLine, String city); 72 * 73 * List<Address> findAddresses(String city); // violation 74 * 75 * // check enforces default methods are explicitly declared "public" 76 * public default Address createAddress(String city) { 77 * return createAddress(UNKNOWN, city); 78 * } 79 * 80 * default Address createOtherAddress() { // violation 81 * return createAddress(OTHER, OTHER); 82 * } 83 * } 84 * </pre> 85 * <p> 86 * Rationale for this check: Methods, fields and nested types are treated differently 87 * depending on whether they are part of an interface or part of a class. For example, by 88 * default methods are package-scoped on classes, but public in interfaces. However, from 89 * Java 8 onwards, interfaces have changed to be much more like abstract classes. 90 * Interfaces now have static and instance methods with code. Developers should not have to 91 * remember which modifiers are required and which are implied. This check allows the simpler 92 * alternative approach to be adopted where the implied modifiers must always be coded explicitly. 93 * </p> 94 * <ul> 95 * <li> 96 * Property {@code violateImpliedPublicField} - Control whether to enforce that {@code public} 97 * is explicitly coded on interface fields. 98 * Default value is {@code true}. 99 * </li> 100 * <li> 101 * Property {@code violateImpliedStaticField} - Control whether to enforce that {@code static} 102 * is explicitly coded on interface fields. 103 * Default value is {@code true}. 104 * </li> 105 * <li> 106 * Property {@code violateImpliedFinalField} - Control whether to enforce that {@code final} 107 * is explicitly coded on interface fields. 108 * Default value is {@code true}. 109 * </li> 110 * <li> 111 * Property {@code violateImpliedPublicMethod} - Control whether to enforce that {@code public} 112 * is explicitly coded on interface methods. 113 * Default value is {@code true}. 114 * </li> 115 * <li> 116 * Property {@code violateImpliedAbstractMethod} - Control whether to enforce that {@code abstract} 117 * is explicitly coded on interface methods. 118 * Default value is {@code true}. 119 * </li> 120 * <li> 121 * Property {@code violateImpliedPublicNested} - Control whether to enforce that {@code public} 122 * is explicitly coded on interface nested types. 123 * Default value is {@code true}. 124 * </li> 125 * <li> 126 * Property {@code violateImpliedStaticNested} - Control whether to enforce that {@code static} 127 * is explicitly coded on interface nested types. 128 * Default value is {@code true}. 129 * </li> 130 * </ul> 131 * <p> 132 * This example checks that all implicit modifiers on methods, fields and nested 133 * types are explicitly specified in interfaces. 134 * </p> 135 * <p> 136 * Configuration: 137 * </p> 138 * <pre> 139 * <module name="InterfaceMemberImpliedModifier"/> 140 * </pre> 141 * <p> 142 * Code: 143 * </p> 144 * <pre> 145 * public interface AddressFactory { 146 * 147 * public static final String UNKNOWN = "Unknown"; // valid 148 * 149 * String OTHER = "Other"; // violation 150 * 151 * public static AddressFactory instance(); // valid 152 * 153 * public abstract Address createAddress(String addressLine, String city); // valid 154 * 155 * List<Address> findAddresses(String city); // violation 156 * 157 * interface Address { // violation 158 * 159 * String getCity(); // violation 160 * } 161 * } 162 * </pre> 163 * <p> 164 * This example checks that all implicit modifiers on methods and fields are 165 * explicitly specified, but nested types do not need to be. 166 * </p> 167 * <p> 168 * Configuration: 169 * </p> 170 * <pre> 171 * <module name="InterfaceMemberImpliedModifier"> 172 * <property name="violateImpliedPublicNested" value="false"/> 173 * <property name="violateImpliedStaticNested" value="false"/> 174 * </module> 175 * </pre> 176 * <p> 177 * Code: 178 * </p> 179 * <pre> 180 * public interface RoadFeature { 181 * 182 * String STOP = "Stop"; // violation 183 * 184 * enum Lights { // valid because of configured properties 185 * 186 * RED, YELLOW, GREEN; 187 * } 188 * } 189 * </pre> 190 * @since 8.12 191 */ 192 @StatelessCheck 193 public class InterfaceMemberImpliedModifierCheck 194 extends AbstractCheck { 195 196 /** 197 * A key is pointing to the warning message text in "messages.properties" file. 198 */ 199 public static final String MSG_KEY = "interface.implied.modifier"; 200 201 /** Name for 'public' access modifier. */ 202 private static final String PUBLIC_ACCESS_MODIFIER = "public"; 203 204 /** Name for 'abstract' keyword. */ 205 private static final String ABSTRACT_KEYWORD = "abstract"; 206 207 /** Name for 'static' keyword. */ 208 private static final String STATIC_KEYWORD = "static"; 209 210 /** Name for 'final' keyword. */ 211 private static final String FINAL_KEYWORD = "final"; 212 213 /** 214 * Control whether to enforce that {@code public} is explicitly coded 215 * on interface fields. 216 */ 217 private boolean violateImpliedPublicField = true; 218 219 /** 220 * Control whether to enforce that {@code static} is explicitly coded 221 * on interface fields. 222 */ 223 private boolean violateImpliedStaticField = true; 224 225 /** 226 * Control whether to enforce that {@code final} is explicitly coded 227 * on interface fields. 228 */ 229 private boolean violateImpliedFinalField = true; 230 231 /** 232 * Control whether to enforce that {@code public} is explicitly coded 233 * on interface methods. 234 */ 235 private boolean violateImpliedPublicMethod = true; 236 237 /** 238 * Control whether to enforce that {@code abstract} is explicitly coded 239 * on interface methods. 240 */ 241 private boolean violateImpliedAbstractMethod = true; 242 243 /** 244 * Control whether to enforce that {@code public} is explicitly coded 245 * on interface nested types. 246 */ 247 private boolean violateImpliedPublicNested = true; 248 249 /** 250 * Control whether to enforce that {@code static} is explicitly coded 251 * on interface nested types. 252 */ 253 private boolean violateImpliedStaticNested = true; 254 255 /** 256 * Setter to control whether to enforce that {@code public} is explicitly coded 257 * on interface fields. 258 * @param violateImpliedPublicField 259 * True to perform the check, false to turn the check off. 260 */ 261 public void setViolateImpliedPublicField(boolean violateImpliedPublicField) { 262 this.violateImpliedPublicField = violateImpliedPublicField; 263 } 264 265 /** 266 * Setter to control whether to enforce that {@code static} is explicitly coded 267 * on interface fields. 268 * @param violateImpliedStaticField 269 * True to perform the check, false to turn the check off. 270 */ 271 public void setViolateImpliedStaticField(boolean violateImpliedStaticField) { 272 this.violateImpliedStaticField = violateImpliedStaticField; 273 } 274 275 /** 276 * Setter to control whether to enforce that {@code final} is explicitly coded 277 * on interface fields. 278 * @param violateImpliedFinalField 279 * True to perform the check, false to turn the check off. 280 */ 281 public void setViolateImpliedFinalField(boolean violateImpliedFinalField) { 282 this.violateImpliedFinalField = violateImpliedFinalField; 283 } 284 285 /** 286 * Setter to control whether to enforce that {@code public} is explicitly coded 287 * on interface methods. 288 * @param violateImpliedPublicMethod 289 * True to perform the check, false to turn the check off. 290 */ 291 public void setViolateImpliedPublicMethod(boolean violateImpliedPublicMethod) { 292 this.violateImpliedPublicMethod = violateImpliedPublicMethod; 293 } 294 295 /** 296 * Setter to control whether to enforce that {@code abstract} is explicitly coded 297 * on interface methods. 298 * @param violateImpliedAbstractMethod 299 * True to perform the check, false to turn the check off. 300 */ 301 public void setViolateImpliedAbstractMethod(boolean violateImpliedAbstractMethod) { 302 this.violateImpliedAbstractMethod = violateImpliedAbstractMethod; 303 } 304 305 /** 306 * Setter to control whether to enforce that {@code public} is explicitly coded 307 * on interface nested types. 308 * @param violateImpliedPublicNested 309 * True to perform the check, false to turn the check off. 310 */ 311 public void setViolateImpliedPublicNested(boolean violateImpliedPublicNested) { 312 this.violateImpliedPublicNested = violateImpliedPublicNested; 313 } 314 315 /** 316 * Setter to control whether to enforce that {@code static} is explicitly coded 317 * on interface nested types. 318 * @param violateImpliedStaticNested 319 * True to perform the check, false to turn the check off. 320 */ 321 public void setViolateImpliedStaticNested(boolean violateImpliedStaticNested) { 322 this.violateImpliedStaticNested = violateImpliedStaticNested; 323 } 324 325 @Override 326 public int[] getDefaultTokens() { 327 return getAcceptableTokens(); 328 } 329 330 @Override 331 public int[] getRequiredTokens() { 332 return getAcceptableTokens(); 333 } 334 335 @Override 336 public int[] getAcceptableTokens() { 337 return new int[] { 338 TokenTypes.METHOD_DEF, 339 TokenTypes.VARIABLE_DEF, 340 TokenTypes.INTERFACE_DEF, 341 TokenTypes.CLASS_DEF, 342 TokenTypes.ENUM_DEF, 343 }; 344 } 345 346 @Override 347 public void visitToken(DetailAST ast) { 348 if (ScopeUtil.isInInterfaceBlock(ast) && !ScopeUtil.isInCodeBlock(ast)) { 349 switch (ast.getType()) { 350 case TokenTypes.METHOD_DEF: 351 processMethod(ast); 352 break; 353 case TokenTypes.VARIABLE_DEF: 354 processField(ast); 355 break; 356 case TokenTypes.CLASS_DEF: 357 case TokenTypes.INTERFACE_DEF: 358 case TokenTypes.ENUM_DEF: 359 processNestedType(ast); 360 break; 361 default: 362 throw new IllegalStateException(ast.toString()); 363 } 364 } 365 } 366 367 /** 368 * Check method in interface. 369 * @param ast the method AST 370 */ 371 private void processMethod(DetailAST ast) { 372 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 373 if (violateImpliedPublicMethod 374 && modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null 375 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 376 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 377 } 378 if (violateImpliedAbstractMethod 379 && modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null 380 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null 381 && modifiers.findFirstToken(TokenTypes.LITERAL_DEFAULT) == null 382 && modifiers.findFirstToken(TokenTypes.ABSTRACT) == null) { 383 log(ast, MSG_KEY, ABSTRACT_KEYWORD); 384 } 385 } 386 387 /** 388 * Check field in interface. 389 * @param ast the field AST 390 */ 391 private void processField(DetailAST ast) { 392 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 393 if (violateImpliedPublicField 394 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 395 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 396 } 397 if (violateImpliedStaticField 398 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { 399 log(ast, MSG_KEY, STATIC_KEYWORD); 400 } 401 if (violateImpliedFinalField 402 && modifiers.findFirstToken(TokenTypes.FINAL) == null) { 403 log(ast, MSG_KEY, FINAL_KEYWORD); 404 } 405 } 406 407 /** 408 * Check nested types in interface. 409 * @param ast the nested type AST 410 */ 411 private void processNestedType(DetailAST ast) { 412 final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); 413 if (violateImpliedPublicNested 414 && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) == null) { 415 log(ast, MSG_KEY, PUBLIC_ACCESS_MODIFIER); 416 } 417 if (violateImpliedStaticNested 418 && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { 419 log(ast, MSG_KEY, STATIC_KEYWORD); 420 } 421 } 422 423 }