001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2020 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 * Default value is {@code private}. 041 * </li> 042 * <li> 043 * Property {@code excludeScope} - Specify the visibility scope where Javadoc 044 * comments are not checked. 045 * Default value is {@code null}. 046 * </li> 047 * <li> 048 * Property {@code ignoreNamePattern} - Specify the regexp to define variable names to ignore. 049 * Default value is {@code null}. 050 * </li> 051 * <li> 052 * Property {@code tokens} - tokens to check Default value is: 053 * <a href="https://checkstyle.org/apidocs/com/puppycrawl/tools/checkstyle/api/TokenTypes.html#ENUM_CONSTANT_DEF"> 054 * ENUM_CONSTANT_DEF</a>. 055 * </li> 056 * </ul> 057 * <p> 058 * To configure the default check: 059 * </p> 060 * <pre> 061 * <module name="JavadocVariable"/> 062 * </pre> 063 * <p> 064 * To configure the check for {@code public} scope: 065 * </p> 066 * <pre> 067 * <module name="JavadocVariable"> 068 * <property name="scope" value="public"/> 069 * </module> 070 * </pre> 071 * <p> 072 * To configure the check for members which are in {@code private}, 073 * but not in {@code protected} scope: 074 * </p> 075 * <pre> 076 * <module name="JavadocVariable"> 077 * <property name="scope" value="private"/> 078 * <property name="excludeScope" value="protected"/> 079 * </module> 080 * </pre> 081 * <p> 082 * To ignore absence of Javadoc comments for variables with names {@code log} or {@code logger}: 083 * </p> 084 * <pre> 085 * <module name="JavadocVariable"> 086 * <property name="ignoreNamePattern" value="log|logger"/> 087 * </module> 088 * </pre> 089 * 090 * @since 3.0 091 */ 092@StatelessCheck 093public class JavadocVariableCheck 094 extends AbstractCheck { 095 096 /** 097 * A key is pointing to the warning message text in "messages.properties" 098 * file. 099 */ 100 public static final String MSG_JAVADOC_MISSING = "javadoc.missing"; 101 102 /** Specify the visibility scope where Javadoc comments are checked. */ 103 private Scope scope = Scope.PRIVATE; 104 105 /** Specify the visibility scope where Javadoc comments are not checked. */ 106 private Scope excludeScope; 107 108 /** Specify the regexp to define variable names to ignore. */ 109 private Pattern ignoreNamePattern; 110 111 /** 112 * Setter to specify the visibility scope where Javadoc comments are checked. 113 * 114 * @param scope a scope. 115 */ 116 public void setScope(Scope scope) { 117 this.scope = scope; 118 } 119 120 /** 121 * Setter to specify the visibility scope where Javadoc comments are not checked. 122 * 123 * @param excludeScope a scope. 124 */ 125 public void setExcludeScope(Scope excludeScope) { 126 this.excludeScope = excludeScope; 127 } 128 129 /** 130 * Setter to specify the regexp to define variable names to ignore. 131 * 132 * @param pattern a pattern. 133 */ 134 public void setIgnoreNamePattern(Pattern pattern) { 135 ignoreNamePattern = pattern; 136 } 137 138 @Override 139 public int[] getDefaultTokens() { 140 return getAcceptableTokens(); 141 } 142 143 @Override 144 public int[] getAcceptableTokens() { 145 return new int[] { 146 TokenTypes.VARIABLE_DEF, 147 TokenTypes.ENUM_CONSTANT_DEF, 148 }; 149 } 150 151 /* 152 * Skipping enum values is requested. 153 * Checkstyle's issue #1669: https://github.com/checkstyle/checkstyle/issues/1669 154 */ 155 @Override 156 public int[] getRequiredTokens() { 157 return new int[] { 158 TokenTypes.VARIABLE_DEF, 159 }; 160 } 161 162 @Override 163 public void visitToken(DetailAST ast) { 164 if (shouldCheck(ast)) { 165 final FileContents contents = getFileContents(); 166 final TextBlock textBlock = 167 contents.getJavadocBefore(ast.getLineNo()); 168 169 if (textBlock == null) { 170 log(ast, MSG_JAVADOC_MISSING); 171 } 172 } 173 } 174 175 /** 176 * Decides whether the variable name of an AST is in the ignore list. 177 * @param ast the AST to check 178 * @return true if the variable name of ast is in the ignore list. 179 */ 180 private boolean isIgnored(DetailAST ast) { 181 final String name = ast.findFirstToken(TokenTypes.IDENT).getText(); 182 return ignoreNamePattern != null && ignoreNamePattern.matcher(name).matches() 183 || "serialVersionUID".equals(name); 184 } 185 186 /** 187 * Whether we should check this node. 188 * @param ast a given node. 189 * @return whether we should check a given node. 190 */ 191 private boolean shouldCheck(final DetailAST ast) { 192 boolean result = false; 193 if (!ScopeUtil.isInCodeBlock(ast) && !isIgnored(ast)) { 194 Scope customScope = Scope.PUBLIC; 195 if (ast.getType() != TokenTypes.ENUM_CONSTANT_DEF 196 && !ScopeUtil.isInInterfaceOrAnnotationBlock(ast)) { 197 final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS); 198 customScope = ScopeUtil.getScopeFromMods(mods); 199 } 200 201 final Scope surroundingScope = ScopeUtil.getSurroundingScope(ast); 202 result = customScope.isIn(scope) && surroundingScope.isIn(scope) 203 && (excludeScope == null 204 || !customScope.isIn(excludeScope) 205 || !surroundingScope.isIn(excludeScope)); 206 } 207 return result; 208 } 209 210}