View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 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.javadoc;
21  
22  import java.util.regex.Pattern;
23  
24  import com.puppycrawl.tools.checkstyle.StatelessCheck;
25  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
26  import com.puppycrawl.tools.checkstyle.api.DetailAST;
27  import com.puppycrawl.tools.checkstyle.api.FileContents;
28  import com.puppycrawl.tools.checkstyle.api.Scope;
29  import com.puppycrawl.tools.checkstyle.api.TextBlock;
30  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
31  import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;
32  
33  /**
34   * <div>
35   * Checks that a variable has a Javadoc comment. Ignores {@code serialVersionUID} fields.
36   * </div>
37   * <ul>
38   * <li>
39   * Property {@code excludeScope} - Specify the visibility scope where Javadoc
40   * comments are not checked.
41   * Type is {@code com.puppycrawl.tools.checkstyle.api.Scope}.
42   * Default value is {@code null}.
43   * </li>
44   * <li>
45   * Property {@code ignoreNamePattern} - Specify the regexp to define variable names to ignore.
46   * Type is {@code java.util.regex.Pattern}.
47   * Default value is {@code null}.
48   * </li>
49   * <li>
50   * Property {@code scope} - Specify the visibility scope where Javadoc comments are checked.
51   * Type is {@code com.puppycrawl.tools.checkstyle.api.Scope}.
52   * Default value is {@code private}.
53   * </li>
54   * <li>
55   * Property {@code tokens} - tokens to check
56   * Type is {@code java.lang.String[]}.
57   * Validation type is {@code tokenSet}.
58   * Default value is:
59   * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_CONSTANT_DEF">
60   * ENUM_CONSTANT_DEF</a>.
61   * </li>
62   * </ul>
63   *
64   * <p>
65   * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
66   * </p>
67   *
68   * <p>
69   * Violation Message Keys:
70   * </p>
71   * <ul>
72   * <li>
73   * {@code javadoc.missing}
74   * </li>
75   * </ul>
76   *
77   * @since 3.0
78   */
79  @StatelessCheck
80  public class JavadocVariableCheck
81      extends AbstractCheck {
82  
83      /**
84       * A key is pointing to the warning message text in "messages.properties"
85       * file.
86       */
87      public static final String MSG_JAVADOC_MISSING = "javadoc.missing";
88  
89      /** Specify the visibility scope where Javadoc comments are checked. */
90      private Scope scope = Scope.PRIVATE;
91  
92      /** Specify the visibility scope where Javadoc comments are not checked. */
93      private Scope excludeScope;
94  
95      /** Specify the regexp to define variable names to ignore. */
96      private Pattern ignoreNamePattern;
97  
98      /**
99       * Setter to specify the visibility scope where Javadoc comments are checked.
100      *
101      * @param scope a scope.
102      * @since 3.0
103      */
104     public void setScope(Scope scope) {
105         this.scope = scope;
106     }
107 
108     /**
109      * Setter to specify the visibility scope where Javadoc comments are not checked.
110      *
111      * @param excludeScope a scope.
112      * @since 3.4
113      */
114     public void setExcludeScope(Scope excludeScope) {
115         this.excludeScope = excludeScope;
116     }
117 
118     /**
119      * Setter to specify the regexp to define variable names to ignore.
120      *
121      * @param pattern a pattern.
122      * @since 5.8
123      */
124     public void setIgnoreNamePattern(Pattern pattern) {
125         ignoreNamePattern = pattern;
126     }
127 
128     @Override
129     public int[] getDefaultTokens() {
130         return getAcceptableTokens();
131     }
132 
133     @Override
134     public int[] getAcceptableTokens() {
135         return new int[] {
136             TokenTypes.VARIABLE_DEF,
137             TokenTypes.ENUM_CONSTANT_DEF,
138         };
139     }
140 
141     /*
142      * Skipping enum values is requested.
143      * Checkstyle's issue #1669: https://github.com/checkstyle/checkstyle/issues/1669
144      */
145     @Override
146     public int[] getRequiredTokens() {
147         return new int[] {
148             TokenTypes.VARIABLE_DEF,
149         };
150     }
151 
152     // suppress deprecation until https://github.com/checkstyle/checkstyle/issues/11166
153     @SuppressWarnings("deprecation")
154     @Override
155     public void visitToken(DetailAST ast) {
156         if (shouldCheck(ast)) {
157             final FileContents contents = getFileContents();
158             final TextBlock textBlock =
159                 contents.getJavadocBefore(ast.getLineNo());
160 
161             if (textBlock == null) {
162                 log(ast, MSG_JAVADOC_MISSING);
163             }
164         }
165     }
166 
167     /**
168      * Decides whether the variable name of an AST is in the ignore list.
169      *
170      * @param ast the AST to check
171      * @return true if the variable name of ast is in the ignore list.
172      */
173     private boolean isIgnored(DetailAST ast) {
174         final String name = ast.findFirstToken(TokenTypes.IDENT).getText();
175         return ignoreNamePattern != null && ignoreNamePattern.matcher(name).matches()
176             || "serialVersionUID".equals(name);
177     }
178 
179     /**
180      * Whether we should check this node.
181      *
182      * @param ast a given node.
183      * @return whether we should check a given node.
184      */
185     private boolean shouldCheck(final DetailAST ast) {
186         boolean result = false;
187         if (!ScopeUtil.isInCodeBlock(ast) && !isIgnored(ast)) {
188             final Scope customScope = ScopeUtil.getScope(ast);
189             final Scope surroundingScope = ScopeUtil.getSurroundingScope(ast);
190             result = customScope.isIn(scope) && surroundingScope.isIn(scope)
191                 && (excludeScope == null
192                     || !customScope.isIn(excludeScope)
193                     || !surroundingScope.isIn(excludeScope));
194         }
195         return result;
196     }
197 
198 }