@@ -88,8 +88,11 @@ import org.utbot.engine.symbolic.asUpdate
8888import org.utbot.engine.simplificators.MemoryUpdateSimplificator
8989import org.utbot.engine.simplificators.simplifySymbolicStateUpdate
9090import org.utbot.engine.simplificators.simplifySymbolicValue
91+ import org.utbot.engine.types.CLASS_REF_SOOT_CLASS
92+ import org.utbot.engine.types.CLASS_REF_TYPE
9193import org.utbot.engine.types.ENUM_ORDINAL
9294import org.utbot.engine.types.EQUALS_SIGNATURE
95+ import org.utbot.engine.types.NEW_INSTANCE_SIGNATURE
9396import org.utbot.engine.types.HASHCODE_SIGNATURE
9497import org.utbot.engine.types.METHOD_FILTER_MAP_FIELD_SIGNATURE
9598import org.utbot.engine.types.NUMBER_OF_PREFERRED_TYPES
@@ -340,7 +343,8 @@ class Traverser(
340343 }
341344
342345 /* *
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.
344348 *
345349 * For instance, it could push handmade graph with preparation statements to the path selector.
346350 *
@@ -356,6 +360,7 @@ class Traverser(
356360 return when {
357361 processStaticInitializerIfRequired(current) -> true
358362 unfoldMultiArrayExprIfRequired(current) -> true
363+ pushInitGraphAfterNewInstanceReflectionCall(current) -> true
359364 else -> false
360365 }
361366 }
@@ -411,6 +416,53 @@ class Traverser(
411416 return true
412417 }
413418
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+
414466 /* *
415467 * Processes static initialization for class.
416468 *
@@ -2915,6 +2967,22 @@ class Traverser(
29152967 }
29162968 }
29172969
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+
29182986 val instanceAsWrapperOrNull = instance?.asWrapperOrNull
29192987
29202988 if (instanceAsWrapperOrNull is UtMockWrapper && subSignature == HASHCODE_SIGNATURE ) {
0 commit comments