IJPL-15941 Workspace Model: codegen 7.11

GitOrigin-RevId: 69c54c2a6aa712f848bd0e7ace674cc47ba91e92
This commit is contained in:
Kirill Bochkarev
2025-12-18 22:29:26 +00:00
committed by intellij-monorepo-bot
parent 5a7135df8d
commit 69e6d960c6
7 changed files with 91 additions and 43 deletions
@@ -1,3 +1,3 @@
codegenImplMinorVersion = 10
codegenImplMinorVersion = 11
codegenImplMajorVersion = 7
codegenApiVersion = 3
@@ -21,23 +21,25 @@ class CodeGeneratorImpl : CodeGenerator {
return failedGenerationResult(reporter)
}
val objClassToTopLevelCode = module.types.associateWith {
val topLevelCode = it.generateTopLevelCode(reporter)
topLevelCode
}
if (reporter.hasErrors()) {
return failedGenerationResult(reporter)
}
val generatedCode = objClassToTopLevelCode.map { (objClass, topLevelCode) ->
ObjClassGeneratedCode(
target = objClass,
builderInterface = objClass.generateCompatabilityBuilder(),
companionObject = objClass.generateCompatibilityCompanion(),
topLevelCode = topLevelCode,
implementationClass = objClass.implWsCode()
val generatedCode: MutableList<GeneratedCode> = arrayListOf()
for (type in module.types) {
checkSuperTypes(type, reporter)
checkSymbolicId(type, reporter)
if (reporter.hasErrors()) return failedGenerationResult(reporter)
val topLevelCode = type.generateTopLevelCode(reporter)
if (reporter.hasErrors()) return failedGenerationResult(reporter)
val compatibilityBuilder = type.generateCompatabilityBuilder()
val compatibilityCompanion = type.generateCompatibilityCompanion()
val implementationClass = type.implWsCode(reporter)
if (reporter.hasErrors()) return failedGenerationResult(reporter)
generatedCode.add(
ObjClassGeneratedCode(
target = type,
builderInterface = compatibilityBuilder,
companionObject = compatibilityCompanion,
topLevelCode = topLevelCode,
implementationClass = implementationClass
)
)
}
@@ -62,17 +64,15 @@ class CodeGeneratorImpl : CodeGenerator {
val generatedCode = arrayListOf<GeneratedCode>()
addMetadataStorageCode(
generatedCode, metadataStorageImplModule,
implWsMetadataStorageCode(metadataStorageImplModule, notEmptyModules.flatMap { it.types }, notEmptyModules.flatMap { it.abstractTypes })
)
addMetadataStorageCode(generatedCode,
metadataStorageImplModule,
implWsMetadataStorageCode(metadataStorageImplModule,
notEmptyModules.flatMap { it.types },
notEmptyModules.flatMap { it.abstractTypes }))
val metadataStorageImplFqn = fqn(metadataStorageImplModule.implPackage, MetadataStorage.IMPL_NAME)
metadataStorageBridgeModules.forEach {
addMetadataStorageCode(
generatedCode, it,
it.implWsMetadataStorageBridgeCode(metadataStorageImplFqn)
)
addMetadataStorageCode(generatedCode, it, it.implWsMetadataStorageBridgeCode(metadataStorageImplFqn))
}
return GenerationResult(generatedCode, emptyList())
@@ -22,7 +22,7 @@ class LinesBuilder(val result: StringBuilder) {
}
}
fun section(head: String, s: LinesBuilder.() -> Unit) {
inline fun section(head: String, s: LinesBuilder.() -> Unit) {
lineNoNl(head)
val sub = LinesBuilder(result)
sub.result.append("{\n")
@@ -10,8 +10,6 @@ import com.intellij.workspaceModel.codegen.impl.writer.extensions.*
import com.intellij.workspaceModel.codegen.impl.writer.fields.*
fun ObjClass<*>.generateMutableCode(reporter: ProblemReporter): String = lines {
checkSuperTypes(this@generateMutableCode, reporter)
checkSymbolicId(this@generateMutableCode, reporter)
if (additionalAnnotations.isNotEmpty()) {
line(additionalAnnotations)
}
@@ -23,9 +21,10 @@ fun ObjClass<*>.generateMutableCode(reporter: ProblemReporter): String = lines {
val header = "${generatedCodeVisibilityModifier}interface $defaultJavaBuilderName$typeDeclaration: ${WorkspaceEntity.Builder}<$typeParameter>$superBuilders"
section(header) {
list(allFields.noSymbolicId()) {
checkProperty(this, reporter)
getWsBuilderApi(this@generateMutableCode)
for (field in allFields.noSymbolicId()) {
checkProperty(field, reporter)
if (reporter.hasErrors()) return@generateMutableCode ""
line(field.getWsBuilderApi(this@generateMutableCode))
}
}
}
@@ -43,7 +42,7 @@ fun checkSuperTypes(objClass: ObjClass<*>, reporter: ProblemReporter) {
}
}
private fun checkSymbolicId(objClass: ObjClass<*>, reporter: ProblemReporter) {
fun checkSymbolicId(objClass: ObjClass<*>, reporter: ProblemReporter) {
if (!objClass.isEntityWithSymbolicId) return
if (objClass.openness == ObjClass.Openness.abstract) return
if (objClass.fields.none { it.name == "symbolicId" }) {
@@ -2,15 +2,18 @@
package com.intellij.workspaceModel.codegen.impl.writer.classes
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
import com.intellij.workspaceModel.codegen.impl.writer.*
import com.intellij.workspaceModel.codegen.impl.writer.fields.implWsEntityFieldCode
import com.intellij.workspaceModel.codegen.impl.writer.fields.refsConnectionId
import com.intellij.workspaceModel.codegen.impl.writer.fields.refsConnectionIdCode
import com.intellij.workspaceModel.codegen.engine.GenerationProblem
import com.intellij.workspaceModel.codegen.engine.ProblemLocation
import com.intellij.workspaceModel.codegen.impl.CodeGeneratorVersionCalculator
import com.intellij.workspaceModel.codegen.impl.engine.ProblemReporter
import com.intellij.workspaceModel.codegen.impl.writer.*
import com.intellij.workspaceModel.codegen.impl.writer.extensions.*
import com.intellij.workspaceModel.codegen.impl.writer.fields.javaType
import com.intellij.workspaceModel.codegen.impl.writer.fields.*
fun ObjClass<*>.implWsEntityCode(reporter: ProblemReporter): String {
checkReferences(this@implWsEntityCode, reporter)
if (reporter.hasErrors()) return ""
fun ObjClass<*>.implWsEntityCode(): String {
val inheritanceModifier = when {
openness.extendable && !openness.instantiatable -> "abstract "
openness.extendable && openness.instantiatable -> "open "
@@ -60,6 +63,51 @@ private val ObjClass<*>.implWsEntityAnnotations: String
private fun getLinksOfConnectionIds(type: ObjClass<*>): String {
return lines {
line(type.allRefsFields.joinToString(separator = ",", prefix = "private val connections = listOf<$ConnectionId>(", postfix = ")") { it.refsConnectionId })
line(type.allRefsFields.joinToString(separator = ",",
prefix = "private val connections = listOf<$ConnectionId>(",
postfix = ")") { it.refsConnectionId })
}
}
private fun checkReferences(objClass: ObjClass<*>, reporter: ProblemReporter) {
for (refField in objClass.allRefsFields) {
val ref = refField.valueType.getRefType()
val declaredReferenceFromChild =
ref.target.refsFields.filter { it.valueType.getRefType().target == objClass && it != refField } + setOf(ref.target.module,
objClass.module).flatMap { it.extensions }
.filter { it.valueType.getRefType().target == objClass && it.receiver == ref.target && it != refField }
if (declaredReferenceFromChild.isEmpty()) {
reporter.reportProblem(
GenerationProblem("Reference should be declared at both entities. It exist at ${objClass.name}#${refField.name}, but is absent from ${ref.target.name}",
GenerationProblem.Level.ERROR,
ProblemLocation.Property(refField))
)
return@checkReferences
}
if (declaredReferenceFromChild.size > 1) {
reporter.reportProblem(
GenerationProblem("""
|More then one reference to ${objClass.name} declared at ${declaredReferenceFromChild[0].receiver.name}#${declaredReferenceFromChild[0].name},
|${declaredReferenceFromChild[1].receiver.name}#${declaredReferenceFromChild[1].name}
|""".trimMargin(),
GenerationProblem.Level.ERROR,
ProblemLocation.Property(declaredReferenceFromChild[0]))
)
return@checkReferences
}
val referencedField = declaredReferenceFromChild[0]
if (ref.child == referencedField.valueType.getRefType().child) {
val (childStr, fix) = if (ref.child) {
"child" to "Probably @Parent annotation is missing from one of the properties."
}
else {
"parent" to "Probably both properties are annotated with @Parent, while only one should be."
}
reporter.reportProblem(
GenerationProblem("Both fields ${objClass.name}#${refField.name} and ${ref.target.name}#${referencedField.name} are marked as $childStr. $fix",
GenerationProblem.Level.ERROR,
ProblemLocation.Property(refField))
)
}
}
}
@@ -10,7 +10,7 @@ import com.intellij.workspaceModel.codegen.impl.writer.extensions.isRefType
internal fun checkExtensionFields(module: CompiledObjModule, reporter: ProblemReporter) {
module.extensions.forEach { extProperty ->
if (!extProperty.valueType.isRefType() && !extProperty.isComputable) {
if (!extProperty.valueType.isRefType()) {
reporter.reportProblem(GenerationProblem("Extension property is supposed to be a reference to another entity only.",
GenerationProblem.Level.ERROR, ProblemLocation.Property(extProperty)))
}
@@ -4,6 +4,7 @@ package com.intellij.workspaceModel.codegen.impl.writer
import com.intellij.workspaceModel.codegen.impl.writer.classes.implWsDataClassCode
import com.intellij.workspaceModel.codegen.impl.writer.classes.implWsEntityCode
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
import com.intellij.workspaceModel.codegen.impl.engine.ProblemReporter
/**
* TODO:
@@ -29,7 +30,7 @@ import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
* Перенести тесты идеи к нам или наоборрот <--
*/
fun ObjClass<*>.implWsCode(): String? {
fun ObjClass<*>.implWsCode(reporter: ProblemReporter): String? {
if (!openness.instantiatable) return null
return "${implWsEntityCode()}\n${implWsDataClassCode()}"
return "${implWsEntityCode(reporter)}\n${implWsDataClassCode()}"
}