Skip to content

Commit 3c07f06

Browse files
ArsenHDdenis-fokin
authored andcommitted
Refactor code related to block construction (#571)
* Refactor code related to block construction Code generation relies on CgContext for storing information about the currently available variables, imports, statements, etc. The context also stores info about code block currently being generated (currentBlock). It is possible to collect statements into some list and then update the currentBlock with them, but it is discouraged, because this way it is very easy to occacionally lose some of the statements. That's because some statements will go to the currentBlock, but then will be overriden on update from the new list of statements. Hence, it is recommended to always work with the statements using currentBlock and DSL methods that also use it. Such methods can be found in CgStatementConstructor.kt, see method `ifStatement` for example. This PR makes more use of currentBlock instead of using separate lists. That is done in order to prevent possible future bugs. * Refactor data provider method construction This idea of this refactoring is the same as in the previous commit. Instead of collecting statements into some lists we now collect them right into the currentBlock. * Fix ClassWithEnumTest.testOrdinal test The problem was in the parameterized tests. There were multiple bugs: wrong class ids (class id's name must not include generic parameters, but they did), wrong method id for Arguments.arguments() method (its argument must be vararg, but it wasn't). Also, when a method accepts a vararg and is called via reflection, an array of vararg arguments should be additionally wrapped into an array of Objects (e.g. new Object[]{new Integer[]{1, 2, 3}}). However, when calling this method without reflection there must not be any such wrappers. * Fix Arguments#arguments method call - Make Arguments#arguments method id static. This allowed us to call this method without reflection. Previously we used reflection, because the method id was non-static by mistake. - Construct an array of arguments for Arguments#arguments call. This way we don't have to worry about multiple cases of vararg method calls, but we should think about them later. * Limit the maximum length of an array initializer + use guards for both array allocation and initialization * Rework type parameters for some class ids Earlier type parameters were hardcoded in the class name, simple name, etc. Then they were removed from names completely, but that lead to compilation errors for Kotlin, where type parameters must always be specified. So, this commit adds type parameters, but instead of writing them into names, we add them as a separate property 'typeParameters' of BuiltinClassId.
1 parent 1f988af commit 3c07f06

File tree

14 files changed

+425
-339
lines changed

14 files changed

+425
-339
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,7 @@ open class ClassId @JvmOverloads constructor(
753753
*/
754754
class BuiltinClassId(
755755
name: String,
756+
elementClassId: ClassId? = null,
756757
override val canonicalName: String,
757758
override val simpleName: String,
758759
// by default we assume that the class is not a member class
@@ -769,6 +770,7 @@ class BuiltinClassId(
769770
override val isInner: Boolean = false,
770771
override val isNested: Boolean = false,
771772
override val isSynthetic: Boolean = false,
773+
override val typeParameters: TypeParameters = TypeParameters(),
772774
override val allMethods: Sequence<MethodId> = emptySequence(),
773775
override val allConstructors: Sequence<ConstructorId> = emptySequence(),
774776
override val outerClass: Class<*>? = null,
@@ -777,7 +779,7 @@ class BuiltinClassId(
777779
-1, 0 -> ""
778780
else -> canonicalName.substring(0, index)
779781
},
780-
) : ClassId(name = name, isNullable = isNullable) {
782+
) : ClassId(name = name, isNullable = isNullable, elementClassId = elementClassId) {
781783
init {
782784
BUILTIN_CLASSES_BY_NAMES[name] = this
783785
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.utbot.framework.plugin.api.util
22

3+
import org.utbot.framework.plugin.api.ClassId
34
import org.utbot.framework.plugin.api.ExecutableId
45
import java.lang.reflect.Constructor
56
import java.lang.reflect.Executable
@@ -39,6 +40,23 @@ fun Constructor<*>.bytecodeSignature() = buildString {
3940

4041
fun Class<*>.bytecodeSignature(): String = id.jvmName
4142

43+
/**
44+
* Method [Class.getName] works differently for arrays than for other types.
45+
* - When an element of an array is a reference type (e.g. `java.lang.Object`),
46+
* the array of `java.lang.Object` will have name `[Ljava.lang.Object;`.
47+
* - When an element of an array is a primitive type (e.g. `int`),
48+
* the array of `int` will have name `[I`.
49+
*
50+
* So, this property returns the name of the given class in the format of an array element type name.
51+
* Basically, it performs conversions for primitives and reference types (e.g. `int` -> `I`, `java.lang.Object` -> `Ljava.lang.Object;`.
52+
*/
53+
val ClassId.arrayLikeName: String
54+
get() = when {
55+
isPrimitive -> primitiveTypeJvmNameOrNull()!!
56+
isRefType -> "L$name;"
57+
else -> name
58+
}
59+
4260
fun String.toReferenceTypeBytecodeSignature(): String {
4361
val packageName = this
4462
.takeIf { "." in this }

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/context/CgContext.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ internal interface CgContextOwner {
9999
val collectedExceptions: MutableSet<ClassId>
100100

101101
// annotations required by the current method being built
102-
val collectedTestMethodAnnotations: MutableSet<CgAnnotation>
102+
val collectedMethodAnnotations: MutableSet<CgAnnotation>
103103

104104
// imports required by the test class being built
105105
val collectedImports: MutableSet<Import>
@@ -259,7 +259,7 @@ internal interface CgContextOwner {
259259
}
260260

261261
fun addAnnotation(annotation: CgAnnotation) {
262-
if (collectedTestMethodAnnotations.add(annotation)) {
262+
if (collectedMethodAnnotations.add(annotation)) {
263263
importIfNeeded(annotation.classId) // TODO: check how JUnit annotations are loaded
264264
}
265265
}
@@ -391,7 +391,7 @@ internal data class CgContext(
391391
override val collectedTestClassInterfaces: MutableSet<ClassId> = mutableSetOf(),
392392
override val collectedTestClassAnnotations: MutableSet<CgAnnotation> = mutableSetOf(),
393393
override val collectedExceptions: MutableSet<ClassId> = mutableSetOf(),
394-
override val collectedTestMethodAnnotations: MutableSet<CgAnnotation> = mutableSetOf(),
394+
override val collectedMethodAnnotations: MutableSet<CgAnnotation> = mutableSetOf(),
395395
override val collectedImports: MutableSet<Import> = mutableSetOf(),
396396
override val importedStaticMethods: MutableSet<MethodId> = mutableSetOf(),
397397
override val importedClasses: MutableSet<ClassId> = mutableSetOf(),

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

Lines changed: 252 additions & 254 deletions
Large diffs are not rendered by default.

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ import org.utbot.framework.codegen.model.constructor.context.CgContext
66
import org.utbot.framework.codegen.model.constructor.context.CgContextOwner
77
import org.utbot.framework.codegen.model.constructor.util.CgComponents
88
import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor
9+
import org.utbot.framework.codegen.model.constructor.util.MAX_ARRAY_INITIALIZER_SIZE
10+
import org.utbot.framework.codegen.model.constructor.util.arrayInitializer
911
import org.utbot.framework.codegen.model.constructor.util.get
1012
import org.utbot.framework.codegen.model.constructor.util.isDefaultValueOf
1113
import org.utbot.framework.codegen.model.constructor.util.isNotDefaultValueOf
1214
import org.utbot.framework.codegen.model.constructor.util.typeCast
1315
import org.utbot.framework.codegen.model.tree.CgAllocateArray
14-
import org.utbot.framework.codegen.model.tree.CgAllocateInitializedArray
1516
import org.utbot.framework.codegen.model.tree.CgDeclaration
1617
import org.utbot.framework.codegen.model.tree.CgEnumConstantAccess
1718
import org.utbot.framework.codegen.model.tree.CgExpression
1819
import org.utbot.framework.codegen.model.tree.CgFieldAccess
1920
import org.utbot.framework.codegen.model.tree.CgGetJavaClass
2021
import org.utbot.framework.codegen.model.tree.CgLiteral
21-
import org.utbot.framework.codegen.model.tree.CgNotNullAssertion
2222
import org.utbot.framework.codegen.model.tree.CgStaticFieldAccess
2323
import org.utbot.framework.codegen.model.tree.CgValue
2424
import org.utbot.framework.codegen.model.tree.CgVariable
@@ -222,10 +222,21 @@ internal class CgVariableConstructor(val context: CgContext) :
222222
arrayModel.stores.getOrDefault(it, arrayModel.constModel)
223223
}
224224

225-
val canInitWithValues = elementModels.all { it is UtPrimitiveModel } || elementModels.all { it is UtNullModel }
225+
val allPrimitives = elementModels.all { it is UtPrimitiveModel }
226+
val allNulls = elementModels.all { it is UtNullModel }
227+
// we can use array initializer if all elements are primitives or all of them are null,
228+
// and the size of an array is not greater than the fixed maximum size
229+
val canInitWithValues = (allPrimitives || allNulls) && elementModels.size <= MAX_ARRAY_INITIALIZER_SIZE
226230

227231
val initializer = if (canInitWithValues) {
228-
CgAllocateInitializedArray(arrayModel)
232+
val elements = elementModels.map { model ->
233+
when (model) {
234+
is UtPrimitiveModel -> model.value.resolve()
235+
is UtNullModel -> null.resolve()
236+
else -> error("Non primitive or null model $model is unexpected in array initializer")
237+
}
238+
}
239+
arrayInitializer(arrayModel.classId, elementType, elements)
229240
} else {
230241
CgAllocateArray(arrayModel.classId, elementType, arrayModel.length)
231242
}

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,12 @@ internal abstract class TestFrameworkManager(val context: CgContext)
162162
name = timeoutArgumentName,
163163
value = timeoutMs.resolve()
164164
)
165-
val testAnnotation = collectedTestMethodAnnotations.singleOrNull { it.classId == testFramework.testAnnotationId }
165+
val testAnnotation = collectedMethodAnnotations.singleOrNull { it.classId == testFramework.testAnnotationId }
166166

167167
if (testAnnotation is CgMultipleArgsAnnotation) {
168168
testAnnotation.arguments += timeout
169169
} else {
170-
collectedTestMethodAnnotations += CgMultipleArgsAnnotation(
170+
collectedMethodAnnotations += CgMultipleArgsAnnotation(
171171
testFramework.testAnnotationId,
172172
mutableListOf(timeout)
173173
)
@@ -180,7 +180,7 @@ internal abstract class TestFrameworkManager(val context: CgContext)
180180
// because other test frameworks do not support such feature.
181181
open fun addDisplayName(name: String) {
182182
val displayName = CgSingleArgAnnotation(Junit5.displayNameClassId, stringLiteral(name))
183-
collectedTestMethodAnnotations += CgCommentedAnnotation(displayName)
183+
collectedMethodAnnotations += CgCommentedAnnotation(displayName)
184184
}
185185

186186
protected fun ClassId.toExceptionClass(): CgExpression =
@@ -241,7 +241,7 @@ internal class TestNgManager(context: CgContext) : TestFrameworkManager(context)
241241
value = reason.resolve()
242242
)
243243

244-
val testAnnotation = collectedTestMethodAnnotations.singleOrNull { it.classId == testFramework.testAnnotationId }
244+
val testAnnotation = collectedMethodAnnotations.singleOrNull { it.classId == testFramework.testAnnotationId }
245245
if (testAnnotation is CgMultipleArgsAnnotation) {
246246
testAnnotation.arguments += disabledAnnotationArgument
247247

@@ -271,7 +271,7 @@ internal class TestNgManager(context: CgContext) : TestFrameworkManager(context)
271271
testAnnotation.arguments += descriptionTestAnnotationArgument
272272
}
273273
} else {
274-
collectedTestMethodAnnotations += CgMultipleArgsAnnotation(
274+
collectedMethodAnnotations += CgMultipleArgsAnnotation(
275275
testFramework.testAnnotationId,
276276
mutableListOf(disabledAnnotationArgument, descriptionTestAnnotationArgument)
277277
)
@@ -291,19 +291,19 @@ internal class Junit4Manager(context: CgContext) : TestFrameworkManager(context)
291291
name = "expected",
292292
value = classLiteralAnnotationArgument(exception, codegenLanguage)
293293
)
294-
val testAnnotation = collectedTestMethodAnnotations.singleOrNull { it.classId == testFramework.testAnnotationId }
294+
val testAnnotation = collectedMethodAnnotations.singleOrNull { it.classId == testFramework.testAnnotationId }
295295
if (testAnnotation is CgMultipleArgsAnnotation) {
296296
testAnnotation.arguments += expected
297297
} else {
298-
collectedTestMethodAnnotations += CgMultipleArgsAnnotation(testFramework.testAnnotationId, mutableListOf(expected))
298+
collectedMethodAnnotations += CgMultipleArgsAnnotation(testFramework.testAnnotationId, mutableListOf(expected))
299299
}
300300
block()
301301
}
302302

303303
override fun disableTestMethod(reason: String) {
304304
require(testFramework is Junit4) { "According to settings, JUnit4 was expected, but got: $testFramework" }
305305

306-
collectedTestMethodAnnotations += CgMultipleArgsAnnotation(
306+
collectedMethodAnnotations += CgMultipleArgsAnnotation(
307307
testFramework.ignoreAnnotationClassId,
308308
mutableListOf(
309309
CgNamedAnnotationArgument(
@@ -339,7 +339,7 @@ internal class Junit5Manager(context: CgContext) : TestFrameworkManager(context)
339339

340340
override fun addDisplayName(name: String) {
341341
require(testFramework is Junit5) { "According to settings, JUnit5 was expected, but got: $testFramework" }
342-
collectedTestMethodAnnotations += statementConstructor.annotation(testFramework.displayNameClassId, name)
342+
collectedMethodAnnotations += statementConstructor.annotation(testFramework.displayNameClassId, name)
343343
}
344344

345345
override fun setTestExecutionTimeout(timeoutMs: Long) {
@@ -358,7 +358,7 @@ internal class Junit5Manager(context: CgContext) : TestFrameworkManager(context)
358358
)
359359
importIfNeeded(testFramework.timeunitClassId)
360360

361-
collectedTestMethodAnnotations += CgMultipleArgsAnnotation(
361+
collectedMethodAnnotations += CgMultipleArgsAnnotation(
362362
Junit5.timeoutClassId,
363363
timeoutAnnotationArguments
364364
)
@@ -367,7 +367,7 @@ internal class Junit5Manager(context: CgContext) : TestFrameworkManager(context)
367367
override fun disableTestMethod(reason: String) {
368368
require(testFramework is Junit5) { "According to settings, JUnit5 was expected, but got: $testFramework" }
369369

370-
collectedTestMethodAnnotations += CgMultipleArgsAnnotation(
370+
collectedMethodAnnotations += CgMultipleArgsAnnotation(
371371
testFramework.disabledAnnotationClassId,
372372
mutableListOf(
373373
CgNamedAnnotationArgument(

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgStatementConstructor.kt

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import org.utbot.framework.codegen.model.tree.CgParameterDeclaration
3131
import org.utbot.framework.codegen.model.tree.CgReturnStatement
3232
import org.utbot.framework.codegen.model.tree.CgSingleArgAnnotation
3333
import org.utbot.framework.codegen.model.tree.CgSingleLineComment
34-
import org.utbot.framework.codegen.model.tree.CgStatement
3534
import org.utbot.framework.codegen.model.tree.CgThrowStatement
3635
import org.utbot.framework.codegen.model.tree.CgTryCatch
3736
import org.utbot.framework.codegen.model.tree.CgVariable
@@ -40,7 +39,6 @@ import org.utbot.framework.codegen.model.tree.buildCgForEachLoop
4039
import org.utbot.framework.codegen.model.tree.buildDeclaration
4140
import org.utbot.framework.codegen.model.tree.buildDoWhileLoop
4241
import org.utbot.framework.codegen.model.tree.buildForLoop
43-
import org.utbot.framework.codegen.model.tree.buildSimpleBlock
4442
import org.utbot.framework.codegen.model.tree.buildTryCatch
4543
import org.utbot.framework.codegen.model.tree.buildWhileLoop
4644
import org.utbot.framework.codegen.model.util.buildExceptionHandler
@@ -59,6 +57,7 @@ import org.utbot.framework.plugin.api.util.isSubtypeOf
5957
import org.utbot.framework.plugin.api.util.objectArrayClassId
6058
import org.utbot.framework.plugin.api.util.objectClassId
6159
import fj.data.Either
60+
import org.utbot.framework.codegen.model.tree.CgArrayInitializer
6261
import java.lang.reflect.Constructor
6362
import java.lang.reflect.Method
6463
import kotlin.reflect.KFunction
@@ -106,7 +105,7 @@ interface CgStatementConstructor {
106105
infix fun CgExpression.`=`(value: Any?)
107106
infix fun CgExpression.and(other: CgExpression): CgLogicalAnd
108107
infix fun CgExpression.or(other: CgExpression): CgLogicalOr
109-
fun ifStatement(condition: CgExpression, trueBranch: () -> Unit): CgIfStatement
108+
fun ifStatement(condition: CgExpression, trueBranch: () -> Unit, falseBranch: (() -> Unit)? = null): CgIfStatement
110109
fun forLoop(init: CgForLoopBuilder.() -> Unit)
111110
fun whileLoop(condition: CgExpression, statements: () -> Unit)
112111
fun doWhileLoop(condition: CgExpression, statements: () -> Unit)
@@ -117,7 +116,7 @@ interface CgStatementConstructor {
117116
fun CgTryCatch.catch(exception: ClassId, init: (CgVariable) -> Unit): CgTryCatch
118117
fun CgTryCatch.finally(init: () -> Unit): CgTryCatch
119118

120-
fun innerBlock(init: () -> Unit, additionalStatements: List<CgStatement>): CgInnerBlock
119+
fun innerBlock(init: () -> Unit): CgInnerBlock
121120

122121
// fun CgTryCatchBuilder.statements(init: () -> Unit)
123122
// fun CgTryCatchBuilder.handler(exception: ClassId, init: (CgVariable) -> Unit)
@@ -176,6 +175,7 @@ internal class CgStatementConstructorImpl(context: CgContext) :
176175
val (type, expr) = when (baseExpr) {
177176
is CgEnumConstantAccess -> guardEnumConstantAccess(baseExpr)
178177
is CgAllocateArray -> guardArrayAllocation(baseExpr)
178+
is CgArrayInitializer -> guardArrayInitializer(baseExpr)
179179
is CgExecutableCall -> guardExecutableCall(baseType, baseExpr)
180180
else -> guardExpression(baseType, baseExpr)
181181
}
@@ -250,8 +250,10 @@ internal class CgStatementConstructorImpl(context: CgContext) :
250250
override fun CgExpression.or(other: CgExpression): CgLogicalOr =
251251
CgLogicalOr(this, other)
252252

253-
override fun ifStatement(condition: CgExpression, trueBranch: () -> Unit): CgIfStatement {
254-
return CgIfStatement(condition, block(trueBranch)).also {
253+
override fun ifStatement(condition: CgExpression, trueBranch: () -> Unit, falseBranch: (() -> Unit)?): CgIfStatement {
254+
val trueBranchBlock = block(trueBranch)
255+
val falseBranchBlock = falseBranch?.let { block(it) }
256+
return CgIfStatement(condition, trueBranchBlock, falseBranchBlock).also {
255257
currentBlock += it
256258
}
257259
}
@@ -300,12 +302,10 @@ internal class CgStatementConstructorImpl(context: CgContext) :
300302
return this.copy(finally = finallyBlock)
301303
}
302304

303-
override fun innerBlock(
304-
init: () -> Unit,
305-
additionalStatements: List<CgStatement>,
306-
): CgInnerBlock = buildSimpleBlock {
307-
statements = mutableListOf<CgStatement>() + block(init) + additionalStatements
308-
}
305+
override fun innerBlock(init: () -> Unit): CgInnerBlock =
306+
CgInnerBlock(block(init)).also {
307+
currentBlock += it
308+
}
309309

310310
override fun comment(text: String): CgComment =
311311
CgSingleLineComment(text).also {
@@ -421,13 +421,21 @@ internal class CgStatementConstructorImpl(context: CgContext) :
421421
}
422422

423423
private fun guardArrayAllocation(allocation: CgAllocateArray): ExpressionWithType {
424+
return guardArrayCreation(allocation.type, allocation.size, allocation)
425+
}
426+
427+
private fun guardArrayInitializer(initializer: CgArrayInitializer): ExpressionWithType {
428+
return guardArrayCreation(initializer.type, initializer.size, initializer)
429+
}
430+
431+
private fun guardArrayCreation(arrayType: ClassId, arraySize: Int, initialization: CgExpression): ExpressionWithType {
424432
// TODO: check if this is the right way to check array type accessibility
425-
return if (allocation.type.isAccessibleFrom(testClassPackageName)) {
426-
ExpressionWithType(allocation.type, allocation)
433+
return if (arrayType.isAccessibleFrom(testClassPackageName)) {
434+
ExpressionWithType(arrayType, initialization)
427435
} else {
428436
ExpressionWithType(
429437
objectArrayClassId,
430-
testClassThisInstance[createArray](allocation.elementType.name, allocation.size)
438+
testClassThisInstance[createArray](arrayType.elementClassId!!.name, arraySize)
431439
)
432440
}
433441
}

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/ConstructorUtils.kt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ import org.utbot.framework.plugin.api.util.shortClassId
4242
import org.utbot.framework.plugin.api.util.underlyingType
4343
import kotlinx.collections.immutable.PersistentList
4444
import kotlinx.collections.immutable.PersistentSet
45+
import org.utbot.framework.codegen.model.tree.CgAllocateInitializedArray
46+
import org.utbot.framework.codegen.model.tree.CgArrayInitializer
47+
import org.utbot.framework.plugin.api.util.arrayLikeName
4548

4649
internal data class EnvironmentFieldStateCache(
4750
val thisInstance: FieldStateCache,
@@ -153,6 +156,8 @@ private fun FieldPath.toStringList(): List<String> =
153156
internal fun infiniteInts(): Sequence<Int> =
154157
generateSequence(1) { it + 1 }
155158

159+
internal const val MAX_ARRAY_INITIALIZER_SIZE = 10
160+
156161
/**
157162
* Checks if we have already imported a class with such simple name.
158163
* If so, we cannot import [type] (because it will be used with simple name and will be clashed with already imported)
@@ -216,6 +221,39 @@ internal fun CgContextOwner.typeCast(
216221
return CgTypeCast(targetType, expression, isSafetyCast)
217222
}
218223

224+
@Suppress("unused")
225+
internal fun newArrayOf(elementType: ClassId, values: List<CgExpression>): CgAllocateInitializedArray {
226+
val arrayType = arrayTypeOf(elementType)
227+
return CgAllocateInitializedArray(arrayInitializer(arrayType, elementType, values))
228+
}
229+
230+
internal fun arrayInitializer(arrayType: ClassId, elementType: ClassId, values: List<CgExpression>): CgArrayInitializer =
231+
CgArrayInitializer(arrayType, elementType, values)
232+
233+
/**
234+
* For a given [elementType] returns a [ClassId] of an array with elements of this type.
235+
* For example, for an id of `int` the result will be an id of `int[]`.
236+
*
237+
* @param elementType the element type of the returned array class id
238+
* @param isNullable a flag whether returned array is nullable or not
239+
*/
240+
internal fun arrayTypeOf(elementType: ClassId, isNullable: Boolean = false): ClassId {
241+
val arrayIdName = "[${elementType.arrayLikeName}"
242+
return when (elementType) {
243+
is BuiltinClassId -> BuiltinClassId(
244+
name = arrayIdName,
245+
canonicalName = "${elementType.canonicalName}[]",
246+
simpleName = "${elementType.simpleName}[]",
247+
isNullable = isNullable
248+
)
249+
else -> ClassId(
250+
name = arrayIdName,
251+
elementClassId = elementType,
252+
isNullable = isNullable
253+
)
254+
}
255+
}
256+
219257
@Suppress("unused")
220258
internal fun CgContextOwner.getJavaClass(classId: ClassId): CgGetClass {
221259
importIfNeeded(classId)

0 commit comments

Comments
 (0)