Issue #2451: removed excess hierarchy from CyclomaticComplexityCheck

This commit is contained in:
rnveach 2015-11-17 07:26:56 -05:00 committed by Roman Ivanov
parent 69ccfd3fa9
commit ed79281fff
3 changed files with 118 additions and 12 deletions

View File

@ -1719,6 +1719,7 @@
<exclude>com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalCheck.class</exclude>
<exclude>com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalMethodCheck.class</exclude>
<exclude>com/puppycrawl/tools/checkstyle/checks/coding/AbstractNestedDepthCheck.class</exclude>
<exclude>com/puppycrawl/tools/checkstyle/checks/metrics/AbstractComplexityCheck.class</exclude>
<exclude>com/puppycrawl/tools/checkstyle/checks/naming/AbstractTypeParameterNameCheck.class</exclude>
</excludes>
</instrumentation>

View File

@ -20,7 +20,10 @@
package com.puppycrawl.tools.checkstyle.checks.metrics;
import java.math.BigInteger;
import java.util.ArrayDeque;
import java.util.Deque;
import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
@ -43,7 +46,7 @@ import com.puppycrawl.tools.checkstyle.api.TokenTypes;
* @author <a href="mailto:andreyselkin@gmail.com">Andrei Selkin</a>
*/
public class CyclomaticComplexityCheck
extends AbstractComplexityCheck {
extends Check {
/**
* A key is pointing to the warning message text in "messages.properties"
@ -51,16 +54,23 @@ public class CyclomaticComplexityCheck
*/
public static final String MSG_KEY = "cyclomaticComplexity";
/** The initial current value. */
private static final BigInteger INITIAL_VALUE = BigInteger.ONE;
/** Default allowed complexity. */
private static final int DEFAULT_VALUE = 10;
private static final int DEFAULT_COMPLEXITY_VALUE = 10;
/** Whether to treat the whole switch block as a single decision point.*/
private boolean switchBlockAsSingleDecisionPoint;
/** Create an instance. */
public CyclomaticComplexityCheck() {
super(DEFAULT_VALUE);
}
/** Stack of values - all but the current value. */
private final Deque<BigInteger> valueStack = new ArrayDeque<>();
/** The current value. */
private BigInteger currentValue = INITIAL_VALUE;
/** Threshold to report error for. */
private int max = DEFAULT_COMPLEXITY_VALUE;
/**
* Sets whether to treat the whole switch block as a single decision point.
@ -71,6 +81,15 @@ public class CyclomaticComplexityCheck
this.switchBlockAsSingleDecisionPoint = switchBlockAsSingleDecisionPoint;
}
/**
* Set the maximum threshold allowed.
*
* @param max the maximum threshold
*/
public final void setMax(int max) {
this.max = max;
}
@Override
public int[] getDefaultTokens() {
return new int[] {
@ -112,6 +131,49 @@ public class CyclomaticComplexityCheck
}
@Override
public final int[] getRequiredTokens() {
return new int[] {
TokenTypes.CTOR_DEF,
TokenTypes.METHOD_DEF,
TokenTypes.INSTANCE_INIT,
TokenTypes.STATIC_INIT,
};
}
@Override
public void visitToken(DetailAST ast) {
switch (ast.getType()) {
case TokenTypes.CTOR_DEF:
case TokenTypes.METHOD_DEF:
case TokenTypes.INSTANCE_INIT:
case TokenTypes.STATIC_INIT:
visitMethodDef();
break;
default:
visitTokenHook(ast);
}
}
@Override
public void leaveToken(DetailAST ast) {
switch (ast.getType()) {
case TokenTypes.CTOR_DEF:
case TokenTypes.METHOD_DEF:
case TokenTypes.INSTANCE_INIT:
case TokenTypes.STATIC_INIT:
leaveMethodDef(ast);
break;
default:
break;
}
}
/**
* Hook called when visiting a token. Will not be called the method
* definition tokens.
*
* @param ast the token being visited
*/
protected final void visitTokenHook(DetailAST ast) {
if (switchBlockAsSingleDecisionPoint) {
if (ast.getType() != TokenTypes.LITERAL_CASE) {
@ -123,13 +185,45 @@ public class CyclomaticComplexityCheck
}
}
@Override
protected final String getMessageID() {
return MSG_KEY;
/**
* Process the end of a method definition.
*
* @param ast the token representing the method definition
*/
private void leaveMethodDef(DetailAST ast) {
final BigInteger bigIntegerMax = BigInteger.valueOf(max);
if (currentValue.compareTo(bigIntegerMax) > 0) {
log(ast, MSG_KEY, currentValue, bigIntegerMax);
}
popValue();
}
@Override
protected void leaveTokenHook(DetailAST ast) {
// no code
/**
* Increments the current value by a specified amount.
*
* @param by the amount to increment by
*/
protected final void incrementCurrentValue(BigInteger by) {
currentValue = currentValue.add(by);
}
/** Push the current value on the stack. */
protected final void pushValue() {
valueStack.push(currentValue);
currentValue = INITIAL_VALUE;
}
/**
* Pops a value off the stack and makes it the current value.
* @return pop a value off the stack and make it the current value
*/
protected final BigInteger popValue() {
currentValue = valueStack.pop();
return currentValue;
}
/** Process the start of the method definition. */
private void visitMethodDef() {
pushValue();
}
}

View File

@ -24,6 +24,7 @@ import static com.puppycrawl.tools.checkstyle.checks.metrics.CyclomaticComplexit
import java.io.File;
import java.io.IOException;
import org.apache.commons.lang3.ArrayUtils;
import org.junit.Assert;
import org.junit.Test;
@ -113,4 +114,14 @@ public class CyclomaticComplexityCheckTest
};
Assert.assertArrayEquals(expected, actual);
}
@Test
public void testHighMax() throws Exception {
final DefaultConfiguration checkConfig =
createCheckConfig(CyclomaticComplexityCheck.class);
checkConfig.addAttribute("max", "100");
final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY;
verify(checkConfig, getPath("InputComplexitySwitchBlocks.java"), expected);
}
}