001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2014  Oliver Burn
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////////////////////////////////////////////////////////////////////////////////
019package com.puppycrawl.tools.checkstyle.checks.javadoc;
020
021import com.puppycrawl.tools.checkstyle.api.Check;
022import com.puppycrawl.tools.checkstyle.api.DetailAST;
023import com.puppycrawl.tools.checkstyle.api.FileContents;
024import com.puppycrawl.tools.checkstyle.api.Scope;
025import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
026import com.puppycrawl.tools.checkstyle.api.TextBlock;
027import com.puppycrawl.tools.checkstyle.api.TokenTypes;
028
029import java.util.regex.Pattern;
030
031/**
032 * Checks that a variable has Javadoc comment.
033 *
034 * @author Oliver Burn
035 * @version 1.0
036 */
037public class JavadocVariableCheck
038    extends Check
039{
040    /** the scope to check */
041    private Scope scope = Scope.PRIVATE;
042
043    /** the visibility scope where Javadoc comments shouldn't be checked **/
044    private Scope excludeScope;
045
046    /** the regular expression to ignore variable name */
047    private String ignoreNameRegexp;
048
049    /** the pattern to ignore variable name */
050    private Pattern ignoreNamePattern;
051
052    /**
053     * Sets the scope to check.
054     * @param from string to get the scope from
055     */
056    public void setScope(String from)
057    {
058        scope = Scope.getInstance(from);
059    }
060
061    /**
062     * Set the excludeScope.
063     * @param scope a <code>String</code> value
064     */
065    public void setExcludeScope(String scope)
066    {
067        excludeScope = Scope.getInstance(scope);
068    }
069
070    /**
071     * Sets the variable names to ignore in the check.
072     * @param regexp regexp to define variable names to ignore.
073     */
074    public void setIgnoreNamePattern(String regexp)
075    {
076        ignoreNameRegexp = regexp;
077        if (!(regexp == null || regexp.length() == 0)) {
078            ignoreNamePattern = Pattern.compile(regexp);
079        }
080        else {
081            ignoreNamePattern = null;
082        }
083    }
084
085    /**
086     * Gets the variable names to ignore in the check.
087     * @return true regexp string to define variable names to ignore.
088     */
089    public String getIgnoreNamePattern()
090    {
091        return ignoreNameRegexp;
092    }
093
094    @Override
095    public int[] getDefaultTokens()
096    {
097        return new int[] {
098            TokenTypes.VARIABLE_DEF,
099            TokenTypes.ENUM_CONSTANT_DEF,
100        };
101    }
102
103    @Override
104    public void visitToken(DetailAST ast)
105    {
106        if (shouldCheck(ast)) {
107            final FileContents contents = getFileContents();
108            final TextBlock cmt =
109                contents.getJavadocBefore(ast.getLineNo());
110
111            if (cmt == null) {
112                log(ast, "javadoc.missing");
113            }
114        }
115    }
116
117    /**
118     * Decides whether the variable name of an AST is in the ignore list.
119     * @param ast the AST to check
120     * @return true if the variable name of ast is in the ignore list.
121     */
122    private boolean isIgnored(DetailAST ast)
123    {
124        final String name = ast.findFirstToken(TokenTypes.IDENT).getText();
125        return ignoreNamePattern != null
126                && ignoreNamePattern.matcher(name).matches();
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    {
136        if (ScopeUtils.inCodeBlock(ast) || isIgnored(ast)) {
137            return false;
138        }
139
140        final Scope scope;
141        if (ast.getType() == TokenTypes.ENUM_CONSTANT_DEF) {
142            scope = Scope.PUBLIC;
143        }
144        else {
145            final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS);
146            final Scope declaredScope = ScopeUtils.getScopeFromMods(mods);
147            scope =
148                ScopeUtils.inInterfaceOrAnnotationBlock(ast)
149                    ? Scope.PUBLIC : declaredScope;
150        }
151
152        final Scope surroundingScope = ScopeUtils.getSurroundingScope(ast);
153
154        return scope.isIn(this.scope) && surroundingScope.isIn(this.scope)
155            && ((excludeScope == null)
156                || !scope.isIn(excludeScope)
157                || !surroundingScope.isIn(excludeScope));
158    }
159}