Skip to content

Commit 41f3316

Browse files
committed
Fix review comments
1 parent fd0c649 commit 41f3316

File tree

14 files changed

+128
-145
lines changed

14 files changed

+128
-145
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ object UtSettings : AbstractSettings(
7373
* Timeout for symbolic execution
7474
*
7575
*/
76-
var utBotGenerationTimeoutInMillis by getLongProperty(600000L)
76+
var utBotGenerationTimeoutInMillis by getLongProperty(60000L)
7777

7878
/**
7979
* Random seed in path selector.
@@ -113,7 +113,7 @@ object UtSettings : AbstractSettings(
113113
*
114114
* False by default, set it to true if debug visualization is needed.
115115
*/
116-
var useDebugVisualization by getBooleanProperty(true)
116+
var useDebugVisualization by getBooleanProperty(false)
117117

118118
/**
119119
* Set the value to true if you want to automatically copy the path of the
@@ -136,7 +136,7 @@ object UtSettings : AbstractSettings(
136136
* @see <a href="CONFLUENCE:UtBot+Expression+Optimizations">
137137
* UtBot Expression Optimizations</a>
138138
*/
139-
var useExpressionSimplification by getBooleanProperty(false)
139+
var useExpressionSimplification by getBooleanProperty(true)
140140

141141
/*
142142
* Activate or deactivate tests on comments && names/displayNames
@@ -188,7 +188,7 @@ object UtSettings : AbstractSettings(
188188
*
189189
* True by default.
190190
*/
191-
var useConcreteExecution by getBooleanProperty(false)
191+
var useConcreteExecution by getBooleanProperty(true)
192192

193193
/**
194194
* Enable check of full coverage for methods with code generations tests.
@@ -300,7 +300,7 @@ object UtSettings : AbstractSettings(
300300
*
301301
* False by default.
302302
*/
303-
var enableUnsatCoreCalculationForHardConstraints by getBooleanProperty(true)
303+
var enableUnsatCoreCalculationForHardConstraints by getBooleanProperty(false)
304304

305305
/**
306306
* Enable it to process states with unknown solver status

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -521,10 +521,21 @@ data class UtAssembleModel(
521521
* Depending on the captured variables, this method will be either static or non-static.
522522
*
523523
* Since lambdas are not classes we cannot use a class loader to get info about them as we can do for other models.
524-
* Hence, the necessity for this specific lambda model that will be processed differently: instead of working
525-
* with a class we will be working with the synthetic method that represents our lambda.
524+
* Hence, the necessity for this specific lambda model that will be processed differently:
525+
* instead of working with a class we will be working with the synthetic method that represents our lambda.
526+
*
527+
* @property id see documentation on [UtReferenceModel.id]
528+
* @property samType the type of functional interface that this lambda will be used for (e.g. [java.util.function.Predicate]).
529+
* `sam` means single abstract method. See https://kotlinlang.org/docs/fun-interfaces.html for more details about it in Kotlin.
530+
* In Java it means the same.
531+
* @property declaringClass a class where the lambda is located.
532+
* We need this class, because the synthetic method the lambda is compiled into will be located in it.
533+
* @property lambdaName the name of synthetic method the lambda is compiled into.
534+
* We need it to find this method in the [declaringClass]
535+
* @property capturedValues models of values captured by lambda.
536+
* Lambdas can capture local variables, method arguments, static and non-static fields.
526537
*/
527-
// TODO: what about support for Kotlin lambdas (they are not exactly the same as Java's due to functional types)
538+
// TODO: what about support for Kotlin lambdas and function types? See https://github.com/UnitTestBot/UTBotJava/issues/852
528539
class UtLambdaModel(
529540
override val id: Int?,
530541
val samType: ClassId,

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/IdUtil.kt

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,25 +53,6 @@ val ClassId.denotableType: ClassId
5353
}
5454
}
5555

