DescendantTokenCheck.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
com.puppycrawl.tools.checkstyle.checks |
![]() |
![]() |
Checkstyle |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2007 Oliver Burn
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle.checks;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Set;
import antlr.collections.AST;
import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
/**
* <p>
* Checks for restricted tokens beneath other tokens.
* </p>
* <p>
* Examples of how to configure the check:
* </p>
* <pre>
* <!-- String literal equality check -->
* <module name="DescendantToken">
* <property name="tokens" value="EQUAL,NOT_EQUAL"/>
* <property name="limitedTokens" value="STRING_LITERAL"/>
* <property name="maximumNumber" value="0"/>
* <property name="maximumDepth" value="1"/>
* </module>
*
* <!-- Switch with no default -->
* <module name="DescendantToken">
* <property name="tokens" value="LITERAL_SWITCH"/>
* <property name="maximumDepth" value="2"/>
* <property name="limitedTokens" value="LITERAL_DEFAULT"/>
* <property name="minimumNumber" value="1"/>
* </module>
*
* <!-- Assert statement may have side effects -->
* <module name="DescendantToken">
* <property name="tokens" value="LITERAL_ASSERT"/>
* <property name="limitedTokens" value="ASSIGN,DEC,INC,POST_DEC,
* POST_INC,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,DIV_ASSIGN,MOD_ASSIGN,
* BSR_ASSIGN,SR_ASSIGN,SL_ASSIGN,BAND_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,
* METHOD_CALL"/>
* <property name="maximumNumber" value="0"/>
* </module>
*
* <!-- Initialiser in for performs no setup - use while instead? -->
* <module name="DescendantToken">
* <property name="tokens" value="FOR_INIT"/>
* <property name="limitedTokens" value="EXPR"/>
* <property name="minimumNumber" value="1"/>
* </module>
*
* <!-- Condition in for performs no check -->
* <module name="DescendantToken">
* <property name="tokens" value="FOR_CONDITION"/>
* <property name="limitedTokens" value="EXPR"/>
* <property name="minimumNumber" value="1"/>
* </module>
*
* <!-- Switch within switch -->
* <module name="DescendantToken">
* <property name="tokens" value="LITERAL_SWITCH"/>
* <property name="limitedTokens" value="LITERAL_SWITCH"/>
* <property name="maximumNumber" value="0"/>
* <property name="minimumDepth" value="1"/>
* </module>
*
* <!-- Return from within a catch or finally block -->
* <module name="DescendantToken">
* <property name="tokens" value="LITERAL_FINALLY,LITERAL_CATCH"/>
* <property name="limitedTokens" value="LITERAL_RETURN"/>
* <property name="maximumNumber" value="0"/>
* </module>
*
* <!-- Try within catch or finally block -->
* <module name="DescendantToken">
* <property name="tokens" value="LITERAL_CATCH,LITERAL_FINALLY"/>
* <property name="limitedTokens" value="LITERAL_TRY"/>
* <property name="maximumNumber" value="0"/>
* </module>
*
* <!-- Too many cases within a switch -->
* <module name="DescendantToken">
* <property name="tokens" value="LITERAL_SWITCH"/>
* <property name="limitedTokens" value="LITERAL_CASE"/>
* <property name="maximumDepth" value="2"/>
* <property name="maximumNumber" value="10"/>
* </module>
*
* <!-- Too many local variables within a method -->
* <module name="DescendantToken">
* <property name="tokens" value="METHOD_DEF"/>
* <property name="limitedTokens" value="VARIABLE_DEF"/>
* <property name="maximumDepth" value="2"/>
* <property name="maximumNumber" value="10"/>
* </module>
*
* <!-- Too many returns from within a method -->
* <module name="DescendantToken">
* <property name="tokens" value="METHOD_DEF"/>
* <property name="limitedTokens" value="LITERAL_RETURN"/>
* <property name="maximumNumber" value="3"/>
* </module>
*
* <!-- Too many fields within an interface -->
* <module name="DescendantToken">
* <property name="tokens" value="INTERFACE_DEF"/>
* <property name="limitedTokens" value="VARIABLE_DEF"/>
* <property name="maximumDepth" value="2"/>
* <property name="maximumNumber" value="0"/>
* </module>
*
* <!-- Limit the number of exceptions a method can throw -->
* <module name="DescendantToken">
* <property name="tokens" value="LITERAL_THROWS"/>
* <property name="limitedTokens" value="IDENT"/>
* <property name="maximumNumber" value="1"/>
* </module>
*
* <!-- Limit the number of expressions in a method -->
* <module name="DescendantToken">
* <property name="tokens" value="METHOD_DEF"/>
* <property name="limitedTokens" value="EXPR"/>
* <property name="maximumNumber" value="200"/>
* </module>
*
* <!-- Disallow empty statements -->
* <module name="DescendantToken">
* <property name="tokens" value="EMPTY_STAT"/>
* <property name="limitedTokens" value="EMPTY_STAT"/>
* <property name="maximumNumber" value="0"/>
* <property name="maximumDepth" value="0"/>
* <property name="maximumMessage"
* value="Empty statement is not allowed."/>
* </module>
*
* <!-- Too many fields within a class -->
* <module name="DescendantToken">
* <property name="tokens" value="CLASS_DEF"/>
* <property name="limitedTokens" value="VARIABLE_DEF"/>
* <property name="maximumDepth" value="2"/>
* <property name="maximumNumber" value="10"/>
* </module>
* </pre>
*
* @author Tim Tyler <tim@tt1.org>
* @author Rick Giles
*/
public class DescendantTokenCheck extends Check
{
/** minimum depth */
private int mMinimumDepth;
/** maximum depth */
private int mMaximumDepth = Integer.MAX_VALUE;
/** minimum number */
private int mMinimumNumber;
/** maximum number */
private int mMaximumNumber = Integer.MAX_VALUE;
/** limited tokens */
private int[] mLimitedTokens = new int[0];
/** error message when minimum count not reached */
private String mMinimumMessage = "descendant.token.min";
/** error message when maximum count exceeded */
private String mMaximumMessage = "descendant.token.max";
/**
* Counts of descendant tokens.
* Indexed by (token ID - 1) for performance.
*/
private int[] mCounts = new int[0];
/** {@inheritDoc} */
public int[] getDefaultTokens()
{
return new int[0];
}
/** {@inheritDoc} */
public void visitToken(DetailAST aAST)
{
//reset counts
Arrays.fill(mCounts, 0);
countTokens(aAST, 0);
// name of this token
final String name = TokenTypes.getTokenName(aAST.getType());
for (int i = 0; i < mLimitedTokens.length; i++) {
final int tokenCount = mCounts[mLimitedTokens[i] - 1];
if (tokenCount < mMinimumNumber) {
final String descendantName =
TokenTypes.getTokenName(mLimitedTokens[i]);
log(aAST.getLineNo(),
aAST.getColumnNo(),
mMinimumMessage,
new String[] {
"" + tokenCount,
"" + mMinimumNumber,
name,
descendantName,
});
}
if (tokenCount > mMaximumNumber) {
final String descendantName =
TokenTypes.getTokenName(mLimitedTokens[i]);
log(aAST.getLineNo(),
aAST.getColumnNo(),
mMaximumMessage,
new String[] {
"" + tokenCount,
"" + mMaximumNumber,
name,
descendantName,
});
}
}
}
/**
* Counts the number of occurrences of descendant tokens.
* @param aAST the root token for descendants.
* @param aDepth the maximum depth of the counted descendants.
*/
private void countTokens(AST aAST, int aDepth)
{
if (aDepth <= mMaximumDepth) {
//update count
if (aDepth >= mMinimumDepth) {
final int type = aAST.getType();
if (type <= mCounts.length) {
mCounts[type - 1]++;
}
}
AST child = aAST.getFirstChild();
final int nextDepth = aDepth + 1;
while (child != null) {
countTokens(child, nextDepth);
child = child.getNextSibling();
}
}
}
/** {@inheritDoc} */
public int[] getAcceptableTokens()
{
// Any tokens set by property 'tokens' are acceptable
final Set tokenNames = getTokenNames();
final int[] result = new int[tokenNames.size()];
int i = 0;
final Iterator it = tokenNames.iterator();
while (it.hasNext()) {
final String name = (String) it.next();
result[i] = TokenTypes.getTokenId(name);
i++;
}
return result;
}
/**
* Sets the tokens which occurance as descendant is limited.
* @param aLimitedTokens - list of tokens to ignore.
*/
public void setLimitedTokens(String[] aLimitedTokens)
{
mLimitedTokens = new int[aLimitedTokens.length];
int maxToken = 0;
for (int i = 0; i < aLimitedTokens.length; i++) {
mLimitedTokens[i] = TokenTypes.getTokenId(aLimitedTokens[i]);
if (mLimitedTokens[i] > maxToken) {
maxToken = mLimitedTokens[i];
}
}
mCounts = new int[maxToken];
}
/**
* Sets the mimimum depth for descendant counts.
* @param aMinimumDepth the mimimum depth for descendant counts.
*/
public void setMinimumDepth(int aMinimumDepth)
{
mMinimumDepth = aMinimumDepth;
}
/**
* Sets the maximum depth for descendant counts.
* @param aMaximumDepth the maximum depth for descendant counts.
*/
public void setMaximumDepth(int aMaximumDepth)
{
mMaximumDepth = aMaximumDepth;
}
/**
* Sets a minimum count for descendants.
* @param aMinimumNumber the minimum count for descendants.
*/
public void setMinimumNumber(int aMinimumNumber)
{
mMinimumNumber = aMinimumNumber;
}
/**
* Sets a maximum count for descendants.
* @param aMaximumNumber the maximum count for descendants.
*/
public void setMaximumNumber(int aMaximumNumber)
{
mMaximumNumber = aMaximumNumber;
}
/**
* Sets the error message for minimum count not reached.
* @param aMessage the error message for minimum count not reached.
* Used as a <code>MessageFormat</code> pattern with arguments
* <ul>
* <li>{0} - token count</li>
* <li>{1} - minimum number</li>
* <li>{2} - name of token</li>
* <li>{3} - name of limited token</li>
* </ul>
*/
public void setMinimumMessage(String aMessage)
{
mMinimumMessage = aMessage;
}
/**
* Sets the error message for maximum count exceeded.
* @param aMessage the error message for maximum count exceeded.
* Used as a <code>MessageFormat</code> pattern with arguments
* <ul>
* <li>{0} - token count</li>
* <li>{1} - maximum number</li>
* <li>{2} - name of token</li>
* <li>{3} - name of limited token</li>
* </ul>
*/
public void setMaximumMessage(String aMessage)
{
mMaximumMessage = aMessage;
}
}
The table below shows all metrics for DescendantTokenCheck.java.




