diff --git a/docs/pages/pmd/devdocs/adding_metrics_framework_for_language.md b/docs/pages/pmd/devdocs/adding_metrics_framework_for_language.md index b351665992..9811676bad 100644 --- a/docs/pages/pmd/devdocs/adding_metrics_framework_for_language.md +++ b/docs/pages/pmd/devdocs/adding_metrics_framework_for_language.md @@ -36,9 +36,10 @@ a singleton. your `MetricsComputer`. It backs the real end user façade, and handles user provided parameters before delegating to your `MetricsComputer`. * Create the static façade of your framework. This one has an instance of your `MetricsFaçade` object and delegates -static methods to that instance. It should be able to give back +static methods to that instance. * If you want to implement signature matching, create an `AbstractMetric` class, which gives access to a -`SignatureMatcher` to your metrics. +`SignatureMatcher` to your metrics. Typically, your implementation of `ProjectMirror` implements a +custom `SignatureMatcher` interface, and your façade can give back its instance of the project mirror. * Create classes `AbstractOperationMetric` and `AbstractClassMetric`. These must implement `Metric` and `Metric`, respectively. They typically provide defaults for the `supports` method of each metric. * Create enums `ClassMetricKey` and `OperationMetricKey`. These must implement `MetricKey` and `MetricKey`. The diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java new file mode 100644 index 0000000000..88e6ed1ce3 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetrics.java @@ -0,0 +1,132 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.metrics; + +import net.sourceforge.pmd.lang.apex.ast.ASTMethod; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.metrics.Metric.Version; +import net.sourceforge.pmd.lang.metrics.MetricKey; +import net.sourceforge.pmd.lang.metrics.MetricVersion; +import net.sourceforge.pmd.lang.metrics.ResultOption; + +/** + * @author Clément Fournier + */ +public final class ApexMetrics { + + private static final ApexMetricsFacade FACADE = new ApexMetricsFacade(); + + + private ApexMetrics() { // Cannot be instantiated + + } + + + /** + * Returns the project mirror of the analysed project. + * + * @return The project mirror + */ + static ApexProjectMirror getTopLevelPackageStats() { + return FACADE.getLanguageSpecificProjectMirror(); + } + + + /** Resets the entire data structure. Used for tests. */ + static void reset() { + FACADE.reset(); + } + + + /** + * Computes the standard value of the 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 + * + * @return The value of the metric, or {@code Double.NaN} if the value couln't be computed + */ + public static double get(MetricKey key, ASTUserClass node) { + return FACADE.computeForType(key, node, Version.STANDARD); + } + + + /** + * Computes a metric identified by its code on a class AST node, possibly selecting a variant with the {@code + * MetricVersion} parameter. + * + * @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(MetricKey key, ASTUserClass node, MetricVersion version) { + return FACADE.computeForType(key, node, version); + } + + + /** + * Computes the standard version of the metric identified by the key 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 + * + * @return The value of the metric, or {@code Double.NaN} if the value couln't be computed + */ + public static double get(MetricKey key, ASTMethod node) { + return FACADE.computeForOperation(key, node, Version.STANDARD); + } + + + /** + * Computes a metric identified by its key 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(MetricKey key, ASTMethod node, MetricVersion version) { + return FACADE.computeForOperation(key, node, version); + } + + + /** + * Compute the sum, average, or highest value of the standard operation metric on all operations of the class node. + * The type of operation is specified by the {@link ResultOption} parameter. + * + * @param key The key identifying the metric to be computed + * @param node The node on which to compute the metric + * @param option The result option to use + * + * @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(MetricKey key, ASTUserClass node, ResultOption option) { + return FACADE.computeWithResultOption(key, node, Version.STANDARD, option); + } + + + /** + * Compute the sum, average, or highest value of the operation metric on all operations of the class node. The type + * of operation is specified by the {@link ResultOption} parameter. + * + * @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 + * @param option The result option to use + * + * @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(MetricKey key, ASTUserClass node, MetricVersion version, + ResultOption option) { + return FACADE.computeWithResultOption(key, node, version, option); + } + + +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java new file mode 100644 index 0000000000..7329455e57 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsComputer.java @@ -0,0 +1,24 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.metrics; + +import java.util.List; + +import net.sourceforge.pmd.lang.apex.ast.ASTMethod; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.metrics.AbstractMetricsComputer; + +/** + * @author Clément Fournier + */ +public class ApexMetricsComputer extends AbstractMetricsComputer { + + public static final ApexMetricsComputer INSTANCE = new ApexMetricsComputer(); + + @Override + protected List findOperations(ASTUserClass node) { + return node.findChildrenOfType(ASTMethod.class); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsFacade.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsFacade.java new file mode 100644 index 0000000000..a82c688641 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexMetricsFacade.java @@ -0,0 +1,36 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.metrics; + +import net.sourceforge.pmd.lang.apex.ast.ASTMethod; +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.metrics.AbstractMetricsFacade; +import net.sourceforge.pmd.lang.metrics.MetricsComputer; + +/** + * @author Clément Fournier + */ +public class ApexMetricsFacade extends AbstractMetricsFacade { + + private final ApexProjectMirror projectMirror = new ApexProjectMirror(); + + + /** Resets the entire project mirror. Used for tests. */ + void reset() { + projectMirror.reset(); + } + + + @Override + protected MetricsComputer getLanguageSpecificComputer() { + return ApexMetricsComputer.INSTANCE; + } + + + @Override + protected ApexProjectMirror getLanguageSpecificProjectMirror() { + return projectMirror; + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirror.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirror.java index 941fab5119..586417005e 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirror.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/metrics/ApexProjectMirror.java @@ -25,6 +25,12 @@ public class ApexProjectMirror implements ProjectMirror private final Map classes = new HashMap<>(); + void reset() { + operations.clear(); + classes.clear(); + } + + ApexOperationStats addOperation(ApexQualifiedName qname, ApexOperationSignature sig) { if (!operations.containsKey(sig)) { operations.put(sig, new HashMap<>());