@@ -15,6 +15,8 @@ import org.jacodb.ets.model.EtsBitOrExpr
1515import org.jacodb.ets.model.EtsBitXorExpr
1616import org.jacodb.ets.model.EtsBooleanConstant
1717import org.jacodb.ets.model.EtsCastExpr
18+ import org.jacodb.ets.model.EtsClassSignature
19+ import org.jacodb.ets.model.EtsClassType
1820import org.jacodb.ets.model.EtsConstant
1921import org.jacodb.ets.model.EtsDeleteExpr
2022import org.jacodb.ets.model.EtsDivExpr
@@ -82,6 +84,7 @@ import org.usvm.UHeapRef
8284import org.usvm.USort
8385import org.usvm.api.allocateArray
8486import org.usvm.dataflow.ts.infer.tryGetKnownType
87+ import org.usvm.dataflow.ts.util.type
8588import org.usvm.isTrue
8689import org.usvm.machine.TsConcreteMethodCallStmt
8790import org.usvm.machine.TsContext
@@ -96,9 +99,11 @@ import org.usvm.machine.state.TsState
9699import org.usvm.machine.state.lastStmt
97100import org.usvm.machine.state.localsCount
98101import org.usvm.machine.state.newStmt
102+ import org.usvm.machine.types.AuxiliaryType
99103import org.usvm.machine.types.mkFakeValue
100104import org.usvm.memory.ULValue
101105import org.usvm.sizeSort
106+ import org.usvm.util.isResolved
102107import org.usvm.util.mkArrayIndexLValue
103108import org.usvm.util.mkArrayLengthLValue
104109import org.usvm.util.mkFieldLValue
@@ -167,7 +172,7 @@ class TsExprResolver(
167172 dependency0 : EtsEntity ,
168173 dependency1 : EtsEntity ,
169174 block : (UExpr <out USort >, UExpr <out USort >) -> T ,
170- ):T ? {
175+ ): T ? {
171176 val result0 = resolve(dependency0) ? : return null
172177 val result1 = resolve(dependency1) ? : return null
173178 return block(result0, result1)
@@ -413,9 +418,11 @@ class TsExprResolver(
413418 error(" Not supported $expr " )
414419 }
415420
416- override fun visit (expr : EtsInstanceOfExpr ): UExpr <out USort >? {
417- logger.warn { " visit(${expr::class .simpleName} ) is not implemented yet" }
418- error(" Not supported $expr " )
421+ override fun visit (expr : EtsInstanceOfExpr ): UExpr <out USort >? = with (ctx) {
422+ val arg = resolve(expr.arg)?.asExpr(addressSort) ? : return null
423+ scope.calcOnState {
424+ memory.types.evalIsSubtype(arg, expr.checkType)
425+ }
419426 }
420427
421428 // endregion
@@ -580,20 +587,20 @@ class TsExprResolver(
580587 // region ACCESS
581588
582589 override fun visit (value : EtsArrayAccess ): UExpr <out USort >? = with (ctx) {
583- val instance = resolve(value.array)?.asExpr(ctx. addressSort) ? : return null
584- val index = resolve(value.index)?.asExpr(ctx. fp64Sort) ? : return null
590+ val array = resolve(value.array)?.asExpr(addressSort) ? : return null
591+ val index = resolve(value.index)?.asExpr(fp64Sort) ? : return null
585592 val bvIndex = mkFpToBvExpr(
586593 roundingMode = fpRoundingModeSortDefaultValue(),
587594 value = index,
588595 bvSize = 32 ,
589- isSigned = true
590- )
596+ isSigned = true ,
597+ ).asExpr(sizeSort)
591598
592599 val lValue = mkArrayIndexLValue(
593- addressSort,
594- instance ,
595- bvIndex.asExpr(ctx.sizeSort) ,
596- value.array.type as EtsArrayType
600+ sort = addressSort,
601+ ref = array ,
602+ index = bvIndex,
603+ type = value.array.type as EtsArrayType
597604 )
598605 val expr = scope.calcOnState { memory.read(lValue) }
599606
@@ -604,8 +611,8 @@ class TsExprResolver(
604611
605612 private fun checkUndefinedOrNullPropertyRead (instance : UHeapRef ) = with (ctx) {
606613 val neqNull = mkAnd(
607- mkHeapRefEq(instance, ctx. mkUndefinedValue()).not (),
608- mkHeapRefEq(instance, ctx. mkTsNullValue()).not ()
614+ mkHeapRefEq(instance, mkUndefinedValue()).not (),
615+ mkHeapRefEq(instance, mkTsNullValue()).not ()
609616 )
610617
611618 scope.fork(
@@ -624,10 +631,25 @@ class TsExprResolver(
624631 instanceRef : UHeapRef ,
625632 field : EtsFieldSignature ,
626633 ): UExpr <out USort >? = with (ctx) {
634+ val resolvedAddr = if (instanceRef.isFakeObject()) instanceRef.extractRef(scope) else instanceRef
635+ scope.doWithState {
636+ pathConstraints + = if (field.enclosingClass != EtsClassSignature .UNKNOWN ) {
637+ // If we know an enclosing class of the field,
638+ // we can add a type constraint about the instance type.
639+ // Probably, it's redundant since either both class and field
640+ // know exactly their types or none of them.
641+ val type = EtsClassType (field.enclosingClass)
642+ memory.types.evalIsSubtype(resolvedAddr, type)
643+ } else {
644+ // Otherwise, we add a type constraint that every type containing such field is fine
645+ memory.types.evalIsSubtype(resolvedAddr, AuxiliaryType (setOf (field.name)))
646+ }
647+ }
648+
627649 val etsField = resolveEtsField(instance, field)
628650 val sort = typeToSort(etsField.type)
629651
630- val expr = if (sort == unresolvedSort) {
652+ if (sort == unresolvedSort) {
631653 val boolLValue = mkFieldLValue(boolSort, instanceRef, field)
632654 val fpLValue = mkFieldLValue(fp64Sort, instanceRef, field)
633655 val refLValue = mkFieldLValue(addressSort, instanceRef, field)
@@ -653,13 +675,6 @@ class TsExprResolver(
653675 val lValue = mkFieldLValue(sort, instanceRef, field)
654676 scope.calcOnState { memory.read(lValue) }
655677 }
656-
657- // TODO: check 'field.type' vs 'etsField.type'
658- if (assertIsSubtype(expr, field.type)) {
659- expr
660- } else {
661- null
662- }
663678 }
664679
665680 override fun visit (value : EtsInstanceFieldRef ): UExpr <out USort >? = with (ctx) {
@@ -739,8 +754,17 @@ class TsExprResolver(
739754
740755 // region OTHER
741756
742- override fun visit (expr : EtsNewExpr ): UExpr <out USort >? = scope.calcOnState {
743- memory.allocConcrete(expr.type)
757+ override fun visit (expr : EtsNewExpr ): UExpr <out USort >? = with (ctx) {
758+ // Try to resolve the concrete type if possible.
759+ // Otherwise, create an object with UnclearRefType
760+ val resolvedType = if (expr.type.isResolved()) {
761+ scene.projectAndSdkClasses
762+ .singleOrNull { it.name == expr.type.typeName }?.type
763+ ? : expr.type
764+ } else {
765+ expr.type
766+ }
767+ scope.calcOnState { memory.allocConcrete(resolvedType) }
744768 }
745769
746770 override fun visit (expr : EtsNewArrayExpr ): UExpr <out USort >? = with (ctx) {
@@ -752,10 +776,10 @@ class TsExprResolver(
752776 }
753777
754778 val bvSize = mkFpToBvExpr(
755- fpRoundingModeSortDefaultValue(),
756- size.asExpr(fp64Sort),
779+ roundingMode = fpRoundingModeSortDefaultValue(),
780+ value = size.asExpr(fp64Sort),
757781 bvSize = 32 ,
758- isSigned = true
782+ isSigned = true ,
759783 )
760784
761785 val condition = mkAnd(
@@ -782,11 +806,6 @@ class TsExprResolver(
782806 }
783807
784808 // endregion
785-
786- // TODO incorrect implementation
787- private fun assertIsSubtype (expr : UExpr <out USort >, type : EtsType ): Boolean {
788- return true
789- }
790809}
791810
792811class TsSimpleValueResolver (
0 commit comments