56-
private val isLambdaRegex = ".*(\\$)lambda_.*".toRegex()
57-
58-
val ClassId.isLambda: Boolean
59-
get() = name matches isLambdaRegex
60-
61-
val ClassId.isFunctionalInterface: Boolean
62-
get() {
63-
// we cannot access jClass of a builtin type, so we have to return false
64-
if (this is BuiltinClassId) return false
65-
// we cannot access jClass for lambdas, but we know that it is not a functional interface anyway
66-
if (this.isLambda) return false
67-
68-
val clazz = this.jClass
69-
if (!clazz.isInterface) return false
70-
71-
val abstractMethods = clazz.methods.filter { java.lang.reflect.Modifier.isAbstract(it.modifiers) }
72-
return abstractMethods.size == 1
73-
}
74-
7556
@Suppress("unused")
7657
val ClassId.enclosingClass: ClassId?
7758
get() = jClass.enclosingClass?.id

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import org.utbot.framework.UtSettings.checkNpeInNestedMethods
3535
import org.utbot.framework.UtSettings.checkNpeInNestedNotPrivateMethods
3636
import org.utbot.framework.plugin.api.FieldId
3737
import org.utbot.framework.plugin.api.id
38-
import org.utbot.framework.plugin.api.util.isLambda
3938
import soot.ArrayType
4039
import soot.PrimType
4140
import soot.RefLikeType
@@ -193,8 +192,10 @@ private val isAnonymousRegex = ".*\\$\\d+$".toRegex()
193192
val SootClass.isAnonymous
194193
get() = name matches isAnonymousRegex
195194

195+
private val isLambdaRegex = ".*(\\$)lambda_.*".toRegex()
196+
196197
val SootClass.isLambda: Boolean
197-
get() = this.id.isLambda
198+
get() = this.isArtificialEntity && this.name matches isLambdaRegex
198199

199200
val Type.numDimensions get() = if (this is ArrayType) numDimensions else 0
200201

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

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.utbot.engine
22

33
import org.utbot.framework.plugin.api.ClassId
4-
import org.utbot.framework.plugin.api.util.isFunctionalInterface
54

