Skip to content

Commit e625e45

Browse files
authored
Refactor Class rendering in codegen (merge abstractions for regular and test classes) #1255 #1256 (#1275)
* Refactor Class rendering in codegen (merge abstractions for regular and test classes)
1 parent 95d503a commit e625e45

File tree

14 files changed

+178
-253
lines changed

14 files changed

+178
-253
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import org.utbot.framework.plugin.api.util.isPrimitive
2727
import org.utbot.framework.plugin.api.util.isStatic
2828
import org.utbot.framework.plugin.api.util.jClass
2929
import org.utbot.framework.plugin.api.util.jField
30+
import org.utbot.framework.plugin.api.util.kClass
3031
import org.utbot.framework.plugin.api.util.longClassId
3132
import org.utbot.framework.plugin.api.util.method
3233
import org.utbot.framework.plugin.api.util.primitiveTypeJvmNameOrNull
@@ -793,6 +794,9 @@ open class ClassId @JvmOverloads constructor(
793794
open val isSynthetic: Boolean
794795
get() = jClass.isSynthetic
795796

797+
open val isKotlinObject: Boolean
798+
get() = kClass.objectInstance != null
799+
796800
/**
797801
* Collects all declared methods (including private and protected) from class and all its superclasses to sequence
798802
*/
@@ -887,6 +891,7 @@ class BuiltinClassId(
887891
override val isInner: Boolean = false,
888892
override val isNested: Boolean = false,
889893
override val isSynthetic: Boolean = false,
894+
override val isKotlinObject: Boolean = false,
890895
override val typeParameters: TypeParameters = TypeParameters(),
891896
override val allMethods: Sequence<MethodId> = emptySequence(),
892897
override val allConstructors: Sequence<ConstructorId> = emptySequence(),

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/CodeGenerator.kt

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,16 @@ import org.utbot.framework.codegen.model.constructor.context.CgContextOwner
1414
import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor
1515
import org.utbot.framework.codegen.model.constructor.tree.CgUtilClassConstructor
1616
import org.utbot.framework.codegen.model.constructor.tree.TestsGenerationReport
17-
import org.utbot.framework.codegen.model.tree.AbstractCgClassFile
18-
import org.utbot.framework.codegen.model.tree.CgRegularClassFile
17+
import org.utbot.framework.codegen.model.tree.CgClassFile
1918
import org.utbot.framework.codegen.model.visitor.CgAbstractRenderer
2019
import org.utbot.framework.plugin.api.ClassId
2120
import org.utbot.framework.plugin.api.CodegenLanguage
2221
import org.utbot.framework.plugin.api.ExecutableId
2322
import org.utbot.framework.plugin.api.MockFramework
2423
import org.utbot.framework.plugin.api.UtMethodTestSet
2524
import org.utbot.framework.codegen.model.constructor.TestClassModel
26-
import org.utbot.framework.codegen.model.tree.CgComment
27-
import org.utbot.framework.codegen.model.tree.CgSingleLineComment
25+
import org.utbot.framework.codegen.model.tree.CgDocRegularStmt
26+
import org.utbot.framework.codegen.model.tree.CgDocumentationComment
2827

2928
class CodeGenerator(
3029
private val classUnderTest: ClassId,
@@ -106,7 +105,7 @@ class CodeGenerator(
106105
}
107106
}
108107

109-
private fun renderClassFile(file: AbstractCgClassFile<*>): String {
108+
private fun renderClassFile(file: CgClassFile): String {
110109
val renderer = CgAbstractRenderer.makeRenderer(context)
111110
file.accept(renderer)
112111
return renderer.toString()
@@ -145,30 +144,24 @@ sealed class UtilClassKind(
145144
private val priority: Int
146145
) : Comparable<UtilClassKind> {
147146

147+
/**
148+
* Contains comments specifying the version and the kind of util class being generated and
149+
*/
150+
val utilClassDocumentation: CgDocumentationComment
151+
get() = CgDocumentationComment(
152+
listOf(
153+
CgDocRegularStmt(utilClassKindCommentText),
154+
CgDocRegularStmt("$UTIL_CLASS_VERSION_COMMENT_PREFIX${utilClassVersion}"),
155+
)
156+
)
157+
148158
/**
149159
* The version of util class being generated.
150160
* For more details see [UtilClassFileMethodProvider.UTIL_CLASS_VERSION].
151161
*/
152162
val utilClassVersion: String
153163
get() = UtilClassFileMethodProvider.UTIL_CLASS_VERSION
154164

155-
/**
156-
* The comment specifying the version of util class being generated.
157-
*
158-
* @see UtilClassFileMethodProvider.UTIL_CLASS_VERSION
159-
*/
160-
val utilClassVersionComment: CgComment
161-
get() = CgSingleLineComment("$UTIL_CLASS_VERSION_COMMENT_PREFIX${utilClassVersion}")
162-
163-
164-
/**
165-
* The comment specifying the kind of util class being generated.
166-
*
167-
* @see utilClassKindCommentText
168-
*/
169-
val utilClassKindComment: CgComment
170-
get() = CgSingleLineComment(utilClassKindCommentText)
171-
172165
/**
173166
* The text of comment specifying the kind of util class.
174167
* At the moment, there are two kinds: [RegularUtUtils] (without Mockito) and [UtUtilsWithMockito].
@@ -200,7 +193,7 @@ sealed class UtilClassKind(
200193
}
201194

202195
/**
203-
* Construct an util class file as a [CgRegularClassFile] and render it.
196+
* Construct an util class file as a [CgClassFile] and render it.
204197
* @return the text of the generated util class file.
205198
*/
206199
fun getUtilClassText(codegenLanguage: CodegenLanguage): String {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import org.utbot.framework.codegen.model.constructor.context.CgContextOwner
44
import org.utbot.framework.codegen.model.tree.CgAnnotation
55
import org.utbot.framework.codegen.model.tree.CgMethod
66
import org.utbot.framework.plugin.api.ClassId
7-
import org.utbot.framework.codegen.model.tree.CgTestClass
7+
import org.utbot.framework.codegen.model.tree.CgClass
88

99
/**
10-
* This class stores context information needed to build [CgTestClass].
10+
* This class stores context information needed to build [CgClass].
1111
* Should only be used in [CgContextOwner].
1212
*/
1313
internal data class TestClassContext(

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/builtin/UtilMethodBuiltins.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ internal val utUtilsClassId: ClassId
280280
canonicalName = "org.utbot.runtime.utils.UtUtils",
281281
simpleName = "UtUtils",
282282
isFinal = true,
283+
isKotlinObject = true
283284
)
284285

285286
/**

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,8 @@ internal data class CgContext(
495495
val name = "$packagePrefix$simpleName"
496496
BuiltinClassId(
497497
canonicalName = name,
498-
simpleName = simpleName
498+
simpleName = simpleName,
499+
isFinal = true,
499500
)
500501
}
501502

@@ -551,7 +552,8 @@ internal data class CgContext(
551552
val simpleName = "${testClassModel.classUnderTest.simpleName}Test"
552553
return BuiltinClassId(
553554
canonicalName = currentTestClass.canonicalName + "." + simpleName,
554-
simpleName = simpleName
555+
simpleName = simpleName,
556+
isFinal = true,
555557
)
556558
}
557559

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

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,21 @@ import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor
1919
import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor
2020
import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructorImpl
2121
import org.utbot.framework.codegen.model.tree.CgAuxiliaryClass
22-
import org.utbot.framework.codegen.model.tree.CgExecutableUnderTestCluster
22+
import org.utbot.framework.codegen.model.tree.CgMethodsCluster
2323
import org.utbot.framework.codegen.model.tree.CgMethod
2424
import org.utbot.framework.codegen.model.tree.CgRegion
2525
import org.utbot.framework.codegen.model.tree.CgSimpleRegion
2626
import org.utbot.framework.codegen.model.tree.CgStaticsRegion
27-
import org.utbot.framework.codegen.model.tree.CgTestClass
27+
import org.utbot.framework.codegen.model.tree.CgClass
28+
import org.utbot.framework.codegen.model.tree.CgRealNestedClassesRegion
2829
import org.utbot.framework.codegen.model.tree.CgTestClassFile
2930
import org.utbot.framework.codegen.model.tree.CgTestMethod
3031
import org.utbot.framework.codegen.model.tree.CgTestMethodCluster
3132
import org.utbot.framework.codegen.model.tree.CgTripleSlashMultilineComment
3233
import org.utbot.framework.codegen.model.tree.CgUtilEntity
3334
import org.utbot.framework.codegen.model.tree.CgUtilMethod
34-
import org.utbot.framework.codegen.model.tree.buildTestClass
35-
import org.utbot.framework.codegen.model.tree.buildTestClassBody
35+
import org.utbot.framework.codegen.model.tree.buildClass
36+
import org.utbot.framework.codegen.model.tree.buildClassBody
3637
import org.utbot.framework.codegen.model.tree.buildTestClassFile
3738
import org.utbot.framework.codegen.model.visitor.importUtilMethodDependencies
3839
import org.utbot.framework.plugin.api.ClassId
@@ -69,8 +70,8 @@ internal class CgTestClassConstructor(val context: CgContext) :
6970
}
7071
}
7172

72-
private fun constructTestClass(testClassModel: TestClassModel): CgTestClass {
73-
return buildTestClass {
73+
private fun constructTestClass(testClassModel: TestClassModel): CgClass {
74+
return buildClass {
7475
id = currentTestClass
7576

7677
if (currentTestClass != outerMostTestClass) {
@@ -86,9 +87,9 @@ internal class CgTestClassConstructor(val context: CgContext) :
8687
}
8788
}
8889

89-
body = buildTestClassBody {
90+
body = buildClassBody(currentTestClass) {
9091
for (nestedClass in testClassModel.nestedClasses) {
91-
nestedClassRegions += CgSimpleRegion(
92+
nestedClassRegions += CgRealNestedClassesRegion(
9293
"Tests for ${nestedClass.classUnderTest.simpleName}",
9394
listOf(
9495
withNestedClassScope(nestedClass) { constructTestClass(nestedClass) }
@@ -99,11 +100,11 @@ internal class CgTestClassConstructor(val context: CgContext) :
99100
for (testSet in testClassModel.methodTestSets) {
100101
updateCurrentExecutable(testSet.executableId)
101102
val currentMethodUnderTestRegions = constructTestSet(testSet) ?: continue
102-
val executableUnderTestCluster = CgExecutableUnderTestCluster(
103+
val executableUnderTestCluster = CgMethodsCluster(
103104
"Test suites for executable $currentExecutable",
104105
currentMethodUnderTestRegions
105106
)
106-
testMethodRegions += executableUnderTestCluster
107+
methodRegions += executableUnderTestCluster
107108
}
108109

109110
val currentTestClassDataProviderMethods = currentTestClassContext.cgDataProviderMethods

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

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,34 @@ import org.utbot.framework.codegen.model.CodeGenerator
44
import org.utbot.framework.codegen.model.UtilClassKind
55
import org.utbot.framework.codegen.model.constructor.builtin.utUtilsClassId
66
import org.utbot.framework.codegen.model.tree.CgAuxiliaryClass
7-
import org.utbot.framework.codegen.model.tree.CgRegularClassFile
7+
import org.utbot.framework.codegen.model.tree.CgAuxiliaryNestedClassesRegion
8+
import org.utbot.framework.codegen.model.tree.CgClassFile
9+
import org.utbot.framework.codegen.model.tree.CgStaticsRegion
810
import org.utbot.framework.codegen.model.tree.CgUtilMethod
9-
import org.utbot.framework.codegen.model.tree.buildRegularClass
10-
import org.utbot.framework.codegen.model.tree.buildRegularClassBody
11-
import org.utbot.framework.codegen.model.tree.buildRegularClassFile
11+
import org.utbot.framework.codegen.model.tree.buildClass
12+
import org.utbot.framework.codegen.model.tree.buildClassBody
13+
import org.utbot.framework.codegen.model.tree.buildClassFile
1214

1315
/**
1416
* This class is used to construct a file containing an util class UtUtils.
1517
* The util class is constructed when the argument `generateUtilClassFile` in the [CodeGenerator] is true.
1618
*/
1719
internal object CgUtilClassConstructor {
18-
fun constructUtilsClassFile(utilClassKind: UtilClassKind): CgRegularClassFile {
20+
fun constructUtilsClassFile(utilClassKind: UtilClassKind): CgClassFile {
1921
val utilMethodProvider = utilClassKind.utilMethodProvider
20-
return buildRegularClassFile {
22+
return buildClassFile {
2123
// imports are empty, because we use fully qualified classes and static methods,
2224
// so they will be imported once IDEA reformatting action has worked
23-
declaredClass = buildRegularClass {
25+
declaredClass = buildClass {
2426
id = utUtilsClassId
25-
body = buildRegularClassBody {
26-
content += utilClassKind.utilClassVersionComment
27-
content += utilClassKind.utilClassKindComment
28-
content += utilMethodProvider.utilMethodIds.map { CgUtilMethod(it) }
29-
content += CgAuxiliaryClass(utilMethodProvider.capturedArgumentClassId)
27+
body = buildClassBody(utUtilsClassId) {
28+
documentation = utilClassKind.utilClassDocumentation
29+
staticDeclarationRegions += CgStaticsRegion("Util methods", utilMethodProvider.utilMethodIds.map { CgUtilMethod(it) })
30+
nestedClassRegions += CgAuxiliaryNestedClassesRegion(
31+
nestedClasses = listOf(
32+
CgAuxiliaryClass(utilMethodProvider.capturedArgumentClassId)
33+
)
34+
)
3035
}
3136
}
3237
}

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

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,71 +12,49 @@ interface CgBuilder<T : CgElement> {
1212

1313
// Code entities
1414

15-
class CgRegularClassFileBuilder : CgBuilder<CgRegularClassFile> {
15+
class CgClassFileBuilder : CgBuilder<CgClassFile> {
1616
val imports: MutableList<Import> = mutableListOf()
17-
lateinit var declaredClass: CgRegularClass
17+
lateinit var declaredClass: CgClass
1818

19-
override fun build() = CgRegularClassFile(imports, declaredClass)
19+
override fun build() = CgClassFile(imports, declaredClass)
2020
}
2121

22-
fun buildRegularClassFile(init: CgRegularClassFileBuilder.() -> Unit) = CgRegularClassFileBuilder().apply(init).build()
22+
fun buildClassFile(init: CgClassFileBuilder.() -> Unit) = CgClassFileBuilder().apply(init).build()
2323

2424
class CgTestClassFileBuilder : CgBuilder<CgTestClassFile> {
2525
val imports: MutableList<Import> = mutableListOf()
26-
lateinit var declaredClass: CgTestClass
26+
lateinit var declaredClass: CgClass
2727
lateinit var testsGenerationReport: TestsGenerationReport
2828

2929
override fun build() = CgTestClassFile(imports, declaredClass, testsGenerationReport)
3030
}
3131

3232
fun buildTestClassFile(init: CgTestClassFileBuilder.() -> Unit) = CgTestClassFileBuilder().apply(init).build()
3333

34-
class CgRegularClassBuilder : CgBuilder<CgRegularClass> {
34+
class CgClassBuilder : CgBuilder<CgClass> {
3535
lateinit var id: ClassId
3636
val annotations: MutableList<CgAnnotation> = mutableListOf()
3737
var superclass: ClassId? = null
3838
val interfaces: MutableList<ClassId> = mutableListOf()
39-
lateinit var body: CgRegularClassBody
4039
var isStatic: Boolean = false
4140
var isNested: Boolean = false
41+
lateinit var body: CgClassBody
4242

43-
override fun build() = CgRegularClass(id, annotations, superclass, interfaces, body, isStatic, isNested)
43+
override fun build() = CgClass(id, annotations, superclass, interfaces, body, isStatic, isNested)
4444
}
4545

46-
fun buildRegularClass(init: CgRegularClassBuilder.() -> Unit) = CgRegularClassBuilder().apply(init).build()
46+
fun buildClass(init: CgClassBuilder.() -> Unit) = CgClassBuilder().apply(init).build()
4747

48-
class CgTestClassBuilder : CgBuilder<CgTestClass> {
49-
lateinit var id: ClassId
50-
val annotations: MutableList<CgAnnotation> = mutableListOf()
51-
var superclass: ClassId? = null
52-
val interfaces: MutableList<ClassId> = mutableListOf()
53-
var isStatic: Boolean = false
54-
var isNested: Boolean = false
55-
lateinit var body: CgTestClassBody
56-
57-
override fun build() = CgTestClass(id, annotations, superclass, interfaces, body, isStatic, isNested)
58-
}
59-
60-
fun buildTestClass(init: CgTestClassBuilder.() -> Unit) = CgTestClassBuilder().apply(init).build()
61-
62-
class CgTestClassBodyBuilder : CgBuilder<CgTestClassBody> {
63-
val testMethodRegions: MutableList<CgExecutableUnderTestCluster> = mutableListOf()
48+
class CgClassBodyBuilder(val classId: ClassId) : CgBuilder<CgClassBody> {
49+
var documentation: CgDocumentationComment? = null
50+
val methodRegions: MutableList<CgMethodsCluster> = mutableListOf()
6451
val staticDeclarationRegions: MutableList<CgStaticsRegion> = mutableListOf()
65-
val nestedClassRegions: MutableList<CgRegion<CgTestClass>> = mutableListOf()
52+
val nestedClassRegions: MutableList<CgNestedClassesRegion<*>> = mutableListOf()
6653

67-
override fun build() = CgTestClassBody(testMethodRegions, staticDeclarationRegions, nestedClassRegions)
54+
override fun build() = CgClassBody(classId, documentation, methodRegions, staticDeclarationRegions, nestedClassRegions)
6855
}
6956

70-
fun buildTestClassBody(init: CgTestClassBodyBuilder.() -> Unit) = CgTestClassBodyBuilder().apply(init).build()
71-
72-
class CgRegularClassBodyBuilder : CgBuilder<CgRegularClassBody> {
73-
val content: MutableList<CgElement> = mutableListOf()
74-
75-
override fun build() = CgRegularClassBody(content)
76-
}
77-
78-
fun buildRegularClassBody(init: CgRegularClassBodyBuilder.() -> Unit) = CgRegularClassBodyBuilder().apply(init).build()
79-
57+
fun buildClassBody(classId: ClassId, init: CgClassBodyBuilder.() -> Unit) = CgClassBodyBuilder(classId).apply(init).build()
8058
// Methods
8159

8260
interface CgMethodBuilder<T : CgMethod> : CgBuilder<T> {

0 commit comments

Comments
 (0)