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> view; - PrimitiveHierarchy primitiveHierarchy = new PrimitiveHierarchy(); public AugEvalFunction(View> 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 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> 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