65
/**
76
* Mock strategies.
@@ -18,24 +17,15 @@ enum class MockStrategy {
1817
},
1918

2019
OTHER_PACKAGES {
21-
override fun eligibleToMock(classToMock: ClassId, classUnderTest: ClassId): Boolean {
22-
if (classToMock == classUnderTest) return false
23-
if (classToMock.packageName == classUnderTest.packageName) return false
24-
25-
// we always mock functional interfaces
26-
if (classToMock.isFunctionalInterface) return true
27-
28-
return !isSystemPackage(classToMock.packageName)
29-
}
20+
override fun eligibleToMock(classToMock: ClassId, classUnderTest: ClassId): Boolean =
21+
classToMock != classUnderTest && classToMock.packageName.let {
22+
it != classUnderTest.packageName && !isSystemPackage(it)
23+
}
3024
},
3125

3226
OTHER_CLASSES {
33-
override fun eligibleToMock(classToMock: ClassId, classUnderTest: ClassId): Boolean {
34-
if (classToMock == classUnderTest) return false
35-
// we always mock functional interfaces
36-
if (classToMock.isFunctionalInterface) return true
37-
return !isSystemPackage(classToMock.packageName)
38-
}
27+
override fun eligibleToMock(classToMock: ClassId, classUnderTest: ClassId): Boolean =
28+
classToMock != classUnderTest && !isSystemPackage(classToMock.packageName)
3929
};
4030

4131
/**

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ class Resolver(
642642
val samType = sootClass.interfaces.singleOrNull()?.id
643643
?: error("Lambda must implement single interface, but ${sootClass.interfaces.size} found for ${sootClass.name}")
644644

645-
val declaringClass = classLoader.loadClass(sootClass.name.substringBeforeLast("\$lambda"))
645+
val declaringClass = classLoader.loadClass(sootClass.name.substringBefore("\$lambda"))
646646

647647
// Java compiles lambdas into synthetic methods with specific names.
648648
// However, Soot represents lambdas as classes.
@@ -654,7 +654,7 @@ class Resolver(
654654
// Here we obtain the synthetic method name of lambda from the name of its SootClass.
655655
val lambdaName = sootClass.name
656656
.let { name ->
657-
val start = name.lastIndexOf("\$lambda") + 1
657+
val start = name.indexOf("\$lambda") + 1
658658
val end = name.lastIndexOf("__")
659659
name.substring(start, end)
660660
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1832,7 +1832,7 @@ class Traverser(
18321832
return fromMemory
18331833
}
18341834
val addr = fromMemory?.addr ?: findNewAddr()
1835-
val created = createObject(addr, classType, useConcreteType = true, mockInfoGenerator)
1835+
val created = createObject(addr, classType, useConcreteType = false, mockInfoGenerator)
18361836
queuedSymbolicStateUpdates += MemoryUpdate(staticInstanceStorage = persistentHashMapOf(classType.id to created))
18371837
return created
18381838
}

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

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy
112112
if (numDimensions == 0) baseType else baseType.makeArrayType(numDimensions)
113113
}
114114

115-
return TypeStorage(type, concretePossibleTypes)//.filterInappropriateClassesForCodeGeneration()
115+
return TypeStorage(type, concretePossibleTypes).filterInappropriateClassesForCodeGeneration()
116116
}
117117

118118
private fun isInappropriateOrArrayOfMocksOrLocals(numDimensions: Int, baseType: Type?): Boolean {
@@ -182,7 +182,7 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy
182182
else -> error("Unexpected type $type")
183183
}
184184

185-
return TypeStorage(type, possibleTypes)//.filterInappropriateClassesForCodeGeneration()
185+
return TypeStorage(type, possibleTypes).filterInappropriateClassesForCodeGeneration()
186186
}
187187

188188
/**
@@ -197,26 +197,23 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy
197197
val leastCommonSootClass = (leastCommonType as? RefType)?.sootClass
198198
val keepArtificialEntities = leastCommonSootClass?.isArtificialEntity == true
199199

200-
heuristic(WorkaroundReason.REMOVE_ANONYMOUS_CLASSES) {
201-
possibleConcreteTypes.forEach {
202-
val sootClass = (it.baseType as? RefType)?.sootClass ?: run {
203-
// All not RefType should be included in the concreteTypes, e.g., arrays
204-
concreteTypes += it
205-
return@forEach
206-
}
207-
when {
208-
sootClass.isUtMock -> unwantedTypes += it
209-
sootClass.isArtificialEntity -> {
210-
// if (sootClass.isLambda) {
211-
// unwantedTypes += it
212-
// } else
213-
if (keepArtificialEntities) {
214-
concreteTypes += it
215-
}
200+
possibleConcreteTypes.forEach {
201+
val sootClass = (it.baseType as? RefType)?.sootClass ?: run {
202+
// All not RefType should be included in the concreteTypes, e.g., arrays
203+
concreteTypes += it
204+
return@forEach
205+
}
206+
when {
207+
sootClass.isUtMock -> unwantedTypes += it
208+
sootClass.isArtificialEntity -> {
209+
if (sootClass.isLambda) {
210+
unwantedTypes += it
211+
} else if (keepArtificialEntities) {
212+
concreteTypes += it
216213
}
217-
workaround(WorkaroundReason.HACK) { leastCommonSootClass == OBJECT_TYPE && sootClass.isOverridden } -> Unit
218-
else -> concreteTypes += it
219214
}
215+
workaround(WorkaroundReason.HACK) { leastCommonSootClass == OBJECT_TYPE && sootClass.isOverridden } -> Unit
216+
else -> concreteTypes += it
220217
}
221218
}
222219

utbot-framework/src/main/kotlin/org/utbot/engine/util/lambda/LambdaConstructionUtils.kt

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,46 @@ private fun getInstantiatedMethodType(
5858
*/
5959
private fun getLambdaMethod(declaringClass: Class<*>, lambdaName: String): Method {
6060
return declaringClass.declaredMethods.firstOrNull { it.name == lambdaName }
61-
?: throw IllegalArgumentException("No lambda method named ${'$'}lambdaName was found in class: ${'$'}{declaringClass.canonicalName}")
61+
?: throw IllegalArgumentException("No lambda method named $lambdaName was found in class: ${declaringClass.canonicalName}")
62+
}
63+
64+
/**
65+
* This class contains some info that is needed by both [constructLambda] and [constructStaticLambda].
66+
* We obtain this info in [prepareLambdaInfo] to avoid duplicated code in [constructLambda] and [constructStaticLambda].
67+
*/
68+
private data class LambdaMetafactoryInfo(
69+
val caller: MethodHandles.Lookup,
70+
val invokedName: String,
71+
val samMethodType: MethodType,
72+
val lambdaMethod: Method,
73+
val lambdaMethodType: MethodType
74+
)
75+
76+
/**
77+
* Obtain and prepare [LambdaMetafactoryInfo] that is needed by [constructLambda] and [constructStaticLambda].
78+
*/
79+
private fun prepareLambdaInfo(
80+
samType: Class<*>,
81+
declaringClass: Class<*>,
82+
lambdaName: String,
83+
): LambdaMetafactoryInfo {
84+
// Create lookup for class where the lambda is declared in.
85+
val caller = getLookupIn(declaringClass)
86+
87+
// Obtain the single abstract method of a functional interface whose instance we are building.
88+
// For example, for `java.util.function.Predicate` it will be method `test`.
89+
val singleAbstractMethod = getSingleAbstractMethod(samType)
90+
91+
val invokedName = singleAbstractMethod.name
92+
93+
// Method type of single abstract method of the target functional interface.
94+
val samMethodType = MethodType.methodType(singleAbstractMethod.returnType, singleAbstractMethod.parameterTypes)
95+
96+
val lambdaMethod = getLambdaMethod(declaringClass, lambdaName)
97+
lambdaMethod.isAccessible = true
98+
val lambdaMethodType = MethodType.methodType(lambdaMethod.returnType, lambdaMethod.parameterTypes)
99+
100+
return LambdaMetafactoryInfo(caller, invokedName, samMethodType, lambdaMethod, lambdaMethodType)
62101
}
63102

