forked from phoedos/pmd
Merge branch 'pr-1558'
This commit is contained in:
@ -54,8 +54,9 @@ This is a {{ site.pmd.release_type }} release.
|
||||
|
||||
### Fixed Issues
|
||||
|
||||
* all
|
||||
* core
|
||||
* [#1196](https://github.com/pmd/pmd/issues/1196): \[core] CPD results not consistent between runs
|
||||
* [#1496](https://github.com/pmd/pmd/issues/1496) \[core] Refactor metrics to be dealt with generically from pmd-core
|
||||
* apex
|
||||
* [#1542](https://github.com/pmd/pmd/pull/1542): \[apex] Include the documentation category
|
||||
* [#1546](https://github.com/pmd/pmd/issues/1546): \[apex] PMD parsing exception for Apex classes using 'inherited sharing' keyword
|
||||
|
@ -5,21 +5,34 @@
|
||||
package net.sourceforge.pmd.lang.apex;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler;
|
||||
import net.sourceforge.pmd.lang.Parser;
|
||||
import net.sourceforge.pmd.lang.ParserOptions;
|
||||
import net.sourceforge.pmd.lang.VisitorStarter;
|
||||
import net.sourceforge.pmd.lang.XPathHandler;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTMethod;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ApexNode;
|
||||
import net.sourceforge.pmd.lang.apex.ast.DumpFacade;
|
||||
import net.sourceforge.pmd.lang.apex.metrics.ApexMetricsComputer;
|
||||
import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey;
|
||||
import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey;
|
||||
import net.sourceforge.pmd.lang.apex.multifile.ApexMultifileVisitorFacade;
|
||||
import net.sourceforge.pmd.lang.apex.rule.ApexRuleViolationFactory;
|
||||
import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler;
|
||||
import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.lang.metrics.internal.AbstractLanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
|
||||
|
||||
|
||||
public class ApexHandler extends AbstractLanguageVersionHandler {
|
||||
|
||||
private final ApexMetricsProvider myMetricsProvider = new ApexMetricsProvider();
|
||||
|
||||
|
||||
@Override
|
||||
public VisitorStarter getMultifileFacade() {
|
||||
return rootNode -> new ApexMultifileVisitorFacade().initializeWith((ApexNode<?>) rootNode);
|
||||
@ -51,4 +64,31 @@ public class ApexHandler extends AbstractLanguageVersionHandler {
|
||||
return rootNode -> new DumpFacade().initializeWith(writer, prefix, recurse, (ApexNode<?>) rootNode);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public LanguageMetricsProvider<ASTUserClassOrInterface<?>, ASTMethod> getLanguageMetricsProvider() {
|
||||
return myMetricsProvider;
|
||||
}
|
||||
|
||||
|
||||
private static class ApexMetricsProvider extends AbstractLanguageMetricsProvider<ASTUserClassOrInterface<?>, ASTMethod> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ApexMetricsProvider() {
|
||||
// a wild double cast
|
||||
super((Class<ASTUserClassOrInterface<?>>) (Object) ASTUserClassOrInterface.class, ASTMethod.class, ApexMetricsComputer.getInstance());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ApexClassMetricKey> getAvailableTypeMetrics() {
|
||||
return Arrays.asList(ApexClassMetricKey.values());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<ApexOperationMetricKey> getAvailableOperationMetrics() {
|
||||
return Arrays.asList(ApexOperationMetricKey.values());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.apex.metrics;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTMethod;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTUserClassOrInterface;
|
||||
import net.sourceforge.pmd.lang.metrics.AbstractMetricsComputer;
|
||||
@ -18,7 +19,13 @@ import net.sourceforge.pmd.lang.metrics.AbstractMetricsComputer;
|
||||
*/
|
||||
public class ApexMetricsComputer extends AbstractMetricsComputer<ASTUserClassOrInterface<?>, ASTMethod> {
|
||||
|
||||
static final ApexMetricsComputer INSTANCE = new ApexMetricsComputer();
|
||||
private static final ApexMetricsComputer INSTANCE = new ApexMetricsComputer();
|
||||
|
||||
|
||||
@InternalApi
|
||||
public static ApexMetricsComputer getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
|
@ -27,7 +27,7 @@ public class ApexMetricsFacade extends AbstractMetricsFacade<ASTUserClassOrInter
|
||||
|
||||
@Override
|
||||
protected MetricsComputer<ASTUserClassOrInterface<?>, ASTMethod> getLanguageSpecificComputer() {
|
||||
return ApexMetricsComputer.INSTANCE;
|
||||
return ApexMetricsComputer.getInstance();
|
||||
}
|
||||
|
||||
|
||||
|
@ -91,7 +91,7 @@ public class ApexProjectMirrorTest {
|
||||
@Override
|
||||
public Object visit(ASTMethod node, Object data) {
|
||||
MetricMemoizer<ASTMethod> op = toplevel.getOperationMemoizer(node.getQualifiedName());
|
||||
result.add((int) ApexMetricsComputer.INSTANCE.computeForOperation(opMetricKey, node, force,
|
||||
result.add((int) ApexMetricsComputer.getInstance().computeForOperation(opMetricKey, node, force,
|
||||
MetricOptions.emptyOptions(), op));
|
||||
return super.visit(node, data);
|
||||
}
|
||||
@ -100,7 +100,7 @@ public class ApexProjectMirrorTest {
|
||||
@Override
|
||||
public Object visit(ASTUserClass node, Object data) {
|
||||
MetricMemoizer<ASTUserClassOrInterface<?>> clazz = toplevel.getClassMemoizer(node.getQualifiedName());
|
||||
result.add((int) ApexMetricsComputer.INSTANCE.computeForType(classMetricKey, node, force,
|
||||
result.add((int) ApexMetricsComputer.getInstance().computeForType(classMetricKey, node, force,
|
||||
MetricOptions.emptyOptions(), clazz));
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ package net.sourceforge.pmd.lang;
|
||||
import java.io.Writer;
|
||||
|
||||
import net.sourceforge.pmd.lang.dfa.DFAGraphRule;
|
||||
import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
|
||||
|
||||
|
||||
/**
|
||||
* This is a generic implementation of the LanguageVersionHandler interface.
|
||||
@ -71,4 +73,10 @@ public abstract class AbstractLanguageVersionHandler implements LanguageVersionH
|
||||
public DFAGraphRule getDFAGraphRule() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public LanguageMetricsProvider<?, ?> getLanguageMetricsProvider() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,10 @@ package net.sourceforge.pmd.lang;
|
||||
|
||||
import java.io.Writer;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.dfa.DFAGraphRule;
|
||||
import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
|
||||
|
||||
/**
|
||||
@ -135,4 +137,17 @@ public interface LanguageVersionHandler {
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
DFAGraphRule getDFAGraphRule();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the metrics provider for this language version,
|
||||
* or null if it has none.
|
||||
*
|
||||
* Note: this is experimental, ie unstable until 7.0.0, after
|
||||
* which it will probably be promoted to a stable API. For
|
||||
* instance the return type will probably be changed to an Optional.
|
||||
*/
|
||||
@Experimental
|
||||
LanguageMetricsProvider<?, ?> getLanguageMetricsProvider();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.metrics;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
import net.sourceforge.pmd.lang.LanguageVersionHandler;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.QualifiableNode;
|
||||
|
||||
|
||||
/**
|
||||
* Language-specific provider for metrics. Knows about all the metrics
|
||||
* defined for a language. Can be used e.g. to build GUI applications
|
||||
* like the designer, in a language independent way. Accessible through
|
||||
* {@link LanguageVersionHandler#getLanguageMetricsProvider()}.
|
||||
*
|
||||
* Note: this is experimental, ie unstable until 7.0.0, after which it will probably
|
||||
* be promoted to a real API.
|
||||
*
|
||||
* @param <T> Type of type declaration nodes of the language
|
||||
* @param <O> Type of operation declaration nodes of the language
|
||||
*
|
||||
* @author Clément Fournier
|
||||
* @since 6.11.0
|
||||
*/
|
||||
@Experimental
|
||||
public interface LanguageMetricsProvider<T extends QualifiableNode, O extends QualifiableNode> {
|
||||
|
||||
/**
|
||||
* Returns a list of all supported type metric keys
|
||||
* for the language.
|
||||
*/
|
||||
List<? extends MetricKey<T>> getAvailableTypeMetrics();
|
||||
|
||||
|
||||
/**
|
||||
* Returns a list of all supported operation metric keys
|
||||
* for the language.
|
||||
*/
|
||||
List<? extends MetricKey<O>> getAvailableOperationMetrics();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the given node casted to {@link T} if it's of the correct
|
||||
* type, otherwise returns null.
|
||||
*/
|
||||
T asTypeNode(Node anyNode);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the given node casted to {@link O} if it's of the correct
|
||||
* type, otherwise returns null.
|
||||
*/
|
||||
O asOperationNode(Node anyNode);
|
||||
|
||||
|
||||
/**
|
||||
* Like {@link MetricsComputer#computeForType(MetricKey, QualifiableNode, boolean, MetricOptions, MetricMemoizer)},
|
||||
* but performs no memoisation.
|
||||
*/
|
||||
double computeForType(MetricKey<T> key, T node, MetricOptions options);
|
||||
|
||||
|
||||
/**
|
||||
* Like {@link MetricsComputer#computeForOperation(MetricKey, QualifiableNode, boolean, MetricOptions, MetricMemoizer)}
|
||||
* but performs no memoisation.
|
||||
*/
|
||||
double computeForOperation(MetricKey<O> key, O node, MetricOptions options);
|
||||
|
||||
|
||||
/**
|
||||
* Like {@link MetricsComputer#computeWithResultOption(MetricKey, QualifiableNode, boolean, MetricOptions, ResultOption, ProjectMemoizer)}
|
||||
* but performs no memoisation.
|
||||
*/
|
||||
double computeWithResultOption(MetricKey<O> key, T node, MetricOptions options, ResultOption option);
|
||||
|
||||
|
||||
/**
|
||||
* Computes all metrics available on the given node.
|
||||
* The returned results may contain Double.NaN as a value.
|
||||
*
|
||||
* @param node Node to inspect
|
||||
*
|
||||
* @return A map of metric key to their result, possibly empty, but with no null value
|
||||
*/
|
||||
Map<MetricKey<?>, Double> computeAllMetricsFor(Node node);
|
||||
}
|
@ -41,5 +41,6 @@ public interface MetricKey<N extends Node> {
|
||||
*/
|
||||
boolean supports(N node);
|
||||
|
||||
// TODO the metric key should know about supported options
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.metrics.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.QualifiableNode;
|
||||
import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.lang.metrics.MetricKey;
|
||||
import net.sourceforge.pmd.lang.metrics.MetricOptions;
|
||||
import net.sourceforge.pmd.lang.metrics.MetricsComputer;
|
||||
import net.sourceforge.pmd.lang.metrics.ResultOption;
|
||||
|
||||
|
||||
/**
|
||||
* Base implementation for {@link LanguageMetricsProvider}.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
* @since 6.11.0
|
||||
*/
|
||||
public abstract class AbstractLanguageMetricsProvider<T extends QualifiableNode, O extends QualifiableNode> implements LanguageMetricsProvider<T, O> {
|
||||
|
||||
private final Class<T> tClass;
|
||||
private final Class<O> oClass;
|
||||
private final MetricsComputer<T, O> myComputer;
|
||||
|
||||
|
||||
protected AbstractLanguageMetricsProvider(Class<T> tClass,
|
||||
Class<O> oClass,
|
||||
MetricsComputer<T, O> computer) {
|
||||
this.tClass = tClass;
|
||||
this.oClass = oClass;
|
||||
this.myComputer = computer;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public T asTypeNode(Node anyNode) {
|
||||
return tClass.isInstance(anyNode) ? tClass.cast(anyNode) : null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public O asOperationNode(Node anyNode) {
|
||||
return oClass.isInstance(anyNode) ? oClass.cast(anyNode) : null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double computeForType(MetricKey<T> key, T node, MetricOptions options) {
|
||||
return myComputer.computeForType(key, node, true, options, DummyMetricMemoizer.<T>getInstance());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double computeForOperation(MetricKey<O> key, O node, MetricOptions options) {
|
||||
return myComputer.computeForOperation(key, node, true, options, DummyMetricMemoizer.<O>getInstance());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double computeWithResultOption(MetricKey<O> key, T node, MetricOptions options, ResultOption option) {
|
||||
return myComputer.computeWithResultOption(key, node, true, options, option, DummyProjectMemoizer.<T, O>getInstance());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<MetricKey<?>, Double> computeAllMetricsFor(Node node) {
|
||||
Map<MetricKey<?>, Double> results = new HashMap<>();
|
||||
T t = asTypeNode(node);
|
||||
if (t != null) {
|
||||
for (MetricKey<T> tkey : getAvailableTypeMetrics()) {
|
||||
results.put(tkey, computeForType(tkey, t, MetricOptions.emptyOptions()));
|
||||
}
|
||||
}
|
||||
O o = asOperationNode(node);
|
||||
if (o != null) {
|
||||
for (MetricKey<O> okey : getAvailableOperationMetrics()) {
|
||||
results.put(okey, computeForOperation(okey, o, MetricOptions.emptyOptions()));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.metrics.internal;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.metrics.MetricMemoizer;
|
||||
import net.sourceforge.pmd.lang.metrics.ParameterizedMetricKey;
|
||||
|
||||
|
||||
/**
|
||||
* Memoizes nothing.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
* @since 6.11.0
|
||||
*/
|
||||
public final class DummyMetricMemoizer<N extends Node> implements MetricMemoizer<N> {
|
||||
|
||||
private static final DummyMetricMemoizer<Node> INSTANCE = new DummyMetricMemoizer<>();
|
||||
|
||||
|
||||
private DummyMetricMemoizer() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Double getMemo(ParameterizedMetricKey<N> key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void memoize(ParameterizedMetricKey<N> key, double value) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <N extends Node> DummyMetricMemoizer<N> getInstance() {
|
||||
return (DummyMetricMemoizer<N>) INSTANCE;
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.metrics.internal;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.QualifiableNode;
|
||||
import net.sourceforge.pmd.lang.ast.QualifiedName;
|
||||
import net.sourceforge.pmd.lang.metrics.MetricMemoizer;
|
||||
import net.sourceforge.pmd.lang.metrics.ProjectMemoizer;
|
||||
|
||||
|
||||
/**
|
||||
* Memoizes nothing.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
* @since 6.11.0
|
||||
*/
|
||||
public final class DummyProjectMemoizer<T extends QualifiableNode, O extends QualifiableNode> implements ProjectMemoizer<T, O> {
|
||||
|
||||
private static final DummyProjectMemoizer<? extends QualifiableNode, ? extends QualifiableNode> INSTANCE = new DummyProjectMemoizer<>();
|
||||
|
||||
|
||||
private DummyProjectMemoizer() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MetricMemoizer<O> getOperationMemoizer(QualifiedName qname) {
|
||||
return DummyMetricMemoizer.getInstance();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MetricMemoizer<T> getClassMemoizer(QualifiedName qname) {
|
||||
return DummyMetricMemoizer.getInstance();
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends QualifiableNode, O extends QualifiableNode> DummyProjectMemoizer<T, O> getInstance() {
|
||||
return (DummyProjectMemoizer<T, O>) INSTANCE;
|
||||
}
|
||||
}
|
@ -5,6 +5,8 @@
|
||||
package net.sourceforge.pmd.lang.java;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler;
|
||||
import net.sourceforge.pmd.lang.DataFlowHandler;
|
||||
@ -14,11 +16,16 @@ import net.sourceforge.pmd.lang.XPathHandler;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler;
|
||||
import net.sourceforge.pmd.lang.dfa.DFAGraphRule;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
import net.sourceforge.pmd.lang.java.ast.DumpFacade;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.MethodLikeNode;
|
||||
import net.sourceforge.pmd.lang.java.dfa.DataFlowFacade;
|
||||
import net.sourceforge.pmd.lang.java.dfa.JavaDFAGraphRule;
|
||||
import net.sourceforge.pmd.lang.java.metrics.JavaMetricsComputer;
|
||||
import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey;
|
||||
import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey;
|
||||
import net.sourceforge.pmd.lang.java.multifile.MultifileVisitorFacade;
|
||||
import net.sourceforge.pmd.lang.java.qname.QualifiedNameResolver;
|
||||
import net.sourceforge.pmd.lang.java.rule.JavaRuleViolationFactory;
|
||||
@ -30,6 +37,9 @@ import net.sourceforge.pmd.lang.java.xpath.MetricFunction;
|
||||
import net.sourceforge.pmd.lang.java.xpath.TypeIsExactlyFunction;
|
||||
import net.sourceforge.pmd.lang.java.xpath.TypeIsFunction;
|
||||
import net.sourceforge.pmd.lang.java.xpath.TypeOfFunction;
|
||||
import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.lang.metrics.MetricKey;
|
||||
import net.sourceforge.pmd.lang.metrics.internal.AbstractLanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
|
||||
|
||||
import net.sf.saxon.sxpath.IndependentContext;
|
||||
@ -42,6 +52,8 @@ import net.sf.saxon.sxpath.IndependentContext;
|
||||
*/
|
||||
public abstract class AbstractJavaHandler extends AbstractLanguageVersionHandler {
|
||||
|
||||
private final LanguageMetricsProvider<ASTAnyTypeDeclaration, MethodLikeNode> myMetricsProvider = new JavaMetricsProvider();
|
||||
|
||||
@Override
|
||||
public DataFlowHandler getDataFlowHandler() {
|
||||
return new JavaDataFlowHandler();
|
||||
@ -147,4 +159,31 @@ public abstract class AbstractJavaHandler extends AbstractLanguageVersionHandler
|
||||
public DFAGraphRule getDFAGraphRule() {
|
||||
return new JavaDFAGraphRule();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public LanguageMetricsProvider<ASTAnyTypeDeclaration, MethodLikeNode> getLanguageMetricsProvider() {
|
||||
return myMetricsProvider;
|
||||
}
|
||||
|
||||
|
||||
private static class JavaMetricsProvider extends AbstractLanguageMetricsProvider<ASTAnyTypeDeclaration, MethodLikeNode> {
|
||||
|
||||
|
||||
JavaMetricsProvider() {
|
||||
super(ASTAnyTypeDeclaration.class, MethodLikeNode.class, JavaMetricsComputer.getInstance());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<? extends MetricKey<ASTAnyTypeDeclaration>> getAvailableTypeMetrics() {
|
||||
return Arrays.asList(JavaClassMetricKey.values());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<? extends MetricKey<MethodLikeNode>> getAvailableOperationMetrics() {
|
||||
return Arrays.asList(JavaOperationMetricKey.values());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.metrics;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
|
||||
@ -20,12 +21,19 @@ import net.sourceforge.pmd.lang.metrics.AbstractMetricsComputer;
|
||||
*/
|
||||
public final class JavaMetricsComputer extends AbstractMetricsComputer<ASTAnyTypeDeclaration, MethodLikeNode> {
|
||||
|
||||
static final JavaMetricsComputer INSTANCE = new JavaMetricsComputer();
|
||||
private static final JavaMetricsComputer INSTANCE = new JavaMetricsComputer();
|
||||
|
||||
|
||||
private JavaMetricsComputer() {
|
||||
}
|
||||
|
||||
|
||||
@InternalApi
|
||||
public static JavaMetricsComputer getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
// TODO: doesn't consider lambdas
|
||||
@Override
|
||||
protected List<MethodLikeNode> findOperations(ASTAnyTypeDeclaration node) {
|
||||
|
@ -33,7 +33,7 @@ class JavaMetricsFacade extends AbstractMetricsFacade<ASTAnyTypeDeclaration, Met
|
||||
|
||||
@Override
|
||||
protected MetricsComputer<ASTAnyTypeDeclaration, MethodLikeNode> getLanguageSpecificComputer() {
|
||||
return JavaMetricsComputer.INSTANCE;
|
||||
return JavaMetricsComputer.getInstance();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -96,5 +96,4 @@ public enum JavaClassMetricKey implements MetricKey<ASTAnyTypeDeclaration> {
|
||||
return calculator.supports(node);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -205,12 +205,12 @@ public class ParserTstUtil {
|
||||
}
|
||||
|
||||
|
||||
public static LanguageVersionHandler getLanguageVersionHandler(String version) {
|
||||
return LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion(version).getLanguageVersionHandler();
|
||||
public static AbstractJavaHandler getLanguageVersionHandler(String version) {
|
||||
return (AbstractJavaHandler) LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion(version).getLanguageVersionHandler();
|
||||
}
|
||||
|
||||
public static LanguageVersionHandler getDefaultLanguageVersionHandler() {
|
||||
return LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getDefaultVersion().getLanguageVersionHandler();
|
||||
public static AbstractJavaHandler getDefaultLanguageVersionHandler() {
|
||||
return (AbstractJavaHandler) LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getDefaultVersion().getLanguageVersionHandler();
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.metrics;
|
||||
|
||||
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ParserTstUtil;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
import net.sourceforge.pmd.lang.java.ast.MethodLikeNode;
|
||||
import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey;
|
||||
import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey;
|
||||
import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.lang.metrics.MetricKey;
|
||||
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class JavaMetricsProviderTest {
|
||||
|
||||
@Test
|
||||
public void testComputeAllMetrics() {
|
||||
|
||||
LanguageMetricsProvider<?, ?> provider = ParserTstUtil.getLanguageVersionHandler("1.8").getLanguageMetricsProvider();
|
||||
|
||||
ASTCompilationUnit acu = ParserTstUtil.parseAndTypeResolveJava("1.8",
|
||||
"class Foo { void bar() { System.out.println(1); } }");
|
||||
|
||||
ASTAnyTypeDeclaration type = acu.getFirstDescendantOfType(ASTAnyTypeDeclaration.class);
|
||||
|
||||
Map<MetricKey<?>, Double> results = provider.computeAllMetricsFor(type);
|
||||
|
||||
for (JavaClassMetricKey key : JavaClassMetricKey.values()) {
|
||||
assertTrue(results.containsKey(key));
|
||||
}
|
||||
|
||||
MethodLikeNode op = acu.getFirstDescendantOfType(MethodLikeNode.class);
|
||||
|
||||
Map<MetricKey<?>, Double> opResults = provider.computeAllMetricsFor(op);
|
||||
|
||||
for (JavaOperationMetricKey key : JavaOperationMetricKey.values()) {
|
||||
assertTrue(opResults.containsKey(key));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testThereIsNoMemoisation() {
|
||||
|
||||
LanguageMetricsProvider<?, ?> provider = ParserTstUtil.getLanguageVersionHandler("1.8").getLanguageMetricsProvider();
|
||||
|
||||
ASTAnyTypeDeclaration tdecl1 = ParserTstUtil.parseAndTypeResolveJava("1.8",
|
||||
"class Foo { void bar() { System.out.println(1); } }").getFirstDescendantOfType(ASTAnyTypeDeclaration.class);
|
||||
|
||||
Map<MetricKey<?>, Double> reference = provider.computeAllMetricsFor(tdecl1);
|
||||
|
||||
ASTAnyTypeDeclaration tdecl2 = ParserTstUtil.parseAndTypeResolveJava("1.8",
|
||||
// same name, different characteristics
|
||||
"class Foo { void bar(){} \npublic void hey() { System.out.println(1); } }").getFirstDescendantOfType(ASTAnyTypeDeclaration.class);
|
||||
|
||||
Map<MetricKey<?>, Double> secondTest = provider.computeAllMetricsFor(tdecl2);
|
||||
|
||||
assertNotEquals(reference, secondTest);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -74,7 +74,7 @@ public class ProjectMemoizerTest {
|
||||
@Override
|
||||
public Object visit(ASTMethodOrConstructorDeclaration node, Object data) {
|
||||
MetricMemoizer<MethodLikeNode> op = toplevel.getOperationMemoizer(node.getQualifiedName());
|
||||
result.add((int) JavaMetricsComputer.INSTANCE.computeForOperation(opMetricKey, node, force,
|
||||
result.add((int) JavaMetricsComputer.getInstance().computeForOperation(opMetricKey, node, force,
|
||||
MetricOptions.emptyOptions(), op));
|
||||
return super.visit(node, data);
|
||||
}
|
||||
@ -83,7 +83,7 @@ public class ProjectMemoizerTest {
|
||||
@Override
|
||||
public Object visit(ASTAnyTypeDeclaration node, Object data) {
|
||||
MetricMemoizer<ASTAnyTypeDeclaration> clazz = toplevel.getClassMemoizer(node.getQualifiedName());
|
||||
result.add((int) JavaMetricsComputer.INSTANCE.computeForType(classMetricKey, node, force,
|
||||
result.add((int) JavaMetricsComputer.getInstance().computeForType(classMetricKey, node, force,
|
||||
MetricOptions.emptyOptions(), clazz));
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
@ -143,48 +143,56 @@
|
||||
<artifactId>pmd-apex</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-java</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-javascript</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-jsp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-plsql</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-visualforce</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-vm</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-xml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
@ -6,15 +6,16 @@ package net.sourceforge.pmd.util.fxdesigner;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.reactfx.EventStreams;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
import net.sourceforge.pmd.lang.metrics.LanguageMetricsProvider;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
import net.sourceforge.pmd.util.fxdesigner.model.MetricEvaluator;
|
||||
import net.sourceforge.pmd.util.fxdesigner.model.MetricResult;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.AbstractController;
|
||||
import net.sourceforge.pmd.util.fxdesigner.util.controls.ScopeHierarchyTreeCell;
|
||||
@ -56,7 +57,7 @@ public class NodeInfoPanelController extends AbstractController {
|
||||
private Label metricsTitleLabel;
|
||||
@FXML
|
||||
private TreeView<Object> scopeHierarchyTreeView;
|
||||
private final MetricEvaluator metricEvaluator = new MetricEvaluator();
|
||||
|
||||
private Node selectedNode;
|
||||
|
||||
public NodeInfoPanelController(MainDesignerController mainController) {
|
||||
@ -122,11 +123,17 @@ public class NodeInfoPanelController extends AbstractController {
|
||||
|
||||
|
||||
private ObservableList<MetricResult> evaluateAllMetrics(Node n) {
|
||||
try {
|
||||
return FXCollections.observableArrayList(metricEvaluator.evaluateAllMetrics(n));
|
||||
} catch (UnsupportedOperationException e) {
|
||||
LanguageMetricsProvider<?, ?> provider = parent.getLanguageVersion().getLanguageVersionHandler().getLanguageMetricsProvider();
|
||||
if (provider == null) {
|
||||
return FXCollections.emptyObservableList();
|
||||
}
|
||||
List<MetricResult> resultList =
|
||||
provider.computeAllMetricsFor(n)
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(e -> new MetricResult(e.getKey(), e.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
return FXCollections.observableArrayList(resultList);
|
||||
}
|
||||
|
||||
|
||||
@ -143,9 +150,10 @@ public class NodeInfoPanelController extends AbstractController {
|
||||
+ ((attribute.getValue() != null) ? attribute.getStringValue() : "null"));
|
||||
}
|
||||
|
||||
if (node instanceof TypeNode) {
|
||||
result.add("typeIs() = " + ((TypeNode) node).getType());
|
||||
}
|
||||
// TODO maybe put some equivalent to TypeNode inside pmd-core
|
||||
// if (node instanceof TypeNode) {
|
||||
// result.add("typeIs() = " + ((TypeNode) node).getType());
|
||||
// }
|
||||
Collections.sort(result);
|
||||
return result;
|
||||
}
|
||||
|
@ -1,92 +0,0 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.util.fxdesigner.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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.apex.metrics.ApexMetrics;
|
||||
import net.sourceforge.pmd.lang.apex.metrics.api.ApexClassMetricKey;
|
||||
import net.sourceforge.pmd.lang.apex.metrics.api.ApexOperationMetricKey;
|
||||
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.metrics.JavaMetrics;
|
||||
import net.sourceforge.pmd.lang.java.metrics.api.JavaClassMetricKey;
|
||||
import net.sourceforge.pmd.lang.java.metrics.api.JavaOperationMetricKey;
|
||||
|
||||
/**
|
||||
* Evaluates metrics.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class MetricEvaluator {
|
||||
|
||||
/**
|
||||
* Evaluates all available metrics and returns a list of results.
|
||||
*
|
||||
* @param node Node
|
||||
*
|
||||
* @return List of all metric results (metric key + result), including NaN results
|
||||
*
|
||||
* @throws UnsupportedOperationException If no metrics are available for this node
|
||||
*/
|
||||
public List<MetricResult> evaluateAllMetrics(Node node) throws UnsupportedOperationException {
|
||||
if (ASTAnyTypeDeclaration.class.isInstance(node)) {
|
||||
return evaluateAllMetrics((ASTAnyTypeDeclaration) node);
|
||||
} else if (ASTMethodOrConstructorDeclaration.class.isInstance(node)) {
|
||||
return evaluateAllMetrics((ASTMethodOrConstructorDeclaration) node);
|
||||
} else if (ASTMethod.class.isInstance(node)) {
|
||||
return evaluateAllMetrics((ASTMethod) node);
|
||||
} else if (ASTUserClass.class.isInstance(node)) {
|
||||
return evaluateAllMetrics((ASTUserClass) node);
|
||||
}
|
||||
throw new UnsupportedOperationException("That language does not support metrics");
|
||||
}
|
||||
|
||||
|
||||
private List<MetricResult> evaluateAllMetrics(ASTMethodOrConstructorDeclaration node) {
|
||||
List<MetricResult> metricResults = new ArrayList<>();
|
||||
for (JavaOperationMetricKey key : JavaOperationMetricKey.values()) {
|
||||
metricResults.add(new MetricResult(key, JavaMetrics.get(key, node)));
|
||||
}
|
||||
|
||||
return metricResults;
|
||||
}
|
||||
|
||||
|
||||
private List<MetricResult> evaluateAllMetrics(ASTAnyTypeDeclaration node) {
|
||||
List<MetricResult> metricResults = new ArrayList<>();
|
||||
for (JavaClassMetricKey key : JavaClassMetricKey.values()) {
|
||||
metricResults.add(new MetricResult(key, JavaMetrics.get(key, node)));
|
||||
}
|
||||
|
||||
return metricResults;
|
||||
}
|
||||
|
||||
|
||||
private List<MetricResult> evaluateAllMetrics(ASTMethod node) {
|
||||
List<MetricResult> metricResults = new ArrayList<>();
|
||||
for (ApexOperationMetricKey key : ApexOperationMetricKey.values()) {
|
||||
metricResults.add(new MetricResult(key, ApexMetrics.get(key, node)));
|
||||
}
|
||||
|
||||
return metricResults;
|
||||
}
|
||||
|
||||
|
||||
private List<MetricResult> evaluateAllMetrics(ASTUserClass node) {
|
||||
List<MetricResult> metricResults = new ArrayList<>();
|
||||
for (ApexClassMetricKey key : ApexClassMetricKey.values()) {
|
||||
metricResults.add(new MetricResult(key, ApexMetrics.get(key, node)));
|
||||
}
|
||||
|
||||
return metricResults;
|
||||
}
|
||||
|
||||
}
|
@ -4,10 +4,6 @@
|
||||
|
||||
package net.sourceforge.pmd.util.fxdesigner.util.controls;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.ClassNameDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
import net.sourceforge.pmd.lang.symboltable.Scope;
|
||||
|
||||
@ -42,31 +38,7 @@ public class ScopeHierarchyTreeCell extends TreeCell<Object> {
|
||||
|
||||
|
||||
private String getTextForDeclaration(NameDeclaration declaration) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (declaration instanceof MethodNameDeclaration
|
||||
|| declaration instanceof net.sourceforge.pmd.lang.plsql.symboltable.MethodNameDeclaration) {
|
||||
sb.append("Method ");
|
||||
} else if (declaration instanceof VariableNameDeclaration
|
||||
|| declaration instanceof net.sourceforge.pmd.lang.plsql.symboltable.VariableNameDeclaration) {
|
||||
sb.append("Variable ");
|
||||
} else if (declaration instanceof ClassNameDeclaration
|
||||
|| declaration instanceof net.sourceforge.pmd.lang.plsql.symboltable.ClassNameDeclaration) {
|
||||
sb.append("Class ");
|
||||
}
|
||||
|
||||
Class<?> type = declaration.getNode() instanceof TypeNode ? ((TypeNode) declaration.getNode()).getType()
|
||||
: null;
|
||||
|
||||
sb.append(declaration.getName());
|
||||
|
||||
if (type != null) {
|
||||
sb.append(" : ").append(type.getSimpleName());
|
||||
}
|
||||
|
||||
sb.append(" (l. ").append(declaration.getNode().getBeginLine()).append(")");
|
||||
|
||||
return sb.toString();
|
||||
return declaration.toString(); // that's nice enough for now
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user