Object pooling for Signatures

This commit is contained in:
oowekyala
2017-06-10 01:16:48 +02:00
parent 57c6aadd88
commit 7fde2478bc
6 changed files with 121 additions and 50 deletions

View File

@ -9,6 +9,6 @@ import net.sourceforge.pmd.lang.ast.Node;
/**
* @author Clément Fournier
*/
public interface ASTMethodOrConstructorDeclaration extends QualifiableNode, Node {
public interface ASTMethodOrConstructorDeclaration extends QualifiableNode, Node, AccessNode {
}

View File

@ -104,7 +104,7 @@ public class QualifiedName {
// Might be useful with type resolution
public static QualifiedName parseJavaCanonicalName(String canon) {
public static QualifiedName makeClassOf(Class<?> clazz) {
throw new UnsupportedOperationException();
}

View File

@ -4,6 +4,9 @@
package net.sourceforge.pmd.lang.java.oom.visitor;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
/**
@ -13,6 +16,8 @@ import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
*/
public class FieldSignature extends Signature {
private static final Map<Integer, FieldSignature> POOL = new HashMap<>();
public final boolean isStatic;
public final boolean isFinal;
@ -30,7 +35,16 @@ public class FieldSignature extends Signature {
* @return The signature of the field.
*/
public static FieldSignature buildFor(ASTFieldDeclaration node) {
return new FieldSignature(Visibility.get(node), node.isStatic(), node.isFinal());
int code = code(Visibility.get(node), node.isStatic(), node.isAbstract());
if (!POOL.containsKey(code)) {
POOL.put(code, new FieldSignature(Visibility.get(node), node.isStatic(), node.isAbstract()));
}
return POOL.get(code);
}
/** Used internally by the pooler. */
private static int code(Visibility visibility, boolean isStatic, boolean isAbstract) {
return visibility.hashCode() * 31 + (isStatic ? 1 : 0) * 2 + (isAbstract ? 1 : 0);
}
@Override

View File

@ -4,6 +4,9 @@
package net.sourceforge.pmd.lang.java.oom.visitor;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
@ -15,44 +18,18 @@ import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
*/
public class OperationSignature extends Signature {
public final Role role;
private static final Map<Integer, OperationSignature> POOL = new HashMap<>();
public final Role role;
public final boolean isAbstract;
public OperationSignature(Visibility visibility, Role role, boolean isAbstract) {
private OperationSignature(Visibility visibility, Role role, boolean isAbstract) {
super(visibility);
this.role = role;
this.isAbstract = isAbstract;
}
/**
* Builds an operation signature from a method declaration.
*
* @param node The method declaration
*
* @return The signature of the parameter
*/
public static OperationSignature buildFor(ASTMethodDeclaration node) {
// TODO better getter or setter detection
boolean isGetterOrSetter = node.getName().startsWith("get")
|| node.getName().startsWith("set");
Role role = isGetterOrSetter ? Role.GETTER_OR_SETTER
: node.isStatic() ? Role.STATIC : Role.METHOD;
return new OperationSignature(Visibility.get(node), role, node.isAbstract());
}
/**
* Builds an operation signature from a constructor declaration.
*
* @param node The constructor declaration
*
* @return The signature of the parameter
*/
public static OperationSignature buildFor(ASTConstructorDeclaration node) {
return new OperationSignature(Visibility.get(node), Role.CONSTRUCTOR, node.isAbstract());
}
/**
* Builds an operation signature from a method or constructor declaration.
*
@ -61,14 +38,21 @@ public class OperationSignature extends Signature {
* @return The signature of the parameter
*/
public static OperationSignature buildFor(ASTMethodOrConstructorDeclaration node) {
return node instanceof ASTMethodDeclaration ? buildFor((ASTMethodDeclaration) node)
: buildFor((ASTConstructorDeclaration) node);
int code = code(Visibility.get(node), Role.get(node), node.isAbstract());
if (!POOL.containsKey(code)) {
POOL.put(code, new OperationSignature(Visibility.get(node), Role.get(node), node.isAbstract()));
}
return POOL.get(code);
}
/** Used internally by the pooler. */
private static int code(Visibility visibility, Role role, boolean isAbstract) {
return visibility.hashCode() * 31 + role.hashCode() * 2 + (isAbstract ? 1 : 0);
}
@Override
public boolean equals(Object o) {
return o instanceof OperationSignature && super.equals(o) && role == (
(OperationSignature) o).role
return o instanceof OperationSignature && super.equals(o) && role == ((OperationSignature) o).role
&& isAbstract == ((OperationSignature) o).isAbstract;
}
@ -81,6 +65,18 @@ public class OperationSignature extends Signature {
* Role of an operation.
*/
public enum Role {
GETTER_OR_SETTER, CONSTRUCTOR, METHOD, STATIC
GETTER_OR_SETTER, CONSTRUCTOR, METHOD, STATIC;
public static Role get(ASTMethodOrConstructorDeclaration node) {
return node instanceof ASTConstructorDeclaration ? CONSTRUCTOR : get((ASTMethodDeclaration) node);
}
private static Role get(ASTMethodDeclaration node) {
// TODO better getter or setter detection
boolean isGetterOrSetter = node.getName().startsWith("get")
|| node.getName().startsWith("set");
return node.isStatic() ? Role.STATIC : isGetterOrSetter ? Role.GETTER_OR_SETTER : Role.METHOD;
}
}
}

View File

@ -4,7 +4,7 @@
package net.sourceforge.pmd.lang.java.oom.visitor;
import net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessNode;
import net.sourceforge.pmd.lang.java.ast.AccessNode;
/**
* Generic signature. This class is extended by classes specific to operations and fields.
@ -35,7 +35,6 @@ public abstract class Signature {
public enum Visibility {
PUBLIC, PACKAGE, PROTECTED, PRIVATE, UNDEF;
/**
* Returns the Visibility enum key for a node.
*
@ -43,13 +42,12 @@ public abstract class Signature {
*
* @return The visibility enum key for a node.
*/
public static Visibility get(AbstractJavaAccessNode node) {
public static Visibility get(AccessNode node) {
return node.isPublic() ? PUBLIC
: node.isPackagePrivate() ? PACKAGE
: node.isProtected() ? PROTECTED
: node.isPrivate()
? PRIVATE
: UNDEF;
: node.isPackagePrivate() ? PACKAGE
: node.isProtected() ? PROTECTED
: node.isPrivate() ? PRIVATE
: UNDEF;
}
}
}

View File

@ -81,8 +81,7 @@ public class SignatureTest extends ParserTst {
" public void doSomething(){}}";
List<ASTMethodOrConstructorDeclaration> nodes = getOrderedNodes(ASTMethodOrConstructorDeclaration
.class, TEST);
List<ASTMethodOrConstructorDeclaration> nodes = getOrderedNodes(ASTMethodOrConstructorDeclaration.class, TEST);
List<OperationSignature> sigs = new ArrayList<>();
for (ASTMethodOrConstructorDeclaration node : nodes) {
@ -106,8 +105,7 @@ public class SignatureTest extends ParserTst {
"public void doSomething(){}}";
List<ASTMethodOrConstructorDeclaration> nodes = getOrderedNodes(ASTMethodOrConstructorDeclaration
.class, TEST);
List<ASTMethodOrConstructorDeclaration> nodes = getOrderedNodes(ASTMethodOrConstructorDeclaration.class, TEST);
List<OperationSignature> sigs = new ArrayList<>();
for (ASTMethodOrConstructorDeclaration node : nodes) {
@ -121,4 +119,69 @@ public class SignatureTest extends ParserTst {
assertFalse(sigs.get(3).isAbstract);
assertFalse(sigs.get(4).isAbstract);
}
@Test
public void operationPoolTest() {
final String TEST = "class Bzaz{ " +
"public static void foo(){} " +
"public static void az(){} " +
"public static int getX(){return x;}}";
final String TEST2 = "class Bzaz{ " +
"void foo(){} " +
"void az(){} " +
"int rand(){return x;}}";
List<ASTMethodOrConstructorDeclaration> nodes = getOrderedNodes(ASTMethodOrConstructorDeclaration.class, TEST);
List<ASTMethodOrConstructorDeclaration> nodes2 = getOrderedNodes(ASTMethodOrConstructorDeclaration.class, TEST2);
List<OperationSignature> sigs = new ArrayList<>();
List<OperationSignature> sigs2 = new ArrayList<>();
for (int i = 0; i < sigs.size(); i++) {
sigs.add(OperationSignature.buildFor(nodes.get(i)));
sigs2.add(OperationSignature.buildFor(nodes2.get(i)));
}
for (int i = 0; i < sigs.size() - 1; i++) {
assertTrue(sigs.get(i) == sigs.get(i + 1));
assertTrue(sigs2.get(i) == sigs2.get(i + 1));
}
}
@Test
public void fieldPoolTest() {
final String TEST = "class Bzaz {" +
"public int bar;" +
"public String k;" +
"public double d;" +
"}";
final String TEST2 = "class Foo {" +
"private final int i;" +
"private final int x;" +
"private final String k;" +
"}";
List<ASTFieldDeclaration> nodes = getOrderedNodes(ASTFieldDeclaration.class, TEST);
List<ASTFieldDeclaration> nodes2 = getOrderedNodes(ASTFieldDeclaration.class, TEST2);
List<FieldSignature> sigs = new ArrayList<>();
List<FieldSignature> sigs2 = new ArrayList<>();
for (int i = 0; i < sigs.size(); i++) {
sigs.add(FieldSignature.buildFor(nodes.get(i)));
sigs2.add(FieldSignature.buildFor(nodes2.get(i)));
}
for (int i = 0; i < sigs.size() - 1; i++) {
assertTrue(sigs.get(i) == sigs.get(i + 1));
assertTrue(sigs2.get(i) == sigs2.get(i + 1));
}
}
}