64103
/**
@@ -82,19 +121,9 @@ internal fun constructStaticLambda(
82121
lambdaName: String,
83122
vararg capturedArguments: CapturedArgument
84123
): Any {
85-
// Create lookup for class where the lambda is declared in.
86-
val caller = getLookupIn(declaringClass)
124+
val (caller, invokedName, samMethodType, lambdaMethod, lambdaMethodType) =
125+
prepareLambdaInfo(samType, declaringClass, lambdaName)
87126

88-
// Obtain the single abstract method of a functional interface whose instance we are building.
89-
// For example, for `java.util.function.Predicate` it will be method `test`.
90-
val singleAbstractMethod = getSingleAbstractMethod(samType)
91-
val invokedName = singleAbstractMethod.name
92-
// Method type of single abstract method of the target functional interface.
93-
val samMethodType = MethodType.methodType(singleAbstractMethod.returnType, singleAbstractMethod.parameterTypes)
94-
95-
val lambdaMethod = getLambdaMethod(declaringClass, lambdaName)
96-
lambdaMethod.isAccessible = true
97-
val lambdaMethodType = MethodType.methodType(lambdaMethod.returnType, lambdaMethod.parameterTypes)
98127
val lambdaMethodHandle = caller.findStatic(declaringClass, lambdaName, lambdaMethodType)
99128

100129
val capturedArgumentTypes = capturedArguments.map { it.type }.toTypedArray()
@@ -129,19 +158,9 @@ internal fun constructLambda(
129158
capturedReceiver: Any,
130159
vararg capturedArguments: CapturedArgument
131160
): Any {
132-
// Create lookup for class where the lambda is declared in.
133-
val caller = getLookupIn(declaringClass)
134-
135-
// Obtain the single abstract method of a functional interface whose instance we are building.
136-
// For example, for `java.util.function.Predicate` it will be method `test`.
137-
val singleAbstractMethod = getSingleAbstractMethod(samType)
138-
val invokedName = singleAbstractMethod.name
139-
// Method type of single abstract method of the target functional interface.
140-
val samMethodType = MethodType.methodType(singleAbstractMethod.returnType, singleAbstractMethod.parameterTypes)
161+
val (caller, invokedName, samMethodType, lambdaMethod, lambdaMethodType) =
162+
prepareLambdaInfo(samType, declaringClass, lambdaName)
141163

142-
val lambdaMethod = getLambdaMethod(declaringClass, lambdaName)
143-
lambdaMethod.isAccessible = true
144-
val lambdaMethodType = MethodType.methodType(lambdaMethod.returnType, lambdaMethod.parameterTypes)
145164
val lambdaMethodHandle = caller.findVirtual(declaringClass, lambdaName, lambdaMethodType)
146165

147166
val capturedArgumentTypes = capturedArguments.map { it.type }.toTypedArray()

utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@ class AssembleModelGenerator(private val methodPackageName: String) {
233233
}
234234

235235
try {
236-
// TODO: we can't use simpleName for anonymous classes, because it's empty
237236
val modelName = nextModelName(compositeModel.classId.jClass.simpleName.decapitalize())
238237

239238
val instantiationChain = mutableListOf<UtStatementModel>()

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
695695
)
696696
}
697697
}
698-
is UtLambdaModel -> Unit
698+
is UtLambdaModel -> Unit // we do not check equality of lambdas
699699
is UtVoidModel -> {
700700
// Unit result is considered in generateResultAssertions method
701701
error("Unexpected UtVoidModel in deep equals")
@@ -960,8 +960,8 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
960960
}
961961
}
962962

963-
is UtLambdaModel -> Unit // TODO: lambda model
964-
963+
// Lambdas do not have fields. They have captured values, but we do not consider them here.
964+
is UtLambdaModel,
965965
is UtNullModel,
966966
is UtPrimitiveModel,
967967
is UtArrayModel,
@@ -1001,8 +1001,8 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
10011001
}
10021002
}
10031003

1004-
is UtLambdaModel -> Unit // TODO: lambda model
1005-
1004+
// Lambdas do not have fields. They have captured values, but we do not consider them here.
1005+
is UtLambdaModel,
10061006
is UtNullModel,
10071007
is UtPrimitiveModel,
10081008
is UtArrayModel,

0 commit comments

Comments
 (0)