Adapt the metrics framework to consider MethodLike

This commit is contained in:
Clément Fournier
2018-01-31 23:42:29 +01:00
parent ba10a60a7c
commit 7e2930be3f
17 changed files with 78 additions and 63 deletions

View File

@ -22,7 +22,7 @@ public class MetricKeyUtil {
/**
* Creates a new metric key holding a metric which can be computed on a class.
* Creates a new metric key from its metric and name.
*
* @param name The name of the metric
* @param metric The metric to use

View File

@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.java.metrics;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.metrics.MetricKey;
import net.sourceforge.pmd.lang.metrics.MetricOptions;
import net.sourceforge.pmd.lang.metrics.ResultOption;
@ -79,7 +79,7 @@ public final class JavaMetrics {
*
* @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed
*/
public static double get(MetricKey<ASTMethodOrConstructorDeclaration> key, ASTMethodOrConstructorDeclaration node) {
public static double get(MetricKey<MethodLike> key, MethodLike node) {
return FACADE.computeForOperation(key, node, MetricOptions.emptyOptions());
}
@ -93,8 +93,7 @@ public final class JavaMetrics {
*
* @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed
*/
public static double get(MetricKey<ASTMethodOrConstructorDeclaration> key, ASTMethodOrConstructorDeclaration node,
MetricOptions options) {
public static double get(MetricKey<MethodLike> key, MethodLike node, MetricOptions options) {
return FACADE.computeForOperation(key, node, options);
}
@ -107,10 +106,9 @@ public final class JavaMetrics {
* @param node The node on which to compute the metric
* @param resultOption The result option to use
*
* @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed or {@code option} is
* {@code null}
* @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed
*/
public static double get(MetricKey<ASTMethodOrConstructorDeclaration> key, ASTAnyTypeDeclaration node, ResultOption resultOption) {
public static double get(MetricKey<MethodLike> key, ASTAnyTypeDeclaration node, ResultOption resultOption) {
return FACADE.computeWithResultOption(key, node, MetricOptions.emptyOptions(), resultOption);
}
@ -124,10 +122,9 @@ public final class JavaMetrics {
* @param resultOption The result option to use
* @param options The version of the metric
*
* @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed or {@code option} is
* {@code null}
* @return The value of the metric, or {@code Double.NaN} if the value couldn't be computed
*/
public static double get(MetricKey<ASTMethodOrConstructorDeclaration> key, ASTAnyTypeDeclaration node,
public static double get(MetricKey<MethodLike> key, ASTAnyTypeDeclaration node,
MetricOptions options, ResultOption resultOption) {
return FACADE.computeWithResultOption(key, node, options, resultOption);
}

View File

@ -10,6 +10,7 @@ import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.metrics.AbstractMetricsComputer;
/**
@ -17,7 +18,7 @@ import net.sourceforge.pmd.lang.metrics.AbstractMetricsComputer;
*
* @author Clément Fournier
*/
public class JavaMetricsComputer extends AbstractMetricsComputer<ASTAnyTypeDeclaration, ASTMethodOrConstructorDeclaration> {
public class JavaMetricsComputer extends AbstractMetricsComputer<ASTAnyTypeDeclaration, MethodLike> {
static final JavaMetricsComputer INSTANCE = new JavaMetricsComputer();
@ -26,11 +27,11 @@ public class JavaMetricsComputer extends AbstractMetricsComputer<ASTAnyTypeDecla
}
// TODO: doesn't consider lambdas
@Override
protected List<ASTMethodOrConstructorDeclaration> findOperations(ASTAnyTypeDeclaration node) {
protected List<MethodLike> findOperations(ASTAnyTypeDeclaration node) {
List<ASTMethodOrConstructorDeclaration> operations = new ArrayList<>();
List<MethodLike> operations = new ArrayList<>();
for (ASTAnyTypeBodyDeclaration decl : node.getDeclarations()) {
if (decl.jjtGetNumChildren() > 0 && decl.jjtGetChild(0) instanceof ASTMethodOrConstructorDeclaration) {

View File

@ -5,7 +5,7 @@
package net.sourceforge.pmd.lang.java.metrics;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.metrics.AbstractMetricsFacade;
import net.sourceforge.pmd.lang.metrics.MetricsComputer;
@ -14,7 +14,7 @@ import net.sourceforge.pmd.lang.metrics.MetricsComputer;
*
* @author Clément Fournier
*/
class JavaMetricsFacade extends AbstractMetricsFacade<ASTAnyTypeDeclaration, ASTMethodOrConstructorDeclaration> {
class JavaMetricsFacade extends AbstractMetricsFacade<ASTAnyTypeDeclaration, MethodLike> {
private final JavaProjectMemoizer memoizer = new JavaProjectMemoizer();
@ -32,7 +32,7 @@ class JavaMetricsFacade extends AbstractMetricsFacade<ASTAnyTypeDeclaration, AST
@Override
protected MetricsComputer<ASTAnyTypeDeclaration, ASTMethodOrConstructorDeclaration> getLanguageSpecificComputer() {
protected MetricsComputer<ASTAnyTypeDeclaration, MethodLike> getLanguageSpecificComputer() {
return JavaMetricsComputer.INSTANCE;
}

View File

@ -5,7 +5,7 @@
package net.sourceforge.pmd.lang.java.metrics;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.metrics.BasicProjectMemoizer;
/**
@ -13,6 +13,6 @@ import net.sourceforge.pmd.lang.metrics.BasicProjectMemoizer;
*
* @author Clément Fournier
*/
class JavaProjectMemoizer extends BasicProjectMemoizer<ASTAnyTypeDeclaration, ASTMethodOrConstructorDeclaration> {
class JavaProjectMemoizer extends BasicProjectMemoizer<ASTAnyTypeDeclaration, MethodLike> {
}

View File

@ -4,7 +4,7 @@
package net.sourceforge.pmd.lang.java.metrics.api;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.metrics.Metric;
/**
@ -12,7 +12,7 @@ import net.sourceforge.pmd.lang.metrics.Metric;
*
* @author Clément Fournier
*/
public interface JavaOperationMetric extends Metric<ASTMethodOrConstructorDeclaration> {
public interface JavaOperationMetric extends Metric<MethodLike> {
}

View File

@ -4,7 +4,7 @@
package net.sourceforge.pmd.lang.java.metrics.api;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.java.metrics.impl.AtfdMetric.AtfdOperationMetric;
import net.sourceforge.pmd.lang.java.metrics.impl.CycloMetric;
import net.sourceforge.pmd.lang.java.metrics.impl.LocMetric.LocOperationMetric;
@ -12,10 +12,11 @@ import net.sourceforge.pmd.lang.java.metrics.impl.NcssMetric.NcssOperationMetric
import net.sourceforge.pmd.lang.java.metrics.impl.NpathMetric;
import net.sourceforge.pmd.lang.metrics.MetricKey;
/**
* Keys identifying standard operation metrics.
*/
public enum JavaOperationMetricKey implements MetricKey<ASTMethodOrConstructorDeclaration> {
public enum JavaOperationMetricKey implements MetricKey<MethodLike> {
/**
* Access to Foreign Data.
@ -69,9 +70,7 @@ public enum JavaOperationMetricKey implements MetricKey<ASTMethodOrConstructorDe
@Override
public boolean supports(ASTMethodOrConstructorDeclaration node) {
public boolean supports(MethodLike node) {
return calculator.supports(node);
}
}

View File

@ -4,17 +4,19 @@
package net.sourceforge.pmd.lang.java.metrics.impl;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.java.metrics.AbstractJavaMetric;
import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetric;
/**
* Base class for operation metrics.
* Base class for operation metrics. Can be applied on method and constructor declarations, and
* lambda expressions.
*
* @author Clément Fournier
*/
public abstract class AbstractJavaOperationMetric extends AbstractJavaMetric<ASTMethodOrConstructorDeclaration>
implements JavaOperationMetric {
public abstract class AbstractJavaOperationMetric extends AbstractJavaMetric<MethodLike>
implements JavaOperationMetric {
/**
* Returns true if the metric can be computed on this operation. By default, abstract operations are filtered out.
@ -23,7 +25,7 @@ public abstract class AbstractJavaOperationMetric extends AbstractJavaMetric<AST
*
* @return True if the metric can be computed on this operation
*/
public boolean supports(ASTMethodOrConstructorDeclaration node) {
public boolean supports(MethodLike node) {
return !node.isAbstract();
}
}

View File

@ -8,7 +8,7 @@ import org.apache.commons.lang3.mutable.MutableInt;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.java.metrics.JavaMetrics;
import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey;
import net.sourceforge.pmd.lang.java.metrics.impl.visitors.AtfdBaseVisitor;
@ -27,13 +27,13 @@ public final class AtfdMetric {
public static final class AtfdOperationMetric extends AbstractJavaOperationMetric {
@Override
public boolean supports(ASTMethodOrConstructorDeclaration node) {
public boolean supports(MethodLike node) {
return node instanceof ASTMethodDeclaration && super.supports(node);
}
@Override
public double computeFor(ASTMethodOrConstructorDeclaration node, MetricOptions options) {
public double computeFor(MethodLike node, MetricOptions options) {
return ((MutableInt) node.jjtAccept(new AtfdBaseVisitor(), new MutableInt(0))).getValue();
}

View File

@ -12,8 +12,8 @@ import org.apache.commons.lang3.mutable.MutableInt;
import net.sourceforge.pmd.lang.java.ast.ASTConditionalAndExpression;
import net.sourceforge.pmd.lang.java.ast.ASTConditionalOrExpression;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.JavaParserDecoratedVisitor;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.java.metrics.impl.visitors.CycloAssertAwareDecorator;
import net.sourceforge.pmd.lang.java.metrics.impl.visitors.CycloBaseVisitor;
import net.sourceforge.pmd.lang.java.metrics.impl.visitors.CycloPathAwareDecorator;
@ -34,7 +34,7 @@ public final class CycloMetric extends AbstractJavaOperationMetric {
@Override
public double computeFor(ASTMethodOrConstructorDeclaration node, MetricOptions options) {
public double computeFor(final MethodLike node, MetricOptions options) {
Set<MetricOption> opts = options.getOptions();
JavaParserDecoratedVisitor visitor = new JavaParserDecoratedVisitor(CycloBaseVisitor.INSTANCE);

View File

@ -5,7 +5,7 @@
package net.sourceforge.pmd.lang.java.metrics.impl;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.metrics.MetricOptions;
/**
@ -21,13 +21,13 @@ public final class LocMetric {
public static final class LocOperationMetric extends AbstractJavaOperationMetric {
@Override
public boolean supports(ASTMethodOrConstructorDeclaration node) {
public boolean supports(MethodLike node) {
return true;
}
@Override
public double computeFor(ASTMethodOrConstructorDeclaration node, MetricOptions options) {
public double computeFor(MethodLike node, MetricOptions options) {
return 1 + node.getEndLine() - node.getBeginLine();
}
}

View File

@ -9,8 +9,8 @@ import java.util.Set;
import org.apache.commons.lang3.mutable.MutableInt;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.JavaParserDecoratedVisitor;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.java.metrics.impl.visitors.NcssBaseVisitor;
import net.sourceforge.pmd.lang.java.metrics.impl.visitors.NcssCountImportsDecorator;
import net.sourceforge.pmd.lang.metrics.MetricOption;
@ -73,13 +73,13 @@ public final class NcssMetric {
public static final class NcssOperationMetric extends AbstractJavaOperationMetric {
@Override
public boolean supports(ASTMethodOrConstructorDeclaration node) {
public boolean supports(MethodLike node) {
return true;
}
@Override
public double computeFor(ASTMethodOrConstructorDeclaration node, MetricOptions version) {
public double computeFor(MethodLike node, MetricOptions version) {
Set<MetricOption> options = version.getOptions();
JavaParserDecoratedVisitor visitor = new JavaParserDecoratedVisitor(NcssBaseVisitor.INSTANCE);

View File

@ -5,7 +5,7 @@
package net.sourceforge.pmd.lang.java.metrics.impl;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.java.metrics.impl.visitors.NpathBaseVisitor;
import net.sourceforge.pmd.lang.metrics.MetricOptions;
@ -18,7 +18,7 @@ import net.sourceforge.pmd.lang.metrics.MetricOptions;
public class NpathMetric extends AbstractJavaOperationMetric {
@Override
public double computeFor(ASTMethodOrConstructorDeclaration node, MetricOptions options) {
public double computeFor(MethodLike node, MetricOptions options) {
return (Integer) node.jjtAccept(NpathBaseVisitor.INSTANCE, null);
}

View File

@ -9,9 +9,12 @@ import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
/**
* Java Rule with convenient visit methods to e.g. treat contructors and methods the same.
@ -54,10 +57,19 @@ public abstract class AbstractJavaMetricsRule extends AbstractJavaRule {
return visit((ASTMethodOrConstructorDeclaration) node, data);
}
public Object visit(ASTMethodOrConstructorDeclaration node, Object data) {
return visit((JavaNode) node, data);
@Override
public final Object visit(ASTLambdaExpression node, Object data) {
return visit((MethodLike) node, data);
}
public Object visit(ASTMethodOrConstructorDeclaration node, Object data) {
return visit((MethodLike) node, data);
}
public Object visit(MethodLike node, Object data) {
return visit((JavaNode) node, data);
}
}

View File

@ -10,18 +10,23 @@ import java.util.Map;
import org.apache.commons.lang3.EnumUtils;
import org.jaxen.Context;
import org.jaxen.Function;
import org.jaxen.FunctionCallException;
import org.jaxen.SimpleFunctionContext;
import org.jaxen.XPathFunctionContext;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.java.metrics.JavaMetrics;
import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey;
import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey;
/**
* Implements the {@code metric()} XPath function. Takes the
* string name of a metric and the context node and returns
* the result if the metric can be computed, otherwise returns
* {@link Double#NaN}.
*
* @author Clément Fournier
* @since 6.0.0
*/
@ -33,9 +38,7 @@ public class MetricFunction implements Function {
@Override
public Object call(Context context, List args) throws FunctionCallException {
String metricKeyName = null;
public Object call(Context context, List args) {
if (args.size() == 0) {
throw new IllegalArgumentException(badMetricKeyArgMessage());
@ -45,9 +48,9 @@ public class MetricFunction implements Function {
throw new IllegalArgumentException(badMetricKeyArgMessage());
}
metricKeyName = (String) args.get(0);
String metricKeyName = (String) args.get(0);
Node n = (Node) context.getNodeSet().get(0);
return getMetric(n, metricKeyName);
}
@ -75,8 +78,8 @@ public class MetricFunction implements Function {
public static double getMetric(Node n, String metricKeyName) {
if (n instanceof ASTAnyTypeDeclaration) {
return getClassMetric((ASTAnyTypeDeclaration) n, getClassMetricKey(metricKeyName));
} else if (n instanceof ASTMethodOrConstructorDeclaration) {
return getOpMetric((ASTMethodOrConstructorDeclaration) n, getOperationMetricKey(metricKeyName));
} else if (n instanceof MethodLike) {
return getOpMetric((MethodLike) n, getOperationMetricKey(metricKeyName));
} else {
throw new IllegalStateException(genericBadNodeMessage());
}
@ -101,7 +104,7 @@ public class MetricFunction implements Function {
}
private static double getOpMetric(ASTMethodOrConstructorDeclaration node, JavaOperationMetricKey key) {
private static double getOpMetric(MethodLike node, JavaOperationMetricKey key) {
return JavaMetrics.get(key, node);
}

View File

@ -19,6 +19,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorReducedAdapter;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.java.metrics.impl.AbstractJavaClassMetric;
import net.sourceforge.pmd.lang.java.metrics.impl.AbstractJavaOperationMetric;
import net.sourceforge.pmd.lang.java.metrics.testdata.MetricsVisitorTestData;
@ -33,7 +34,7 @@ import net.sourceforge.pmd.lang.metrics.MetricOptions;
public class ProjectMemoizerTest {
private MetricKey<ASTAnyTypeDeclaration> classMetricKey = MetricKeyUtil.of(null, new RandomClassMetric());
private MetricKey<ASTMethodOrConstructorDeclaration> opMetricKey = MetricKeyUtil.of(null, new RandomOperationMetric());
private MetricKey<MethodLike> opMetricKey = MetricKeyUtil.of(null, new RandomOperationMetric());
@Test
@ -72,7 +73,7 @@ public class ProjectMemoizerTest {
acu.jjtAccept(new JavaParserVisitorReducedAdapter() {
@Override
public Object visit(ASTMethodOrConstructorDeclaration node, Object data) {
MetricMemoizer<ASTMethodOrConstructorDeclaration> op = toplevel.getOperationMemoizer(node.getQualifiedName());
MetricMemoizer<MethodLike> op = toplevel.getOperationMemoizer(node.getQualifiedName());
result.add((int) JavaMetricsComputer.INSTANCE.computeForOperation(opMetricKey, node, force,
MetricOptions.emptyOptions(), op));
return super.visit(node, data);
@ -98,7 +99,7 @@ public class ProjectMemoizerTest {
@Override
public double computeFor(ASTMethodOrConstructorDeclaration node, MetricOptions options) {
public double computeFor(MethodLike node, MetricOptions options) {
return random.nextInt();
}
}

View File

@ -11,7 +11,7 @@ import java.util.Map;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.MethodLike;
import net.sourceforge.pmd.lang.java.metrics.JavaMetrics;
import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey;
import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey;
@ -157,7 +157,7 @@ public abstract class AbstractMetricTestRule extends AbstractJavaMetricsRule {
@Override
public Object visit(ASTMethodOrConstructorDeclaration node, Object data) {
public Object visit(MethodLike node, Object data) {
if (opKey != null && reportMethods && opKey.supports(node)) {
double methodValue = JavaMetrics.get(opKey, node, metricOptions);
if (methodValue >= reportLevel) {