forked from phoedos/pmd
Groundwork: qualifiednames
This commit is contained in:
@ -0,0 +1,22 @@
|
||||
---
|
||||
title: How to implement a metrics framework for an existing language
|
||||
short_title: Implement a metrics framework
|
||||
tags: [customizing]
|
||||
summary: "PMD's Java module has an extensive framework for the calculation of metrics, which allows rule developers
|
||||
to implement and use new code metrics very simply. Most of the functionality of this framework is abstracted in such
|
||||
a way that any PMD supported language can implement such a framework without too much trouble. Here's how."
|
||||
last_updated: July 3, 2016
|
||||
sidebar: pmd_sidebar
|
||||
permalink: pmd_devdocs_adding_new_cpd_language.html
|
||||
folder: pmd/devdocs
|
||||
---
|
||||
|
||||
## Basic steps
|
||||
* Implement the interface `QualifiedName` in a class. This implementation must be tailored to the target language so
|
||||
that it can indentify unambiguously any class and operation in the analysed project (see JavaQualifiedName).
|
||||
* Determine the AST nodes that correspond to class and method declaration in your language. Both these types must
|
||||
implement the interface `QualifiableNode`, which means they must provide a `getQualifiedName` method to find their
|
||||
qualified name.
|
||||
* Implement the interface `Signature<N>`, parameterized with the type of the method AST nodes. Method signatures
|
||||
describe basic information about a method, which typically includes most of the modifiers they declare (eg
|
||||
visibility, abstract or virtual, etc.). It's up to you to define a
|
@ -4,9 +4,13 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.ast;
|
||||
|
||||
import net.sourceforge.pmd.lang.apex.metrics.signature.ApexOperationSignature;
|
||||
import net.sourceforge.pmd.lang.ast.SignedNode;
|
||||
import net.sourceforge.pmd.lang.metrics.Signature;
|
||||
|
||||
import apex.jorje.semantic.ast.member.Method;
|
||||
|
||||
public class ASTMethod extends AbstractApexNode<Method> {
|
||||
public class ASTMethod extends AbstractApexNode<Method> implements ApexQualifiableNode, SignedNode<ASTMethod> {
|
||||
|
||||
public ASTMethod(Method method) {
|
||||
super(method);
|
||||
@ -40,4 +44,16 @@ public class ASTMethod extends AbstractApexNode<Method> {
|
||||
|
||||
return super.getEndColumn();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ApexQualifiedName getQualifiedName() {
|
||||
return ApexQualifiedName.ofMethod(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ApexOperationSignature getSignature() {
|
||||
return ApexOperationSignature.of(this);
|
||||
}
|
||||
}
|
||||
|
@ -9,16 +9,21 @@ import java.lang.reflect.Field;
|
||||
import apex.jorje.data.ast.Identifier;
|
||||
import apex.jorje.semantic.ast.compilation.UserClass;
|
||||
|
||||
public class ASTUserClass extends ApexRootNode<UserClass> {
|
||||
public class ASTUserClass extends ApexRootNode<UserClass> implements ApexQualifiableNode {
|
||||
|
||||
private ApexQualifiedName qname;
|
||||
|
||||
|
||||
public ASTUserClass(UserClass userClass) {
|
||||
super(userClass);
|
||||
}
|
||||
|
||||
|
||||
public Object jjtAccept(ApexParserVisitor visitor, Object data) {
|
||||
return visitor.visit(this, data);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getImage() {
|
||||
try {
|
||||
@ -31,4 +36,21 @@ public class ASTUserClass extends ApexRootNode<UserClass> {
|
||||
}
|
||||
return super.getImage();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ApexQualifiedName getQualifiedName() {
|
||||
if (qname == null) {
|
||||
|
||||
ASTUserClass parent = this.getFirstParentOfType(ASTUserClass.class);
|
||||
|
||||
if (parent != null) {
|
||||
qname = ApexQualifiedName.ofNestedClass(parent.getQualifiedName(), this);
|
||||
} else {
|
||||
qname = ApexQualifiedName.ofOuterClass(this);
|
||||
}
|
||||
}
|
||||
|
||||
return qname;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.ast;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.QualifiableNode;
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public interface ApexQualifiableNode extends QualifiableNode {
|
||||
|
||||
@Override
|
||||
ApexQualifiedName getQualifiedName();
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.ast;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.QualifiedName;
|
||||
|
||||
/**
|
||||
* Qualified name of an apex class or method.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class ApexQualifiedName implements QualifiedName {
|
||||
|
||||
private final String nameSpace;
|
||||
private final String[] classes;
|
||||
private final String operation;
|
||||
|
||||
|
||||
private ApexQualifiedName(String nameSpace, String[] classes, String operation) {
|
||||
this.nameSpace = nameSpace;
|
||||
this.operation = operation;
|
||||
this.classes = classes;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String[] getClasses() {
|
||||
return Arrays.copyOf(classes, classes.length);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the namespace prefix of this resource.
|
||||
*
|
||||
* @return The namespace prefix
|
||||
*/
|
||||
public String getNameSpace() {
|
||||
return nameSpace;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isClass() {
|
||||
return operation == null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isOperation() {
|
||||
return operation != null;
|
||||
}
|
||||
|
||||
|
||||
static ApexQualifiedName ofOuterClass(ASTUserClass astUserClass) {
|
||||
String ns = astUserClass.node.getDefiningType().getNamespace().toString();
|
||||
String[] classes = {astUserClass.getImage()};
|
||||
return new ApexQualifiedName(ns, classes, null);
|
||||
}
|
||||
|
||||
|
||||
static ApexQualifiedName ofNestedClass(ApexQualifiedName parent, ASTUserClass astUserClass) {
|
||||
|
||||
String[] classes = Arrays.copyOf(parent.classes, parent.classes.length);
|
||||
classes[classes.length - 1] = astUserClass.getImage();
|
||||
return new ApexQualifiedName(parent.nameSpace, classes, null);
|
||||
}
|
||||
|
||||
|
||||
static ApexQualifiedName ofMethod(ASTMethod node) {
|
||||
ApexQualifiedName parent = node.getFirstParentOfType(ASTUserClass.class).getQualifiedName();
|
||||
|
||||
return new ApexQualifiedName(parent.nameSpace, parent.classes, node.getImage());
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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.ASTUserClass;
|
||||
import net.sourceforge.pmd.lang.metrics.AbstractMetricMemoizer;
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class ApexClassStats extends AbstractMetricMemoizer<ASTUserClass> {
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* 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.metrics.AbstractMetricMemoizer;
|
||||
|
||||
/**
|
||||
* Apex operation stats.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class ApexOperationStats extends AbstractMetricMemoizer<ASTMethod> {
|
||||
}
|
@ -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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTMethod;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTUserClass;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ApexQualifiedName;
|
||||
import net.sourceforge.pmd.lang.ast.QualifiedName;
|
||||
import net.sourceforge.pmd.lang.metrics.MetricMemoizer;
|
||||
import net.sourceforge.pmd.lang.metrics.ProjectMirror;
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class ApexProjectMirror implements ProjectMirror<ASTUserClass, ASTMethod> {
|
||||
|
||||
private final Map<ApexQualifiedName, ApexOperationStats> operations = new HashMap<>();
|
||||
private final Map<ApexQualifiedName, ApexClassStats> classes = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public MetricMemoizer<ASTMethod> getOperationStats(QualifiedName qname) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MetricMemoizer<ASTUserClass> getClassStats(QualifiedName qname) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.metrics.signature;
|
||||
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTMethod;
|
||||
import net.sourceforge.pmd.lang.metrics.Signature;
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class ApexOperationSignature implements Signature<ASTMethod> {
|
||||
|
||||
private String foo;
|
||||
|
||||
|
||||
/**
|
||||
* Builds the signature of this node.
|
||||
*
|
||||
* @param node The method node
|
||||
*
|
||||
* @return The signature of the node
|
||||
*/
|
||||
public static ApexOperationSignature of(ASTMethod node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.metrics.signature;
|
||||
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class ApexSignature {
|
||||
}
|
@ -33,4 +33,21 @@ public interface QualifiedName {
|
||||
*/
|
||||
String[] getClasses();
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the resource addressed by this qualified name is a class.
|
||||
*
|
||||
* @return true if the resource addressed by this qualified name is a class.
|
||||
*/
|
||||
boolean isClass();
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the resource addressed by this qualified name is an operation.
|
||||
*
|
||||
* @return true if the resource addressed by this qualified name is an operation.
|
||||
*/
|
||||
boolean isOperation();
|
||||
|
||||
|
||||
}
|
||||
|
@ -180,20 +180,12 @@ public final class JavaQualifiedName implements QualifiedName {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the resource addressed by this qualified name is a class.
|
||||
*
|
||||
* @return true if the resource addressed by this qualified name is a class.
|
||||
*/
|
||||
@Override
|
||||
public boolean isClass() {
|
||||
return classes[0] != null && operation == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the resource addressed by this qualified name is an operation.
|
||||
*
|
||||
* @return true if the resource addressed by this qualified name is an operation.
|
||||
*/
|
||||
@Override
|
||||
public boolean isOperation() {
|
||||
return operation != null;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ package net.sourceforge.pmd.lang.java.metrics.impl;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.metrics.impl.visitors.DefaultNpathVisitor;
|
||||
import net.sourceforge.pmd.lang.metrics.api.MetricVersion;
|
||||
import net.sourceforge.pmd.lang.metrics.MetricVersion;
|
||||
|
||||
/**
|
||||
* NPath complexity is a measurement of the acyclic execution paths through a function. See Nejmeh, Communications of
|
||||
@ -21,4 +21,5 @@ public class NpathMetric extends AbstractJavaOperationMetric {
|
||||
public double computeFor(ASTMethodOrConstructorDeclaration node, MetricVersion version) {
|
||||
return (Integer) node.jjtAccept(new DefaultNpathVisitor(), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user