1
0
forked from phoedos/pmd

Abstracted Metrics to use MetricKeys

This commit is contained in:
oowekyala
2017-07-11 14:41:54 +02:00
parent 1d5ec7f1b6
commit 341d66b694
11 changed files with 101 additions and 80 deletions

@ -19,7 +19,6 @@ import net.sourceforge.pmd.lang.java.oom.api.Metric;
* Base class for metrics. Metric objects encapsulate the computational logic required to compute a metric from a
* PackageStats and node. They're stateless.
*
*
* @author Clément Fournier
*/
public abstract class AbstractMetric implements Metric {

@ -16,9 +16,9 @@ import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.QualifiedName;
import net.sourceforge.pmd.lang.java.oom.api.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.api.ClassMetricKey;
import net.sourceforge.pmd.lang.java.oom.api.MetricKey;
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.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.api.ResultOption;
import net.sourceforge.pmd.lang.java.oom.signature.FieldSigMask;
import net.sourceforge.pmd.lang.java.oom.signature.FieldSignature;
@ -159,14 +159,14 @@ import net.sourceforge.pmd.lang.java.oom.signature.OperationSignature;
*
* @return The result of the computation, or {@code Double.NaN} if it couldn't be performed
*/
/* default */ double computeWithResultOption(OperationMetricKey key, ASTAnyTypeDeclaration node,
/* default */ double computeWithResultOption(MetricKey<OperationMetric> key, ASTAnyTypeDeclaration node,
boolean force, MetricVersion version, ResultOption option) {
List<ASTMethodOrConstructorDeclaration> ops = findOperations(node, false);
List<Double> values = new ArrayList<>();
for (ASTMethodOrConstructorDeclaration op : ops) {
if (key.supports(op)) {
if (key.getCalculator().supports(op)) {
double val = this.compute(key, op, op.getQualifiedName().getOperation(), force, version);
if (val != Double.NaN) {
values.add(val);
@ -188,6 +188,38 @@ import net.sourceforge.pmd.lang.java.oom.signature.OperationSignature;
}
/**
* 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
*/
private 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;
}
/**
* Computes the value of a metric for an operation.
*
@ -199,8 +231,8 @@ import net.sourceforge.pmd.lang.java.oom.signature.OperationSignature;
*
* @return The result of the computation, or {@code Double.NaN} if it couldn't be performed
*/
/* default */ double compute(OperationMetricKey key, ASTMethodOrConstructorDeclaration node, String name,
boolean force, MetricVersion version) {
/* default */ double compute(MetricKey<OperationMetric> key, ASTMethodOrConstructorDeclaration node,
String name, boolean force, MetricVersion version) {
// TODO:cf the operation signature might be built many times, consider storing it in the node
Map<String, OperationStats> sigMap = operations.get(OperationSignature.buildFor(node));
@ -249,7 +281,8 @@ import net.sourceforge.pmd.lang.java.oom.signature.OperationSignature;
*
* @return The result of the computation, or {@code Double.NaN} if it couldn't be performed
*/
/* default */ double compute(ClassMetricKey key, ASTAnyTypeDeclaration node, boolean force, MetricVersion version) {
/* default */ double compute(MetricKey<ClassMetric> key, ASTAnyTypeDeclaration node, boolean force,
MetricVersion version) {
ParameterizedMetricKey paramKey = ParameterizedMetricKey.getInstance(key, version);
// if memo.get(key) == null then the metric has never been computed. NaN is a valid value.
@ -265,36 +298,4 @@ import net.sourceforge.pmd.lang.java.oom.signature.OperationSignature;
return val;
}
/**
* 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
*/
private 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;
}
}

@ -7,10 +7,11 @@ package net.sourceforge.pmd.lang.java.oom;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.oom.api.ClassMetricKey;
import net.sourceforge.pmd.lang.java.oom.api.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.api.Metric.Version;
import net.sourceforge.pmd.lang.java.oom.api.MetricKey;
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.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.api.ResultOption;
@ -34,13 +35,15 @@ public final class Metrics {
*
* @return The top level package stats
*/
/* default */ static PackageStats getTopLevelPackageStats() {
/* default */
static PackageStats getTopLevelPackageStats() {
return TOP_LEVEL_PACKAGE;
}
/** Sets whether computations are forced or not. Used for tests. */
/* default */ static void reset() {
/* default */
static void reset() {
TOP_LEVEL_PACKAGE.reset();
}
@ -53,7 +56,7 @@ public final class Metrics {
*
* @return The value of the metric, or {@code Double.NaN} if the value couln't be computed
*/
public static double get(ClassMetricKey key, ASTAnyTypeDeclaration node) {
public static double get(MetricKey<ClassMetric> key, ASTAnyTypeDeclaration node) {
return get(key, node, Version.STANDARD);
}
@ -68,7 +71,7 @@ public final class Metrics {
*
* @return The value of the metric, or {@code Double.NaN} if the value couln't be computed
*/
public static double get(ClassMetricKey key, ASTAnyTypeDeclaration node, MetricVersion version) {
public static double get(MetricKey<ClassMetric> key, ASTAnyTypeDeclaration node, MetricVersion version) {
if (!key.getCalculator().supports(node)) {
return Double.NaN;
}
@ -87,7 +90,7 @@ public final class Metrics {
*
* @return The value of the metric, or {@code Double.NaN} if the value couln't be computed
*/
public static double get(OperationMetricKey key, ASTMethodOrConstructorDeclaration node) {
public static double get(MetricKey<OperationMetric> key, ASTMethodOrConstructorDeclaration node) {
return get(key, node, Version.STANDARD);
}
@ -101,7 +104,7 @@ public final class Metrics {
*
* @return The value of the metric, or {@code Double.NaN} if the value couln't be computed
*/
public static double get(OperationMetricKey key, ASTMethodOrConstructorDeclaration node, MetricVersion version) {
public static double get(MetricKey<OperationMetric> key, ASTMethodOrConstructorDeclaration node, MetricVersion version) {
if (!key.getCalculator().supports(node)) {
return Double.NaN;
}
@ -123,7 +126,7 @@ public final class Metrics {
* @return The value of the metric, or {@code Double.NaN} if the value couln't be computed or {@code option} is
* {@code null}
*/
public static double get(OperationMetricKey key, ASTAnyTypeDeclaration node, ResultOption option) {
public static double get(MetricKey<OperationMetric> key, ASTAnyTypeDeclaration node, ResultOption option) {
return get(key, node, Version.STANDARD, option);
}
@ -140,7 +143,8 @@ public final class Metrics {
* @return The value of the metric, or {@code Double.NaN} if the value couln't be computed or {@code option} is
* {@code null}
*/
public static double get(OperationMetricKey key, ASTAnyTypeDeclaration node, MetricVersion version, ResultOption option) {
public static double get(MetricKey<OperationMetric> key, ASTAnyTypeDeclaration node, MetricVersion version,
ResultOption option) {
MetricVersion safeVersion = (version == null) ? Version.STANDARD : version;
return option == null ? Double.NaN

@ -8,9 +8,9 @@ import java.util.HashMap;
import java.util.Map;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.oom.api.MetricKey;
import net.sourceforge.pmd.lang.java.oom.api.MetricVersion;
import net.sourceforge.pmd.lang.java.oom.api.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.api.OperationMetricKey;
/**
@ -43,8 +43,8 @@ import net.sourceforge.pmd.lang.java.oom.api.OperationMetricKey;
*
* @return The result of the computation, or {@code Double.NaN} if it couldn't be performed
*/
/* default */ double compute(OperationMetricKey key, ASTMethodOrConstructorDeclaration node, boolean force,
MetricVersion version) {
/* default */ double compute(MetricKey<OperationMetric> key, ASTMethodOrConstructorDeclaration node,
boolean force, MetricVersion version) {
ParameterizedMetricKey paramKey = ParameterizedMetricKey.getInstance(key, version);
Double prev = memo.get(paramKey);

@ -10,9 +10,10 @@ import java.util.Map;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.QualifiedName;
import net.sourceforge.pmd.lang.java.oom.api.ClassMetricKey;
import net.sourceforge.pmd.lang.java.oom.api.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.api.MetricKey;
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.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.api.ResultOption;
import net.sourceforge.pmd.lang.java.oom.signature.FieldSigMask;
import net.sourceforge.pmd.lang.java.oom.signature.OperationSigMask;
@ -158,7 +159,7 @@ public final class PackageStats {
*
* @return The result of the computation, or {@code Double.NaN} if it couldn't be performed
*/
/* default */ double compute(ClassMetricKey key, ASTAnyTypeDeclaration node, boolean force,
/* default */ double compute(MetricKey<ClassMetric> key, ASTAnyTypeDeclaration node, boolean force,
MetricVersion version) {
ClassStats container = getClassStats(node.getQualifiedName(), false);
@ -177,8 +178,8 @@ public final class PackageStats {
*
* @return The result of the computation, or {@code Double.NaN} if it couldn't be performed
*/
/* default */ double compute(OperationMetricKey key, ASTMethodOrConstructorDeclaration node, boolean force,
MetricVersion version) {
/* default */ double compute(MetricKey<OperationMetric> key, ASTMethodOrConstructorDeclaration node,
boolean force, MetricVersion version) {
QualifiedName qname = node.getQualifiedName();
ClassStats container = getClassStats(qname, false);
@ -198,7 +199,7 @@ public final class PackageStats {
*
* @return The result of the computation, or {@code Double.NaN} if it couldn't be performed
*/
/* default */ double computeWithResultOption(OperationMetricKey key, ASTAnyTypeDeclaration node,
/* default */ double computeWithResultOption(MetricKey<OperationMetric> key, ASTAnyTypeDeclaration node,
boolean force, MetricVersion version, ResultOption option) {
ClassStats container = getClassStats(node.getQualifiedName(), false);

@ -16,7 +16,7 @@ import net.sourceforge.pmd.lang.java.oom.api.MetricVersion;
*
* @author Clément Fournier
*/
public final class ParameterizedMetricKey {
/* default */ final class ParameterizedMetricKey {
private static final Map<Integer, ParameterizedMetricKey> POOL = new HashMap<>();

@ -12,17 +12,22 @@ import net.sourceforge.pmd.lang.java.oom.metrics.NcssMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.WmcMetric;
/**
* Keys identifying class metrics.
* Keys identifying standard class metrics.
*/
public enum ClassMetricKey implements MetricKey<ClassMetric> {
/** Access to Foreign Data. */
ATFD(new AtfdMetric()),
/** Weighed Method Count. */
WMC(new WmcMetric()),
/** Cyclomatic complexity. */
CYCLO(new CycloMetric()),
/** Non Commenting Source Statements. */
NCSS(new NcssMetric()),
/** Lines of Code. */
LOC(new LocMetric());

@ -11,16 +11,19 @@ import net.sourceforge.pmd.lang.java.oom.metrics.LocMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.NcssMetric;
/**
* Keys identifying operation metrics.
* Keys identifying standard operation metrics.
*/
public enum OperationMetricKey implements MetricKey<OperationMetric> {
/** Access to Foreign Data. */
ATFD(new AtfdMetric()),
/** Cyclomatic complexity. */
CYCLO(new CycloMetric()),
/** Non Commenting Source Statements. */
NCSS(new NcssMetric()),
/** Lines of Code. */
LOC(new LocMetric());

@ -28,13 +28,13 @@ import net.sourceforge.pmd.lang.rule.properties.IntegerProperty;
*/
public class CyclomaticComplexityRule extends AbstractJavaMetricsRule {
public static final IntegerProperty REPORT_LEVEL_DESCRIPTOR = new IntegerProperty(
private static final IntegerProperty REPORT_LEVEL_DESCRIPTOR = new IntegerProperty(
"reportLevel", "Cyclomatic Complexity reporting threshold", 1, 30, 10, 1.0f);
public static final BooleanProperty REPORT_CLASSES_DESCRIPTOR = new BooleanProperty(
private static final BooleanProperty REPORT_CLASSES_DESCRIPTOR = new BooleanProperty(
"reportClasses", "Add class average violations to the report", true, 2.0f);
public static final BooleanProperty REPORT_METHODS_DESCRIPTOR = new BooleanProperty(
private static final BooleanProperty REPORT_METHODS_DESCRIPTOR = new BooleanProperty(
"reportMethods", "Add method average violations to the report", true, 3.0f);
@ -42,7 +42,7 @@ public class CyclomaticComplexityRule extends AbstractJavaMetricsRule {
private static final MetricVersion[] CYCLO_VERSIONS = {Metric.Version.STANDARD, CycloMetric.Version.IGNORE_BOOLEAN_PATHS};
public static final EnumeratedProperty<MetricVersion> CYCLO_VERSION_DESCRIPTOR = new EnumeratedProperty<>(
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);

@ -18,7 +18,7 @@ import java.util.Set;
public abstract class SigMask<T extends Signature> {
/** Visibility mask. */
protected Set<Signature.Visibility> visMask = new HashSet<>();
private Set<Signature.Visibility> visMask = new HashSet<>();
public SigMask() {

@ -39,6 +39,7 @@ public abstract class AbstractMetricTestRule extends AbstractJavaMetricsRule {
private ClassMetricKey classKey;
private OperationMetricKey opKey;
public AbstractMetricTestRule() {
classKey = getClassKey();
opKey = getOpKey();
@ -48,6 +49,23 @@ public abstract class AbstractMetricTestRule extends AbstractJavaMetricsRule {
definePropertyDescriptor(reportLevelDescriptor);
}
/**
* Returns the class metric key to test, or null if we shouldn't test classes.
*
* @return The class metric key to test.
*/
protected abstract ClassMetricKey getClassKey();
/**
* Returns the class metric key to test, or null if we shouldn't test classes.
*
* @return The class metric key to test.
*/
protected abstract OperationMetricKey getOpKey();
public Object visit(ASTCompilationUnit node, Object data) {
reportClasses = getProperty(reportClassesDescriptor);
reportMethods = getProperty(reportMethodsDescriptor);
@ -55,6 +73,7 @@ public abstract class AbstractMetricTestRule extends AbstractJavaMetricsRule {
return super.visit(node, data);
}
/**
* Sets the default for reportClasses descriptor.
*
@ -64,6 +83,7 @@ public abstract class AbstractMetricTestRule extends AbstractJavaMetricsRule {
return true;
}
/**
* Sets the default for reportMethods descriptor.
*
@ -73,6 +93,7 @@ public abstract class AbstractMetricTestRule extends AbstractJavaMetricsRule {
return true;
}
/**
* Sets the version to test
*
@ -82,19 +103,6 @@ public abstract class AbstractMetricTestRule extends AbstractJavaMetricsRule {
return Version.STANDARD;
}
/**
* Returns the class metric key to test, or null if we shouldn't test classes.
*
* @return The class metric key to test.
*/
protected abstract ClassMetricKey getClassKey();
/**
* Returns the class metric key to test, or null if we shouldn't test classes.
*
* @return The class metric key to test.
*/
protected abstract OperationMetricKey getOpKey();
/**
* Default report level, which is 0.