Refactored NcssMethodCountRule to use metrics

This commit is contained in:
oowekyala
2017-06-18 00:01:55 +02:00
parent 4f517f98fb
commit ae7c21b326
33 changed files with 297 additions and 245 deletions

View File

@ -4,48 +4,78 @@
package net.sourceforge.pmd.lang.java.oom;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.oom.Metrics.OperationMetricKey;
import net.sourceforge.pmd.lang.java.oom.keys.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.interfaces.ClassMetric;
/**
* Shares common logic across class metrics. Many class metrics actually sum the metric over the operations of
* the class, so it makes sense to share that, and similar behaviour (TBD).
*
* @author Clément Fournier
* @since June 2017
*/
public abstract class AbstractClassMetric extends AbstractMetric implements ClassMetric {
/**
* Gets the sum of the value of an operation metric over all operations in this class. The computation is not forced
* (memoized results are used if they can be found).
* Gets the sum 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).
*
* @param node The class node.
* @param holder The toplevel package stats.
* @param key The operation metric to use.
* @param useNestedClasses Adds the operations of nested classes to the sum.
* @param node The class node.
* @param holder The toplevel package stats.
* @param key The operation metric to use.
* @param includeNested Adds the operations of nested classes to the sum.
*
* @return Returns the sum of a metric over all operations of a class.
*/
protected double sumMetricOverOperations(ASTClassOrInterfaceDeclaration node,
PackageStats holder, OperationMetricKey key, boolean useNestedClasses) {
protected double sumMetricOverOperations(ASTClassOrInterfaceDeclaration node, PackageStats holder,
OperationMetricKey key, boolean includeNested) {
List<ASTMethodOrConstructorDeclaration> operations
= node.findDescendantsOfType(ASTMethodOrConstructorDeclaration.class);
List<ASTMethodOrConstructorDeclaration> operations = findOperations(node, includeNested);
double sum = 0;
for (ASTMethodOrConstructorDeclaration op : operations) {
if (!useNestedClasses && op.getFirstParentOfType(ASTClassOrInterfaceDeclaration.class) != node) {
continue;
}
double val = Metrics.get(key, op);
sum += val == Double.NaN ? 0 : val;
}
return sum;
}
/**
* 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.
*/
protected List<ASTMethodOrConstructorDeclaration> findOperations(ASTClassOrInterfaceDeclaration node,
boolean includeNested) {
if (includeNested) {
return node.findDescendantsOfType(ASTMethodOrConstructorDeclaration.class);
}
ASTClassOrInterfaceBody body = (ASTClassOrInterfaceBody) node.jjtGetChild(0);
List<ASTClassOrInterfaceBodyDeclaration> outerDecls
= body.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;
}
}

View File

@ -9,7 +9,7 @@ import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.QualifiedName;
import net.sourceforge.pmd.lang.java.oom.keys.Metric;
import net.sourceforge.pmd.lang.java.oom.interfaces.Metric;
/**
@ -20,8 +20,19 @@ import net.sourceforge.pmd.lang.java.oom.keys.Metric;
*/
public abstract class AbstractMetric implements Metric {
// TODO:cf useful?
protected boolean isAbstractHandler = false;
/**
* Gives access to the toplevel package stats to metrics without having to pass them as a parameter to metrics.
*
* @return The toplevel package stats (singleton contained within {@link Metrics}.
*/
protected PackageStats getTopLevelPackageStats() {
return Metrics.getTopLevelPackageStats();
}
protected List<QualifiedName> findAllCalls(ASTMethodOrConstructorDeclaration node) {
List<QualifiedName> result = new ArrayList<>();
// TODO:cf

View File

@ -0,0 +1,34 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.oom;
import net.sourceforge.pmd.lang.java.oom.interfaces.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricKey;
import net.sourceforge.pmd.lang.java.oom.metrics.AtfdMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.CycloMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.WmcMetric;
/**
* Keys identifying 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());
private final ClassMetric calculator;
ClassMetricKey(ClassMetric m) {
calculator = m;
}
@Override
public ClassMetric getCalculator() {
return calculator;
}
}

View File

@ -12,9 +12,8 @@ import java.util.Set;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.QualifiedName;
import net.sourceforge.pmd.lang.java.oom.Metrics.OperationMetricKey;
import net.sourceforge.pmd.lang.java.oom.keys.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
import net.sourceforge.pmd.lang.java.oom.interfaces.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion;
import net.sourceforge.pmd.lang.java.oom.signature.FieldSigMask;
import net.sourceforge.pmd.lang.java.oom.signature.FieldSignature;
import net.sourceforge.pmd.lang.java.oom.signature.OperationSigMask;
@ -153,7 +152,7 @@ class ClassStats {
* @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, MetricOption option) {
boolean force, MetricVersion version) {
Map<String, OperationStats> sigMap = operations.get(OperationSignature.buildFor(node));
// TODO:cf the operation signature will be built many times, we might as well store it in the node
@ -162,7 +161,7 @@ class ClassStats {
}
OperationStats stats = sigMap.get(name);
return stats == null ? Double.NaN : stats.compute(key, node, force, option);
return stats == null ? Double.NaN : stats.compute(key, node, force, version);
}
/**
@ -174,9 +173,9 @@ class ClassStats {
*
* @return The result of the computation, or {@code Double.NaN} if it couldn't be performed.
*/
/* default */ double compute(Metrics.ClassMetricKey key, ASTClassOrInterfaceDeclaration node, boolean force,
MetricOption options) {
ParameterizedMetricKey paramKey = ParameterizedMetricKey.build(key, new MetricOption[] {options});
/* default */ double compute(ClassMetricKey key, ASTClassOrInterfaceDeclaration node, boolean force,
MetricVersion version) {
ParameterizedMetricKey paramKey = ParameterizedMetricKey.build(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) {
@ -184,7 +183,7 @@ class ClassStats {
}
ClassMetric metric = key.getCalculator();
double val = metric.computeFor(node, Metrics.getTopLevelPackageStats(), options);
double val = metric.computeFor(node, version);
memo.put(paramKey, val);
return val;
}

View File

@ -7,15 +7,8 @@ package net.sourceforge.pmd.lang.java.oom;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.oom.keys.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.keys.Metric.Option;
import net.sourceforge.pmd.lang.java.oom.keys.MetricKey;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
import net.sourceforge.pmd.lang.java.oom.keys.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.AtfdMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.CycloMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.NcssMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.WmcMetric;
import net.sourceforge.pmd.lang.java.oom.interfaces.Metric.Version;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion;
/**
@ -36,7 +29,7 @@ public final class Metrics {
*
* @return The top level package stats.
*/
static PackageStats getTopLevelPackageStats() {
/* default */ static PackageStats getTopLevelPackageStats() {
return TOP_LEVEL_PACKAGE;
}
@ -50,7 +43,7 @@ public final class Metrics {
*/
public static double get(ClassMetricKey key, ASTClassOrInterfaceDeclaration node) {
// TODO:cf think about caching
return TOP_LEVEL_PACKAGE.compute(key, node, false, Option.STANDARD);
return TOP_LEVEL_PACKAGE.compute(key, node, false, Version.STANDARD);
}
/**
@ -63,66 +56,18 @@ public final class Metrics {
*/
public static double get(OperationMetricKey key, ASTMethodOrConstructorDeclaration node) {
// TODO:cf think about caching
return TOP_LEVEL_PACKAGE.compute(key, node, false, Option.STANDARD);
return TOP_LEVEL_PACKAGE.compute(key, node, false, Version.STANDARD);
}
public static double get(OperationMetricKey key, ASTMethodOrConstructorDeclaration node, MetricOption option) {
MetricOption safeOption = (option == null) ? Option.STANDARD : option;
public static double get(OperationMetricKey key, ASTMethodOrConstructorDeclaration node, MetricVersion option) {
MetricVersion safeOption = (option == null) ? Version.STANDARD : option;
return TOP_LEVEL_PACKAGE.compute(key, node, false, safeOption);
}
public static double get(ClassMetricKey key, ASTClassOrInterfaceDeclaration node, MetricOption option) {
MetricOption safeOption = (option == null) ? Option.STANDARD : option;
public static double get(ClassMetricKey key, ASTClassOrInterfaceDeclaration node, MetricVersion option) {
MetricVersion safeOption = (option == null) ? Version.STANDARD : option;
return TOP_LEVEL_PACKAGE.compute(key, node, false, safeOption);
}
/**
* Keys identifying class metrics.
*/
public enum ClassMetricKey implements MetricKey {
/** Access to Foreign Data. */
ATFD(new AtfdMetric()),
/** Weighed Method Count. */
WMC(new WmcMetric()),
/** Cyclometric complexity. */
CYCLO(new CycloMetric());
private final ClassMetric calculator;
ClassMetricKey(ClassMetric m) {
calculator = m;
}
/** Returns the object used to calculate the metric. @return The calculator. */
ClassMetric getCalculator() {
return calculator;
}
}
/**
* Keys identifying operation metrics.
*/
public enum OperationMetricKey implements MetricKey {
/** Access to Foreign Data. */ // TODO:cf add short description here for javadoc hints
ATFD(new AtfdMetric()),
/** Cyclometric complexity. */
CYCLO(new CycloMetric()),
NCSS(new NcssMetric());
private final OperationMetric calculator;
OperationMetricKey(OperationMetric m) {
calculator = m;
}
/** Returns the object used to calculate the metric. @return The calculator. */
OperationMetric getCalculator() {
return calculator;
}
}
}

View File

@ -0,0 +1,34 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.oom;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricKey;
import net.sourceforge.pmd.lang.java.oom.interfaces.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.AtfdMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.CycloMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.NcssMetric;
/**
* Keys identifying operation metrics.
*/
public enum OperationMetricKey implements MetricKey<OperationMetric> {
/** Access to Foreign Data. */ // TODO:cf add short description here for javadoc hints
ATFD(new AtfdMetric()),
/** Cyclometric complexity. */
CYCLO(new CycloMetric()),
NCSS(new NcssMetric());
private final OperationMetric calculator;
OperationMetricKey(OperationMetric m) {
calculator = m;
}
@Override
public OperationMetric getCalculator() {
return calculator;
}
}

View File

@ -8,8 +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.keys.MetricOption;
import net.sourceforge.pmd.lang.java.oom.keys.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion;
import net.sourceforge.pmd.lang.java.oom.interfaces.OperationMetric;
/**
* Statistics for an operation. Keeps a map of all memoized metrics results.
@ -39,16 +40,16 @@ class OperationStats {
*
* @return The result of the computation, or {@code Double.NaN} if it couldn't be performed.
*/
double compute(Metrics.OperationMetricKey key, ASTMethodOrConstructorDeclaration node, boolean force,
MetricOption options) {
ParameterizedMetricKey paramKey = ParameterizedMetricKey.build(key, new MetricOption[] {options});
double compute(OperationMetricKey key, ASTMethodOrConstructorDeclaration node, boolean force, MetricVersion version) {
ParameterizedMetricKey paramKey = ParameterizedMetricKey.build(key, version);
Double prev = memo.get(paramKey);
if (!force && prev != null) {
return prev;
}
OperationMetric metric = key.getCalculator();
double val = metric.computeFor(node, Metrics.getTopLevelPackageStats(), options);
double val = metric.computeFor(node, version);
memo.put(paramKey, val);
return val;
}

View File

@ -10,7 +10,7 @@ import java.util.Map;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.QualifiedName;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion;
import net.sourceforge.pmd.lang.java.oom.signature.FieldSigMask;
import net.sourceforge.pmd.lang.java.oom.signature.OperationSigMask;
@ -142,8 +142,8 @@ public final class PackageStats {
*
* @return The result of the computation, or {@code Double.NaN} if it couldn't be performed.
*/
double compute(Metrics.ClassMetricKey key, ASTClassOrInterfaceDeclaration node, boolean force,
MetricOption options) {
double compute(ClassMetricKey key, ASTClassOrInterfaceDeclaration node, boolean force,
MetricVersion options) {
ClassStats container = getClassStats(node.getQualifiedName(), false);
return container == null ? Double.NaN
@ -160,8 +160,8 @@ public final class PackageStats {
*
* @return The result of the computation, or {@code Double.NaN} if it couldn't be performed.
*/
double compute(Metrics.OperationMetricKey key, ASTMethodOrConstructorDeclaration node, boolean force,
MetricOption options) {
double compute(OperationMetricKey key, ASTMethodOrConstructorDeclaration node, boolean force,
MetricVersion options) {
QualifiedName qname = node.getQualifiedName();
ClassStats container = getClassStats(qname, false);

View File

@ -4,12 +4,11 @@
package net.sourceforge.pmd.lang.java.oom;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.pmd.lang.java.oom.keys.MetricKey;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricKey;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion;
/**
* Represents a key parameterized with its options. Used to index memoization maps.
@ -20,32 +19,43 @@ public class ParameterizedMetricKey {
private static final Map<Integer, ParameterizedMetricKey> POOL = new HashMap<>();
/** The metric key. */
public final MetricKey key;
public final MetricOption[] options;
/** The version of the metric. */
public final MetricVersion version;
/** Used internally by the pooler. */
private ParameterizedMetricKey(MetricKey key, MetricOption[] options) {
private ParameterizedMetricKey(MetricKey key, MetricVersion version) {
this.key = key;
this.options = options;
this.version = version;
}
/** Builds a parameterized metric key. */
public static ParameterizedMetricKey build(MetricKey key, MetricOption[] options) {
int code = code(key, options);
public static ParameterizedMetricKey build(MetricKey key, MetricVersion version) {
int code = code(key, version);
ParameterizedMetricKey paramKey = POOL.get(code);
if (paramKey == null) {
POOL.put(code, new ParameterizedMetricKey(key, options));
POOL.put(code, new ParameterizedMetricKey(key, version));
}
return POOL.get(code);
}
/** Used by the pooler. */
private static int code(MetricKey key, MetricOption[] options) {
private static int code(MetricKey key, MetricVersion version) {
int result = key.hashCode();
result = 31 * result + Arrays.hashCode(options);
result = 31 * result + version.hashCode();
return result;
}
@Override
public String toString() {
return "ParameterizedMetricKey{" +
"key=" + key +
", options=" + version +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
@ -60,22 +70,13 @@ public class ParameterizedMetricKey {
if (!key.equals(that.key)) {
return false;
}
// Probably incorrect - comparing Object[] arrays with Arrays.equals
return Arrays.equals(options, that.options);
return version.equals(that.version);
}
@Override
public int hashCode() {
int result = key.hashCode();
result = 31 * result + Arrays.hashCode(options);
result = 31 * result + version.hashCode();
return result;
}
@Override
public String toString() {
return "ParameterizedMetricKey{"
+ "key=" + key
+ ", options=" + Arrays.toString(options)
+ '}';
}
}

View File

@ -2,12 +2,9 @@
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.oom.keys;
package net.sourceforge.pmd.lang.java.oom.interfaces;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.oom.PackageStats;
import net.sourceforge.pmd.lang.java.oom.keys.Metric;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
/**
* Metric that can be computed on a class node.
@ -20,11 +17,10 @@ public interface ClassMetric extends Metric {
* Actually computes the value of a metric for an AST node.
*
* @param node The node.
* @param holder The toplevel package stats (used to help the calculation).
* @param option A possibly empty list of options.
* @param version A possibly empty list of options.
*
* @return The value of the metric.
*/
double computeFor(ASTClassOrInterfaceDeclaration node, PackageStats holder, MetricOption option);
double computeFor(ASTClassOrInterfaceDeclaration node, MetricVersion version);
}

View File

@ -2,17 +2,17 @@
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.oom.keys;
package net.sourceforge.pmd.lang.java.oom.interfaces;
/**
* Umbrella marker interface.
* Umbrella marker interface for metrics.
*
* @author Clément Fournier
*/
public interface Metric {
/** Default metric option. */
enum Option implements MetricOption {
/** Default metric version. */
enum Version implements MetricVersion {
/** Standard option, used as a default. */
STANDARD
}

View File

@ -0,0 +1,29 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.oom.interfaces;
/**
* Key identifying a metric.
*
* @param <T> Type of the metric to identify (ClassMetric or OperationMetric).
*/
public interface MetricKey<T extends Metric> {
/**
* Returns the name of the metric.
*
* @return The name of the metric.
*/
String name();
/**
* Returns the object used to calculate the metric.
*
* @return The calculator.
*/
T getCalculator();
}

View File

@ -0,0 +1,21 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.oom.interfaces;
/**
* 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.
*
* @author Clément Fournier
*/
public interface MetricVersion {
/**
* Returns the name of the version.
*
* @return The name of the version.
*/
String name();
}

View File

@ -2,12 +2,9 @@
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.oom.keys;
package net.sourceforge.pmd.lang.java.oom.interfaces;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.oom.PackageStats;
import net.sourceforge.pmd.lang.java.oom.keys.Metric;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
/**
* Metric that can be computed on an operation.
@ -20,12 +17,11 @@ public interface OperationMetric extends Metric {
* Actually computes the value of a metric for an AST node.
*
* @param node The node.
* @param holder The toplevel package stats (used to help the calculation).
* @param option A possibly empty list of options.
* @param version A possibly empty list of options.
*
* @return The value of the metric.
*/
double computeFor(ASTMethodOrConstructorDeclaration node, PackageStats holder, MetricOption option);
double computeFor(ASTMethodOrConstructorDeclaration node, MetricVersion version);
}

View File

@ -1,19 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.oom.keys;
/**
* Key identifying a metric.
*/
public interface MetricKey {
/**
* Returns the name of the metric.
*
* @return The name of the metric.
*/
String name();
}

View File

@ -1,21 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.oom.keys;
/**
* Option that can be passed to a metric. Options should be defined in a class or enum nested inside the implementation
* class of the metric. Bonus point for using an enum, as the name() method is already defined.
*
* @author Clément Fournier
*/
public interface MetricOption {
/**
* Returns the name of the option.
*
* @return The name of the option.
*/
String name();
}

View File

@ -10,10 +10,9 @@ import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.QualifiedName;
import net.sourceforge.pmd.lang.java.oom.AbstractMetric;
import net.sourceforge.pmd.lang.java.oom.keys.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
import net.sourceforge.pmd.lang.java.oom.keys.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.PackageStats;
import net.sourceforge.pmd.lang.java.oom.interfaces.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion;
import net.sourceforge.pmd.lang.java.oom.interfaces.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.signature.OperationSigMask;
import net.sourceforge.pmd.lang.java.oom.signature.OperationSignature.Role;
import net.sourceforge.pmd.lang.java.oom.signature.Signature.Visibility;
@ -26,7 +25,7 @@ import net.sourceforge.pmd.lang.java.oom.signature.Signature.Visibility;
public class AtfdMetric extends AbstractMetric implements ClassMetric, OperationMetric {
@Override
public double computeFor(ASTMethodOrConstructorDeclaration node, PackageStats holder, MetricOption option) {
public double computeFor(ASTMethodOrConstructorDeclaration node, MetricVersion version) {
if (!isSupported(node)) {
return Double.NaN;
}
@ -38,7 +37,7 @@ public class AtfdMetric extends AbstractMetric implements ClassMetric, Operation
List<QualifiedName> callQNames = findAllCalls(node);
int foreignCalls = 0;
for (QualifiedName name : callQNames) {
if (holder.hasMatchingSig(name, targetOps)) {
if (getTopLevelPackageStats().hasMatchingSig(name, targetOps)) {
foreignCalls++;
}
}
@ -47,7 +46,7 @@ public class AtfdMetric extends AbstractMetric implements ClassMetric, Operation
}
@Override
public double computeFor(ASTClassOrInterfaceDeclaration node, PackageStats holder, MetricOption option) {
public double computeFor(ASTClassOrInterfaceDeclaration node, MetricVersion version) {
// TODO
return 0;
}

View File

@ -11,17 +11,16 @@ import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.oom.AbstractClassMetric;
import net.sourceforge.pmd.lang.java.oom.keys.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
import net.sourceforge.pmd.lang.java.oom.Metrics.OperationMetricKey;
import net.sourceforge.pmd.lang.java.oom.keys.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.PackageStats;
import net.sourceforge.pmd.lang.java.oom.OperationMetricKey;
import net.sourceforge.pmd.lang.java.oom.interfaces.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion;
import net.sourceforge.pmd.lang.java.oom.interfaces.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.metrics.cyclo.CycloOperationVisitor;
import net.sourceforge.pmd.lang.java.oom.metrics.cyclo.CycloPathAwareOperationVisitor;
/**
* McCabe's Cyclomatic Complexity. Number of independent paths in a block of code. It is calculated by counting decision
* points (control flow statements) in the block. [1]
* points (control flow statements) in the block. [1] Doesn't support abstract methods.
*
* <p>Standard rules to calculate CYCLO: +1 for every control flow statement. The independent paths of boolean
* expressions are not counted. Switch cases count as one, but not the switch itself ---the point is that a switch
@ -40,15 +39,15 @@ import net.sourceforge.pmd.lang.java.oom.metrics.cyclo.CycloPathAwareOperationVi
public class CycloMetric extends AbstractClassMetric implements OperationMetric, ClassMetric {
@Override
public double computeFor(ASTClassOrInterfaceDeclaration node, PackageStats holder, MetricOption option) {
return sumMetricOverOperations(node, holder, OperationMetricKey.CYCLO, false);
public double computeFor(ASTClassOrInterfaceDeclaration node, MetricVersion version) {
return sumMetricOverOperations(node, getTopLevelPackageStats(), OperationMetricKey.CYCLO, false);
}
@Override
public double computeFor(ASTMethodOrConstructorDeclaration node, PackageStats holder, MetricOption option) {
public double computeFor(ASTMethodOrConstructorDeclaration node, MetricVersion version) {
CycloOperationVisitor visitor;
if (option.equals(Option.COUNT_SWITCH_STATEMENTS)) {
if (version.equals(Version.COUNT_SWITCH_STATEMENTS)) {
visitor = new CycloOperationVisitor() {
@Override
public Object visit(ASTSwitchStatement node, Object data) {
@ -57,7 +56,7 @@ public class CycloMetric extends AbstractClassMetric implements OperationMetric,
return data;
}
};
} else if (option.equals(Option.COUNT_EXPRESSION_PATHS)) {
} else if (version.equals(Version.COUNT_EXPRESSION_PATHS)) {
visitor = new CycloPathAwareOperationVisitor();
} else {
visitor = new CycloOperationVisitor();
@ -67,8 +66,8 @@ public class CycloMetric extends AbstractClassMetric implements OperationMetric,
return (double) cyclo.getValue();
}
/** Options for CYCLO. */
public enum Option implements MetricOption {
/** Variants of CYCLO. */
public enum Version implements MetricVersion {
/** Switch statements are counted as 1. */
COUNT_SWITCH_STATEMENTS,
/** Count the paths in boolean expressions as decision points. */

View File

@ -7,9 +7,8 @@ package net.sourceforge.pmd.lang.java.oom.metrics;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.oom.AbstractClassMetric;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
import net.sourceforge.pmd.lang.java.oom.keys.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.PackageStats;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion;
import net.sourceforge.pmd.lang.java.oom.interfaces.OperationMetric;
/**
* Lines of Code. Equates the length in lines of code of the measured entity, counting everything including blank lines
@ -23,12 +22,12 @@ import net.sourceforge.pmd.lang.java.oom.PackageStats;
public class LocMetric extends AbstractClassMetric implements OperationMetric {
@Override
public double computeFor(ASTClassOrInterfaceDeclaration node, PackageStats holder, MetricOption option) {
public double computeFor(ASTClassOrInterfaceDeclaration node, MetricVersion version) {
return node.getEndLine() - node.getBeginLine();
}
@Override
public double computeFor(ASTMethodOrConstructorDeclaration node, PackageStats holder, MetricOption option) {
public double computeFor(ASTMethodOrConstructorDeclaration node, MetricVersion version) {
if (node.isAbstract()) {
return 1;
}

View File

@ -33,12 +33,13 @@ import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement;
import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter;
import net.sourceforge.pmd.lang.java.oom.AbstractClassMetric;
import net.sourceforge.pmd.lang.java.oom.PackageStats;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
import net.sourceforge.pmd.lang.java.oom.keys.OperationMetric;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion;
import net.sourceforge.pmd.lang.java.oom.interfaces.OperationMetric;
/**
* Non Commenting Source Statements.
* Non Commenting Source Statements. Similar to LOC but only counts statements, which is roughly equivalent
* to counting the number of semicolons and opening braces in the program. The precise rules for counting
* statements comply with <a href="http://www.kclee.de/clemens/java/javancss/">JavaNCSS rules</a>.
*
* @author Clément Fournier
* @see LocMetric
@ -47,12 +48,12 @@ import net.sourceforge.pmd.lang.java.oom.keys.OperationMetric;
public class NcssMetric extends AbstractClassMetric implements OperationMetric {
@Override
public double computeFor(ASTClassOrInterfaceDeclaration node, PackageStats holder, MetricOption options) {
public double computeFor(ASTClassOrInterfaceDeclaration node, MetricVersion version) {
return ((MutableInt) node.jjtAccept(new NcssVisitor(), new MutableInt(1))).getValue();
}
@Override
public double computeFor(ASTMethodOrConstructorDeclaration node, PackageStats holder, MetricOption options) {
public double computeFor(ASTMethodOrConstructorDeclaration node, MetricVersion version) {
return ((MutableInt) node.jjtAccept(new NcssVisitor(), new MutableInt(1))).getValue();
}

View File

@ -6,10 +6,9 @@ package net.sourceforge.pmd.lang.java.oom.metrics;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.oom.AbstractClassMetric;
import net.sourceforge.pmd.lang.java.oom.keys.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
import net.sourceforge.pmd.lang.java.oom.Metrics.OperationMetricKey;
import net.sourceforge.pmd.lang.java.oom.PackageStats;
import net.sourceforge.pmd.lang.java.oom.OperationMetricKey;
import net.sourceforge.pmd.lang.java.oom.interfaces.ClassMetric;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion;
/**
* Weighed Method Count. It is the sum of the statical complexity of all operations of a class. We use
@ -23,7 +22,7 @@ import net.sourceforge.pmd.lang.java.oom.PackageStats;
public class WmcMetric extends AbstractClassMetric implements ClassMetric {
@Override
public double computeFor(ASTClassOrInterfaceDeclaration node, PackageStats holder, MetricOption option) {
return sumMetricOverOperations(node, holder, OperationMetricKey.CYCLO, false);
public double computeFor(ASTClassOrInterfaceDeclaration node, MetricVersion version) {
return sumMetricOverOperations(node, getTopLevelPackageStats(), OperationMetricKey.CYCLO, false);
}
}

View File

@ -1,6 +0,0 @@
/**
* Provides the implementations of metrics.
*
* @author Clément Fournier
*/
package net.sourceforge.pmd.lang.java.oom.metrics;

View File

@ -9,7 +9,7 @@ package net.sourceforge.pmd.lang.java.oom.signature;
*
* @author Clément Fournier
*/
public class FieldSigMask extends SigMask<FieldSignature> {
public final class FieldSigMask extends SigMask<FieldSignature> {
private boolean coverFinal = true;
private boolean coverStatic = true;

View File

@ -14,7 +14,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
*
* @author Clément Fournier
*/
public class FieldSignature extends Signature {
public final class FieldSignature extends Signature {
private static final Map<Integer, FieldSignature> POOL = new HashMap<>();

View File

@ -13,7 +13,7 @@ import java.util.Set;
*
* @author Clément Fournier
*/
public class OperationSigMask extends SigMask<OperationSignature> {
public final class OperationSigMask extends SigMask<OperationSignature> {
private Set<OperationSignature.Role> roleMask = new HashSet<>();
private boolean coverAbstract = false;

View File

@ -16,7 +16,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
*
* @author Clément Fournier
*/
public class OperationSignature extends Signature {
public final class OperationSignature extends Signature {
private static final Map<Integer, OperationSignature> POOL = new HashMap<>();
@ -71,11 +71,15 @@ public class OperationSignature extends Signature {
return node instanceof ASTConstructorDeclaration ? CONSTRUCTOR : get((ASTMethodDeclaration) node);
}
private static boolean isGetterOrSetter(ASTMethodDeclaration node) {
return node.getName() != null && (node.getName().startsWith("get")
|| node.getName().startsWith("set"));
}
private static Role get(ASTMethodDeclaration node) {
if (node.isStatic()) {
return STATIC;
} else if (node.getName() != null && (node.getName().startsWith("get")
|| node.getName().startsWith("set"))) {
} else if (isGetterOrSetter(node)) {
return GETTER_OR_SETTER; // TODO:cf better getter or setter detection
} else {
return METHOD;

View File

@ -4,7 +4,7 @@
package net.sourceforge.pmd.lang.java.rule.codesize;
import net.sourceforge.pmd.lang.java.oom.metrics.CycloMetric.Option;
import net.sourceforge.pmd.lang.java.oom.metrics.CycloMetric.Version;
/**
* This version calculates the cyclomatic complexity of operations by taking into account the number of paths of the
@ -19,6 +19,6 @@ public class CyclomaticComplexityRule extends StdCyclomaticComplexityRule {
public CyclomaticComplexityRule() {
super();
metricOption = Option.COUNT_EXPRESSION_PATHS;
metricOption = Version.COUNT_EXPRESSION_PATHS;
}
}

View File

@ -4,7 +4,7 @@
package net.sourceforge.pmd.lang.java.rule.codesize;
import net.sourceforge.pmd.lang.java.oom.metrics.CycloMetric.Option;
import net.sourceforge.pmd.lang.java.oom.metrics.CycloMetric.Version;
/**
* Implements the modified cyclomatic complexity rule.
@ -21,7 +21,7 @@ public class ModifiedCyclomaticComplexityRule extends StdCyclomaticComplexityRul
public ModifiedCyclomaticComplexityRule() {
super();
metricOption = Option.COUNT_SWITCH_STATEMENTS;
metricOption = Version.COUNT_SWITCH_STATEMENTS;
}

View File

@ -4,10 +4,9 @@
package net.sourceforge.pmd.lang.java.rule.codesize;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.oom.Metrics;
import net.sourceforge.pmd.lang.java.oom.Metrics.OperationMetricKey;
import net.sourceforge.pmd.lang.java.oom.OperationMetricKey;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.rule.properties.DoubleProperty;

View File

@ -12,10 +12,10 @@ import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.oom.keys.Metric.Option;
import net.sourceforge.pmd.lang.java.oom.keys.MetricOption;
import net.sourceforge.pmd.lang.java.oom.interfaces.Metric.Version;
import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion;
import net.sourceforge.pmd.lang.java.oom.Metrics;
import net.sourceforge.pmd.lang.java.oom.Metrics.OperationMetricKey;
import net.sourceforge.pmd.lang.java.oom.OperationMetricKey;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.rule.properties.BooleanProperty;
import net.sourceforge.pmd.lang.rule.properties.IntegerProperty;
@ -51,7 +51,7 @@ public class StdCyclomaticComplexityRule extends AbstractJavaRule {
protected int reportLevel;
protected boolean showClassesComplexity = true;
protected boolean showMethodsComplexity = true;
protected MetricOption metricOption = Option.STANDARD;
protected MetricVersion metricOption = Version.STANDARD;
Stack<ClassEntry> entryStack = new Stack<>();
public StdCyclomaticComplexityRule() {

Some files were not shown because too many files have changed in this diff Show More