diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/AbstractClassMetric.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/AbstractClassMetric.java index 8eae08f6b6..bf88ebb3a4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/AbstractClassMetric.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/AbstractClassMetric.java @@ -12,6 +12,7 @@ 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.interfaces.ClassMetric; +import net.sourceforge.pmd.lang.java.oom.interfaces.OperationMetricKey; /** * Shares common logic across class metrics. Many class metrics actually sum the metric over the operations of diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/ClassStats.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/ClassStats.java index 29fae6d31c..3f5cc66017 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/ClassStats.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/ClassStats.java @@ -13,7 +13,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.interfaces.ClassMetric; +import net.sourceforge.pmd.lang.java.oom.interfaces.ClassMetricKey; import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion; +import net.sourceforge.pmd.lang.java.oom.interfaces.OperationMetricKey; 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; @@ -152,7 +154,7 @@ 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) { + boolean force, MetricVersion version) { Map 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 @@ -174,7 +176,7 @@ 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, ASTClassOrInterfaceDeclaration node, boolean force, - MetricVersion version) { + 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); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/Metrics.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/Metrics.java index 0c2f0aa93c..1f94b4d42e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/Metrics.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/Metrics.java @@ -7,8 +7,10 @@ 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.interfaces.ClassMetricKey; 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.interfaces.OperationMetricKey; /** @@ -33,6 +35,7 @@ public final class Metrics { return TOP_LEVEL_PACKAGE; } + /** * Computes a metric identified by its code on a class AST node. * @@ -46,6 +49,7 @@ public final class Metrics { return TOP_LEVEL_PACKAGE.compute(key, node, false, Version.STANDARD); } + /** * Computes a metric identified by its code on a operation AST node. * @@ -59,14 +63,34 @@ public final class Metrics { return TOP_LEVEL_PACKAGE.compute(key, node, false, Version.STANDARD); } - public static double get(OperationMetricKey key, ASTMethodOrConstructorDeclaration node, MetricVersion option) { - MetricVersion safeOption = (option == null) ? Version.STANDARD : option; + + /** + * Computes a metric identified by its code on a class AST node. + * + * @param key The key identifying the metric to be computed + * @param node The node on which to compute the metric + * @param version The version of the metric. + * + * @return The value of the metric, or {@code Double.NaN} if the value couln't be computed. + */ + public static double get(ClassMetricKey key, ASTClassOrInterfaceDeclaration node, MetricVersion version) { + MetricVersion safeOption = (version == null) ? Version.STANDARD : version; return TOP_LEVEL_PACKAGE.compute(key, node, false, safeOption); } - public static double get(ClassMetricKey key, ASTClassOrInterfaceDeclaration node, MetricVersion option) { - MetricVersion safeOption = (option == null) ? Version.STANDARD : option; + + /** + * Computes a metric identified by its code on a operation AST node. + * + * @param key The key identifying the metric to be computed + * @param node The node on which to compute the metric + * @param version The version of the metric. + * + * @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) { + MetricVersion safeOption = (version == null) ? Version.STANDARD : version; return TOP_LEVEL_PACKAGE.compute(key, node, false, safeOption); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/OperationStats.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/OperationStats.java index 4092739c30..a1a624502f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/OperationStats.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/OperationStats.java @@ -10,6 +10,7 @@ import java.util.Map; import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration; 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.interfaces.OperationMetricKey; /** diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/PackageStats.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/PackageStats.java index 8932ab4c1e..66157c2f46 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/PackageStats.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/PackageStats.java @@ -10,7 +10,9 @@ 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.interfaces.ClassMetricKey; import net.sourceforge.pmd.lang.java.oom.interfaces.MetricVersion; +import net.sourceforge.pmd.lang.java.oom.interfaces.OperationMetricKey; import net.sourceforge.pmd.lang.java.oom.signature.FieldSigMask; import net.sourceforge.pmd.lang.java.oom.signature.OperationSigMask; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/ParameterizedMetricKey.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/ParameterizedMetricKey.java index aa137e98f0..f66971252f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/ParameterizedMetricKey.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/ParameterizedMetricKey.java @@ -7,11 +7,12 @@ package net.sourceforge.pmd.lang.java.oom; import java.util.HashMap; import java.util.Map; +import net.sourceforge.pmd.lang.java.oom.interfaces.Metric; 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. + * Represents a key parameterized with its version. Used to index memoization maps. * * @author Clément Fournier */ @@ -20,18 +21,18 @@ public final class ParameterizedMetricKey { private static final Map POOL = new HashMap<>(); /** The metric key. */ - public final MetricKey key; + public final MetricKey key; /** The version of the metric. */ public final MetricVersion version; /** Used internally by the pooler. */ - private ParameterizedMetricKey(MetricKey key, MetricVersion version) { + private ParameterizedMetricKey(MetricKey key, MetricVersion version) { this.key = key; this.version = version; } /** Builds a parameterized metric key. */ - public static ParameterizedMetricKey build(MetricKey key, MetricVersion version) { + public static ParameterizedMetricKey build(MetricKey key, MetricVersion version) { int code = code(key, version); ParameterizedMetricKey paramKey = POOL.get(code); if (paramKey == null) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/ClassMetricKey.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/interfaces/ClassMetricKey.java similarity index 77% rename from pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/ClassMetricKey.java rename to pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/interfaces/ClassMetricKey.java index f6b3cd25cd..23f11dac94 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/ClassMetricKey.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/interfaces/ClassMetricKey.java @@ -2,12 +2,11 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.java.oom; +package net.sourceforge.pmd.lang.java.oom.interfaces; -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.NcssMetric; import net.sourceforge.pmd.lang.java.oom.metrics.WmcMetric; /** @@ -19,7 +18,9 @@ public enum ClassMetricKey implements MetricKey { /** Weighed Method Count. */ WMC(new WmcMetric()), /** Cyclomatic complexity. */ - CYCLO(new CycloMetric()); + CYCLO(new CycloMetric()), + /** Non Commenting Source Statements. */ + NCSS(new NcssMetric()); private final ClassMetric calculator; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/OperationMetricKey.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/interfaces/OperationMetricKey.java similarity index 82% rename from pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/OperationMetricKey.java rename to pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/interfaces/OperationMetricKey.java index a912bdd526..91cb42e1fc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/OperationMetricKey.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/interfaces/OperationMetricKey.java @@ -2,10 +2,8 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -package net.sourceforge.pmd.lang.java.oom; +package net.sourceforge.pmd.lang.java.oom.interfaces; -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; @@ -19,6 +17,7 @@ public enum OperationMetricKey implements MetricKey { ATFD(new AtfdMetric()), /** Cyclometric complexity. */ CYCLO(new CycloMetric()), + /** Non Commenting Source Statements. */ NCSS(new NcssMetric()); private final OperationMetric calculator; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/metrics/CycloMetric.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/metrics/CycloMetric.java index 86504f76e0..47e0e456a5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/metrics/CycloMetric.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/metrics/CycloMetric.java @@ -9,19 +9,18 @@ import org.apache.commons.lang3.mutable.MutableInt; 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.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.interfaces.OperationMetricKey; import net.sourceforge.pmd.lang.java.oom.metrics.cyclo.CycloPathUnawareOperationVisitor; import net.sourceforge.pmd.lang.java.oom.metrics.cyclo.CycloVisitor; import net.sourceforge.pmd.lang.java.oom.metrics.cyclo.StandardCycloVisitor; /** - * McCabe's Cyclomatic Complexity. Number of independent paths through a block of code. Formally, given that the control - * flow graph of a method has n edges, m nodes and p connected components, the Cyclomatic complexity of the method is - * given by CYCLO = n - m + 2p. In practice it can be calculated by counting control flow statements following the - * standard rules given below. + * McCabe's Cyclomatic Complexity. Number of independent paths through a block of code [1, 2]. Formally, given that the + * control flow graph of the block has n vertices, e edges and p connected components, the Cyclomatic complexity of the + * block is given by {@code CYCLO = e - n + 2p} [2]. In practice it can be calculated by counting control flow + * statements following the standard rules given below. * *

The standard version of the metric complies with McCabe's original definition: * @@ -35,15 +34,19 @@ import net.sourceforge.pmd.lang.java.oom.metrics.cyclo.StandardCycloVisitor; * statement in itself. * * - *

Version {@link Version#DO_NOT_COUNT_EXPRESSION_PATHS}: Boolean operators are not counted, which means that empty + *

Version {@link Version#DO_NOT_COUNT_EXPRESSION_PATHS}: Boolean operators are not counted, which means that empty * fall-through cases in {@code switch} statements are not counted as well. * - *

[1] Lanza. Object-Oriented Metrics in Practice. + *

References: + *

    + *
  • [1] Lanza, Object-Oriented Metrics in Practice, 2005. + *
  • [2] McCabe, A Complexity Measure, in Proceedings of the 2nd ICSE (1976). + *
* * @author Clément Fournier * @since June 2017 */ -public class CycloMetric extends AbstractClassMetric implements OperationMetric, ClassMetric { +public class CycloMetric extends AbstractClassMetric implements OperationMetric { @Override public double computeFor(ASTClassOrInterfaceDeclaration node, MetricVersion version) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/metrics/WmcMetric.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/metrics/WmcMetric.java index 9e387e9103..8c08fe33e8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/metrics/WmcMetric.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/oom/metrics/WmcMetric.java @@ -6,9 +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.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.OperationMetricKey; /** * Weighed Method Count. It is the sum of the statical complexity of all operations of a class. We use