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 <a href="#RedundantModifier">RedundantModifier</a>.
034 * It checks the modifiers on interface members, ensuring that certain modifiers are explicitly
035 * specified even though they are actually redundant.
036 * </p>
037 * <p>
038 * Methods in interfaces are {@code public} by default, however from Java 9 they can also be
039 * {@code private}. This check provides the ability to enforce that {@code public} is explicitly
040 * coded and not implicitly added by the compiler.
041 * </p>
042 * <p>
043 * From Java 8, there are three types of methods in interfaces - static methods marked with
044 * {@code static}, default methods marked with {@code default} and abstract methods which do not
045 * have to be marked with anything. From Java 9, there are also private methods marked with
046 * {@code private}. This check provides the ability to enforce that {@code abstract} is
047 * explicitly coded and not implicitly added by the compiler.
048 * </p>
049 * <p>
050 * Fields in interfaces are always {@code public static final} and as such the compiler does not
051 * require these modifiers. This check provides the ability to enforce that these modifiers are
052 * explicitly coded and not implicitly added by the compiler.
053 * </p>
054 * <p>
055 * Nested types within an interface are always {@code public static} and as such the compiler
056 * does not require the {@code public static} modifiers. This check provides the ability to
057 * enforce that the {@code public} and {@code static} modifiers are explicitly coded and not
058 * implicitly added by the compiler.
059 * </p>
060 * <pre>
061 * public interface AddressFactory {
062 *   // check enforces code contains "public static final"
063 *   public static final String UNKNOWN = "Unknown";
064 *
065 *   String OTHER = "Other";  // violation
066 *
067 *   // check enforces code contains "public" or "private"
068 *   public static AddressFactory instance();
069 *
070 *   // check enforces code contains "public abstract"
071 *   public abstract Address createAddress(String addressLine, String city);
072 *
073 *   List&lt;Address&gt; findAddresses(String city);  // violation
074 *
075 *   // check enforces default methods are explicitly declared "public"
076 *   public default Address createAddress(String city) {
077 *     return createAddress(UNKNOWN, city);
078 *   }
079 *
080 *   default Address createOtherAddress() {  // violation
081 *     return createAddress(OTHER, OTHER);
082 *   }
083 * }
084 * </pre>
085 * <p>
086 * Rationale for this check: Methods, fields and nested types are treated differently
087 * depending on whether they are part of an interface or part of a class. For example, by
088 * default methods are package-scoped on classes, but public in interfaces. However, from
089 * Java 8 onwards, interfaces have changed to be much more like abstract classes.
090 * Interfaces now have static and instance methods with code. Developers should not have to
091 * remember which modifiers are required and which are implied. This check allows the simpler
092 * alternative approach to be adopted where the implied modifiers must always be coded explicitly.
093 * </p>
094 * <ul>
095 * <li>
096 * Property {@code violateImpliedPublicField} - Control whether to enforce that {@code public}
097 * is explicitly coded on interface fields.
098 * Default value is {@code true}.
099 * </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 * &lt;module name=&quot;InterfaceMemberImpliedModifier&quot;/&gt;
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&lt;Address&gt; 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 * &lt;module name=&quot;InterfaceMemberImpliedModifier&quot;&gt;
172 *   &lt;property name=&quot;violateImpliedPublicNested&quot; value=&quot;false&quot;/&gt;
173 *   &lt;property name=&quot;violateImpliedStaticNested&quot; value=&quot;false&quot;/&gt;
174 * &lt;/module&gt;
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
193public 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}