Merge branch 'pr-1558'

This commit is contained in:
Andreas Dangel
2019-01-26 18:45:06 +01:00
23 changed files with 506 additions and 144 deletions

View File

@ -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

View File

@ -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());
}
}
}

View File

@ -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

View File

@ -27,7 +27,7 @@ public class ApexMetricsFacade extends AbstractMetricsFacade<ASTUserClassOrInter
@Override
protected MetricsComputer<ASTUserClassOrInterface<?>, ASTMethod> getLanguageSpecificComputer() {
return ApexMetricsComputer.INSTANCE;
return ApexMetricsComputer.getInstance();
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -41,5 +41,6 @@ public interface MetricKey<N extends Node> {
*/
boolean supports(N node);
// TODO the metric key should know about supported options
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}
}

View File

@ -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) {

View File

@ -33,7 +33,7 @@ class JavaMetricsFacade extends AbstractMetricsFacade<ASTAnyTypeDeclaration, Met
@Override
protected MetricsComputer<ASTAnyTypeDeclaration, MethodLikeNode> getLanguageSpecificComputer() {
return JavaMetricsComputer.INSTANCE;
return JavaMetricsComputer.getInstance();
}
}

View File

@ -96,5 +96,4 @@ public enum JavaClassMetricKey implements MetricKey<ASTAnyTypeDeclaration> {
return calculator.supports(node);
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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>

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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
}
}