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