Skip to content

Commit 410c58d

Browse files
committed
Fixes for type system and fallbacks in it
1 parent 3a6f06f commit 410c58d

File tree

3 files changed

+50
-7
lines changed

3 files changed

+50
-7
lines changed

utbot-framework-test/src/test/kotlin/org/utbot/examples/collections/MapsPart1Test.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ internal class MapsPart1Test : UtValueTestCaseChecker(
116116
withoutConcrete {
117117
check(
118118
Maps::containsKeyAndPuts,
119-
eq(2),
119+
ignoreExecutionsNumber,
120120
{ values, _ -> values == null },
121121
{ values, r -> 1 !in values.keys && r == 3 },
122122
coverage = DoNotCalculate

utbot-framework/src/main/kotlin/org/utbot/engine/Resolver.kt

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -717,11 +717,16 @@ class Resolver(
717717
* Constructs a type for the addr.
718718
*
719719
* There are three options here:
720+
*
720721
* * it successfully constructs a type suitable with defaultType and returns it;
722+
*
721723
* * it constructs a type that cannot be assigned in a variable with the [defaultType] and we `touched`
722-
* the [addr] during the analysis. In such case the method returns [defaultType] as a result
723-
* if the constructed type is not an array, and in case of array it returns the [defaultType] if it has the same
724-
* dimensions as the constructed type and its ancestors includes the constructed type, or null otherwise;
724+
* the [addr] during the analysis. In such case we have only two options: either this object was aliased with
725+
* an object of another type (by solver's decision) and we didn't touch it in fact, or it happened because
726+
* of missed connection between an array type and types of its elements. For example, we might case
727+
* array to a succ type after we `touched` it's element. In the first scenario null will be returns, in the
728+
* second one -- a default type (that will be a subtype of actualType).
729+
*
725730
* * it constructs a type that cannot be assigned in a variable with the [defaultType] and we did **not** `touched`
726731
* the [addr] during the analysis. It means we can create [UtNullModel] to represent such element. In such case
727732
* the method returns null as the result.
@@ -816,19 +821,35 @@ class Resolver(
816821
// as const or store model.
817822
if (defaultBaseType is PrimType) return null
818823

824+
// There is no way you have java.lang.Object as a defaultType here, since it'd mean that
825+
// some actualType is not an inheritor of it
819826
require(!defaultType.isJavaLangObject()) {
820827
"Object type $defaultType is unexpected in fallback to default type"
821828
}
822829

823-
if (defaultType.numDimensions == 0) {
824-
return defaultType
830+
// It might happen only if we have a wrong aliasing here: some object has not been touched
831+
// during the execution, and solver returned for him an address of already existed object
832+
// with another type. In such case `UtNullModel` should be constructed.
833+
if (defaultBaseType.isJavaLangObject() && actualType.numDimensions < defaultType.numDimensions) {
834+
return null
835+
}
836+
837+
// All cases with `java.lang.Object` as default base type should have been already processed
838+
require(!defaultBaseType.isJavaLangObject()) {
839+
"Unexpected `java.lang.Object` as a default base type"
825840
}
826841

827842
val actualBaseType = actualType.baseType
828843

829844
require(actualBaseType is RefType) { "Expected RefType, but $actualBaseType found" }
830845
require(defaultBaseType is RefType) { "Expected RefType, but $defaultBaseType found" }
831846

847+
848+
// The same idea about fake aliasing. It might happen only if there have been an aliasing
849+
// because of the solver's decision. In fact an object for which we construct type has not been
850+
// touched during analysis.
851+
if (actualType.numDimensions != defaultType.numDimensions) return null
852+
832853
val ancestors = typeResolver.findOrConstructAncestorsIncludingTypes(defaultBaseType)
833854

834855
// This is intended to fix a specific problem. We have code:
@@ -840,7 +861,27 @@ class Resolver(
840861
// when the array is ColoredPoint[], but the first element of it got type Point from the solver.
841862
// In such case here we'll have ColoredPoint as defaultType and Point as actualType. It is obvious from the example
842863
// that we can construct ColoredPoint instance instead of it with randomly filled colored-specific fields.
843-
return defaultType.takeIf { actualBaseType in ancestors && actualType.numDimensions == defaultType.numDimensions }
864+
// Note that it won't solve a problem when this `array[0]` has already been constructed somewhere above,
865+
// since a model for it is already presented in cache and will be taken by addr from it.
866+
// TODO corresponding issue https://github.com/UnitTestBot/UTBotJava/issues/1232
867+
if (actualBaseType in ancestors) return defaultType
868+
869+
val inheritors = typeResolver.findOrConstructInheritorsIncludingTypes(defaultBaseType)
870+
871+
// If we have an actual type that is not a subclass of defaultBaseType and isTouched is true,
872+
// it means that we have encountered unexpected aliasing between an object for which we resolve its type
873+
// and some object in the system. The reason is `isTouched` means that we processed this object
874+
// during the analysis, therefore we create correct type constraints for it. Since we have
875+
// inappropriate actualType here, these constraints were supposed to define type for another object,
876+
// and, in fact, we didn't touch our object.
877+
// For example, we have an array of two elements: Integer[] = new Integer[2], and this instance: ThisClass.
878+
// During the execution we `touched` only the first element of the array, and we know its type.
879+
// During resolving we found that second element of the array has set in true `isTouched` field,
880+
// and its actualType is `ThisClass`. So, we have wrong aliasing here and can return `null` to construct
881+
// UtNullModel instead.
882+
if (actualBaseType !in inheritors) return null
883+
884+
return null
844885
}
845886

846887
/**

utbot-framework/src/main/kotlin/org/utbot/tests/infrastructure/CompilationAndRunUtils.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ fun runTests(
6161
val classpath = System.getProperty("java.class.path") + File.pathSeparator + buildDirectory
6262
val executionInvoke = generatedLanguage.executorInvokeCommand
6363
val additionalArguments = listOf(
64+
"--add-opens",
65+
"java.base/sun.reflect.generics.repository=ALL-UNNAMED",
6466
"-ea", // Enable assertions
6567
)
6668

0 commit comments

Comments
 (0)