diff --git a/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java b/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java
index d3d355e531..6e70a97ae2 100644
--- a/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java
+++ b/sootup.core/src/main/java/sootup/core/typehierarchy/TypeHierarchy.java
@@ -172,7 +172,7 @@ default boolean isSubtype(@Nonnull Type supertype, @Nonnull Type potentialSubtyp
/**
* Returns all superclasses of classType
up to java.lang.Object
, which
- * will be the last entry in the list.
+ * will be the last entry in the list. i.e. its ordered from bottom level to top level.
*/
@Nonnull
default List superClassesOf(@Nonnull ClassType classType) {
@@ -207,4 +207,10 @@ default List incompleteSuperClassesOf(@Nonnull ClassType classType) {
}
return superClasses;
}
+
+ Set directlyImplementedInterfacesOf(@Nonnull ClassType type);
+
+ boolean isInterface(@Nonnull ClassType type);
+
+ Set directlyExtendedInterfacesOf(@Nonnull ClassType type);
}
diff --git a/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java b/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java
index 713edba8e7..f04cbbefaf 100644
--- a/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java
+++ b/sootup.core/src/main/java/sootup/core/typehierarchy/ViewTypeHierarchy.java
@@ -181,7 +181,6 @@ public Stream directlyExtendedInterfacesOf(@Nonnull Vertex interfaceVert
.map(graph::getEdgeTarget);
}
- /** for completeness - You could use Sootclass.getSuperclass() directly */
public Stream directSuperClassOf(@Nonnull Vertex classVertex) {
Graph graph = lazyScanResult.get().graph;
return graph.outgoingEdgesOf(classVertex).stream()
@@ -192,7 +191,7 @@ public Stream directSuperClassOf(@Nonnull Vertex classVertex) {
public Set directlyImplementedInterfacesOf(@Nonnull ClassType classType) {
Vertex vertex = lazyScanResult.get().typeToVertex.get(classType);
if (vertex == null) {
- throw new RuntimeException("Could not find " + classType + " in hierarchy.");
+ throw new IllegalStateException("Could not find '" + classType + "' in hierarchy.");
}
if (vertex.type != VertexType.Class) {
throw new IllegalArgumentException(classType + " is not a class.");
@@ -206,7 +205,7 @@ public Set directlyImplementedInterfacesOf(@Nonnull ClassType classTy
public Set directlyExtendedInterfacesOf(@Nonnull ClassType interfaceType) {
Vertex vertex = lazyScanResult.get().typeToVertex.get(interfaceType);
if (vertex == null) {
- throw new RuntimeException("Could not find " + interfaceType + " in hierarchy.");
+ throw new IllegalStateException("Could not find " + interfaceType + " in hierarchy.");
}
if (vertex.type != VertexType.Interface) {
throw new IllegalArgumentException(interfaceType + " is not a class.");
@@ -216,11 +215,16 @@ public Set directlyExtendedInterfacesOf(@Nonnull ClassType interfaceT
.collect(Collectors.toSet());
}
+ /**
+ * method exists for completeness - superClassOf() / which is basically SootClass.getSuperClass()
+ * should be more performant.
+ */
@Nullable
+ @Deprecated
public ClassType directSuperClassOf(@Nonnull ClassType classType) {
Vertex vertex = lazyScanResult.get().typeToVertex.get(classType);
if (vertex == null) {
- throw new RuntimeException("Could not find " + classType + " in hierarchy.");
+ throw new IllegalStateException("Could not find " + classType + " in hierarchy.");
}
Graph graph = lazyScanResult.get().graph;
List list =
@@ -230,6 +234,7 @@ public ClassType directSuperClassOf(@Nonnull ClassType classType) {
.collect(Collectors.toList());
if (list.isEmpty()) {
+ /* is java.lang.Object */
return null;
} else if (list.size() > 1) {
throw new RuntimeException(classType + "cannot have multiple superclasses");
@@ -245,7 +250,7 @@ public Set implementedInterfacesOf(@Nonnull ClassType type) {
Vertex vertex = scanResult.typeToVertex.get(type);
if (vertex == null) {
- throw new ResolveException("Could not find " + type + " in hierarchy for view " + view);
+ throw new IllegalStateException("Could not find " + type + " in hierarchy for view " + view);
}
switch (vertex.type) {
diff --git a/sootup.core/src/main/java/sootup/core/types/Type.java b/sootup.core/src/main/java/sootup/core/types/Type.java
index 3a256db688..5415f91b9b 100644
--- a/sootup.core/src/main/java/sootup/core/types/Type.java
+++ b/sootup.core/src/main/java/sootup/core/types/Type.java
@@ -22,6 +22,7 @@
* #L%
*/
+import javax.annotation.Nonnull;
import sootup.core.jimple.visitor.Acceptor;
import sootup.core.jimple.visitor.TypeVisitor;
@@ -50,7 +51,7 @@ public static boolean isObject(Type type) {
* This method is used to make an array type for the given type. If the given type is an array
* type, then increase its dimension with given dim
*/
- public static ArrayType makeArrayType(Type type, int dim) {
+ public static ArrayType createArrayType(@Nonnull Type type, int dim) {
if (type instanceof ArrayType) {
return new ArrayType(
((ArrayType) type).getBaseType(), ((ArrayType) type).getDimension() + dim);
diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/AugEvalFunction.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/AugEvalFunction.java
index 06785cc9bc..33fb855957 100644
--- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/AugEvalFunction.java
+++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/AugEvalFunction.java
@@ -21,6 +21,7 @@
* #L%
*/
+import com.google.common.collect.ImmutableSet;
import java.util.*;
import javax.annotation.Nonnull;
import sootup.core.IdentifierFactory;
@@ -33,7 +34,6 @@
import sootup.core.jimple.common.ref.*;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.model.SootClass;
-import sootup.core.typehierarchy.ViewTypeHierarchy;
import sootup.core.types.ArrayType;
import sootup.core.types.ClassType;
import sootup.core.types.PrimitiveType;
@@ -41,16 +41,35 @@
import sootup.core.views.View;
import sootup.java.bytecode.interceptors.typeresolving.types.AugIntegerTypes;
import sootup.java.bytecode.interceptors.typeresolving.types.BottomType;
-import sootup.java.core.JavaIdentifierFactory;
/** @author Zun Wang */
public class AugEvalFunction {
- IdentifierFactory factory = JavaIdentifierFactory.getInstance();
+
+ private final ImmutableSet evalClassTypes;
+ private final ClassType stringClassType;
+ private final ClassType classClassType;
+ private final ClassType methodHandleClassType;
+ private final ClassType methodTypeClassType;
+ private final ClassType throwableClassType;
+
View extends SootClass>> view;
- PrimitiveHierarchy primitiveHierarchy = new PrimitiveHierarchy();
public AugEvalFunction(View extends SootClass>> view) {
this.view = view;
+
+ // one time setup
+ final IdentifierFactory identifierFactory = view.getIdentifierFactory();
+ evalClassTypes =
+ ImmutableSet.of(
+ identifierFactory.getClassType("java.lang.Object"),
+ identifierFactory.getClassType("java.lang.Cloneable"),
+ identifierFactory.getClassType("java.io.Serializable"));
+
+ stringClassType = identifierFactory.getClassType("java.lang.String");
+ classClassType = identifierFactory.getClassType("java.lang.Class");
+ methodHandleClassType = identifierFactory.getClassType("java.lang.MethodHandle");
+ methodTypeClassType = identifierFactory.getClassType("java.lang.MethodType");
+ throwableClassType = identifierFactory.getClassType("java.lang.Throwable");
}
/**
@@ -62,12 +81,15 @@ public Type evaluate(
@Nonnull Value value,
@Nonnull Stmt stmt,
@Nonnull StmtGraph> graph) {
+
+ // TODO: [ms] make use of the ValueVisitor..
+
if (value instanceof Immediate) {
if (value instanceof Local) {
return typing.getType((Local) value);
// if value instanceof Constant
} else {
- if (value instanceof IntConstant) {
+ if (value.getClass() == IntConstant.class) {
int val = ((IntConstant) value).getValue();
if (val >= 0 && val < 2) {
return AugIntegerTypes.getInteger1();
@@ -84,22 +106,22 @@ public Type evaluate(
} else {
return PrimitiveType.getInt();
}
- } else if (value instanceof LongConstant
- || value instanceof FloatConstant
- || value instanceof DoubleConstant
- || value instanceof NullConstant
- || value instanceof EnumConstant) {
+ } else if (value.getClass() == LongConstant.class
+ || value.getClass() == FloatConstant.class
+ || value.getClass() == DoubleConstant.class
+ || value.getClass() == NullConstant.class
+ || value.getClass() == EnumConstant.class) {
return value.getType();
- } else if (value instanceof StringConstant) {
- return factory.getClassType("java.lang.String");
- } else if (value instanceof ClassConstant) {
- return factory.getClassType("java.lang.Class");
- } else if (value instanceof MethodHandle) {
- return factory.getClassType("java.lang.MethodHandle");
- } else if (value instanceof MethodType) {
- return factory.getClassType("java.lang.MethodType");
+ } else if (value.getClass() == StringConstant.class) {
+ return stringClassType;
+ } else if (value.getClass() == ClassConstant.class) {
+ return classClassType;
+ } else if (value.getClass() == MethodHandle.class) {
+ return methodHandleClassType;
+ } else if (value.getClass() == MethodType.class) {
+ return methodTypeClassType;
} else {
- throw new RuntimeException("Invaluable constant in AugEvalFunction: " + value);
+ throw new RuntimeException("Invaluable constant in AugEvalFunction '" + value + "'.");
}
}
} else if (value instanceof Expr) {
@@ -119,20 +141,23 @@ public Type evaluate(
return (tl instanceof PrimitiveType.IntType) ? PrimitiveType.getInt() : tl;
} else {
if (tl instanceof PrimitiveType.IntType && tr instanceof PrimitiveType.IntType) {
- if (tl instanceof PrimitiveType.BooleanType) {
- return (tr instanceof PrimitiveType.BooleanType) ? PrimitiveType.getBoolean() : tr;
- } else if (tr instanceof PrimitiveType.BooleanType) {
+
+ if (tl.getClass() == PrimitiveType.BooleanType.class) {
+ return (tr.getClass() == PrimitiveType.BooleanType.class)
+ ? PrimitiveType.getBoolean()
+ : tr;
+ } else if (tr.getClass() == PrimitiveType.BooleanType.class) {
return tl;
} else {
- Collection set = primitiveHierarchy.getLeastCommonAncestor(tl, tr);
- if (set.isEmpty()) {
+ Collection lca = PrimitiveHierarchy.getLeastCommonAncestor(tl, tr);
+ if (lca.isEmpty()) {
throw new RuntimeException(
- "Invaluable expression by using AugEvalFunction: " + value);
+ "Invaluable expression by using AugEvalFunction '" + value + "'.");
}
- return set.iterator().next();
+ return lca.iterator().next();
}
} else {
- return (tl instanceof PrimitiveType.LongType) ? PrimitiveType.getLong() : tr;
+ return (tl.getClass() == PrimitiveType.LongType.class) ? PrimitiveType.getLong() : tr;
}
}
} else if (value instanceof AbstractFloatBinopExpr) {
@@ -151,7 +176,6 @@ public Type evaluate(
} else if (value instanceof Ref) {
if (value instanceof JCaughtExceptionRef) {
Set exceptionTypes = getExceptionTypeCandidates(stmt, graph);
- ClassType throwable = factory.getClassType("java.lang.Throwable");
ClassType type = null;
for (ClassType exceptionType : exceptionTypes) {
Optional> exceptionClassOp = view.getClass(exceptionType);
@@ -159,11 +183,10 @@ public Type evaluate(
if (exceptionClassOp.isPresent()) {
exceptionClass = (SootClass>) exceptionClassOp.get();
} else {
- throw new RuntimeException(
- "ExceptionType: \"" + exceptionType + "\" is not in the view");
+ throw new RuntimeException("ExceptionType '" + exceptionType + "' is not in the view");
}
if (exceptionClass.isPhantomClass()) {
- return throwable;
+ return throwableClassType;
} else if (type == null) {
type = exceptionType;
} else {
@@ -171,7 +194,7 @@ public Type evaluate(
}
}
if (type == null) {
- throw new RuntimeException("Invaluable reference in AugEvalFunction: " + value);
+ throw new RuntimeException("Invaluable reference in AugEvalFunction '" + value + "'.");
}
return type;
} else if (value instanceof JArrayRef) {
@@ -181,31 +204,16 @@ public Type evaluate(
// Because Object, Serializable and Cloneable are super types of any ArrayType, thus the
// base type of ArrayRef could be one of this three types
} else if (type instanceof ClassType) {
- String name = ((ClassType) type).getFullyQualifiedName();
- Type retType;
- switch (name) {
- case "java.lang.Object":
- retType = factory.getClassType("java.lang.Object");
- break;
- case "java.lang.Cloneable":
- retType = factory.getClassType("java.lang.Cloneable");
- break;
- case "java.io.Serializable":
- retType = factory.getClassType("java.io.Serializable");
- break;
- default:
- retType = BottomType.getInstance();
- }
- return retType;
+ return evalClassTypes.contains(type) ? type : BottomType.getInstance();
} else {
return BottomType.getInstance();
}
- } else if (value instanceof JThisRef
- || value instanceof JParameterRef
+ } else if (value.getClass() == JThisRef.class
+ || value.getClass() == JParameterRef.class
|| value instanceof JFieldRef) {
return value.getType();
} else {
- throw new RuntimeException("Invaluable reference in AugEvalFunction: " + value);
+ throw new RuntimeException("Invaluable reference in AugEvalFunction '" + value + "'.");
}
}
return null;
@@ -225,20 +233,20 @@ private Set getExceptionTypeCandidates(
* type
*/
private Deque getExceptionPath(@Nonnull ClassType exceptionType) {
- ViewTypeHierarchy hierarchy = new ViewTypeHierarchy(view);
- ClassType throwable = factory.getClassType("java.lang.Throwable");
Deque path = new ArrayDeque<>();
path.push(exceptionType);
- while (!exceptionType.equals(throwable)) {
- ClassType superType = hierarchy.directSuperClassOf(exceptionType);
- if (superType != null) {
- path.push(superType);
- exceptionType = superType;
- } else {
- throw new RuntimeException(
- "The path from " + exceptionType + " to java.lang.Throwable cannot be found!");
+ while (exceptionType != throwableClassType) {
+ final Optional extends ClassType> superclassOpt =
+ view.getClass(exceptionType).flatMap(SootClass::getSuperclass);
+ if (!superclassOpt.isPresent()) {
+ throw new IllegalStateException(
+ "The path from '" + exceptionType + "' to java.lang.Throwable cannot be found!");
}
+
+ ClassType superType = superclassOpt.get();
+ path.push(superType);
+ exceptionType = superType;
}
return path;
}
@@ -250,13 +258,13 @@ private Deque getExceptionPath(@Nonnull ClassType exceptionType) {
* @param b an exception type
*/
private ClassType getLeastCommonExceptionType(@Nonnull ClassType a, @Nonnull ClassType b) {
- if (a.equals(b)) {
+ if (a == b) {
return a;
}
ClassType commonType = null;
Deque pathA = getExceptionPath(a);
Deque pathB = getExceptionPath(b);
- while (!pathA.isEmpty() && !pathB.isEmpty() && pathA.getFirst().equals(pathB.getFirst())) {
+ while (!pathA.isEmpty() && !pathB.isEmpty() && pathA.peekFirst().equals(pathB.peekFirst())) {
commonType = pathA.removeFirst();
pathB.removeFirst();
}
diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/BytecodeHierarchy.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/BytecodeHierarchy.java
index d043b9f8c1..bc154fcd05 100644
--- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/BytecodeHierarchy.java
+++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/BytecodeHierarchy.java
@@ -20,99 +20,118 @@
* .
* #L%
*/
+
import java.util.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import sootup.core.IdentifierFactory;
import sootup.core.model.SootClass;
-import sootup.core.typehierarchy.ViewTypeHierarchy;
+import sootup.core.typehierarchy.TypeHierarchy;
import sootup.core.types.*;
import sootup.core.views.View;
import sootup.java.bytecode.interceptors.typeresolving.types.BottomType;
/** @author Zun Wang */
-public class BytecodeHierarchy implements IHierarchy {
+public class BytecodeHierarchy {
- private final ViewTypeHierarchy typeHierarchy;
- private final ClassType object;
- private final ClassType serializable;
- private final ClassType cloneable;
- private final PrimitiveHierarchy primitiveHierarchy;
+ private final TypeHierarchy typeHierarchy;
+ public final ClassType objectClassType;
+ public final ClassType throwableClassType;
+ private final ClassType serializableClassType;
+ private final ClassType cloneableClassType;
public BytecodeHierarchy(View extends SootClass>> view) {
- this.typeHierarchy = new ViewTypeHierarchy(view);
+ this.typeHierarchy = view.getTypeHierarchy();
IdentifierFactory factory = view.getIdentifierFactory();
- object = factory.getClassType("java.lang.Object");
- serializable = factory.getClassType("java.io.Serializable");
- cloneable = factory.getClassType("java.lang.Cloneable");
- primitiveHierarchy = new PrimitiveHierarchy();
+ objectClassType = factory.getClassType("java.lang.Object");
+ throwableClassType = factory.getClassType("java.lang.Throwable");
+ serializableClassType = factory.getClassType("java.io.Serializable");
+ cloneableClassType = factory.getClassType("java.lang.Cloneable");
}
- @Override
public boolean isAncestor(@Nonnull Type ancestor, @Nonnull Type child) {
- boolean isAncestor = primitiveHierarchy.isAncestor(ancestor, child);
- if (!isAncestor && !(primitiveHierarchy.arePrimitives(ancestor, child))) {
- if (ancestor.equals(child)) {
- isAncestor = true;
- } else if (child instanceof BottomType) {
- isAncestor = true;
- } else if (ancestor instanceof BottomType) {
+ if (PrimitiveHierarchy.isAncestor(ancestor, child)) {
+ return true;
+ }
+
+ if (!PrimitiveHierarchy.arePrimitives(ancestor, child)) {
+ if (ancestor == child) {
+ return true;
+ }
+ if (child.getClass() == BottomType.class) {
+ return true;
+ }
+ if (ancestor.getClass() == BottomType.class) {
return false;
- } else if (ancestor instanceof PrimitiveType || child instanceof PrimitiveType) {
+ }
+ if (ancestor instanceof PrimitiveType || child instanceof PrimitiveType) {
return false;
- } else if (child instanceof NullType) {
- isAncestor = true;
- } else if (ancestor instanceof NullType) {
+ }
+ if (child == NullType.getInstance()) {
+ return true;
+ }
+ if (ancestor == NullType.getInstance()) {
return false;
- } else if (child instanceof ClassType && ancestor instanceof ClassType) {
-
- isAncestor = canStoreType((ClassType) ancestor, (ClassType) child);
-
- } else if (child instanceof ArrayType && ancestor instanceof ClassType) {
-
- isAncestor =
- ancestor.equals(object) || ancestor.equals(serializable) || ancestor.equals(cloneable);
-
- } else if (child instanceof ArrayType && ancestor instanceof ArrayType) {
- ArrayType anArr = (ArrayType) ancestor;
- ArrayType chArr = (ArrayType) child;
- Type anBase = anArr.getBaseType();
- Type chBase = chArr.getBaseType();
- if (anArr.getDimension() == chArr.getDimension()) {
- if (anBase.equals(chBase)) {
- isAncestor = true;
- } else if (anBase instanceof ClassType && chBase instanceof ClassType) {
- isAncestor = canStoreType((ClassType) anBase, (ClassType) chBase);
+ }
+ if (child instanceof ClassType && ancestor instanceof ClassType) {
+ return canStoreType((ClassType) ancestor, (ClassType) child);
+ }
+ if (child instanceof ArrayType && ancestor instanceof ClassType) {
+ return ancestor == objectClassType
+ || ancestor == serializableClassType
+ || ancestor == cloneableClassType;
+ }
+ if (child instanceof ArrayType && ancestor instanceof ArrayType) {
+ ArrayType ancestorArr = (ArrayType) ancestor;
+ ArrayType childArr = (ArrayType) child;
+ Type ancestorBase = ancestorArr.getBaseType();
+ Type childBase = childArr.getBaseType();
+ if (ancestorArr.getDimension() == childArr.getDimension()) {
+ if (ancestorBase == childBase) {
+ return true;
+ }
+ if (ancestorBase instanceof ClassType && childBase instanceof ClassType) {
+ return canStoreType((ClassType) ancestorBase, (ClassType) childBase);
}
- } else if (anArr.getDimension() < chArr.getDimension()) {
- isAncestor =
- anBase.equals(object) || anBase.equals(serializable) || anBase.equals(cloneable);
+ } else if (ancestorArr.getDimension() < childArr.getDimension()) {
+ // TODO: [ms] check: the dimension condition check seems weird?
+ return ancestorBase == objectClassType
+ || ancestorBase == serializableClassType
+ || ancestorBase == cloneableClassType;
}
}
}
- return isAncestor;
+ return false;
}
- @Override
public Collection getLeastCommonAncestor(Type a, Type b) {
- Collection ret = new HashSet<>();
+ Set ret = new HashSet<>();
if (a instanceof BottomType) {
return Collections.singleton(b);
- } else if (b instanceof BottomType) {
+ }
+ if (b instanceof BottomType) {
return Collections.singleton(a);
- } else if (a instanceof NullType) {
+ }
+ if (a == NullType.getInstance()) {
return Collections.singleton(b);
- } else if (b instanceof NullType) {
+ }
+ if (b == NullType.getInstance()) {
return Collections.singleton(a);
- } else if (isAncestor(a, b)) {
+ }
+ if (isAncestor(a, b)) {
return Collections.singleton(a);
- } else if (isAncestor(b, a)) {
+ }
+ if (isAncestor(b, a)) {
return Collections.singleton(b);
- } else if (a instanceof PrimitiveType && b instanceof PrimitiveType) {
- return primitiveHierarchy.getLeastCommonAncestor(a, b);
- } else if (a instanceof PrimitiveType || b instanceof PrimitiveType) {
+ }
+ if (a instanceof PrimitiveType && b instanceof PrimitiveType) {
+ return PrimitiveHierarchy.getLeastCommonAncestor(a, b);
+ }
+ if (a instanceof PrimitiveType || b instanceof PrimitiveType) {
return Collections.emptySet();
- } else if (a instanceof ArrayType && b instanceof ArrayType) {
+ }
+
+ if (a instanceof ArrayType && b instanceof ArrayType) {
Collection temp;
Type et_a = ((ArrayType) a).getElementType();
Type et_b = ((ArrayType) b).getElementType();
@@ -122,31 +141,34 @@ public Collection getLeastCommonAncestor(Type a, Type b) {
temp = getLeastCommonAncestor(et_a, et_b);
}
if (temp.isEmpty()) {
- ret.add(object);
- ret.add(serializable);
- ret.add(cloneable);
+ ret.add(objectClassType);
+ ret.add(serializableClassType);
+ ret.add(cloneableClassType);
} else {
for (Type type : temp) {
- ret.add(Type.makeArrayType(type, 1));
+ ret.add(Type.createArrayType(type, 1));
}
}
} else if (a instanceof ArrayType || b instanceof ArrayType) {
ClassType nonArray = (ClassType) ((a instanceof ArrayType) ? b : a);
if (!nonArray.getFullyQualifiedName().equals("java.lang.Object")) {
- if (isAncestor(serializable, nonArray)) {
- ret.add(serializable);
+ if (isAncestor(serializableClassType, nonArray)) {
+ ret.add(serializableClassType);
}
- if (isAncestor(cloneable, nonArray)) {
- ret.add(cloneable);
+ if (isAncestor(cloneableClassType, nonArray)) {
+ ret.add(cloneableClassType);
}
}
if (ret.isEmpty()) {
- ret.add(object);
+ ret.add(objectClassType);
}
} else {
// if a and b are both ClassType
Set pathsA = buildAncestryPaths((ClassType) a);
Set pathsB = buildAncestryPaths((ClassType) b);
+ // TODO: [ms] implement an algorithm with better wc runtime costs.. e.g.
+ // https://www.baeldung.com/cs/tree-lowest-common-ancestor /
+ // https://de.wikipedia.org/wiki/Range_Minimum_Query
for (AncestryPath pathA : pathsA) {
for (AncestryPath pathB : pathsB) {
ClassType lcn = leastCommonNode(pathA, pathB);
@@ -169,18 +191,14 @@ public Collection getLeastCommonAncestor(Type a, Type b) {
}
}
if (ret.isEmpty()) {
- ret.add(object);
+ ret.add(objectClassType);
}
}
return ret;
}
private boolean canStoreType(ClassType ancestor, ClassType child) {
- if (ancestor.equals(object)) {
- return true;
- } else {
- return typeHierarchy.subtypesOf(ancestor).contains(child);
- }
+ return ancestor == objectClassType || typeHierarchy.subtypesOf(ancestor).contains(child);
}
private Set buildAncestryPaths(ClassType type) {
@@ -189,7 +207,7 @@ private Set buildAncestryPaths(ClassType type) {
Set paths = new HashSet<>();
while (!pathNodes.isEmpty()) {
AncestryPath node = pathNodes.removeFirst();
- if (node.type.getFullyQualifiedName().equals("java.lang.Object")) {
+ if (node.type == objectClassType) {
paths.add(node);
} else {
if (typeHierarchy.isInterface(node.type)) {
@@ -208,7 +226,9 @@ private Set buildAncestryPaths(ClassType type) {
AncestryPath superNode = new AncestryPath(superInterface, node);
pathNodes.add(superNode);
}
- ClassType superClass = typeHierarchy.directSuperClassOf(node.type);
+ ClassType superClass = typeHierarchy.superClassOf(node.type);
+ // only java.lang.Object can have no SuperClass i.e. is null - this is already filtered
+ // above
AncestryPath superNode = new AncestryPath(superClass, node);
pathNodes.add(superNode);
}
@@ -220,7 +240,7 @@ private Set buildAncestryPaths(ClassType type) {
@Nullable
private ClassType leastCommonNode(AncestryPath a, AncestryPath b) {
ClassType lcn = null;
- while (a != null && b != null && a.type.equals(b.type)) {
+ while (a != null && b != null && a.type == b.type) {
lcn = a.type;
a = a.next;
b = b.next;
@@ -228,6 +248,7 @@ private ClassType leastCommonNode(AncestryPath a, AncestryPath b) {
return lcn;
}
+ // TODO: [ms] thats a linked list.. please refactor that
private static class AncestryPath {
public AncestryPath next;
public ClassType type;
diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/IHierarchy.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/IHierarchy.java
deleted file mode 100644
index 73164fd016..0000000000
--- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/IHierarchy.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package sootup.java.bytecode.interceptors.typeresolving;
-
-import java.util.Collection;
-import javax.annotation.Nonnull;
-import sootup.core.types.Type;
-
-/*-
- * #%L
- * Soot - a J*va Optimization Framework
- * %%
- * Copyright (C) 2019-2022 Zun Wang
- * %%
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 2.1 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Lesser Public License for more details.
- *
- * You should have received a copy of the GNU General Lesser Public
- * License along with this program. If not, see
- * .
- * #L%
- */
-public interface IHierarchy {
-
- @Nonnull
- Collection getLeastCommonAncestor(@Nonnull Type a, @Nonnull Type b);
-
- boolean isAncestor(@Nonnull Type ancestor, @Nonnull Type child);
-}
diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/PrimitiveHierarchy.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/PrimitiveHierarchy.java
index ff1de2ce86..30db578be9 100644
--- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/PrimitiveHierarchy.java
+++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/PrimitiveHierarchy.java
@@ -31,7 +31,7 @@
import sootup.java.bytecode.interceptors.typeresolving.types.BottomType;
/** @author Zun Wang */
-public class PrimitiveHierarchy implements IHierarchy {
+public class PrimitiveHierarchy {
/**
* Calculate the least common ancestor of two types(primitive or BottomType). If there's a = b
@@ -40,41 +40,43 @@ public class PrimitiveHierarchy implements IHierarchy {
* least common ancestor of a and b;
*/
@Nonnull
- @Override
- public Collection getLeastCommonAncestor(@Nonnull Type a, @Nonnull Type b) {
- if (a.equals(b)) {
+ public static Collection getLeastCommonAncestor(@Nonnull Type a, @Nonnull Type b) {
+ if (a == b) {
return Collections.singleton(a);
- } else if (arePrimitives(a, b)) {
+ }
+
+ if (arePrimitives(a, b)) {
if (isAncestor(a, b)) {
return Collections.singleton(a);
- } else if (isAncestor(b, a)) {
+ }
+ if (isAncestor(b, a)) {
return Collections.singleton(b);
- } else if (a instanceof PrimitiveType.ByteType) {
- if (b instanceof PrimitiveType.ShortType
- || b instanceof PrimitiveType.CharType
- || b instanceof AugIntegerTypes.Integer32767Type) {
+ }
+ if (a.getClass() == PrimitiveType.ByteType.class) {
+ if (b.getClass() == PrimitiveType.ShortType.class
+ || b.getClass() == PrimitiveType.CharType.class
+ || b.getClass() == AugIntegerTypes.Integer32767Type.class) {
return Collections.singleton(PrimitiveType.getInt());
- } else {
- return Collections.emptySet();
}
- } else if (a instanceof PrimitiveType.ShortType) {
- if (b instanceof PrimitiveType.ByteType || b instanceof PrimitiveType.CharType) {
+ return Collections.emptySet();
+ }
+ if (a.getClass() == PrimitiveType.ShortType.class) {
+ if (b.getClass() == PrimitiveType.ByteType.class
+ || b.getClass() == PrimitiveType.CharType.class) {
return Collections.singleton(PrimitiveType.getInt());
- } else {
- return Collections.emptySet();
}
- } else if (a instanceof PrimitiveType.CharType) {
- if (b instanceof PrimitiveType.ByteType || b instanceof PrimitiveType.ShortType) {
+ return Collections.emptySet();
+ }
+ if (a.getClass() == PrimitiveType.CharType.class) {
+ if (b.getClass() == PrimitiveType.ByteType.class
+ || b.getClass() == PrimitiveType.ShortType.class) {
return Collections.singleton(PrimitiveType.getInt());
- } else {
- return Collections.emptySet();
}
- } else {
return Collections.emptySet();
}
- } else {
return Collections.emptySet();
}
+ return Collections.emptySet();
}
/**
@@ -82,75 +84,83 @@ public Collection getLeastCommonAncestor(@Nonnull Type a, @Nonnull Type b)
* child, namely, whether child can be assigned to ancestor directly to obtain: ancestor =
* child.
*/
- @Override
- public boolean isAncestor(@Nonnull Type ancestor, @Nonnull Type child) {
+ public static boolean isAncestor(@Nonnull Type ancestor, @Nonnull Type child) {
- if (ancestor.equals(child)) {
+ if (ancestor == child) {
return true;
- } else if (arePrimitives(ancestor, child)) {
- if (ancestor instanceof AugIntegerTypes.Integer1Type) {
- return child instanceof BottomType;
- } else if (ancestor instanceof PrimitiveType.BooleanType
- || ancestor instanceof AugIntegerTypes.Integer127Type) {
- return child instanceof AugIntegerTypes.Integer1Type || child instanceof BottomType;
- } else if (ancestor instanceof PrimitiveType.ByteType
- || ancestor instanceof AugIntegerTypes.Integer32767Type) {
- return child instanceof AugIntegerTypes.Integer127Type
- || child instanceof AugIntegerTypes.Integer1Type
- || child instanceof BottomType;
- } else if (ancestor instanceof PrimitiveType.CharType
- || ancestor instanceof PrimitiveType.ShortType) {
- return child instanceof AugIntegerTypes.Integer32767Type
- || child instanceof AugIntegerTypes.Integer127Type
- || child instanceof AugIntegerTypes.Integer1Type
- || child instanceof BottomType;
- } else if (ancestor instanceof PrimitiveType.IntType) {
- return (!(child instanceof PrimitiveType.BooleanType)
+ }
+
+ if (arePrimitives(ancestor, child)) {
+ if (ancestor.getClass() == AugIntegerTypes.Integer1Type.class) {
+ return child.getClass() == BottomType.class;
+ }
+ if (ancestor.getClass() == PrimitiveType.BooleanType.class
+ || ancestor.getClass() == AugIntegerTypes.Integer127Type.class) {
+ return child.getClass() == AugIntegerTypes.Integer1Type.class
+ || child.getClass() == BottomType.class;
+ }
+ if (ancestor.getClass() == PrimitiveType.ByteType.class
+ || ancestor.getClass() == AugIntegerTypes.Integer32767Type.class) {
+ return child.getClass() == AugIntegerTypes.Integer127Type.class
+ || child.getClass() == AugIntegerTypes.Integer1Type.class
+ || child.getClass() == BottomType.class;
+ }
+ if (ancestor.getClass() == PrimitiveType.CharType.class
+ || ancestor.getClass() == PrimitiveType.ShortType.class) {
+ return child.getClass() == AugIntegerTypes.Integer32767Type.class
+ || child.getClass() == AugIntegerTypes.Integer127Type.class
+ || child.getClass() == AugIntegerTypes.Integer1Type.class
+ || child.getClass() == BottomType.class;
+ }
+ if (ancestor instanceof PrimitiveType.IntType) {
+ return (!(child.getClass() == PrimitiveType.BooleanType.class)
&& (child instanceof PrimitiveType.IntType))
- || child instanceof BottomType;
- } else {
- return child instanceof BottomType;
+ || child.getClass() == BottomType.class;
}
- } else if (ancestor instanceof ArrayType && child instanceof ArrayType) {
+ return child.getClass() == BottomType.class;
+ }
+
+ if (ancestor instanceof ArrayType && child instanceof ArrayType) {
Type ancestorBase = ((ArrayType) ancestor).getBaseType();
Type childBase = ((ArrayType) child).getBaseType();
int ancestorDim = ((ArrayType) ancestor).getDimension();
int childDim = ((ArrayType) child).getDimension();
if (ancestorDim == childDim && arePrimitives(ancestorBase, childBase)) {
- if (ancestorBase instanceof AugIntegerTypes.Integer1Type) {
- return childBase instanceof BottomType;
- } else if (ancestorBase instanceof PrimitiveType.BooleanType
- || ancestorBase instanceof AugIntegerTypes.Integer127Type) {
- return childBase instanceof AugIntegerTypes.Integer1Type
- || childBase instanceof BottomType;
- } else if (ancestorBase instanceof PrimitiveType.ByteType
- || ancestorBase instanceof AugIntegerTypes.Integer32767Type) {
- return childBase instanceof AugIntegerTypes.Integer127Type
- || childBase instanceof AugIntegerTypes.Integer1Type
- || childBase instanceof BottomType;
- } else if (ancestorBase instanceof PrimitiveType.IntType) {
- return childBase instanceof AugIntegerTypes.Integer32767Type
- || childBase instanceof AugIntegerTypes.Integer127Type
- || childBase instanceof AugIntegerTypes.Integer1Type
- || childBase instanceof BottomType;
- } else {
- return childBase instanceof BottomType;
+ // TODO: [ms] dry? looks quite similar to the if-else-tree above.. why are they differing in
+ // structure?
+ if (ancestorBase.getClass() == AugIntegerTypes.Integer1Type.class) {
+ return childBase.getClass() == BottomType.class;
+ }
+ if (ancestorBase.getClass() == PrimitiveType.BooleanType.class
+ || ancestorBase.getClass() == AugIntegerTypes.Integer127Type.class) {
+ return childBase.getClass() == AugIntegerTypes.Integer1Type.class
+ || childBase.getClass() == BottomType.class;
+ }
+ if (ancestorBase.getClass() == PrimitiveType.ByteType.class
+ || ancestorBase.getClass() == AugIntegerTypes.Integer32767Type.class) {
+ return childBase.getClass() == AugIntegerTypes.Integer127Type.class
+ || childBase.getClass() == AugIntegerTypes.Integer1Type.class
+ || childBase.getClass() == BottomType.class;
+ }
+ if (ancestorBase.getClass() == PrimitiveType.CharType.class
+ || ancestorBase.getClass() == PrimitiveType.ShortType.class
+ || ancestorBase instanceof PrimitiveType.IntType) {
+ return childBase.getClass() == AugIntegerTypes.Integer32767Type.class
+ || childBase.getClass() == AugIntegerTypes.Integer127Type.class
+ || childBase.getClass() == AugIntegerTypes.Integer1Type.class
+ || childBase.getClass() == BottomType.class;
}
- } else {
- return childBase instanceof BottomType;
}
- } else {
- return child instanceof BottomType;
+ return childBase.getClass() == BottomType.class;
}
+
+ return child.getClass() == BottomType.class;
}
/** Check whether the two given types are primitives or BottomType */
- public boolean arePrimitives(Type a, Type b) {
- if (a instanceof PrimitiveType || a instanceof BottomType) {
- return b instanceof PrimitiveType || b instanceof BottomType;
- } else {
- return false;
- }
+ public static boolean arePrimitives(@Nonnull Type a, @Nonnull Type b) {
+ return (a instanceof PrimitiveType || a.getClass() == BottomType.class)
+ && (b instanceof PrimitiveType || b.getClass() == BottomType.class);
}
}
diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/TypeChecker.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/TypeChecker.java
index 7358f2d6df..07400de262 100644
--- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/TypeChecker.java
+++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/TypeChecker.java
@@ -27,7 +27,6 @@
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import sootup.core.IdentifierFactory;
import sootup.core.graph.StmtGraph;
import sootup.core.jimple.basic.Local;
import sootup.core.jimple.basic.Value;
@@ -48,7 +47,6 @@
import sootup.core.types.NullType;
import sootup.core.types.PrimitiveType;
import sootup.core.types.Type;
-import sootup.java.core.JavaIdentifierFactory;
public abstract class TypeChecker extends AbstractStmtVisitor {
@@ -58,7 +56,6 @@ public abstract class TypeChecker extends AbstractStmtVisitor {
protected final Body.BodyBuilder builder;
protected final StmtGraph> graph;
- private final IdentifierFactory factory = JavaIdentifierFactory.getInstance();
private static final Logger logger = LoggerFactory.getLogger(TypeChecker.class);
@@ -120,12 +117,12 @@ public void caseAssignStmt(@Nonnull JAssignStmt, ?> stmt) {
}
}
if (!findDef) {
- arrayType = Type.makeArrayType(type_rhs, 1);
+ arrayType = Type.createArrayType(type_rhs, 1);
}
}
}
if (arrayType == null) {
- arrayType = Type.makeArrayType(type_base, 1);
+ arrayType = Type.createArrayType(type_base, 1);
}
}
type_lhs = arrayType.getElementType();
@@ -181,7 +178,7 @@ public void caseAssignStmt(@Nonnull JAssignStmt, ?> stmt) {
if (sel == null) {
sel = type_base;
}
- arrayType = Type.makeArrayType(sel, 1);
+ arrayType = Type.createArrayType(sel, 1);
}
}
if (arrayType != null) {
@@ -204,7 +201,7 @@ public void caseAssignStmt(@Nonnull JAssignStmt, ?> stmt) {
} else if (rhs instanceof JCastExpr) {
visit(rhs, type_lhs, stmt);
} else if (rhs instanceof JInstanceOfExpr) {
- visit(((JInstanceOfExpr) rhs).getOp(), factory.getType("java.lang.Object"), stmt);
+ visit(((JInstanceOfExpr) rhs).getOp(), hierarchy.objectClassType, stmt);
visit(rhs, type_lhs, stmt);
} else if (rhs instanceof JNewArrayExpr) {
visit(((JNewArrayExpr) rhs).getSize(), PrimitiveType.getInt(), stmt);
@@ -229,12 +226,12 @@ public void caseAssignStmt(@Nonnull JAssignStmt, ?> stmt) {
@Override
public void caseEnterMonitorStmt(@Nonnull JEnterMonitorStmt stmt) {
- visit(stmt.getOp(), factory.getType("java.lang.Object"), stmt);
+ visit(stmt.getOp(), hierarchy.objectClassType, stmt);
}
@Override
public void caseExitMonitorStmt(@Nonnull JExitMonitorStmt stmt) {
- visit(stmt.getOp(), factory.getType("java.lang.Object"), stmt);
+ visit(stmt.getOp(), hierarchy.objectClassType, stmt);
}
@Override
@@ -254,7 +251,7 @@ public void caseReturnStmt(@Nonnull JReturnStmt stmt) {
@Override
public void caseThrowStmt(@Nonnull JThrowStmt stmt) {
- visit(stmt.getOp(), factory.getType("java.lang.Throwable"), stmt);
+ visit(stmt.getOp(), hierarchy.throwableClassType, stmt);
}
public AugEvalFunction getFuntion() {
diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/TypeResolver.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/TypeResolver.java
index 6e09e8d061..ca3c4b405f 100644
--- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/TypeResolver.java
+++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/TypeResolver.java
@@ -182,7 +182,7 @@ private Collection applyAssignmentConstraint(
Type t_old = actualTyping.getType(local);
Type t_right = evalFunction.evaluate(actualTyping, defStmt.getRightOp(), defStmt, graph);
if (lhs instanceof JArrayRef) {
- t_right = Type.makeArrayType(t_right, 1);
+ t_right = Type.createArrayType(t_right, 1);
}
boolean isFirstType = true;
@@ -290,7 +290,7 @@ private Type convertType(@Nonnull Type type) {
} else if (type instanceof ArrayType) {
Type eleType = convertType(((ArrayType) type).getElementType());
if (eleType != null) {
- return Type.makeArrayType(eleType, 1);
+ return Type.createArrayType(eleType, 1);
} else {
return null;
}
diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/types/AugIntegerTypes.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/types/AugIntegerTypes.java
index d744d36343..bf7a4aa94e 100644
--- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/types/AugIntegerTypes.java
+++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/interceptors/typeresolving/types/AugIntegerTypes.java
@@ -60,7 +60,7 @@ public static Integer1Type getInstance() {
@Override
public void accept(@Nonnull TypeVisitor v) {
- // todo: case for Integer1Type
+ throw new UnsupportedOperationException();
}
}
@@ -79,7 +79,7 @@ public static Integer127Type getInstance() {
@Override
public void accept(@Nonnull TypeVisitor v) {
- // todo: case for Integer127Type
+ throw new UnsupportedOperationException();
}
}
@@ -98,7 +98,7 @@ public static Integer32767Type getInstance() {
@Override
public void accept(@Nonnull TypeVisitor v) {
- // todo: case for Integer32767Type
+ throw new UnsupportedOperationException();
}
}
}
diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/CastCounterTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/CastCounterTest.java
index 1114ca51eb..21ef1ee8dd 100644
--- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/CastCounterTest.java
+++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/CastCounterTest.java
@@ -70,7 +70,7 @@ public void testAssignStmt() {
final Body.BodyBuilder builder = createMethodsBuilder("assignStmt", "void");
Map map = new HashMap<>();
map.put("l0", classType);
- map.put("l1", Type.makeArrayType(super1, 1));
+ map.put("l1", Type.createArrayType(super1, 1));
map.put("l2", super1);
map.put("$stack3", sub1);
Typing typing = createTyping(builder.getLocals(), map);
diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/PrimitiveHierarchyTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/PrimitiveHierarchyTest.java
index 5cc51cd70c..1f13ac93a2 100644
--- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/PrimitiveHierarchyTest.java
+++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/interceptors/typeresolving/PrimitiveHierarchyTest.java
@@ -34,71 +34,70 @@ public class PrimitiveHierarchyTest {
private Type arr_c = new ArrayType(c, 1);
private Type arr_by = new ArrayType(by, 1);
private Type arr_i127 = new ArrayType(i127, 1);
- private PrimitiveHierarchy primitiveHierarchy = new PrimitiveHierarchy();
@Test
public void testIsAncestor() {
// check all ancestor relationships in lattice
- Assert.assertTrue(primitiveHierarchy.isAncestor(bt, bt2));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(bt, bt2));
- Assert.assertTrue(primitiveHierarchy.isAncestor(i1, bt));
- Assert.assertFalse(primitiveHierarchy.isAncestor(bt, i1));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(i1, bt));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(bt, i1));
- Assert.assertTrue(primitiveHierarchy.isAncestor(boo, i1));
- Assert.assertTrue(primitiveHierarchy.isAncestor(boo, bt));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(boo, i1));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(boo, bt));
- Assert.assertTrue(primitiveHierarchy.isAncestor(i127, i1));
- Assert.assertTrue(primitiveHierarchy.isAncestor(i127, bt));
- Assert.assertFalse(primitiveHierarchy.isAncestor(boo, i127));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(i127, i1));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(i127, bt));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(boo, i127));
- Assert.assertTrue(primitiveHierarchy.isAncestor(by, i127));
- Assert.assertFalse(primitiveHierarchy.isAncestor(by, i32767));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(by, i127));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(by, i32767));
- Assert.assertTrue(primitiveHierarchy.isAncestor(c, i32767));
- Assert.assertFalse(primitiveHierarchy.isAncestor(c, by));
- Assert.assertFalse(primitiveHierarchy.isAncestor(c, s));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(c, i32767));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(c, by));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(c, s));
- Assert.assertTrue(primitiveHierarchy.isAncestor(s, i127));
- Assert.assertFalse(primitiveHierarchy.isAncestor(s, by));
- Assert.assertFalse(primitiveHierarchy.isAncestor(s, boo));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(s, i127));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(s, by));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(s, boo));
- Assert.assertTrue(primitiveHierarchy.isAncestor(i, c));
- Assert.assertTrue(primitiveHierarchy.isAncestor(i, s));
- Assert.assertTrue(primitiveHierarchy.isAncestor(i, i1));
- Assert.assertFalse(primitiveHierarchy.isAncestor(i, boo));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(i, c));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(i, s));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(i, i1));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(i, boo));
- Assert.assertFalse(primitiveHierarchy.isAncestor(d, i));
- Assert.assertFalse(primitiveHierarchy.isAncestor(d, f));
- Assert.assertFalse(primitiveHierarchy.isAncestor(l, c));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(d, i));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(d, f));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(l, c));
- Assert.assertFalse(primitiveHierarchy.isAncestor(arr_i, arr_i2));
- Assert.assertTrue(primitiveHierarchy.isAncestor(arr_i, arr_i127));
- Assert.assertTrue(primitiveHierarchy.isAncestor(arr_c, arr_i127));
- Assert.assertFalse(primitiveHierarchy.isAncestor(arr_i, arr_by));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(arr_i, arr_i2));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(arr_i, arr_i127));
+ Assert.assertTrue(PrimitiveHierarchy.isAncestor(arr_c, arr_i127));
+ Assert.assertFalse(PrimitiveHierarchy.isAncestor(arr_i, arr_by));
}
@Test
public void testLCA() {
Set expect = ImmutableUtils.immutableSet(bt);
- Collection actual = primitiveHierarchy.getLeastCommonAncestor(bt, bt2);
+ Collection actual = PrimitiveHierarchy.getLeastCommonAncestor(bt, bt2);
Assert.assertEquals(expect, actual);
expect = ImmutableUtils.immutableSet(i);
- actual = primitiveHierarchy.getLeastCommonAncestor(c, s);
+ actual = PrimitiveHierarchy.getLeastCommonAncestor(c, s);
Assert.assertEquals(expect, actual);
- actual = primitiveHierarchy.getLeastCommonAncestor(by, s);
+ actual = PrimitiveHierarchy.getLeastCommonAncestor(by, s);
Assert.assertEquals(expect, actual);
- actual = primitiveHierarchy.getLeastCommonAncestor(by, i32767);
+ actual = PrimitiveHierarchy.getLeastCommonAncestor(by, i32767);
Assert.assertEquals(expect, actual);
- actual = primitiveHierarchy.getLeastCommonAncestor(i1, i);
+ actual = PrimitiveHierarchy.getLeastCommonAncestor(i1, i);
Assert.assertEquals(expect, actual);
expect = ImmutableUtils.immutableSet(s);
- actual = primitiveHierarchy.getLeastCommonAncestor(s, i32767);
+ actual = PrimitiveHierarchy.getLeastCommonAncestor(s, i32767);
Assert.assertEquals(expect, actual);
}
}
diff --git a/sootup.java.core/src/main/java/sootup/java/core/JavaIdentifierFactory.java b/sootup.java.core/src/main/java/sootup/java/core/JavaIdentifierFactory.java
index bda893da40..c9742affc4 100644
--- a/sootup.java.core/src/main/java/sootup/java/core/JavaIdentifierFactory.java
+++ b/sootup.java.core/src/main/java/sootup/java/core/JavaIdentifierFactory.java
@@ -60,12 +60,17 @@ public class JavaIdentifierFactory implements IdentifierFactory {
/** Caches the created PackageNames for packages. */
@Nonnull
- protected final Cache packages =
+ protected final Cache packageCache =
CacheBuilder.newBuilder().weakValues().build();
/** Caches annotation types */
@Nonnull
- protected final Cache annotationTypes =
+ protected final Cache annotationTypeCache =
+ CacheBuilder.newBuilder().weakValues().build();
+
+ /** Caches class types */
+ @Nonnull
+ protected final Cache classTypeCache =
CacheBuilder.newBuilder().weakValues().build();
@Nonnull
@@ -77,7 +82,7 @@ public static JavaIdentifierFactory getInstance() {
JavaIdentifierFactory() {
/* Represents the default package. */
- packages.put(PackageName.DEFAULT_PACKAGE.getName(), PackageName.DEFAULT_PACKAGE);
+ packageCache.put(PackageName.DEFAULT_PACKAGE.getName(), PackageName.DEFAULT_PACKAGE);
// initialize primitive map
primitiveTypeMap.put(
@@ -112,7 +117,10 @@ public static JavaIdentifierFactory getInstance() {
@Override
public JavaClassType getClassType(final String className, final String packageName) {
PackageName packageIdentifier = getPackageName(packageName);
- return new JavaClassType(className, packageIdentifier);
+ return classTypeCache
+ .asMap()
+ .computeIfAbsent(
+ className + packageName, (k) -> new JavaClassType(className, packageIdentifier));
}
/**
@@ -216,7 +224,7 @@ public AnnotationType getAnnotationType(final String fullyQualifiedClassName) {
String className = ClassUtils.getShortClassName(fullyQualifiedClassName);
String packageName = ClassUtils.getPackageName(fullyQualifiedClassName);
- return annotationTypes
+ return annotationTypeCache
.asMap()
.computeIfAbsent(
className + packageName,
@@ -260,7 +268,7 @@ public JavaClassType fromPath(@Nonnull final Path rootDirectory, @Nonnull final
*/
@Override
public PackageName getPackageName(@Nonnull final String packageName) {
- return packages.asMap().computeIfAbsent(packageName, PackageName::new);
+ return packageCache.asMap().computeIfAbsent(packageName, PackageName::new);
}
/**
diff --git a/sootup.java.core/src/main/java/sootup/java/core/JavaModuleIdentifierFactory.java b/sootup.java.core/src/main/java/sootup/java/core/JavaModuleIdentifierFactory.java
index 572dc3738e..2f504ac914 100644
--- a/sootup.java.core/src/main/java/sootup/java/core/JavaModuleIdentifierFactory.java
+++ b/sootup.java.core/src/main/java/sootup/java/core/JavaModuleIdentifierFactory.java
@@ -163,7 +163,7 @@ public ModulePackageName getPackageName(
@Nonnull final String packageName, @Nonnull final String moduleName) {
String fqId = moduleName + "." + packageName;
return (ModulePackageName)
- packages
+ packageCache
.asMap()
.computeIfAbsent(
fqId, key -> new ModulePackageName(packageName, getModuleSignature(moduleName)));
@@ -173,7 +173,7 @@ public ModulePackageName getPackageName(
@Nonnull final String packageName, @Nonnull final ModuleSignature moduleSignature) {
String fqId = moduleSignature.getModuleName() + "." + packageName;
return (ModulePackageName)
- packages
+ packageCache
.asMap()
.computeIfAbsent(fqId, key -> new ModulePackageName(packageName, moduleSignature));
}
diff --git a/sootup.java.core/src/test/java/sootup/java/core/signatures/JavaIdentifierFactoryTest.java b/sootup.java.core/src/test/java/sootup/java/core/signatures/JavaIdentifierFactoryTest.java
index 415bcf05d6..a5fcf27b61 100644
--- a/sootup.java.core/src/test/java/sootup/java/core/signatures/JavaIdentifierFactoryTest.java
+++ b/sootup.java.core/src/test/java/sootup/java/core/signatures/JavaIdentifierFactoryTest.java
@@ -84,7 +84,7 @@ public void getClassSignature() {
ClassType classSignature1 = typeFactory.getClassType("System", "java.lang");
ClassType classSignature2 = typeFactory.getClassType("System", "java.lang");
// Class Signatures are unique but not their package
- assertNotSame(classSignature1, classSignature2);
+ assertSame(classSignature1, classSignature2);
}
@Test
@@ -137,7 +137,7 @@ public void getClassSignatureEmptyPackage() {
JavaClassType classSignature1 = typeFactory.getClassType("A", "");
JavaClassType classSignature2 = typeFactory.getClassType("A");
// Class Signatures are unique but not their package
- assertNotSame(classSignature1, classSignature2);
+ assertSame(classSignature1, classSignature2);
assertSame(classSignature1.getPackageName(), classSignature2.getPackageName());
@@ -152,7 +152,7 @@ public void getClassSignatureFullyQualified() {
ClassType classSignature1 = typeFactory.getClassType("java.lang.System");
ClassType classSignature2 = typeFactory.getClassType("System", "java.lang");
// Class Signatures are unique but not their package
- assertNotSame(classSignature1, classSignature2);
+ assertSame(classSignature1, classSignature2);
}
@Test