Added NcssCountRule
This commit is contained in:
@ -28,6 +28,54 @@ import net.sourceforge.pmd.lang.java.oom.api.OperationMetricKey;
|
||||
*/
|
||||
public abstract class AbstractMetric implements Metric {
|
||||
|
||||
protected List<QualifiedName> findAllCalls(ASTMethodOrConstructorDeclaration node) {
|
||||
List<QualifiedName> result = new ArrayList<>();
|
||||
// TODO:cf findAllCalls
|
||||
// Needs TypeRes
|
||||
// Find the qualified names of all methods called in that method's block
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls more specific methods that can be overriden by subclasses.
|
||||
*
|
||||
* @param node The node to check
|
||||
*
|
||||
* @return True if the metric can be computed on this node
|
||||
*/
|
||||
@Override
|
||||
public final boolean supports(AccessNode node) {
|
||||
return node instanceof ASTAnyTypeDeclaration && supports((ASTAnyTypeDeclaration) node)
|
||||
|| node instanceof ASTMethodOrConstructorDeclaration && supports((ASTMethodOrConstructorDeclaration) node);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the metric can be computed on this type declaration. By default, annotation and interface
|
||||
* declarations are filtered out.
|
||||
*
|
||||
* @param node The type declaration
|
||||
*
|
||||
* @return True if the metric can be computed on this type declaration
|
||||
*/
|
||||
protected boolean supports(ASTAnyTypeDeclaration node) {
|
||||
return node.getTypeKind() != TypeKind.ANNOTATION && node.getTypeKind() != TypeKind.INTERFACE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the metric can be computed on this operation. By default, abstract operations are filtered out.
|
||||
*
|
||||
* @param node The operation
|
||||
*
|
||||
* @return True if the metric can be computed on this operation
|
||||
*/
|
||||
protected boolean supports(ASTMethodOrConstructorDeclaration node) {
|
||||
return !node.isAbstract();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gives access to the toplevel package stats to metrics without having to pass them as a parameter to metrics.
|
||||
*
|
||||
@ -63,6 +111,40 @@ public abstract class AbstractMetric implements Metric {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the declaration nodes of all methods or constructors that are declared inside a class.
|
||||
*
|
||||
* @param node The class in which to look for.
|
||||
* @param includeNested Include operations found in nested classes?
|
||||
*
|
||||
* @return The list of all operations declared inside the specified class.
|
||||
*
|
||||
* TODO:cf this one is computed every time
|
||||
*
|
||||
* TODO:cf it might not be at the best place too (used by ClassStats)
|
||||
*/
|
||||
public static List<ASTMethodOrConstructorDeclaration> findOperations(ASTAnyTypeDeclaration node,
|
||||
boolean includeNested) {
|
||||
|
||||
if (includeNested) {
|
||||
return node.findDescendantsOfType(ASTMethodOrConstructorDeclaration.class);
|
||||
}
|
||||
|
||||
List<ASTClassOrInterfaceBodyDeclaration> outerDecls
|
||||
= node.jjtGetChild(0).findChildrenOfType(ASTClassOrInterfaceBodyDeclaration.class);
|
||||
|
||||
|
||||
List<ASTMethodOrConstructorDeclaration> operations = new ArrayList<>();
|
||||
|
||||
for (ASTClassOrInterfaceBodyDeclaration decl : outerDecls) {
|
||||
if (decl.jjtGetChild(0) instanceof ASTMethodOrConstructorDeclaration) {
|
||||
operations.add((ASTMethodOrConstructorDeclaration) decl.jjtGetChild(0));
|
||||
}
|
||||
}
|
||||
return operations;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the average of the value of an operation metric over all operations in this class (excluding nested
|
||||
* classes). The computation is not forced (memoized results are used if they can be found).
|
||||
@ -115,86 +197,4 @@ public abstract class AbstractMetric implements Metric {
|
||||
return highest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the declaration nodes of all methods or constructors that are declared inside a class.
|
||||
*
|
||||
* @param node The class in which to look for.
|
||||
* @param includeNested Include operations found in nested classes?
|
||||
*
|
||||
* @return The list of all operations declared inside the specified class.
|
||||
*
|
||||
* TODO:cf this one is computed every time
|
||||
*
|
||||
* TODO:cf it might not be at the best place too (used by ClassStats)
|
||||
*/
|
||||
public static List<ASTMethodOrConstructorDeclaration> findOperations(ASTAnyTypeDeclaration node,
|
||||
boolean includeNested) {
|
||||
|
||||
if (includeNested) {
|
||||
return node.findDescendantsOfType(ASTMethodOrConstructorDeclaration.class);
|
||||
}
|
||||
|
||||
List<ASTClassOrInterfaceBodyDeclaration> outerDecls
|
||||
= node.jjtGetChild(0).findChildrenOfType(ASTClassOrInterfaceBodyDeclaration.class);
|
||||
|
||||
|
||||
List<ASTMethodOrConstructorDeclaration> operations = new ArrayList<>();
|
||||
|
||||
for (ASTClassOrInterfaceBodyDeclaration decl : outerDecls) {
|
||||
if (decl.jjtGetChild(0) instanceof ASTMethodOrConstructorDeclaration) {
|
||||
operations.add((ASTMethodOrConstructorDeclaration) decl.jjtGetChild(0));
|
||||
}
|
||||
}
|
||||
return operations;
|
||||
}
|
||||
|
||||
|
||||
protected List<QualifiedName> findAllCalls(ASTMethodOrConstructorDeclaration node) {
|
||||
List<QualifiedName> result = new ArrayList<>();
|
||||
// TODO:cf findAllCalls
|
||||
// Needs TypeRes
|
||||
// Find the qualified names of all methods called in that method's block
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calls more specific methods that can be overriden by subclasses.
|
||||
*
|
||||
* @param node The node to check
|
||||
*
|
||||
* @return True if the metric can be computed on this node
|
||||
*/
|
||||
@Override
|
||||
public final boolean supports(AccessNode node) {
|
||||
return node instanceof ASTAnyTypeDeclaration && supports((ASTAnyTypeDeclaration) node)
|
||||
|| node instanceof ASTMethodOrConstructorDeclaration && supports((ASTMethodOrConstructorDeclaration) node);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the metric can be computed on this type declaration. By default, annotation and interface
|
||||
* declarations are filtered out.
|
||||
*
|
||||
* @param node The type declaration
|
||||
*
|
||||
* @return True if the metric can be computed on this type declaration
|
||||
*/
|
||||
protected boolean supports(ASTAnyTypeDeclaration node) {
|
||||
return node.getTypeKind() != TypeKind.ANNOTATION && node.getTypeKind() != TypeKind.INTERFACE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the metric can be computed on this operation. By default, abstract operations are filtered out.
|
||||
*
|
||||
* @param node The operation
|
||||
*
|
||||
* @return True if the metric can be computed on this operation
|
||||
*/
|
||||
protected boolean supports(ASTMethodOrConstructorDeclaration node) {
|
||||
return !node.isAbstract();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ import net.sourceforge.pmd.lang.java.oom.signature.OperationSignature;
|
||||
*/
|
||||
/* default */ double compute(ClassMetricKey key, ASTAnyTypeDeclaration node, boolean force, MetricVersion version) {
|
||||
|
||||
ParameterizedMetricKey paramKey = ParameterizedMetricKey.build(key, version);
|
||||
ParameterizedMetricKey paramKey = ParameterizedMetricKey.getInstance(key, version);
|
||||
// if memo.get(key) == null then the metric has never been computed. NaN is a valid value.
|
||||
Double prev = memo.get(paramKey);
|
||||
if (!force && prev != null) {
|
||||
|
@ -35,8 +35,7 @@ public final class Metrics {
|
||||
*
|
||||
* @return The top level package stats
|
||||
*/
|
||||
/* default */
|
||||
static PackageStats getTopLevelPackageStats() {
|
||||
/* default */ static PackageStats getTopLevelPackageStats() {
|
||||
return TOP_LEVEL_PACKAGE;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ import net.sourceforge.pmd.lang.java.oom.api.OperationMetricKey;
|
||||
/* default */ double compute(OperationMetricKey key, ASTMethodOrConstructorDeclaration node, boolean force,
|
||||
MetricVersion version) {
|
||||
|
||||
ParameterizedMetricKey paramKey = ParameterizedMetricKey.build(key, version);
|
||||
ParameterizedMetricKey paramKey = ParameterizedMetricKey.getInstance(key, version);
|
||||
Double prev = memo.get(paramKey);
|
||||
if (!force && prev != null) {
|
||||
return prev;
|
||||
|
@ -39,6 +39,22 @@ public final class PackageStats {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the signature of the operation designated by the qualified name is covered by
|
||||
* the mask.
|
||||
*
|
||||
* @param qname The operation to test
|
||||
* @param sigMask The signature mask to use
|
||||
*
|
||||
* @return True if the signature of the operation designated by the qualified name is covered by the mask
|
||||
*/
|
||||
public boolean hasMatchingSig(QualifiedName qname, OperationSigMask sigMask) {
|
||||
ClassStats clazz = getClassStats(qname, false);
|
||||
|
||||
return clazz != null && clazz.hasMatchingSig(qname.getOperation(), sigMask);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the ClassStats corresponding to the named resource. The class can be nested. If the
|
||||
* createIfNotFound parameter is set, the method also creates the hierarchy if it doesn't exist.
|
||||
@ -106,22 +122,6 @@ public final class PackageStats {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the signature of the operation designated by the qualified name is covered by
|
||||
* the mask.
|
||||
*
|
||||
* @param qname The operation to test
|
||||
* @param sigMask The signature mask to use
|
||||
*
|
||||
* @return True if the signature of the operation designated by the qualified name is covered by the mask
|
||||
*/
|
||||
public boolean hasMatchingSig(QualifiedName qname, OperationSigMask sigMask) {
|
||||
ClassStats clazz = getClassStats(qname, false);
|
||||
|
||||
return clazz != null && clazz.hasMatchingSig(qname.getOperation(), sigMask);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the signature of the field designated by its name and the qualified name of its class is
|
||||
* covered by the mask.
|
||||
|
@ -25,38 +25,20 @@ public final class ParameterizedMetricKey {
|
||||
/** The version of the metric. */
|
||||
public final MetricVersion version;
|
||||
|
||||
|
||||
/** Used internally by the pooler. */
|
||||
private ParameterizedMetricKey(MetricKey<? extends Metric> key, MetricVersion version) {
|
||||
this.key = key;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/** Builds a parameterized metric key. */
|
||||
public static ParameterizedMetricKey build(MetricKey<? extends Metric> key, MetricVersion version) {
|
||||
int code = code(key, version);
|
||||
ParameterizedMetricKey paramKey = POOL.get(code);
|
||||
if (paramKey == null) {
|
||||
POOL.put(code, new ParameterizedMetricKey(key, version));
|
||||
}
|
||||
return POOL.get(code);
|
||||
}
|
||||
|
||||
/** Used by the pooler. */
|
||||
private static int code(MetricKey key, MetricVersion version) {
|
||||
int result = key.hashCode();
|
||||
result = 31 * result + version.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ParameterizedMetricKey{"
|
||||
+ "key=" + key
|
||||
+ ", version=" + version
|
||||
+ '}';
|
||||
return "ParameterizedMetricKey{key=" + key + ", version=" + version + '}';
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
@ -74,10 +56,28 @@ public final class ParameterizedMetricKey {
|
||||
return version.equals(that.version);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return code(key, version);
|
||||
}
|
||||
|
||||
|
||||
/** Used by the pooler. */
|
||||
private static int code(MetricKey key, MetricVersion version) {
|
||||
int result = key.hashCode();
|
||||
result = 31 * result + version.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** Builds a parameterized metric key. */
|
||||
public static ParameterizedMetricKey getInstance(MetricKey<? extends Metric> key, MetricVersion version) {
|
||||
int code = code(key, version);
|
||||
ParameterizedMetricKey paramKey = POOL.get(code);
|
||||
if (paramKey == null) {
|
||||
POOL.put(code, new ParameterizedMetricKey(key, version));
|
||||
}
|
||||
return POOL.get(code);
|
||||
}
|
||||
}
|
||||
|
@ -6,10 +6,7 @@ package net.sourceforge.pmd.lang.java.oom.api;
|
||||
|
||||
/**
|
||||
* Version of a metric. Only one version can be active on a metric. Versions should typically be defined in an enum
|
||||
* named 'Version' nested inside the implementation class of the metric. Versions <i>cannot</i> be shared between
|
||||
* metrics, otherwise the internal memoization logic breaks down.
|
||||
*
|
||||
* TODO:cf Strictly enforce the non-sharing of versions, eg through generics.
|
||||
* named 'Version' nested inside the implementation class of the metric.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
|
@ -1,7 +1,5 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*
|
||||
* Object-Oriented Metrics module (Metrics framework).
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -4,110 +4,44 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.java.oom.rule;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration.TypeKind;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.oom.Metrics;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.ClassMetricKey;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.Metric;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.Metric.Version;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.MetricVersion;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.OperationMetricKey;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.ResultOption;
|
||||
import net.sourceforge.pmd.lang.java.oom.metrics.CycloMetric;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaMetricsRule;
|
||||
import net.sourceforge.pmd.lang.rule.properties.BooleanProperty;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractSimpleJavaMetricsRule;
|
||||
import net.sourceforge.pmd.lang.rule.properties.EnumeratedProperty;
|
||||
import net.sourceforge.pmd.lang.rule.properties.IntegerProperty;
|
||||
|
||||
/**
|
||||
* Refactored to use metrics.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class CyclomaticComplexityRule extends AbstractJavaMetricsRule {
|
||||
|
||||
private static final IntegerProperty REPORT_LEVEL_DESCRIPTOR = new IntegerProperty(
|
||||
"reportLevel", "Cyclomatic Complexity reporting threshold", 1, 30, 10, 1.0f);
|
||||
|
||||
private static final BooleanProperty SHOW_CLASSES_COMPLEXITY_DESCRIPTOR = new BooleanProperty(
|
||||
"showClassesComplexity", "Add class average violations to the report", true, 2.0f);
|
||||
|
||||
private static final BooleanProperty SHOW_METHODS_COMPLEXITY_DESCRIPTOR = new BooleanProperty(
|
||||
"showMethodsComplexity", "Add method average violations to the report", true, 3.0f);
|
||||
|
||||
public class CyclomaticComplexityRule extends AbstractSimpleJavaMetricsRule {
|
||||
|
||||
// TODO:cf clean that up once the new property API is up
|
||||
private static final String[] VERSION_LABELS = {"standard", "ignoreBooleanPaths"};
|
||||
|
||||
private static final MetricVersion[] CYCLO_VERSIONS = {Metric.Version.STANDARD, CycloMetric.Version.IGNORE_BOOLEAN_PATHS};
|
||||
|
||||
private static final EnumeratedProperty<MetricVersion> CYCLO_VERSION_DESCRIPTOR = new EnumeratedProperty<>(
|
||||
"cycloVersion", "Choose a variant of Cyclo or the standard",
|
||||
VERSION_LABELS, CYCLO_VERSIONS, 0, 3.0f);
|
||||
|
||||
private int reportLevel;
|
||||
private boolean showClassesComplexity = true;
|
||||
private boolean showMethodsComplexity = true;
|
||||
private MetricVersion cycloVersion = Version.STANDARD;
|
||||
|
||||
|
||||
public CyclomaticComplexityRule() {
|
||||
definePropertyDescriptor(REPORT_LEVEL_DESCRIPTOR);
|
||||
definePropertyDescriptor(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR);
|
||||
definePropertyDescriptor(SHOW_METHODS_COMPLEXITY_DESCRIPTOR);
|
||||
definePropertyDescriptor(CYCLO_VERSION_DESCRIPTOR);
|
||||
@Override
|
||||
protected EnumeratedProperty<MetricVersion> versionDescriptor() {
|
||||
return CYCLO_VERSION_DESCRIPTOR;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object visit(ASTCompilationUnit node, Object data) {
|
||||
reportLevel = getProperty(REPORT_LEVEL_DESCRIPTOR);
|
||||
showClassesComplexity = getProperty(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR);
|
||||
showMethodsComplexity = getProperty(SHOW_METHODS_COMPLEXITY_DESCRIPTOR);
|
||||
Object version = getProperty(CYCLO_VERSION_DESCRIPTOR);
|
||||
cycloVersion = version instanceof MetricVersion ? (MetricVersion) version : Version.STANDARD;
|
||||
|
||||
super.visit(node, data);
|
||||
return data;
|
||||
protected ClassMetricKey classMetricKey() {
|
||||
return ClassMetricKey.CYCLO;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object visit(ASTAnyTypeDeclaration node, Object data) {
|
||||
TypeKind kind = node.getTypeKind();
|
||||
if (kind == TypeKind.INTERFACE) {
|
||||
return data;
|
||||
}
|
||||
|
||||
super.visit(node, data);
|
||||
|
||||
if (showClassesComplexity) {
|
||||
int classCyclo = (int) Metrics.get(ClassMetricKey.CYCLO, node, cycloVersion);
|
||||
int classHighest = (int) Metrics.get(OperationMetricKey.CYCLO, node, cycloVersion, ResultOption.HIGHEST);
|
||||
|
||||
if (classCyclo >= reportLevel || classHighest >= reportLevel) {
|
||||
String[] messageParams = {kind.name().toLowerCase(),
|
||||
node.getImage(),
|
||||
classCyclo + " (Highest = " + classHighest + ')',};
|
||||
|
||||
addViolation(data, node, messageParams);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
protected OperationMetricKey operationMetricKey() {
|
||||
return OperationMetricKey.CYCLO;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object visit(ASTMethodOrConstructorDeclaration node, Object data) {
|
||||
int cyclo = (int) Metrics.get(OperationMetricKey.CYCLO, node, cycloVersion);
|
||||
|
||||
if (showMethodsComplexity && cyclo >= reportLevel) {
|
||||
addViolation(data, node, new String[] {node instanceof ASTMethodDeclaration ? "method" : "constructor",
|
||||
node.getQualifiedName().getOperation(), "" + cyclo,});
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.oom.rule;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.oom.api.ClassMetricKey;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.OperationMetricKey;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractSimpleJavaMetricsRule;
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public final class NcssCountRule extends AbstractSimpleJavaMetricsRule {
|
||||
|
||||
|
||||
@Override
|
||||
protected ClassMetricKey classMetricKey() {
|
||||
return ClassMetricKey.NCSS;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected OperationMetricKey operationMetricKey() {
|
||||
return OperationMetricKey.NCSS;
|
||||
}
|
||||
}
|
@ -29,6 +29,24 @@ public final class FieldSignature extends Signature {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return code(visibility, isStatic, isFinal);
|
||||
}
|
||||
|
||||
|
||||
/** Used internally by the pooler. */
|
||||
private static int code(Visibility visibility, boolean isStatic, boolean isFinal) {
|
||||
return (isFinal ? 1 : 0) + visibility.hashCode() << 2 + (isStatic ? 1 : 0) << 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds a field signature from its AST node.
|
||||
*
|
||||
@ -43,22 +61,4 @@ public final class FieldSignature extends Signature {
|
||||
}
|
||||
return POOL.get(code);
|
||||
}
|
||||
|
||||
|
||||
/** Used internally by the pooler. */
|
||||
private static int code(Visibility visibility, boolean isStatic, boolean isFinal) {
|
||||
return visibility.hashCode() * 31 + (isStatic ? 1 : 0) * 2 + (isFinal ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (isFinal ? 1 : 0) + super.hashCode() << 3 + (isStatic ? 1 : 0) << 1;
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,14 @@ public final class OperationSigMask extends SigMask<OperationSignature> {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the mask to cover all roles.
|
||||
*/
|
||||
public void coverAllRoles() {
|
||||
roleMask.addAll(Arrays.asList(OperationSignature.Role.values()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restricts the roles covered by the mask to the parameters.
|
||||
*
|
||||
@ -36,14 +44,6 @@ public final class OperationSigMask extends SigMask<OperationSignature> {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the mask to cover all roles.
|
||||
*/
|
||||
public void coverAllRoles() {
|
||||
roleMask.addAll(Arrays.asList(OperationSignature.Role.values()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Forbid all mentioned roles.
|
||||
*
|
||||
|
@ -48,7 +48,13 @@ public final class OperationSignature extends Signature {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (isAbstract ? 1 : 0) + super.hashCode() << 1 + role.hashCode() << 2;
|
||||
return code(visibility, role, isAbstract);
|
||||
}
|
||||
|
||||
|
||||
/** Used internally by the pooler. */
|
||||
private static int code(Visibility visibility, Role role, boolean isAbstract) {
|
||||
return visibility.hashCode() << 2 + role.hashCode() << 1 + (isAbstract ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
@ -68,12 +74,6 @@ public final class OperationSignature extends Signature {
|
||||
}
|
||||
|
||||
|
||||
/** Used internally by the pooler. */
|
||||
private static int code(Visibility visibility, Role role, boolean isAbstract) {
|
||||
return visibility.hashCode() * 31 + role.hashCode() * 2 + (isAbstract ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Role of an operation.
|
||||
*/
|
||||
@ -114,7 +114,8 @@ public final class OperationSignature extends Signature {
|
||||
for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> decl
|
||||
: scope.getVariableDeclarations().entrySet()) {
|
||||
|
||||
ASTFieldDeclaration field = decl.getKey().getNode()
|
||||
ASTFieldDeclaration field = decl.getKey()
|
||||
.getNode()
|
||||
.getFirstParentOfType(ASTFieldDeclaration.class);
|
||||
|
||||
fieldNames.put(field.getVariableName(), field.getFirstChildOfType(ASTType.class).getTypeImage());
|
||||
@ -139,11 +140,12 @@ public final class OperationSignature extends Signature {
|
||||
/** Attempts to determine if the method is a setter. */
|
||||
private static boolean isSetter(ASTMethodDeclaration node, Map<String, String> fieldNames) {
|
||||
|
||||
if (node.getFirstDescendantOfType(ASTFormalParameters.class).getParameterCount() != 1) {
|
||||
if (node.getFirstDescendantOfType(ASTFormalParameters.class).getParameterCount() != 1
|
||||
|| !node.getFirstDescendantOfType(ASTResultType.class).isVoid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node.getFirstDescendantOfType(ASTResultType.class).isVoid();
|
||||
return fieldNames.containsKey(node.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,14 @@ public abstract class SigMask<T extends Signature> {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the mask to cover all visibilities.
|
||||
*/
|
||||
public void coverAllVisibilities() {
|
||||
visMask.addAll(Arrays.asList(Signature.Visibility.values()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restricts the visibilities covered by the mask to the parameters.
|
||||
*
|
||||
@ -37,14 +45,6 @@ public abstract class SigMask<T extends Signature> {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the mask to cover all visibilities.
|
||||
*/
|
||||
public void coverAllVisibilities() {
|
||||
visMask.addAll(Arrays.asList(Signature.Visibility.values()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Forbid all mentioned visibilities.
|
||||
*
|
||||
|
@ -0,0 +1,140 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.rule;
|
||||
|
||||
import net.sourceforge.pmd.PropertyDescriptor;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.oom.Metrics;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.ClassMetricKey;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.Metric.Version;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.MetricVersion;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.OperationMetricKey;
|
||||
import net.sourceforge.pmd.lang.java.oom.api.ResultOption;
|
||||
import net.sourceforge.pmd.lang.rule.properties.BooleanProperty;
|
||||
import net.sourceforge.pmd.lang.rule.properties.EnumeratedProperty;
|
||||
import net.sourceforge.pmd.lang.rule.properties.IntegerProperty;
|
||||
|
||||
/**
|
||||
* Reports values of a metric that cross a certain threshold.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public abstract class AbstractSimpleJavaMetricsRule extends AbstractJavaMetricsRule {
|
||||
|
||||
private static final PropertyDescriptor<Boolean> SHOW_CLASSES_COMPLEXITY_DESCRIPTOR = new BooleanProperty(
|
||||
"reportClasses", "Add class average violations to the report", true, 2.0f);
|
||||
|
||||
private static final PropertyDescriptor<Boolean> SHOW_METHODS_COMPLEXITY_DESCRIPTOR = new BooleanProperty(
|
||||
"reportMethods", "Add method average violations to the report", true, 3.0f);
|
||||
|
||||
private static final IntegerProperty REPORT_LEVEL_DESCRIPTOR = new IntegerProperty(
|
||||
"reportLevel", "Metric reporting threshold", 1, 30, 10, 1.0f);
|
||||
|
||||
|
||||
private ClassMetricKey classMetricKey;
|
||||
private OperationMetricKey operationMetricKey;
|
||||
private boolean reportClasses = true;
|
||||
private boolean reportMethods = true;
|
||||
private MetricVersion metricVersion = Version.STANDARD;
|
||||
private int reportLevel;
|
||||
|
||||
|
||||
public AbstractSimpleJavaMetricsRule() {
|
||||
definePropertyDescriptor(REPORT_LEVEL_DESCRIPTOR);
|
||||
definePropertyDescriptor(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR);
|
||||
definePropertyDescriptor(SHOW_METHODS_COMPLEXITY_DESCRIPTOR);
|
||||
if (versionDescriptor() != null) {
|
||||
definePropertyDescriptor(versionDescriptor());
|
||||
}
|
||||
classMetricKey = classMetricKey();
|
||||
operationMetricKey = operationMetricKey();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the property descriptor which selects the version of the metric, if the metric has versions.
|
||||
*
|
||||
* @return The property descriptor which selects the version of the metric
|
||||
*/
|
||||
protected EnumeratedProperty<MetricVersion> versionDescriptor() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the class metric key to use.
|
||||
*
|
||||
* @return The class metric key to use
|
||||
*/
|
||||
protected abstract ClassMetricKey classMetricKey();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the operation metric key to use.
|
||||
*
|
||||
* @return The operation metric key to use
|
||||
*/
|
||||
protected abstract OperationMetricKey operationMetricKey();
|
||||
|
||||
|
||||
@Override
|
||||
public final Object visit(ASTCompilationUnit node, Object data) {
|
||||
reportLevel = getProperty(REPORT_LEVEL_DESCRIPTOR);
|
||||
reportClasses = getProperty(SHOW_CLASSES_COMPLEXITY_DESCRIPTOR);
|
||||
reportMethods = getProperty(SHOW_METHODS_COMPLEXITY_DESCRIPTOR);
|
||||
if (versionDescriptor() != null) {
|
||||
Object version = getProperty(versionDescriptor());
|
||||
metricVersion = version instanceof MetricVersion ? (MetricVersion) version : Version.STANDARD;
|
||||
}
|
||||
super.visit(node, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final Object visit(ASTAnyTypeDeclaration node, Object data) {
|
||||
super.visit(node, data);
|
||||
|
||||
if (reportClasses && classMetricKey != null) {
|
||||
int classValue = (int) Metrics.get(classMetricKey, node, metricVersion);
|
||||
int classHighest = (int) Metrics.get(operationMetricKey, node, metricVersion, ResultOption.HIGHEST);
|
||||
|
||||
String valueReport = String.valueOf(classValue);
|
||||
|
||||
if (operationMetricKey != null) {
|
||||
int highest = (int) Metrics.get(operationMetricKey, node, metricVersion, ResultOption.HIGHEST);
|
||||
valueReport += " (Highest = " + highest + ")";
|
||||
}
|
||||
|
||||
|
||||
if (classValue >= reportLevel || classHighest >= reportLevel) {
|
||||
String[] messageParams = {node.getTypeKind().name().toLowerCase(),
|
||||
node.getImage(),
|
||||
valueReport, };
|
||||
|
||||
addViolation(data, node, messageParams);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final Object visit(ASTMethodOrConstructorDeclaration node, Object data) {
|
||||
|
||||
if (reportMethods && operationMetricKey != null) {
|
||||
int cyclo = (int) Metrics.get(operationMetricKey, node, metricVersion);
|
||||
if (cyclo >= reportLevel) {
|
||||
addViolation(data, node, new String[] {node instanceof ASTMethodDeclaration ? "method" : "constructor",
|
||||
node.getQualifiedName().getOperation(), "" + cyclo, });
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<ruleset name="Metrics temporary ruleset"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/3.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/3.0.0 http://pmd.sourceforge.net/ruleset_3_0_0.xsd">
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/3.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/3.0.0 http://pmd.sourceforge.net/ruleset_3_0_0.xsd">
|
||||
|
||||
<description>
|
||||
These are rules which use the Metrics Framework to calculate metrics.
|
||||
</description>
|
||||
<description>
|
||||
These are rules which use the Metrics Framework to calculate metrics.
|
||||
</description>
|
||||
|
||||
<rule name="CyclomaticComplexity"
|
||||
since="1.03"
|
||||
message = "The {0} ''{1}'' has a Cyclomatic Complexity of {2}."
|
||||
message="The {0} ''{1}'' has a Cyclomatic Complexity of {2}."
|
||||
since="1.03"
|
||||
class="net.sourceforge.pmd.lang.java.oom.rule.CyclomaticComplexityRule"
|
||||
metrics="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/rules/java/codesize.html#CyclomaticComplexity">
|
||||
@ -65,4 +65,36 @@ public class Foo { // This has a Cyclomatic Complexity = 12
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
</ruleset>
|
||||
|
||||
<!-- TODO -->
|
||||
<rule name="NcssCount"
|
||||
message="The {0} ''{1}'' has a NCSS line count of {2}."
|
||||
since="3.9"
|
||||
class="net.sourceforge.pmd.lang.java.oom.rule.NcssCountRule"
|
||||
metrics="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/rules/java/codesize.html#NcssTypeCount">
|
||||
<description>
|
||||
This rule uses the NCSS (Non-Commenting Source Statements) algorithm to determine the number of lines
|
||||
of code for a given type. NCSS ignores comments, and counts actual statements. Using this algorithm,
|
||||
lines of code that are split are counted as one.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<example>
|
||||
<![CDATA[
|
||||
public class Foo extends Bar {
|
||||
public Foo() {
|
||||
//this class only has 6 NCSS lines
|
||||
super();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
super.foo();
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
</ruleset>
|
||||
|
@ -32,7 +32,7 @@ public class GetterDetection {
|
||||
}
|
||||
|
||||
|
||||
/* public double speedModified() {
|
||||
/* public double speedModified() {
|
||||
return speed * 12 + 1;
|
||||
}
|
||||
|
||||
@ -55,5 +55,5 @@ public class GetterDetection {
|
||||
public int mutableIntConditional() {
|
||||
return mutX == null ? 0 : mutX.getValue();
|
||||
}
|
||||
*/
|
||||
*/
|
||||
}
|
||||
|
@ -20,33 +20,19 @@ public class SetterDetection {
|
||||
value = x;
|
||||
}
|
||||
|
||||
public void putNewValue(int x) {
|
||||
value = x;
|
||||
}
|
||||
|
||||
public void putNewValueComposed(int x) {
|
||||
value += x;
|
||||
}
|
||||
|
||||
public void putNewValueIf(int x) {
|
||||
if (x > 0) {
|
||||
value = x;
|
||||
}
|
||||
}
|
||||
|
||||
public void putNewValueConditional(int x) {
|
||||
public void value(int x) {
|
||||
value = x > 0 ? x : -x;
|
||||
}
|
||||
|
||||
public void updateWithMethod(int x) {
|
||||
public void speed(int x) {
|
||||
mutX.setValue(x);
|
||||
}
|
||||
|
||||
public void updateWithOtherMethod(int x) {
|
||||
public void mutX(int x) {
|
||||
mutX.increment();
|
||||
}
|
||||
|
||||
public void updateHiddenVal(int value) {
|
||||
public void bool(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.java.rule.metrics;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.oom.MetricsForceHook;
|
||||
import net.sourceforge.pmd.testframework.SimpleAggregatorTst;
|
||||
|
||||
/**
|
||||
@ -14,8 +15,15 @@ public class MetricsRulesTest extends SimpleAggregatorTst {
|
||||
|
||||
private static final String RULESET = "java-metrics";
|
||||
|
||||
|
||||
static {
|
||||
MetricsForceHook.setForce(true); // TODO:cf get rid of that when you can
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setUp() {
|
||||
addRule(RULESET, "CyclomaticComplexity");
|
||||
addRule(RULESET, "NcssCount");
|
||||
}
|
||||
}
|
||||
|
@ -117,20 +117,20 @@
|
||||
|
||||
<test-code>
|
||||
<description>Testing new parameter showClassMethods</description>
|
||||
<rule-property name="showClassesComplexity">false</rule-property>
|
||||
<rule-property name="reportClasses">false</rule-property>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code-ref id="basic-violation"/>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Testing new parameter showMethodsMethods</description>
|
||||
<rule-property name="showMethodsComplexity">false</rule-property>
|
||||
<rule-property name="reportMethods">false</rule-property>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code-ref id="basic-violation"/>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Testing default value of showClassMethods and showClassesComplexity</description>
|
||||
<description>Testing default value of showClassMethods and reportClasses</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<code-ref id="basic-violation"/>
|
||||
</test-code>
|
||||
@ -152,10 +152,10 @@
|
||||
</code-fragment>
|
||||
|
||||
<test-code>
|
||||
<description>#984 Cyclomatic complexity should treat constructors like methods: 1 - showMethodsComplexity=true
|
||||
<description>#984 Cyclomatic complexity should treat constructors like methods: 1 - reportMethods=true
|
||||
</description>
|
||||
<rule-property name="showClassesComplexity">false</rule-property>
|
||||
<rule-property name="showMethodsComplexity">true</rule-property>
|
||||
<rule-property name="reportClasses">false</rule-property>
|
||||
<rule-property name="reportMethods">true</rule-property>
|
||||
<rule-property name="reportLevel">1</rule-property>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code-ref id="constructor-violation"/>
|
||||
@ -163,10 +163,10 @@
|
||||
|
||||
<test-code>
|
||||
<description>#984 Cyclomatic complexity should treat constructors like methods: 2 -
|
||||
showMethodsComplexity=false
|
||||
reportMethods=false
|
||||
</description>
|
||||
<rule-property name="showClassesComplexity">false</rule-property>
|
||||
<rule-property name="showMethodsComplexity">false</rule-property>
|
||||
<rule-property name="reportClasses">false</rule-property>
|
||||
<rule-property name="reportMethods">false</rule-property>
|
||||
<rule-property name="reportLevel">1</rule-property>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code-ref id="constructor-violation"/>
|
||||
@ -211,8 +211,8 @@
|
||||
|
||||
<test-code>
|
||||
<description>Standard Cyclo should count empty switch labels too</description>
|
||||
<rule-property name="showClassesComplexity">false</rule-property>
|
||||
<rule-property name="showMethodsComplexity">true</rule-property>
|
||||
<rule-property name="reportClasses">false</rule-property>
|
||||
<rule-property name="reportMethods">true</rule-property>
|
||||
<rule-property name="reportLevel">2</rule-property>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-messages>
|
||||
@ -223,8 +223,8 @@
|
||||
|
||||
<test-code>
|
||||
<description>IgnoreBooleanPaths Cyclo should not count empty switch labels</description>
|
||||
<rule-property name="showClassesComplexity">false</rule-property>
|
||||
<rule-property name="showMethodsComplexity">true</rule-property>
|
||||
<rule-property name="reportClasses">false</rule-property>
|
||||
<rule-property name="reportMethods">true</rule-property>
|
||||
<rule-property name="cycloVersion">ignoreBooleanPaths</rule-property>
|
||||
<rule-property name="reportLevel">2</rule-property>
|
||||
<expected-problems>1</expected-problems>
|
||||
@ -253,7 +253,7 @@
|
||||
|
||||
<test-code>
|
||||
<description>Standard Cyclo should count boolean paths</description>
|
||||
<rule-property name="showClassesComplexity">false</rule-property>
|
||||
<rule-property name="reportClasses">false</rule-property>
|
||||
<rule-property name="reportLevel">2</rule-property>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-messages>
|
||||
@ -264,7 +264,7 @@
|
||||
|
||||
<test-code>
|
||||
<description>IgnoreBooleanPaths Cyclo should not count boolean paths</description>
|
||||
<rule-property name="showClassesComplexity">false</rule-property>
|
||||
<rule-property name="reportClasses">false</rule-property>
|
||||
<rule-property name="cycloVersion">ignoreBooleanPaths</rule-property>
|
||||
<rule-property name="reportLevel">2</rule-property>
|
||||
<expected-problems>1</expected-problems>
|
||||
|
@ -0,0 +1,157 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<test-data>
|
||||
<code-fragment id="full-example">
|
||||
<![CDATA[
|
||||
public class Foo {
|
||||
int y, z, t;
|
||||
String q;
|
||||
|
||||
{
|
||||
bar();
|
||||
int x;
|
||||
switch (x) {
|
||||
case 1: foo(); break;
|
||||
case 2:
|
||||
case 3: bar(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
public void foo() {}
|
||||
|
||||
public static void main(String args[]) {
|
||||
String k, l, m;
|
||||
|
||||
bar();
|
||||
|
||||
do {
|
||||
x++;
|
||||
} while (x < 2);
|
||||
|
||||
while (x < 4) {
|
||||
x++;
|
||||
}
|
||||
|
||||
for (int i = 1; x < 6; ) {
|
||||
x += i;
|
||||
}
|
||||
|
||||
{
|
||||
x++;;;;;
|
||||
}
|
||||
|
||||
int p =
|
||||
2 + 4 + 5;
|
||||
|
||||
try {
|
||||
x++;
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
bar();
|
||||
x = (int) bar();
|
||||
/*
|
||||
* This is
|
||||
* a comment
|
||||
*/
|
||||
x.foobar();
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</code-fragment>
|
||||
|
||||
<test-code>
|
||||
<description>Full example</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-messages>
|
||||
<message>The class 'Foo' has a NCSS line count of 35 (Highest = 18).</message>
|
||||
<message>The method 'main(String)' has a NCSS line count of 18.</message>
|
||||
</expected-messages>
|
||||
<code-ref id="full-example"/>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
short
|
||||
]]></description>
|
||||
<rule-property name="reportLevel">13</rule-property>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public static void main(String args[]) {
|
||||
bar();
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
lots of comments
|
||||
]]></description>
|
||||
<rule-property name="reportLevel">13</rule-property>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public static void main(String args[]) {
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
bar();
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
foo();
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<code-fragment id="long method"><![CDATA[
|
||||
public class Foo {
|
||||
public static void main(String args[]) {
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
bar();
|
||||
bar();
|
||||
bar();
|
||||
bar();
|
||||
bar();
|
||||
bar();
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
//nothing to see here
|
||||
foo();
|
||||
foo();
|
||||
foo();
|
||||
foo();
|
||||
foo();
|
||||
foo();
|
||||
}
|
||||
}
|
||||
]]></code-fragment>
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
long method
|
||||
]]></description>
|
||||
<rule-property name="reportLevel">13</rule-property>
|
||||
<rule-property name="reportClasses">false</rule-property>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code-ref id="long method"/>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
long method - changed reportLevel
|
||||
]]></description>
|
||||
<!-- validated this number against NCSS -->
|
||||
<rule-property name="reportLevel">15</rule-property>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code-ref id="long method"/>
|
||||
</test-code>
|
||||
</test-data>
|
Reference in New Issue
Block a user