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 * <module name="JavadocVariable"/> 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 * /** 078 * * Some description here 079 * */ 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 * /*package*/ 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 * <module name="JavadocVariable"> 091 * <property name="scope" value="public"/> 092 * </module> 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 * /** 100 * * Some description here 101 * */ 102 * private int b; // OK 103 * protected int c; // OK 104 * public int d; // violation, missing javadoc for public member 105 * /*package*/ 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 * <module name="JavadocVariable"> 114 * <property name="scope" value="private"/> 115 * <property name="excludeScope" value="protected"/> 116 * </module> 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 * /** 127 * * Some description here 128 * */ 129 * private int b; // OK 130 * protected int c; // OK 131 * public int d; // OK 132 * /*package*/ 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 * <module name="JavadocVariable"> 140 * <property name="ignoreNamePattern" value="log|logger"/> 141 * </module> 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 * /** 152 * * Some description here 153 * */ 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 * /*package*/ 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}