Operation signatures
This commit is contained in:
parent
7fd85f77a3
commit
e9fab949b7
@ -14,9 +14,34 @@ 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
|
||||
* Determine the AST nodes that correspond to class and method declaration in your language. These types are
|
||||
referred hereafter as `T` and `O`, respectively. Both these types must implement the interface `QualifiableNode`, which
|
||||
means they must provide a `getQualifiedName` method to give access to their qualified name.
|
||||
* Implement the interface `Signature<O>`, 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
|
||||
visibility, abstract or virtual, etc.). It's up to you to define the right level of detail, depending on the accuracy
|
||||
of the pattern matching required.
|
||||
* Make type `O` implement `SignedNode<O>`. This makes the node capable of giving its signature.
|
||||
* Create a class implementing `Memoizer<T>` and one `Memoizer<O>`. An abstract base class is available. Instances of
|
||||
these classes each represent a class or operation, respectively. They are used to store the results of metrics that
|
||||
are already computed.
|
||||
* Create a class implementing `ProjectMirror<T, O>`. This class will store the memoizers for all the classes and
|
||||
interfaces of the analysed project. This class must be able to fetch and return a memoizer given the qualified name
|
||||
of the resource it represents. As it stores the memoizers, it's a good idea to implement some signature matching
|
||||
utilities in this class. What's signature matching? (See write custom metrics -- TODO)
|
||||
* Create a class extending `AbstractMetricsComputer<T, O>`. This object will be responsible for calculating metrics
|
||||
given a memoizer, a node and info about the metric. Typically, this object is stateless so you might as well make it
|
||||
a singleton.
|
||||
* Create a class extending `AbstractMetricsFacade<T, O>`. This class needs a reference to your `ProjectMirror` and
|
||||
your `MetricsComputer`. It backs the real end user façade, and handles user provided parameters before delegating to
|
||||
your `MetricsComputer`.
|
||||
* Create the static façade of your framework. This one has an instance of your `MetricsFaçade` object and delegates
|
||||
static methods to that instance. It should be able to give back
|
||||
* If you want to implement signature matching, create an `AbstractMetric` class, which gives access to a
|
||||
`SignatureMatcher` to your metrics.
|
||||
* Create classes `AbstractOperationMetric` and `AbstractClassMetric`. These must implement `Metric<T>` and
|
||||
`Metric<O>`, respectively. They typically provide defaults for the `supports` method of each metric.
|
||||
* Create enums `ClassMetricKey` and `OperationMetricKey`. These must implement `MetricKey<T>` and `MetricKey<O>`. The
|
||||
enums list all available metric keys for your language.
|
||||
* Create metrics by extending your base classes, reference them in your enums, and you can start using them with your
|
||||
façade!
|
@ -10,6 +10,7 @@ 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.apex.metrics.signature.ApexOperationSignature;
|
||||
import net.sourceforge.pmd.lang.ast.QualifiedName;
|
||||
import net.sourceforge.pmd.lang.metrics.MetricMemoizer;
|
||||
import net.sourceforge.pmd.lang.metrics.ProjectMirror;
|
||||
@ -19,18 +20,39 @@ import net.sourceforge.pmd.lang.metrics.ProjectMirror;
|
||||
*/
|
||||
public class ApexProjectMirror implements ProjectMirror<ASTUserClass, ASTMethod> {
|
||||
|
||||
private final Map<ApexQualifiedName, ApexOperationStats> operations = new HashMap<>();
|
||||
private final Map<ApexOperationSignature, Map<ApexQualifiedName, ApexOperationStats>> operations = new HashMap<>();
|
||||
private final Map<ApexQualifiedName, ApexClassStats> classes = new HashMap<>();
|
||||
|
||||
|
||||
void addOperation(ApexQualifiedName qname, ApexOperationSignature sig) {
|
||||
if (!operations.containsKey(sig)) {
|
||||
operations.put(sig, new HashMap<>());
|
||||
}
|
||||
|
||||
operations.get(sig).put(qname, new ApexOperationStats());
|
||||
}
|
||||
|
||||
|
||||
void addClass(ApexQualifiedName qname) {
|
||||
classes.put(qname, new ApexClassStats());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MetricMemoizer<ASTMethod> getOperationStats(QualifiedName qname) {
|
||||
for (Map<ApexQualifiedName, ApexOperationStats> map : operations.values()) {
|
||||
ApexOperationStats stats = map.get(qname);
|
||||
if (stats != null) {
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MetricMemoizer<ASTUserClass> getClassStats(QualifiedName qname) {
|
||||
return null;
|
||||
return classes.get(qname);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,15 +4,45 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.metrics.signature;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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> {
|
||||
public final class ApexOperationSignature extends ApexSignature implements Signature<ASTMethod> {
|
||||
|
||||
private String foo;
|
||||
private static final Map<Integer, ApexOperationSignature> POOL = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a signature using its visibility.
|
||||
*
|
||||
* @param visibility The visibility
|
||||
*/
|
||||
private ApexOperationSignature(Visibility visibility) {
|
||||
super(visibility);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return code(visibility);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj == this;
|
||||
}
|
||||
|
||||
|
||||
private static int code(Visibility visibility) {
|
||||
return visibility.hashCode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -23,7 +53,13 @@ public class ApexOperationSignature implements Signature<ASTMethod> {
|
||||
* @return The signature of the node
|
||||
*/
|
||||
public static ApexOperationSignature of(ASTMethod node) {
|
||||
return null;
|
||||
Visibility visibility = Visibility.get(node);
|
||||
int code = code(visibility);
|
||||
if (!POOL.containsKey(code)) {
|
||||
POOL.put(code, new ApexOperationSignature(visibility));
|
||||
}
|
||||
return POOL.get(code);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -4,8 +4,43 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.metrics.signature;
|
||||
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTMethod;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTModifierNode;
|
||||
|
||||
/**
|
||||
* Base class for apex field or method signatures.
|
||||
*
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
public class ApexSignature {
|
||||
public abstract class ApexSignature {
|
||||
|
||||
/** Visibility of the field or method. */
|
||||
public final Visibility visibility;
|
||||
|
||||
|
||||
/** Create a signature using its visibility. */
|
||||
protected ApexSignature(Visibility visibility) {
|
||||
this.visibility = visibility;
|
||||
}
|
||||
|
||||
|
||||
/** Visibility of a field or method. */
|
||||
public enum Visibility {
|
||||
PRIVATE, PUBLIC, PROTECTED, GLOBAL;
|
||||
|
||||
|
||||
public static Visibility get(ASTMethod method) {
|
||||
ASTModifierNode modifierNode = method.getFirstChildOfType(ASTModifierNode.class);
|
||||
if (modifierNode.isPublic()) {
|
||||
return PUBLIC;
|
||||
} else if (modifierNode.isPrivate()) {
|
||||
return PRIVATE;
|
||||
} else if (modifierNode.isProtected()) {
|
||||
return PROTECTED;
|
||||
} else {
|
||||
return GLOBAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user