@@ -88,8 +88,10 @@ 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_TYPE
9192import org.utbot.engine.types.ENUM_ORDINAL
9293import org.utbot.engine.types.EQUALS_SIGNATURE
94+ import org.utbot.engine.types.NEW_INSTANCE_SIGNATURE
9395import org.utbot.engine.types.HASHCODE_SIGNATURE
9496import org.utbot.engine.types.METHOD_FILTER_MAP_FIELD_SIGNATURE
9597import org.utbot.engine.types.NUMBER_OF_PREFERRED_TYPES
@@ -340,7 +342,8 @@ class Traverser(
340342 }
341343
342344 /* *
343- * Handles preparatory work for static initializers and multi-dimensional arrays creation.
345+ * Handles preparatory work for static initializers, multi-dimensional arrays creation
346+ * and `newInstance` reflection call post-processing.
344347 *
345348 * For instance, it could push handmade graph with preparation statements to the path selector.
346349 *
@@ -356,6 +359,7 @@ class Traverser(
356359 return when {
357360 processStaticInitializerIfRequired(current) -> true
358361 unfoldMultiArrayExprIfRequired(current) -> true
362+ pushInitGraphAfterNewInstanceReflectionCall(current) -> true
359363 else -> false
360364 }
361365 }
@@ -411,6 +415,50 @@ class Traverser(
411415 return true
412416 }
413417
418+ /* *
419+ * If the previous stms was `newInstance` method invocation,
420+ * pushes a graph of the default constructor of the constructed type, if present,
421+ * and pushes a state with a [InstantiationException] otherwise.
422+ */
423+ private fun TraversalContext.pushInitGraphAfterNewInstanceReflectionCall (stmt : JAssignStmt ): Boolean {
424+ // Check whether the previous stmt was a `newInstance` invocation
425+ val lastStmt = environment.state.path.lastOrNull() as ? JAssignStmt ? : return false
426+ val lastStmtRight = lastStmt.rightOp as ? JVirtualInvokeExpr ? : return false
427+ val lastMethodInvocation = lastStmtRight.retrieveMethod()
428+ if (lastMethodInvocation.subSignature != NEW_INSTANCE_SIGNATURE ) {
429+ return false
430+ }
431+
432+ // Process the current stmt as cast expression
433+ val right = stmt.rightOp as ? JCastExpr ? : return false
434+ val castType = right.castType as ? RefType ? : return false
435+ val castedJimpleVariable = right.op as ? JimpleLocal ? : return false
436+
437+ val castedLocalVariable = (localVariableMemory.local(castedJimpleVariable.variable) as ? ReferenceValue ) ? : return false
438+
439+ val castSootClass = castType.sootClass
440+
441+ // We need to consider a situation when this class does not have a default constructor
442+ // Since it can be a cast of a class with constructor to the interface (or ot the ancestor without default constructor),
443+ // we cannot always throw a `java.lang.InstantiationException`.
444+ // So, instead we will just continue the analysis without analysis of <init>.
445+ val initMethod = castSootClass.getMethodUnsafe(" void <init>()" ) ? : return false
446+
447+ if (! initMethod.canRetrieveBody()) {
448+ return false
449+ }
450+
451+ val initGraph = ExceptionalUnitGraph (initMethod.activeBody)
452+
453+ pushToPathSelector(
454+ initGraph,
455+ castedLocalVariable,
456+ callParameters = emptyList(),
457+ )
458+
459+ return true
460+ }
461+
414462 /* *
415463 * Processes static initialization for class.
416464 *
@@ -2915,6 +2963,21 @@ class Traverser(
29152963 }
29162964 }
29172965
2966+ // Return an unbounded symbolic variable for any `forName` overloading
2967+ if (instance == null && invocation.method.name == " forName" ) {
2968+ val forNameResult = unboundedVariable(name = " classForName" , invocation.method)
2969+
2970+ return OverrideResult (success = true , forNameResult)
2971+ }
2972+
2973+ // Return an unbounded symbolic variable for the `newInstance` method invocation,
2974+ // and at the next traversing step push <init> graph of the resulted type
2975+ if (instance?.type == CLASS_REF_TYPE && subSignature == NEW_INSTANCE_SIGNATURE ) {
2976+ val getInstanceResult = unboundedVariable(name = " newInstance" , invocation.method)
2977+
2978+ return OverrideResult (success = true , getInstanceResult)
2979+ }
2980+
29182981 val instanceAsWrapperOrNull = instance?.asWrapperOrNull
29192982
29202983 if (instanceAsWrapperOrNull is UtMockWrapper && subSignature == HASHCODE_SIGNATURE ) {
0 commit comments