@@ -906,23 +906,34 @@ class UtBotSymbolicEngine(
906
906
// Gets concrete value, converts to symbolic value
907
907
val declaringClass = field.declaringClass
908
908
909
- val (edge, updates) = if (declaringClass.isEnum) {
909
+ val updates = if (declaringClass.isEnum) {
910
910
makeConcreteUpdatesForEnums(fieldId, declaringClass, stmt)
911
911
} else {
912
- makeConcreteUpdatesForNonEnumStaticField(field, fieldId, declaringClass)
912
+ makeConcreteUpdatesForNonEnumStaticField(field, fieldId, declaringClass, stmt )
913
913
}
914
914
915
+ // a static initializer can be the first statement in method so there will be no last edge
916
+ // for example, as it is during Enum::values method analysis:
917
+ // public static ClassWithEnum$StatusEnum[] values()
918
+ // {
919
+ // ClassWithEnum$StatusEnum[] $r0, $r2;
920
+ // java.lang.Object $r1;
921
+
922
+ // $r0 = <ClassWithEnum$StatusEnum: ClassWithEnum$StatusEnum[] $VALUES>;
923
+ val edge = environment.state.lastEdge ? : globalGraph.succ(stmt)
924
+
915
925
val newState = environment.state.updateQueued(edge, updates)
916
926
pathSelector.offer(newState)
917
927
918
928
return true
919
929
}
920
930
931
+ @Suppress(" UnnecessaryVariable" )
921
932
private fun makeConcreteUpdatesForEnums (
922
933
fieldId : FieldId ,
923
934
declaringClass : SootClass ,
924
935
stmt : Stmt
925
- ): Pair < Edge , SymbolicStateUpdate > {
936
+ ): SymbolicStateUpdate {
926
937
val type = declaringClass.type
927
938
val jClass = type.id.jClass
928
939
@@ -966,46 +977,21 @@ class UtBotSymbolicEngine(
966
977
meaningfulStaticFields = meaningfulStaticFields.map { it.first.fieldId }.toPersistentSet()
967
978
)
968
979
969
- var allUpdates = staticFieldUpdates + nonStaticFieldsUpdates + initializedStaticFieldsMemoryUpdate
970
-
971
- // we need to make locals update if it is an assignment statement
972
- // for enums we have only two types for assignment with enums — enum constant or $VALUES field
973
- // for example, a jimple body for Enum::values method starts with the following lines:
974
- // public static ClassWithEnum$StatusEnum[] values()
975
- // {
976
- // ClassWithEnum$StatusEnum[] $r0, $r2;
977
- // java.lang.Object $r1;
978
- // $r0 = <ClassWithEnum$StatusEnum: ClassWithEnum$StatusEnum[] $VALUES>;
979
- // $r1 = virtualinvoke $r0.<java.lang.Object: java.lang.Object clone()>();
980
-
981
- // so, we have to make an update for the local $r0
982
- if (stmt is JAssignStmt ) {
983
- val local = stmt.leftOp as JimpleLocal
984
- val localUpdate = localMemoryUpdate(
985
- local.variable to curFieldSymbolicValueForLocalVariable
986
- )
987
-
988
- allUpdates + = localUpdate
989
- }
990
-
991
- // enum static initializer can be the first statement in method so there will be no last edge
992
- // for example, as it is during Enum::values method analysis:
993
- // public static ClassWithEnum$StatusEnum[] values()
994
- // {
995
- // ClassWithEnum$StatusEnum[] $r0, $r2;
996
- // java.lang.Object $r1;
997
-
998
- // $r0 = <ClassWithEnum$StatusEnum: ClassWithEnum$StatusEnum[] $VALUES>;
999
- val edge = environment.state.lastEdge ? : globalGraph.succ(stmt)
980
+ val allUpdates = staticFieldUpdates +
981
+ nonStaticFieldsUpdates +
982
+ initializedStaticFieldsMemoryUpdate +
983
+ createConcreteLocalValueUpdate(stmt, curFieldSymbolicValueForLocalVariable)
1000
984
1001
- return edge to allUpdates
985
+ return allUpdates
1002
986
}
1003
987
988
+ @Suppress(" UnnecessaryVariable" )
1004
989
private fun makeConcreteUpdatesForNonEnumStaticField (
1005
990
field : SootField ,
1006
991
fieldId : FieldId ,
1007
- declaringClass : SootClass
1008
- ): Pair <Edge , SymbolicStateUpdate > {
992
+ declaringClass : SootClass ,
993
+ stmt : Stmt
994
+ ): SymbolicStateUpdate {
1009
995
val concreteValue = extractConcreteValue(field, declaringClass)
1010
996
val (symbolicResult, symbolicStateUpdate) = toMethodResult(concreteValue, field.type)
1011
997
val symbolicValue = (symbolicResult as SymbolicSuccess ).value
@@ -1019,9 +1005,40 @@ class UtBotSymbolicEngine(
1019
1005
field = field,
1020
1006
value = valueToExpression(symbolicValue, field.type)
1021
1007
)
1022
- val allUpdates = symbolicStateUpdate + initializedFieldUpdate + objectUpdate
1008
+ val allUpdates = symbolicStateUpdate +
1009
+ initializedFieldUpdate +
1010
+ objectUpdate +
1011
+ createConcreteLocalValueUpdate(stmt, symbolicValue)
1012
+
1013
+ return allUpdates
1014
+ }
1015
+
1016
+ /* *
1017
+ * Creates a local update consisting [symbolicValue] for a local variable from [stmt] in case [stmt] is [JAssignStmt].
1018
+ */
1019
+ private fun createConcreteLocalValueUpdate (
1020
+ stmt : Stmt ,
1021
+ symbolicValue : SymbolicValue ? ,
1022
+ ): LocalMemoryUpdate {
1023
+ // we need to make locals update if it is an assignment statement
1024
+ // for enums we have only two types for assignment with enums — enum constant or $VALUES field
1025
+ // for example, a jimple body for Enum::values method starts with the following lines:
1026
+ // public static ClassWithEnum$StatusEnum[] values()
1027
+ // {
1028
+ // ClassWithEnum$StatusEnum[] $r0, $r2;
1029
+ // java.lang.Object $r1;
1030
+ // $r0 = <ClassWithEnum$StatusEnum: ClassWithEnum$StatusEnum[] $VALUES>;
1031
+ // $r1 = virtualinvoke $r0.<java.lang.Object: java.lang.Object clone()>();
1032
+
1033
+ // so, we have to make an update for the local $r0
1023
1034
1024
- return environment.state.lastEdge!! to allUpdates
1035
+ return if (stmt is JAssignStmt ) {
1036
+ val local = stmt.leftOp as JimpleLocal
1037
+
1038
+ localMemoryUpdate(local.variable to symbolicValue)
1039
+ } else {
1040
+ LocalMemoryUpdate ()
1041
+ }
1025
1042
}
1026
1043
1027
1044
// Some fields are inaccessible with reflection, so we have to instantiate it by ourselves.
0 commit comments