@@ -15,6 +15,7 @@ import soot.SootClass
1515import soot.SootField
1616import soot.SootMethod
1717import soot.Type
18+ import soot.Value
1819import soot.jimple.StaticFieldRef
1920import soot.jimple.Stmt
2021import soot.jimple.internal.JAssignStmt
@@ -154,18 +155,23 @@ fun SootClass.isEnumAffectingExternalStatics(typeResolver: TypeResolver): Boolea
154155 // enum <clinit> active body contains <init> invocations so we can check only <clinit>
155156 val staticInitializer = staticInitializerOrNull() ? : return false
156157
157- return staticInitializer.isAffectingExternalStatics(this , mutableSetOf (), typeResolver)
158+ val implementedInterfaces = typeResolver
159+ .findOrConstructAncestorsIncludingTypes(type)
160+ .filter { type -> type.sootClass.isInterface }
161+
162+ return staticInitializer.isTouchingExternalStatics(this , mutableSetOf (), implementedInterfaces)
158163}
159164
160165/* *
161- * Returns whether [this] method affects any statics from any types except [currentClass] and its interfaces.
166+ * Returns whether [this] method touches any statics from any types
167+ * except [currentClass] and its interfaces in [currentClassImplementedInterfaces].
162168 *
163- * NOTE: see org.utbot.examples.enums.ClassWithEnum.EnumWithStaticAffectingInit for examples.
169+ * NOTE: see org.utbot.examples.enums.ClassWithEnum.{ EnumWithStaticAffectingInit, OuterStaticUsageEnum} for examples.
164170 */
165- fun SootMethod.isAffectingExternalStatics (
171+ fun SootMethod.isTouchingExternalStatics (
166172 currentClass : SootClass ,
167173 alreadyProcessed : MutableSet <SootMethod >,
168- typeResolver : TypeResolver
174+ currentClassImplementedInterfaces : List < Type >
169175): Boolean {
170176 if (this in alreadyProcessed) {
171177 return false
@@ -187,28 +193,48 @@ fun SootMethod.isAffectingExternalStatics(
187193 when (it) {
188194 is JAssignStmt -> {
189195 val leftOp = it.leftOp
196+ val rightOp = it.rightOp
190197
191- if (leftOp !is StaticFieldRef ) {
192- return @any false
193- }
194-
195- val declaringClass = leftOp.field.declaringClass
198+ val assigningOuterStatics =
199+ isExternalStaticField(leftOp, currentClassImplementedInterfaces, currentClass)
196200
197- val currentClassImplementedInterfaces = typeResolver
198- .findOrConstructAncestorsIncludingTypes(currentClass.type)
199- .filter { type -> type.sootClass.isInterface }
200- val inImplementedInterfaces = declaringClass.type in currentClassImplementedInterfaces
201+ val assignmentFromOuterStatics =
202+ isExternalStaticField(rightOp, currentClassImplementedInterfaces, currentClass)
201203
202- // check that no system statics are affected (but implemented interfaces fields are allowed)
203- ! (inImplementedInterfaces || declaringClass == currentClass)
204+ assigningOuterStatics || assignmentFromOuterStatics
204205 }
205206 else -> {
206207 if (it.containsInvokeExpr()) {
207- it.invokeExpr.method.isAffectingExternalStatics(currentClass, alreadyProcessed, typeResolver)
208+ it.invokeExpr.method.isTouchingExternalStatics(
209+ currentClass,
210+ alreadyProcessed,
211+ currentClassImplementedInterfaces
212+ )
208213 } else {
209214 false
210215 }
211216 }
212217 }
213218 }
214219}
220+
221+ /* *
222+ * Determines whether [fieldRef] is static field not from [currentClass]
223+ * (except static fields from all interfaces implemented by [currentClass], stored in [currentClassImplementedInterfaces]).
224+ */
225+ private fun isExternalStaticField (
226+ fieldRef : Value ,
227+ currentClassImplementedInterfaces : List <Type >,
228+ currentClass : SootClass
229+ ): Boolean {
230+ if (fieldRef !is StaticFieldRef ) {
231+ return false
232+ }
233+
234+ val declaringClass = fieldRef.field.declaringClass
235+
236+ val classInImplementedInterfaces =
237+ declaringClass.type in currentClassImplementedInterfaces
238+
239+ return ! (classInImplementedInterfaces || declaringClass == currentClass)
240+ }
0 commit comments