@@ -906,23 +906,34 @@ class UtBotSymbolicEngine(
906906 // Gets concrete value, converts to symbolic value
907907 val declaringClass = field.declaringClass
908908
909- val (edge, updates) = if (declaringClass.isEnum) {
909+ val updates = if (declaringClass.isEnum) {
910910 makeConcreteUpdatesForEnums(fieldId, declaringClass, stmt)
911911 } else {
912- makeConcreteUpdatesForNonEnumStaticField(field, fieldId, declaringClass)
912+ makeConcreteUpdatesForNonEnumStaticField(field, fieldId, declaringClass, stmt )
913913 }
914914
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+
915925 val newState = environment.state.updateQueued(edge, updates)
916926 pathSelector.offer(newState)
917927
918928 return true
919929 }
920930
931+ @Suppress(" UnnecessaryVariable" )
921932 private fun makeConcreteUpdatesForEnums (
922933 fieldId : FieldId ,
923934 declaringClass : SootClass ,
924935 stmt : Stmt
925- ): Pair < Edge , SymbolicStateUpdate > {
936+ ): SymbolicStateUpdate {
926937 val type = declaringClass.type
927938 val jClass = type.id.jClass
928939
@@ -966,46 +977,21 @@ class UtBotSymbolicEngine(
966977 meaningfulStaticFields = meaningfulStaticFields.map { it.first.fieldId }.toPersistentSet()
967978 )
968979
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)
1000984
1001- return edge to allUpdates
985+ return allUpdates
1002986 }
1003987
988+ @Suppress(" UnnecessaryVariable" )
1004989 private fun makeConcreteUpdatesForNonEnumStaticField (
1005990 field : SootField ,
1006991 fieldId : FieldId ,
1007- declaringClass : SootClass
1008- ): Pair <Edge , SymbolicStateUpdate > {
992+ declaringClass : SootClass ,
993+ stmt : Stmt
994+ ): SymbolicStateUpdate {
1009995 val concreteValue = extractConcreteValue(field, declaringClass)
1010996 val (symbolicResult, symbolicStateUpdate) = toMethodResult(concreteValue, field.type)
1011997 val symbolicValue = (symbolicResult as SymbolicSuccess ).value
@@ -1019,9 +1005,40 @@ class UtBotSymbolicEngine(
10191005 field = field,
10201006 value = valueToExpression(symbolicValue, field.type)
10211007 )
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
10231034
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+ }
10251042 }
10261043
10271044 // Some fields are inaccessible with reflection, so we have to instantiate it by ourselves.
0 commit comments