@@ -88,8 +88,11 @@ import org.utbot.engine.symbolic.asUpdate
88
88
import org.utbot.engine.simplificators.MemoryUpdateSimplificator
89
89
import org.utbot.engine.simplificators.simplifySymbolicStateUpdate
90
90
import org.utbot.engine.simplificators.simplifySymbolicValue
91
+ import org.utbot.engine.types.CLASS_REF_SOOT_CLASS
92
+ import org.utbot.engine.types.CLASS_REF_TYPE
91
93
import org.utbot.engine.types.ENUM_ORDINAL
92
94
import org.utbot.engine.types.EQUALS_SIGNATURE
95
+ import org.utbot.engine.types.NEW_INSTANCE_SIGNATURE
93
96
import org.utbot.engine.types.HASHCODE_SIGNATURE
94
97
import org.utbot.engine.types.METHOD_FILTER_MAP_FIELD_SIGNATURE
95
98
import org.utbot.engine.types.NUMBER_OF_PREFERRED_TYPES
@@ -340,7 +343,8 @@ class Traverser(
340
343
}
341
344
342
345
/* *
343
- * Handles preparatory work for static initializers and multi-dimensional arrays creation.
346
+ * Handles preparatory work for static initializers, multi-dimensional arrays creation
347
+ * and `newInstance` reflection call post-processing.
344
348
*
345
349
* For instance, it could push handmade graph with preparation statements to the path selector.
346
350
*
@@ -356,6 +360,7 @@ class Traverser(
356
360
return when {
357
361
processStaticInitializerIfRequired(current) -> true
358
362
unfoldMultiArrayExprIfRequired(current) -> true
363
+ pushInitGraphAfterNewInstanceReflectionCall(current) -> true
359
364
else -> false
360
365
}
361
366
}
@@ -411,6 +416,53 @@ class Traverser(
411
416
return true
412
417
}
413
418
419
+ /* *
420
+ * If the previous stms was `newInstance` method invocation,
421
+ * pushes a graph of the default constructor of the constructed type, if present,
422
+ * and pushes a state with a [InstantiationException] otherwise.
423
+ */
424
+ private fun TraversalContext.pushInitGraphAfterNewInstanceReflectionCall (stmt : JAssignStmt ): Boolean {
425
+ // Check whether the previous stmt was a `newInstance` invocation
426
+ val lastStmt = environment.state.path.lastOrNull() as ? JAssignStmt ? : return false
427
+ if (! lastStmt.containsInvokeExpr()) {
428
+ return false
429
+ }
430
+
431
+ val lastMethodInvocation = lastStmt.invokeExpr.method
432
+ if (lastMethodInvocation.subSignature != NEW_INSTANCE_SIGNATURE ) {
433
+ return false
434
+ }
435
+
436
+ // Process the current stmt as cast expression
437
+ val right = stmt.rightOp as ? JCastExpr ? : return false
438
+ val castType = right.castType as ? RefType ? : return false
439
+ val castedJimpleVariable = right.op as ? JimpleLocal ? : return false
440
+
441
+ val castedLocalVariable = (localVariableMemory.local(castedJimpleVariable.variable) as ? ReferenceValue ) ? : return false
442
+
443
+ val castSootClass = castType.sootClass
444
+
445
+ // We need to consider a situation when this class does not have a default constructor
446
+ // Since it can be a cast of a class with constructor to the interface (or ot the ancestor without default constructor),
447
+ // we cannot always throw a `java.lang.InstantiationException`.
448
+ // So, instead we will just continue the analysis without analysis of <init>.
449
+ val initMethod = castSootClass.getMethodUnsafe(" void <init>()" ) ? : return false
450
+
451
+ if (! initMethod.canRetrieveBody()) {
452
+ return false
453
+ }
454
+
455
+ val initGraph = ExceptionalUnitGraph (initMethod.activeBody)
456
+
457
+ pushToPathSelector(
458
+ initGraph,
459
+ castedLocalVariable,
460
+ callParameters = emptyList(),
461
+ )
462
+
463
+ return true
464
+ }
465
+
414
466
/* *
415
467
* Processes static initialization for class.
416
468
*
@@ -2915,6 +2967,22 @@ class Traverser(
2915
2967
}
2916
2968
}
2917
2969
2970
+ // Return an unbounded symbolic variable for any overloading of method `forName` of class `java.lang.Class`
2971
+ // NOTE: we cannot match by a subsignature here since `forName` method has a few overloadings
2972
+ if (instance == null && invocation.method.declaringClass == CLASS_REF_SOOT_CLASS && invocation.method.name == " forName" ) {
2973
+ val forNameResult = unboundedVariable(name = " classForName" , invocation.method)
2974
+
2975
+ return OverrideResult (success = true , forNameResult)
2976
+ }
2977
+
2978
+ // Return an unbounded symbolic variable for the `newInstance` method invocation,
2979
+ // and at the next traversing step push <init> graph of the resulted type
2980
+ if (instance?.type == CLASS_REF_TYPE && subSignature == NEW_INSTANCE_SIGNATURE ) {
2981
+ val getInstanceResult = unboundedVariable(name = " newInstance" , invocation.method)
2982
+
2983
+ return OverrideResult (success = true , getInstanceResult)
2984
+ }
2985
+
2918
2986
val instanceAsWrapperOrNull = instance?.asWrapperOrNull
2919
2987
2920
2988
if (instanceAsWrapperOrNull is UtMockWrapper && subSignature == HASHCODE_SIGNATURE ) {
0 commit comments