diff --git a/src/main/java/pascal/taie/analysis/pta/core/solver/DefaultSolver.java b/src/main/java/pascal/taie/analysis/pta/core/solver/DefaultSolver.java index f607a7d2a..f0313dce3 100644 --- a/src/main/java/pascal/taie/analysis/pta/core/solver/DefaultSolver.java +++ b/src/main/java/pascal/taie/analysis/pta/core/solver/DefaultSolver.java @@ -175,7 +175,9 @@ public DefaultSolver(AnalysisOptions options, HeapModel heapModel, hierarchy = World.get().getClassHierarchy(); typeSystem = World.get().getTypeSystem(); ptsFactory = new PointsToSetFactory(csManager.getObjectIndexer()); - propTypes = new PropagateTypes((List) options.get("propagate-types")); + propTypes = new PropagateTypes( + (List) options.get("propagate-types"), + typeSystem); onlyApp = options.getBoolean("only-app"); timeLimit = options.getInt("time-limit"); } diff --git a/src/main/java/pascal/taie/analysis/pta/core/solver/PropagateTypes.java b/src/main/java/pascal/taie/analysis/pta/core/solver/PropagateTypes.java index fa3792a61..03d663491 100644 --- a/src/main/java/pascal/taie/analysis/pta/core/solver/PropagateTypes.java +++ b/src/main/java/pascal/taie/analysis/pta/core/solver/PropagateTypes.java @@ -27,10 +27,11 @@ import pascal.taie.language.type.PrimitiveType; import pascal.taie.language.type.ReferenceType; import pascal.taie.language.type.Type; +import pascal.taie.language.type.TypeSystem; -import java.util.EnumSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; /** * Checks whether propagation of objects is allowed. @@ -53,16 +54,13 @@ public class PropagateTypes { *
  • various primitive types: allow the corresponding primitive types
  • * */ - public PropagateTypes(List types) { + public PropagateTypes(List types, TypeSystem typeSystem) { allowReference = types.contains("reference"); allowNull = types.contains("null") || types.contains(null); - List primitiveTypes = types.stream() - .filter(PrimitiveType::isPrimitiveType) - .map(PrimitiveType::get) - .toList(); - allowedPrimitives = primitiveTypes.isEmpty() - ? Set.of() - : EnumSet.copyOf(primitiveTypes); + allowedPrimitives = types.stream() + .filter(typeSystem::isPrimitiveType) + .map(typeSystem::getPrimitiveType) + .collect(Collectors.toUnmodifiableSet()); } public boolean isAllowed(Type type) { diff --git a/src/main/java/pascal/taie/analysis/pta/plugin/reflection/OthersModel.java b/src/main/java/pascal/taie/analysis/pta/plugin/reflection/OthersModel.java index 302155cf5..5f3773e0a 100644 --- a/src/main/java/pascal/taie/analysis/pta/plugin/reflection/OthersModel.java +++ b/src/main/java/pascal/taie/analysis/pta/plugin/reflection/OthersModel.java @@ -40,7 +40,6 @@ import pascal.taie.language.classes.JMethod; import pascal.taie.language.type.ArrayType; import pascal.taie.language.type.ClassType; -import pascal.taie.language.type.PrimitiveType; import pascal.taie.language.type.Type; import pascal.taie.language.type.VoidType; @@ -106,7 +105,7 @@ public void getPrimitiveClass(Context context, Invoke invoke, PointsToSet nameOb String name = CSObjs.toString(nameObj); if (name != null) { Type type = name.equals("void") ? - VoidType.VOID : PrimitiveType.get(name); + VoidType.VOID : typeSystem.getPrimitiveType(name); solver.addVarPointsTo(context, result, heapModel.getConstantObj(ClassLiteral.get(type))); } diff --git a/src/main/java/pascal/taie/frontend/soot/SootWorldBuilder.java b/src/main/java/pascal/taie/frontend/soot/SootWorldBuilder.java index 1cdb17f0e..5589ce01b 100644 --- a/src/main/java/pascal/taie/frontend/soot/SootWorldBuilder.java +++ b/src/main/java/pascal/taie/frontend/soot/SootWorldBuilder.java @@ -36,7 +36,6 @@ import pascal.taie.language.classes.ClassHierarchy; import pascal.taie.language.classes.ClassHierarchyImpl; import pascal.taie.language.classes.StringReps; -import pascal.taie.language.type.PrimitiveType; import pascal.taie.language.type.TypeSystem; import pascal.taie.language.type.TypeSystemImpl; import soot.G; @@ -184,9 +183,7 @@ private static void addReflectionLogClasses(List analyses, Scene if (StringReps.isArrayType(targetClass)) { targetClass = StringReps.getBaseTypeNameOf(target); } - if (!PrimitiveType.isPrimitiveType(targetClass)) { - scene.addBasicClass(targetClass); - } + scene.addBasicClass(targetClass); }); } } diff --git a/src/main/java/pascal/taie/language/type/PrimitiveType.java b/src/main/java/pascal/taie/language/type/PrimitiveType.java index b2bf238e8..a40a495e5 100644 --- a/src/main/java/pascal/taie/language/type/PrimitiveType.java +++ b/src/main/java/pascal/taie/language/type/PrimitiveType.java @@ -22,29 +22,8 @@ package pascal.taie.language.type; -import java.util.Map; -import java.util.Set; - public interface PrimitiveType extends ValueType { - /** - * @return {@code true} if given name represents a primitive type. - */ - static boolean isPrimitiveType(String name) { - // stub implementation to pass compilation - return Set.of("int").contains(name); - } - - /** - * @return the primitive type specified by specific name. - * @throws IllegalArgumentException if given name is irrelevant to any primitive type. - */ - static PrimitiveType get(String name) { - // stub implementation to pass compilation - return Map.of("int", IntType.INT).get(name); - //throw new IllegalArgumentException(name + " is not primitive type"); - } - @Override default String getName() { return toString(); diff --git a/src/main/java/pascal/taie/language/type/TypeSystem.java b/src/main/java/pascal/taie/language/type/TypeSystem.java index aa678844c..fe151b5ff 100644 --- a/src/main/java/pascal/taie/language/type/TypeSystem.java +++ b/src/main/java/pascal/taie/language/type/TypeSystem.java @@ -28,8 +28,8 @@ /** * This class provides APIs for retrieving types in the analyzed program. - * For convenience, the special predefined types, i.e., primitive types, - * null type, and void type can be directly retrieved from their own classes. + * For convenience, null type, void type and single primitive type + * can be directly retrieved from their own classes. */ public interface TypeSystem extends Serializable { @@ -43,9 +43,13 @@ public interface TypeSystem extends Serializable { ArrayType getArrayType(Type baseType, int dimensions); + PrimitiveType getPrimitiveType(String typeName); + ClassType getBoxedType(PrimitiveType type); PrimitiveType getUnboxedType(ClassType type); boolean isSubtype(Type supertype, Type subtype); + + boolean isPrimitiveType(String typeName); } diff --git a/src/main/java/pascal/taie/language/type/TypeSystemImpl.java b/src/main/java/pascal/taie/language/type/TypeSystemImpl.java index 185fa9f97..22e8ec83c 100644 --- a/src/main/java/pascal/taie/language/type/TypeSystemImpl.java +++ b/src/main/java/pascal/taie/language/type/TypeSystemImpl.java @@ -28,7 +28,9 @@ import pascal.taie.util.AnalysisException; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentMap; +import java.util.stream.Collectors; import static pascal.taie.util.collection.Maps.newConcurrentMap; import static pascal.taie.util.collection.Maps.newMap; @@ -49,18 +51,25 @@ public class TypeSystemImpl implements TypeSystem { = newConcurrentMap(8); private final ClassType OBJECT; + private final ClassType SERIALIZABLE; + private final ClassType CLONEABLE; - // Boxed types - private final ClassType BOOLEAN; - private final ClassType BYTE; - private final ClassType SHORT; - private final ClassType CHARACTER; - private final ClassType INTEGER; - private final ClassType LONG; - private final ClassType FLOAT; - private final ClassType DOUBLE; + /** + * Maps a primitive type to its boxed type. + */ + private final Map boxedMap; + + /** + * Maps a boxed class type to its unboxed primitive type. + */ + private final Map unboxedMap; + + /** + * Maps a primitive type name to the corresponding type. + */ + private final Map primitiveTypes; public TypeSystemImpl(ClassHierarchy hierarchy) { this.hierarchy = hierarchy; @@ -69,14 +78,21 @@ public TypeSystemImpl(ClassHierarchy hierarchy) { OBJECT = getClassType(loader, ClassNames.OBJECT); SERIALIZABLE = getClassType(loader, ClassNames.SERIALIZABLE); CLONEABLE = getClassType(loader, ClassNames.CLONEABLE); - BOOLEAN = getClassType(loader, ClassNames.BOOLEAN); - BYTE = getClassType(loader, ClassNames.BYTE); - SHORT = getClassType(loader, ClassNames.SHORT); - CHARACTER = getClassType(loader, ClassNames.CHARACTER); - INTEGER = getClassType(loader, ClassNames.INTEGER); - LONG = getClassType(loader, ClassNames.LONG); - FLOAT = getClassType(loader, ClassNames.FLOAT); - DOUBLE = getClassType(loader, ClassNames.DOUBLE); + boxedMap = Map.of( + BooleanType.BOOLEAN, getClassType(loader, ClassNames.BOOLEAN), + ByteType.BYTE, getClassType(loader, ClassNames.BYTE), + ShortType.SHORT, getClassType(loader, ClassNames.SHORT), + CharType.CHAR, getClassType(loader, ClassNames.CHARACTER), + IntType.INT, getClassType(loader, ClassNames.INTEGER), + LongType.LONG, getClassType(loader, ClassNames.LONG), + FloatType.FLOAT, getClassType(loader, ClassNames.FLOAT), + DoubleType.DOUBLE, getClassType(loader, ClassNames.DOUBLE)); + unboxedMap = boxedMap.entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey)); + primitiveTypes = boxedMap.keySet() + .stream() + .collect(Collectors.toMap(PrimitiveType::getName, t -> t)); } @Override @@ -96,8 +112,8 @@ public Type getType(JClassLoader loader, String typeName) { return getArrayType( getType(loader, typeName.substring(0, i + 1)), dim); - } else if (PrimitiveType.isPrimitiveType(typeName)) { - return PrimitiveType.get(typeName); + } else if (isPrimitiveType(typeName)) { + return getPrimitiveType(typeName); } else { return getClassType(loader, typeName); } @@ -136,40 +152,21 @@ public ArrayType getArrayType(Type baseType, int dim) { dim == 1 ? t : getArrayType(t, dim - 1))); } + @Override + public PrimitiveType getPrimitiveType(String typeName) { + return Objects.requireNonNull(primitiveTypes.get(typeName), + typeName + " is not a primitive type"); + } + @Override public ClassType getBoxedType(PrimitiveType type) { - return switch (type) { - case BooleanType.BOOLEAN -> BOOLEAN; - case ByteType.BYTE -> BYTE; - case ShortType.SHORT -> SHORT; - case CharType.CHAR -> CHARACTER; - case IntType.INT -> INTEGER; - case LongType.LONG -> LONG; - case FloatType.FLOAT -> FLOAT; - case DoubleType.DOUBLE -> DOUBLE; - }; + return boxedMap.get(type); } @Override public PrimitiveType getUnboxedType(ClassType type) { - if (type.equals(BOOLEAN)) { - return BooleanType.BOOLEAN; - } else if (type.equals(BYTE)) { - return ByteType.BYTE; - } else if (type.equals(SHORT)) { - return ShortType.SHORT; - } else if (type.equals(CHARACTER)) { - return CharType.CHAR; - } else if (type.equals(INTEGER)) { - return IntType.INT; - } else if (type.equals(LONG)) { - return LongType.LONG; - } else if (type.equals(FLOAT)) { - return FloatType.FLOAT; - } else if (type.equals(DOUBLE)) { - return DoubleType.DOUBLE; - } - throw new AnalysisException(type + " cannot be unboxed"); + return Objects.requireNonNull(unboxedMap.get(type), + type + " cannot be unboxed"); } @Override @@ -212,4 +209,9 @@ public boolean isSubtype(Type supertype, Type subtype) { } return false; } + + @Override + public boolean isPrimitiveType(String typeName) { + return primitiveTypes.containsKey(typeName); + } }