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 * @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 // Might be useful with type resolution
public static QualifiedName parseJavaCanonicalName(String canon) { public static QualifiedName makeClassOf(Class<?> clazz) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -4,6 +4,9 @@
package net.sourceforge.pmd.lang.java.oom.visitor; package net.sourceforge.pmd.lang.java.oom.visitor;
import java.util.HashMap;
import java.util.Map;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; 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 { public class FieldSignature extends Signature {
private static final Map<Integer, FieldSignature> POOL = new HashMap<>();
public final boolean isStatic; public final boolean isStatic;
public final boolean isFinal; public final boolean isFinal;
@ -30,7 +35,16 @@ public class FieldSignature extends Signature {
* @return The signature of the field. * @return The signature of the field.
*/ */
public static FieldSignature buildFor(ASTFieldDeclaration node) { 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 @Override

View File

@ -4,6 +4,9 @@
package net.sourceforge.pmd.lang.java.oom.visitor; 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.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration; 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 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 final boolean isAbstract;
public OperationSignature(Visibility visibility, Role role, boolean isAbstract) {
private OperationSignature(Visibility visibility, Role role, boolean isAbstract) {
super(visibility); super(visibility);
this.role = role; this.role = role;
this.isAbstract = isAbstract; 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. * 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 * @return The signature of the parameter
*/ */
public static OperationSignature buildFor(ASTMethodOrConstructorDeclaration node) { public static OperationSignature buildFor(ASTMethodOrConstructorDeclaration node) {
return node instanceof ASTMethodDeclaration ? buildFor((ASTMethodDeclaration) node) int code = code(Visibility.get(node), Role.get(node), node.isAbstract());
: buildFor((ASTConstructorDeclaration) node); 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 @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o instanceof OperationSignature && super.equals(o) && role == ( return o instanceof OperationSignature && super.equals(o) && role == ((OperationSignature) o).role
(OperationSignature) o).role
&& isAbstract == ((OperationSignature) o).isAbstract; && isAbstract == ((OperationSignature) o).isAbstract;
} }
@ -81,6 +65,18 @@ public class OperationSignature extends Signature {
* Role of an operation. * Role of an operation.
*/ */
public enum Role { 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; 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. * 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 enum Visibility {
PUBLIC, PACKAGE, PROTECTED, PRIVATE, UNDEF; PUBLIC, PACKAGE, PROTECTED, PRIVATE, UNDEF;
/** /**
* Returns the Visibility enum key for a node. * Returns the Visibility enum key for a node.
* *
@ -43,13 +42,12 @@ public abstract class Signature {
* *
* @return The visibility enum key for a node. * @return The visibility enum key for a node.
*/ */
public static Visibility get(AbstractJavaAccessNode node) { public static Visibility get(AccessNode node) {
return node.isPublic() ? PUBLIC return node.isPublic() ? PUBLIC
: node.isPackagePrivate() ? PACKAGE : node.isPackagePrivate() ? PACKAGE
: node.isProtected() ? PROTECTED : node.isProtected() ? PROTECTED
: node.isPrivate() : node.isPrivate() ? PRIVATE
? PRIVATE : UNDEF;
: UNDEF;
} }
} }
} }

View File

@ -81,8 +81,7 @@ public class SignatureTest extends ParserTst {
" public void doSomething(){}}"; " public void doSomething(){}}";
List<ASTMethodOrConstructorDeclaration> nodes = getOrderedNodes(ASTMethodOrConstructorDeclaration List<ASTMethodOrConstructorDeclaration> nodes = getOrderedNodes(ASTMethodOrConstructorDeclaration.class, TEST);
.class, TEST);
List<OperationSignature> sigs = new ArrayList<>(); List<OperationSignature> sigs = new ArrayList<>();
for (ASTMethodOrConstructorDeclaration node : nodes) { for (ASTMethodOrConstructorDeclaration node : nodes) {
@ -106,8 +105,7 @@ public class SignatureTest extends ParserTst {
"public void doSomething(){}}"; "public void doSomething(){}}";
List<ASTMethodOrConstructorDeclaration> nodes = getOrderedNodes(ASTMethodOrConstructorDeclaration List<ASTMethodOrConstructorDeclaration> nodes = getOrderedNodes(ASTMethodOrConstructorDeclaration.class, TEST);
.class, TEST);
List<OperationSignature> sigs = new ArrayList<>(); List<OperationSignature> sigs = new ArrayList<>();
for (ASTMethodOrConstructorDeclaration node : nodes) { for (ASTMethodOrConstructorDeclaration node : nodes) {
@ -121,4 +119,69 @@ public class SignatureTest extends ParserTst {
assertFalse(sigs.get(3).isAbstract); assertFalse(sigs.get(3).isAbstract);
assertFalse(sigs.get(4).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));
}
}
} }