001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2016 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.api.AbstractCheck; 025import com.puppycrawl.tools.checkstyle.api.DetailAST; 026import com.puppycrawl.tools.checkstyle.api.FileContents; 027import com.puppycrawl.tools.checkstyle.api.Scope; 028import com.puppycrawl.tools.checkstyle.api.TextBlock; 029import com.puppycrawl.tools.checkstyle.api.TokenTypes; 030import com.puppycrawl.tools.checkstyle.utils.CommonUtils; 031import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; 032 033/** 034 * Checks that a variable has Javadoc comment. Ignores <code>serialVersionUID</code> fields. 035 * 036 * @author Oliver Burn 037 */ 038public class JavadocVariableCheck 039 extends AbstractCheck { 040 041 /** 042 * A key is pointing to the warning message text in "messages.properties" 043 * file. 044 */ 045 public static final String MSG_JAVADOC_MISSING = "javadoc.missing"; 046 047 /** The scope to check. */ 048 private Scope scope = Scope.PRIVATE; 049 050 /** The visibility scope where Javadoc comments shouldn't be checked. **/ 051 private Scope excludeScope; 052 053 /** The pattern to ignore variable name. */ 054 private Pattern ignoreNamePattern; 055 056 /** 057 * Sets the scope to check. 058 * @param from string to get the scope from 059 */ 060 public void setScope(String from) { 061 scope = Scope.getInstance(from); 062 } 063 064 /** 065 * Set the excludeScope. 066 * @param excludeScope a {@code String} value 067 */ 068 public void setExcludeScope(String excludeScope) { 069 this.excludeScope = Scope.getInstance(excludeScope); 070 } 071 072 /** 073 * Sets the variable names to ignore in the check. 074 * @param regexp regular expression to define variable names to ignore. 075 * @throws org.apache.commons.beanutils.ConversionException if unable to create Pattern object. 076 */ 077 public void setIgnoreNamePattern(String regexp) { 078 ignoreNamePattern = CommonUtils.createPattern(regexp); 079 } 080 081 @Override 082 public int[] getDefaultTokens() { 083 return getAcceptableTokens(); 084 } 085 086 @Override 087 public int[] getAcceptableTokens() { 088 return new int[] { 089 TokenTypes.VARIABLE_DEF, 090 TokenTypes.ENUM_CONSTANT_DEF, 091 }; 092 } 093 094 /* 095 * Skipping enum values is requested. 096 * Checkstyle's issue #1669: https://github.com/checkstyle/checkstyle/issues/1669 097 */ 098 @Override 099 public int[] getRequiredTokens() { 100 return new int[] { 101 TokenTypes.VARIABLE_DEF, 102 }; 103 } 104 105 @Override 106 public void visitToken(DetailAST ast) { 107 if (shouldCheck(ast)) { 108 final FileContents contents = getFileContents(); 109 final TextBlock textBlock = 110 contents.getJavadocBefore(ast.getLineNo()); 111 112 if (textBlock == null) { 113 log(ast, MSG_JAVADOC_MISSING); 114 } 115 } 116 } 117 118 /** 119 * Decides whether the variable name of an AST is in the ignore list. 120 * @param ast the AST to check 121 * @return true if the variable name of ast is in the ignore list. 122 */ 123 private boolean isIgnored(DetailAST ast) { 124 final String name = ast.findFirstToken(TokenTypes.IDENT).getText(); 125 return ignoreNamePattern != null && ignoreNamePattern.matcher(name).matches() 126 || "serialVersionUID".equals(name); 127 } 128 129 /** 130 * Whether we should check this node. 131 * @param ast a given node. 132 * @return whether we should check a given node. 133 */ 134 private boolean shouldCheck(final DetailAST ast) { 135 if (ScopeUtils.isInCodeBlock(ast) || isIgnored(ast)) { 136 return false; 137 } 138 139 final Scope customScope; 140 if (ast.getType() == TokenTypes.ENUM_CONSTANT_DEF) { 141 customScope = Scope.PUBLIC; 142 } 143 else { 144 final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS); 145 final Scope declaredScope = ScopeUtils.getScopeFromMods(mods); 146 147 if (ScopeUtils.isInInterfaceOrAnnotationBlock(ast)) { 148 customScope = Scope.PUBLIC; 149 } 150 else { 151 customScope = declaredScope; 152 } 153 } 154 155 final Scope surroundingScope = ScopeUtils.getSurroundingScope(ast); 156 157 return customScope.isIn(scope) && surroundingScope.isIn(scope) 158 && (excludeScope == null 159 || !customScope.isIn(excludeScope) 160 || !surroundingScope.isIn(excludeScope)); 161 } 162}