001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2022 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.javadoc;
021
022import java.util.regex.Pattern;
023
024import com.puppycrawl.tools.checkstyle.StatelessCheck;
025import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
026import com.puppycrawl.tools.checkstyle.api.DetailAST;
027import com.puppycrawl.tools.checkstyle.api.FileContents;
028import com.puppycrawl.tools.checkstyle.api.Scope;
029import com.puppycrawl.tools.checkstyle.api.TextBlock;
030import com.puppycrawl.tools.checkstyle.api.TokenTypes;
031import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;
032
033/**
034 * <p>
035 * Checks that a variable has a Javadoc comment. Ignores {@code serialVersionUID} fields.
036 * </p>
037 * <ul>
038 * <li>
039 * Property {@code scope} - Specify the visibility scope where Javadoc comments are checked.
040 * Type is {@code com.puppycrawl.tools.checkstyle.api.Scope}.
041 * Default value is {@code private}.
042 * </li>
043 * <li>
044 * Property {@code excludeScope} - Specify the visibility scope where Javadoc
045 * comments are not checked.
046 * Type is {@code com.puppycrawl.tools.checkstyle.api.Scope}.
047 * Default value is {@code null}.
048 * </li>
049 * <li>
050 * Property {@code ignoreNamePattern} - Specify the regexp to define variable names to ignore.
051 * Type is {@code java.util.regex.Pattern}.
052 * Default value is {@code null}.
053 * </li>
054 * <li>
055 * Property {@code tokens} - tokens to check
056 * Type is {@code java.lang.String[]}.
057 * Validation type is {@code tokenSet}.
058 * Default value is:
059 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_CONSTANT_DEF">
060 * ENUM_CONSTANT_DEF</a>.
061 * </li>
062 * </ul>
063 * <p>
064 * To configure the default check:
065 * </p>
066 * <pre>
067 * &lt;module name="JavadocVariable"/&gt;
068 * </pre>
069 * <p>
070 * By default, this setting will report a violation if
071 * there is no javadoc for any scope member.
072 * </p>
073 * <pre>
074 * public class Test {
075 *   private int a; // violation, missing javadoc for private member
076 *
077 *   &#47;**
078 *    * Some description here
079 *    *&#47;
080 *   private int b; // OK
081 *   protected int c; // violation, missing javadoc for protected member
082 *   public int d; // violation, missing javadoc for public member
083 *   &#47;*package*&#47; int e; // violation, missing javadoc for package member
084 * }
085 * </pre>
086 * <p>
087 * To configure the check for {@code public} scope:
088 * </p>
089 * <pre>
090 * &lt;module name="JavadocVariable"&gt;
091 *   &lt;property name="scope" value="public"/&gt;
092 * &lt;/module&gt;
093 * </pre>
094 * <p>This setting will report a violation if there is no javadoc for {@code public} member.</p>
095 * <pre>
096 * public class Test {
097 *   private int a; // OK
098 *
099 *   &#47;**
100 *    * Some description here
101 *    *&#47;
102 *   private int b; // OK
103 *   protected int c; // OK
104 *   public int d; // violation, missing javadoc for public member
105 *   &#47;*package*&#47; int e; // OK
106 * }
107 * </pre>
108 * <p>
109 * To configure the check for members which are in {@code private},
110 * but not in {@code protected} scope:
111 * </p>
112 * <pre>
113 * &lt;module name="JavadocVariable"&gt;
114 *   &lt;property name="scope" value="private"/&gt;
115 *   &lt;property name="excludeScope" value="protected"/&gt;
116 * &lt;/module&gt;
117 * </pre>
118 * <p>
119 * This setting will report a violation if there is no javadoc for {@code private}
120 * member and ignores {@code protected} member.
121 * </p>
122 * <pre>
123 * public class Test {
124 *   private int a; // violation, missing javadoc for private member
125 *
126 *   &#47;**
127 *    * Some description here
128 *    *&#47;
129 *   private int b; // OK
130 *   protected int c; // OK
131 *   public int d; // OK
132 *   &#47;*package*&#47; int e; // violation, missing javadoc for package member
133 * }
134 * </pre>
135 * <p>
136 * To ignore absence of Javadoc comments for variables with names {@code log} or {@code logger}:
137 * </p>
138 * <pre>
139 * &lt;module name="JavadocVariable"&gt;
140 *   &lt;property name="ignoreNamePattern" value="log|logger"/&gt;
141 * &lt;/module&gt;
142 * </pre>
143 * <p>
144 * This setting will report a violation if there is no javadoc for any scope
145 * member and ignores members with name {@code log} or {@code logger}.
146 * </p>
147 * <pre>
148 * public class Test {
149 *   private int a; // violation, missing javadoc for private member
150 *
151 *   &#47;**
152 *    * Some description here
153 *    *&#47;
154 *   private int b; // OK
155 *   protected int c; // violation, missing javadoc for protected member
156 *   public int d; // violation, missing javadoc for public member
157 *   &#47;*package*&#47; int e; // violation, missing javadoc for package member
158 *   private int log; // OK
159 *   private int logger; // OK
160 * }
161 * </pre>
162 * <p>
163 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
164 * </p>
165 * <p>
166 * Violation Message Keys:
167 * </p>
168 * <ul>
169 * <li>
170 * {@code javadoc.missing}
171 * </li>
172 * </ul>
173 *
174 * @since 3.0
175 */
176@StatelessCheck
177public class JavadocVariableCheck
178    extends AbstractCheck {
179
180    /**
181     * A key is pointing to the warning message text in "messages.properties"
182     * file.
183     */
184    public static final String MSG_JAVADOC_MISSING = "javadoc.missing";
185
186    /** Specify the visibility scope where Javadoc comments are checked. */
187    private Scope scope = Scope.PRIVATE;
188
189    /** Specify the visibility scope where Javadoc comments are not checked. */
190    private Scope excludeScope;
191
192    /** Specify the regexp to define variable names to ignore. */
193    private Pattern ignoreNamePattern;
194
195    /**
196     * Setter to specify the visibility scope where Javadoc comments are checked.
197     *
198     * @param scope a scope.
199     */
200    public void setScope(Scope scope) {
201        this.scope = scope;
202    }
203
204    /**
205     * Setter to specify the visibility scope where Javadoc comments are not checked.
206     *
207     * @param excludeScope a scope.
208     */
209    public void setExcludeScope(Scope excludeScope) {
210        this.excludeScope = excludeScope;
211    }
212
213    /**
214     * Setter to specify the regexp to define variable names to ignore.
215     *
216     * @param pattern a pattern.
217     */
218    public void setIgnoreNamePattern(Pattern pattern) {
219        ignoreNamePattern = pattern;
220    }
221
222    @Override
223    public int[] getDefaultTokens() {
224        return getAcceptableTokens();
225    }
226
227    @Override
228    public int[] getAcceptableTokens() {
229        return new int[] {
230            TokenTypes.VARIABLE_DEF,
231            TokenTypes.ENUM_CONSTANT_DEF,
232        };
233    }
234
235    /*
236     * Skipping enum values is requested.
237     * Checkstyle's issue #1669: https://github.com/checkstyle/checkstyle/issues/1669
238     */
239    @Override
240    public int[] getRequiredTokens() {
241        return new int[] {
242            TokenTypes.VARIABLE_DEF,
243        };
244    }
245
246    // suppress deprecation until https://github.com/checkstyle/checkstyle/issues/11166
247    @SuppressWarnings("deprecation")
248    @Override
249    public void visitToken(DetailAST ast) {
250        if (shouldCheck(ast)) {
251            final FileContents contents = getFileContents();
252            final TextBlock textBlock =
253                contents.getJavadocBefore(ast.getLineNo());
254
255            if (textBlock == null) {
256                log(ast, MSG_JAVADOC_MISSING);
257            }
258        }
259    }
260
261    /**
262     * Decides whether the variable name of an AST is in the ignore list.
263     *
264     * @param ast the AST to check
265     * @return true if the variable name of ast is in the ignore list.
266     */
267    private boolean isIgnored(DetailAST ast) {
268        final String name = ast.findFirstToken(TokenTypes.IDENT).getText();
269        return ignoreNamePattern != null && ignoreNamePattern.matcher(name).matches()
270            || "serialVersionUID".equals(name);
271    }
272
273    /**
274     * Whether we should check this node.
275     *
276     * @param ast a given node.
277     * @return whether we should check a given node.
278     */
279    private boolean shouldCheck(final DetailAST ast) {
280        boolean result = false;
281        if (!ScopeUtil.isInCodeBlock(ast) && !isIgnored(ast)) {
282            final Scope customScope = ScopeUtil.getScope(ast);
283            final Scope surroundingScope = ScopeUtil.getSurroundingScope(ast);
284            result = customScope.isIn(scope) && surroundingScope.isIn(scope)
285                && (excludeScope == null
286                    || !customScope.isIn(excludeScope)
287                    || !surroundingScope.isIn(excludeScope));
288        }
289        return result;
290    }
291
292}