[workspace model] IJPL-156449 Workspace code generator for K2

- IJPL-172502 k1/k2 split
- three-way super search in K2; sort supers (also in K1)
- address star imports (also in K1)
- sort properties (also in K1)
- @Child target test
- add Map property in tests
- fix test imports
- WorkspaceModelDefaults


Merge-request: IJ-MR-151255
Merged-by: Kirill Bochkarev <podockonnik@gmail.com>

GitOrigin-RevId: 20d498af5e2d2ccdf374a368ad78ab72c1914620
This commit is contained in:
Kirill Bochkarev
2025-02-18 05:16:28 +00:00
committed by intellij-monorepo-bot
parent f729f90d00
commit afe181d93e
72 changed files with 4807 additions and 375 deletions
+2
View File
@@ -356,6 +356,8 @@
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/intellij.devkit.themes/intellij.devkit.themes.iml" filepath="$PROJECT_DIR$/plugins/devkit/intellij.devkit.themes/intellij.devkit.themes.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/intellij.devkit.uiDesigner/intellij.devkit.uiDesigner.iml" filepath="$PROJECT_DIR$/plugins/devkit/intellij.devkit.uiDesigner/intellij.devkit.uiDesigner.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/intellij.devkit.workspaceModel/intellij.devkit.workspaceModel.iml" filepath="$PROJECT_DIR$/plugins/devkit/intellij.devkit.workspaceModel/intellij.devkit.workspaceModel.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/intellij.devkit.workspaceModel/k1/intellij.devkit.workspaceModel.k1.iml" filepath="$PROJECT_DIR$/plugins/devkit/intellij.devkit.workspaceModel/k1/intellij.devkit.workspaceModel.k1.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/intellij.devkit.workspaceModel/k2/intellij.devkit.workspaceModel.k2.iml" filepath="$PROJECT_DIR$/plugins/devkit/intellij.devkit.workspaceModel/k2/intellij.devkit.workspaceModel.k2.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/intellij.devkit.workspaceModel/tests/intellij.devkit.workspaceModel.tests.iml" filepath="$PROJECT_DIR$/plugins/devkit/intellij.devkit.workspaceModel/tests/intellij.devkit.workspaceModel.tests.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/env-files-support/intellij.dotenv.iml" filepath="$PROJECT_DIR$/plugins/env-files-support/intellij.dotenv.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/env-files-support/java/intellij.dotenv.java.iml" filepath="$PROJECT_DIR$/plugins/env-files-support/java/intellij.dotenv.java.iml" />
@@ -4,7 +4,7 @@
<facet type="kotlin-language" name="Kotlin">
<configuration version="5" platform="JVM 17" allPlatforms="JVM [17]" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-Xjvm-default=all -opt-in=com.intellij.openapi.util.IntellijInternalApi -opt-in=org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction -opt-in=org.jetbrains.kotlin.analysis.api.KaIdeApi -opt-in=org.jetbrains.kotlin.analysis.api.KaNonPublicApi -opt-in=org.jetbrains.kotlin.idea.base.util.K1ModeProjectStructureApi" />
<option name="additionalArguments" value="-Xjvm-default=all -opt-in=com.intellij.openapi.util.IntellijInternalApi -opt-in=org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction -opt-in=org.jetbrains.kotlin.analysis.api.KaIdeApi -opt-in=org.jetbrains.kotlin.analysis.api.KaNonPublicApi -opt-in=org.jetbrains.kotlin.analysis.api.permissions.KaAllowProhibitedAnalyzeFromWriteAction" />
</compilerSettings>
<compilerArguments>
<stringArguments>
@@ -24,38 +24,38 @@
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-stdlib" level="project" />
<orderEntry type="library" scope="PROVIDED" name="kotlinc.kotlin-compiler-common" level="project" />
<orderEntry type="library" scope="PROVIDED" name="kotlinc.kotlin-jps-common" level="project" />
<orderEntry type="library" name="kotlinx-collections-immutable" level="project" />
<orderEntry type="library" name="workspace-model-codegen" level="project" />
<orderEntry type="module" module-name="intellij.platform.ide.core" />
<orderEntry type="module" module-name="intellij.platform.editor.ui" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="module" module-name="intellij.platform.projectModel" />
<orderEntry type="library" name="kotlin-stdlib" level="project" />
<orderEntry type="library" scope="PROVIDED" name="kotlinc.kotlin-compiler-common" level="project" />
<orderEntry type="module" module-name="intellij.platform.analysis" />
<orderEntry type="module" module-name="intellij.java.psi.impl" />
<orderEntry type="library" name="kotlinx-collections-immutable" level="project" />
<orderEntry type="module" module-name="intellij.platform.ide.impl" />
<orderEntry type="module" module-name="intellij.platform.ide" />
<orderEntry type="module" module-name="intellij.platform.lang.core" />
<orderEntry type="module" module-name="intellij.platform.indexing" />
<orderEntry type="module" module-name="kotlin.base.indices" />
<orderEntry type="module" module-name="intellij.platform.core.ui" />
<orderEntry type="module" module-name="kotlin.base.project-structure" />
<orderEntry type="module" module-name="kotlin.base.fe10.analysis" />
<orderEntry type="library" scope="PROVIDED" name="kotlinc.kotlin-compiler-fe10" level="project" />
<orderEntry type="module" module-name="intellij.platform.lang.impl" />
<orderEntry type="module" module-name="intellij.devkit.core" />
<orderEntry type="module" module-name="intellij.java.ui" />
<orderEntry type="module" module-name="intellij.java.aetherDependencyResolver" />
<orderEntry type="module" module-name="intellij.java" />
<orderEntry type="library" name="workspace-model-codegen" level="project" />
<orderEntry type="module" module-name="intellij.platform.util.classLoader" />
<orderEntry type="module" module-name="kotlin.base.facet" />
<orderEntry type="library" scope="PROVIDED" name="kotlinc.kotlin-jps-common" level="project" />
<orderEntry type="module" module-name="kotlin.base.indices" />
<orderEntry type="module" module-name="kotlin.base.project-structure" />
<orderEntry type="module" module-name="kotlin.formatter.minimal" />
<orderEntry type="module" module-name="kotlin.base.plugin" />
<orderEntry type="library" name="kotlinx-serialization-core" level="project" />
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
<orderEntry type="library" name="kotlin-reflect" level="project" />
<orderEntry type="module" module-name="intellij.platform.backend.workspace" />
<orderEntry type="module" module-name="intellij.platform.util.progress" />
<orderEntry type="module" module-name="intellij.platform.core" />
</component>
</module>
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="com.intellij.devkit.workspaceModel.k1" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" packagePrefix="com.intellij.devkit.workspaceModel.k1" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="intellij.platform.workspace.storage" />
<orderEntry type="module" module-name="intellij.devkit.workspaceModel" />
<orderEntry type="module" module-name="intellij.java.psi" />
<orderEntry type="module" module-name="kotlin.base.fe10.analysis" />
<orderEntry type="module" module-name="intellij.java.indexing" />
<orderEntry type="module" module-name="kotlin.base.project-structure" />
<orderEntry type="library" name="kotlin-stdlib" level="project" />
<orderEntry type="library" scope="PROVIDED" name="kotlinc.kotlin-compiler-common" level="project" />
<orderEntry type="library" scope="PROVIDED" name="kotlinc.kotlin-compiler-fe10" level="project" />
<orderEntry type="library" name="workspace-model-codegen" level="project" />
<orderEntry type="module" module-name="intellij.java.psi.impl" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="module" module-name="intellij.platform.core" />
<orderEntry type="module" module-name="kotlin.base.plugin" scope="TEST" />
<orderEntry type="module" module-name="kotlin.plugin.k1" scope="TEST" />
<orderEntry type="module" module-name="intellij.devkit.workspaceModel.tests" scope="TEST" />
<orderEntry type="module" module-name="kotlin.test-framework" scope="TEST" />
<orderEntry type="module" module-name="kotlin.tests-common" scope="TEST" />
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
<orderEntry type="module" module-name="kotlin.base.test" scope="TEST" />
</component>
</module>
@@ -0,0 +1,13 @@
<idea-plugin package="com.intellij.devkit.workspaceModel.k1">
<dependencies>
<plugin id="com.intellij.modules.kotlin.k1"/>
<module name="intellij.devkit.workspaceModel"/>
</dependencies>
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceInterface="com.intellij.devkit.workspaceModel.metaModel.WorkspaceMetaModelProvider"
serviceImplementation="com.intellij.devkit.workspaceModel.k1.metaModel.WorkspaceMetaModelProviderImpl"
/>
</extensions>
</idea-plugin>
@@ -1,11 +1,13 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.metaModel.impl.extensions
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k1.metaModel
import com.intellij.devkit.workspaceModel.metaModel.impl.*
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceModelDefaults
import com.intellij.devkit.workspaceModel.metaModel.impl.CompiledObjModuleImpl
import com.intellij.devkit.workspaceModel.metaModel.impl.ObjAnnotationImpl
import com.intellij.devkit.workspaceModel.metaModel.impl.ObjClassImpl
import com.intellij.psi.CommonClassNames
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiClass
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.searches.ClassInheritorsSearch
import com.intellij.workspaceModel.codegen.deft.meta.Obj
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
@@ -22,39 +24,31 @@ import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.supertypes
private val moduleAbstractTypesClassIds: List<ClassId> = listOf(
ClassId.topLevel(StandardNames.ENTITY_SOURCE),
ClassId.topLevel(StandardNames.SYMBOLIC_ENTITY_ID)
WorkspaceModelDefaults.ENTITY_SOURCE.classId,
WorkspaceModelDefaults.SYMBOLIC_ENTITY_ID.classId
)
private val entitiesSuperclassFqn = StandardNames.WORKSPACE_ENTITY
private val entitiesSuperclassFqn: FqName = WorkspaceModelDefaults.WORKSPACE_ENTITY.fqName
internal val blobClasses: List<FqName> = arrayListOf(
StandardNames.VIRTUAL_FILE_URL,
StandardNames.ENTITY_POINTER
private val blobClasses: List<FqName> = arrayListOf(
WorkspaceModelDefaults.VIRTUAL_FILE_URL.fqName,
WorkspaceModelDefaults.ENTITY_POINTER.fqName
)
internal val ModuleDescriptor.moduleAbstractTypes: List<ClassDescriptor>
get() = moduleAbstractTypesClassIds.mapNotNull { findClassAcrossModuleDependencies(it) }
internal fun ClassDescriptor.inheritors(
javaPsiFacade: JavaPsiFacade, scope: GlobalSearchScope
javaPsiFacade: JavaPsiFacade, scope: GlobalSearchScope,
): List<ClassDescriptor> {
val psiClass = javaPsiFacade.findClass(fqNameSafe.asString(), scope) ?: return emptyList()
return psiClass.inheritors(scope).map { it.getJavaClassDescriptor()!! }
val inheritors = ClassInheritorsSearch.search(psiClass, scope, true, true, false)
.filterNot { it.qualifiedName == null }
.sortedBy { it.qualifiedName } // Sorting is needed for consistency in case of regeneration
return inheritors.map { it.getJavaClassDescriptor()!! }
}
private fun PsiClass.inheritors(scope: SearchScope): List<PsiClass> {
val inheritors = ClassInheritorsSearch.search(this, scope, true, true, false).asIterable().filterNot { it.isAnonymous }
return inheritors.sortedBy { it.qualifiedName } //Sorting is needed for consistency in case of regeneration
}
private val PsiClass.isAnonymous: Boolean
get() = qualifiedName == null
internal val ClassifierDescriptor.javaClassFqn: String
get() {
val nameWithoutPackage = fqNameSafe.asString()
@@ -73,7 +67,7 @@ internal val ClassDescriptor.superTypesJavaFqns: List<String>
get() = defaultType.supertypes()
.mapNotNull { it.constructor.declarationDescriptor?.javaClassFqn }
.withoutStandardTypes()
.sorted()
internal val ClassDescriptor.isObject: Boolean
get() = kind == ClassKind.OBJECT
@@ -96,11 +90,11 @@ internal val ClassDescriptor.isAbstractClassOrInterface: Boolean
get() = !isFinalClass
internal val ClassDescriptor.isEntityInterface: Boolean
get() = DescriptorUtils.isInterface(this) && defaultType.isSubclassOf(entitiesSuperclassFqn) // If this is `WorkspaceEntity` interface we need to check it
// If this is `WorkspaceEntity` interface, we need to check it
get() = DescriptorUtils.isInterface(this) && defaultType.isSubclassOf(entitiesSuperclassFqn)
internal val ClassDescriptor.isEntityBuilderInterface: Boolean
get() = isEntityInterface && name.identifier == "Builder" //todo improve
get() = isEntityInterface && name.identifier == "Builder" // TODO: improve
private fun KotlinType.isSubclassOf(superClassName: FqName): Boolean {
return constructor.declarationDescriptor?.fqNameSafe == superClassName || constructor.supertypes.any {
@@ -108,32 +102,32 @@ private fun KotlinType.isSubclassOf(superClassName: FqName): Boolean {
}
}
internal fun createObjTypeStub(interfaceDescriptor: ClassDescriptor, module: CompiledObjModuleImpl): ObjClassImpl<Obj> {
val openness = when {
interfaceDescriptor.isAnnotatedBy(StandardNames.ABSTRACT_ANNOTATION) -> ObjClass.Openness.abstract
interfaceDescriptor.isAnnotatedBy(StandardNames.OPEN_ANNOTATION) -> ObjClass.Openness.open
interfaceDescriptor.isAnnotatedBy(WorkspaceModelDefaults.ABSTRACT_ANNOTATION.fqName) -> ObjClass.Openness.abstract
interfaceDescriptor.isAnnotatedBy(WorkspaceModelDefaults.OPEN_ANNOTATION.fqName) -> ObjClass.Openness.open
else -> ObjClass.Openness.final
}
val propertyAnnotations = interfaceDescriptor.annotations
.mapNotNull { it.fqName }
.map { ObjAnnotationImpl(it.asString(), it.pathSegments().map { segment -> segment.asString() }) }
return ObjClassImpl(module, interfaceDescriptor.name.identifier, openness, interfaceDescriptor.source, propertyAnnotations)
.mapNotNull { it.fqName }
.map { ObjAnnotationImpl(it.asString(), it.pathSegments().map { segment -> segment.asString() }) }
return ObjClassImpl(module, interfaceDescriptor.name.identifier, openness, interfaceDescriptor.source.getPsi(), propertyAnnotations)
}
internal fun computeKind(property: PropertyDescriptor): ObjProperty.ValueKind {
val getter = property.getter ?: return ObjProperty.ValueKind.Plain
internal fun PropertyDescriptor.computeKind(): ObjProperty.ValueKind {
val getter = getter ?: return ObjProperty.ValueKind.Plain
if (!getter.hasBody()) return ObjProperty.ValueKind.Plain
val declaration = getter.source.getPsi() as? KtDeclarationWithBody ?: return ObjProperty.ValueKind.Plain
val getterText = (declaration.bodyExpression ?: declaration.bodyBlockExpression)?.text
return when {
getterText == null -> ObjProperty.ValueKind.Plain
getter.isAnnotatedBy(StandardNames.DEFAULT_ANNOTATION) -> ObjProperty.ValueKind.WithDefault(getterText)
getter.isAnnotatedBy(WorkspaceModelDefaults.DEFAULT_ANNOTATION.fqName) -> ObjProperty.ValueKind.WithDefault(getterText)
else -> ObjProperty.ValueKind.Computable(getterText)
}
}
private val standardTypes = setOf(Any::class.qualifiedName, CommonClassNames.JAVA_LANG_OBJECT, CommonClassNames.JAVA_LANG_ENUM)
private fun Iterable<String>.withoutStandardTypes(): List<String> {
return filterNot { standardTypes.contains(it) }
}
}
@@ -0,0 +1,39 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k1.metaModel
import com.intellij.psi.CommonClassNames
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import org.jetbrains.kotlin.name.FqName
internal object ObjTypeConverter {
private val javaPrimitiveTypes = mapOf(
CommonClassNames.JAVA_LANG_BOOLEAN to ValueType.Boolean,
CommonClassNames.JAVA_LANG_BYTE to ValueType.Byte,
CommonClassNames.JAVA_LANG_SHORT to ValueType.Short,
CommonClassNames.JAVA_LANG_INTEGER to ValueType.Int,
CommonClassNames.JAVA_LANG_LONG to ValueType.Long,
CommonClassNames.JAVA_LANG_FLOAT to ValueType.Float,
CommonClassNames.JAVA_LANG_DOUBLE to ValueType.Double,
CommonClassNames.JAVA_LANG_CHARACTER to ValueType.Char,
CommonClassNames.JAVA_LANG_STRING to ValueType.String,
)
private val kotlinPrimitiveTypes = mapOf(
"kotlin.Boolean" to ValueType.Boolean,
"kotlin.Byte" to ValueType.Byte,
"kotlin.Short" to ValueType.Short,
"kotlin.Int" to ValueType.Int,
"kotlin.Long" to ValueType.Long,
"kotlin.Float" to ValueType.Float,
"kotlin.Double" to ValueType.Double,
"kotlin.UByte" to ValueType.UByte,
"kotlin.UShort" to ValueType.UShort,
"kotlin.UInt" to ValueType.UInt,
"kotlin.ULong" to ValueType.ULong,
"kotlin.Char" to ValueType.Char,
"kotlin.String" to ValueType.String,
)
operator fun get(fqName: FqName): ValueType.Primitive<*>? =
kotlinPrimitiveTypes[fqName.asString()] ?: javaPrimitiveTypes[fqName.asString()]
}
@@ -0,0 +1,29 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k1.metaModel
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceModelDefaults
import com.intellij.workspaceModel.codegen.deft.meta.CompiledObjModule
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.name.FqName
internal fun Annotated.isAnnotatedBy(fqName: FqName) = annotations.hasAnnotation(fqName)
internal val FqName.isCollection: Boolean
get() = isList || isSet || isMap
internal val FqName.isList: Boolean
get() = this == WorkspaceModelDefaults.LIST_INTERFACE.fqName
internal val FqName.isSet: Boolean
get() = this == WorkspaceModelDefaults.SET_INTERFACE.fqName
internal val FqName.isMap: Boolean
get() = this == WorkspaceModelDefaults.MAP_INTERFACE.fqName
internal data class CompiledObjModuleAndK1Module(
val compiledObjModule: CompiledObjModule,
val kotlinModule: ModuleDescriptor,
)
internal infix fun CompiledObjModule.and(moduleDescriptor: ModuleDescriptor) = CompiledObjModuleAndK1Module(this, moduleDescriptor)
@@ -1,24 +1,17 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.metaModel.impl
package com.intellij.devkit.workspaceModel.k1.metaModel
import com.intellij.devkit.workspaceModel.metaModel.IncorrectObjInterfaceException
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceMetaModelProvider
import com.intellij.devkit.workspaceModel.metaModel.impl.extensions.*
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceModelDefaults
import com.intellij.devkit.workspaceModel.metaModel.impl.*
import com.intellij.devkit.workspaceModel.metaModel.unsupportedType
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.annotations.Abstract
import com.intellij.platform.workspace.storage.annotations.Child
import com.intellij.platform.workspace.storage.annotations.Default
import com.intellij.platform.workspace.storage.annotations.Open
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import com.intellij.psi.CommonClassNames
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.workspaceModel.codegen.deft.meta.*
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotated
import org.jetbrains.kotlin.idea.base.projectStructure.productionSourceInfo
import org.jetbrains.kotlin.idea.base.projectStructure.testSourceInfo
import org.jetbrains.kotlin.name.FqName
@@ -26,42 +19,46 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import java.util.concurrent.ConcurrentHashMap
internal class WorkspaceMetaModelProviderImpl(
internal class WorkspaceMetaModelBuilder(
private val processAbstractTypes: Boolean,
project: Project
): WorkspaceMetaModelProvider {
private val objModuleByName = ConcurrentHashMap<String, Pair<CompiledObjModule, ModuleDescriptor>>()
project: Project,
) {
private val objModuleByName = ConcurrentHashMap<String, CompiledObjModuleAndK1Module>()
private val javaPsiFacade = JavaPsiFacade.getInstance(project)
private val allScope = GlobalSearchScope.allScope(project)
override fun getObjModule(packageName: String, module: Module, isTestSourceFolder: Boolean): CompiledObjModule {
val sourceInfo = if (!isTestSourceFolder) {
fun getObjModule(packageName: String, module: Module, isTestSourceFolder: Boolean): CompiledObjModule {
val sourceInfo = if (!isTestSourceFolder) {
module.productionSourceInfo
} else {
}
else {
module.testSourceInfo
} ?: error("No production sources in ${module.name}")
val resolutionFacade = KotlinCacheService.getInstance(module.project).getResolutionFacadeByModuleInfo(sourceInfo, sourceInfo.platform)!!
val resolutionFacade = KotlinCacheService.getInstance(module.project).getResolutionFacadeByModuleInfo(sourceInfo, sourceInfo.platform)
val moduleDescriptor = resolutionFacade.moduleDescriptor
return getObjModule(packageName, moduleDescriptor)
}
private fun getObjModule(packageName: String, moduleDescriptor: ModuleDescriptor): CompiledObjModule {
val cached = objModuleByName[packageName]
if (cached != null && cached.second == moduleDescriptor) return cached.first
if (cached != null && cached.kotlinModule == moduleDescriptor) return cached.compiledObjModule
val packageViewDescriptor = moduleDescriptor.getPackage(FqName(packageName))
val objModuleStub = createObjModuleStub(moduleDescriptor, packageViewDescriptor, packageName)
val result = registerObjModuleContent(packageViewDescriptor, objModuleStub, moduleDescriptor)
objModuleByName[packageName] = result to moduleDescriptor
return result
val compiledObjModule = registerObjModuleContent(packageViewDescriptor, objModuleStub, moduleDescriptor)
objModuleByName[packageName] = compiledObjModule and moduleDescriptor
return compiledObjModule
}
private fun registerObjModuleContent(packageViewDescriptor: PackageViewDescriptor,
objModuleStub: ObjModuleStub,
moduleDescriptor: ModuleDescriptor): CompiledObjModule {
private fun registerObjModuleContent(
packageViewDescriptor: PackageViewDescriptor,
objModuleStub: ObjModuleStub,
moduleDescriptor: ModuleDescriptor,
): CompiledObjModule {
val extensionProperties = packageViewDescriptor.fragments.flatMap { fragment ->
fragment.getMemberScope().getContributedDescriptors(DescriptorKindFilter.VARIABLES)
.filterIsInstance<PropertyDescriptor>()
@@ -69,14 +66,16 @@ internal class WorkspaceMetaModelProviderImpl(
.filter { it.module == moduleDescriptor }
}
val externalProperties = extensionProperties.mapNotNull { property ->
val receiver = property.extensionReceiverParameter?.value?.type?.constructor?.declarationDescriptor as? ClassDescriptor
receiver?.let { property to receiver }
}.filter { it.second.isEntityInterface && !it.second.isEntityBuilderInterface }
val receiver = property.extensionReceiverParameter?.value?.type?.constructor?.declarationDescriptor as? ClassDescriptor
receiver?.let { property to receiver }
}.filter { it.second.isEntityInterface && !it.second.isEntityBuilderInterface }
return objModuleStub.registerContent(externalProperties)
}
private fun createObjModuleStub(moduleDescriptor: ModuleDescriptor,
packageViewDescriptor: PackageViewDescriptor, packageName: String): ObjModuleStub {
private fun createObjModuleStub(
moduleDescriptor: ModuleDescriptor,
packageViewDescriptor: PackageViewDescriptor, packageName: String,
): ObjModuleStub {
val entityInterfaces = packageViewDescriptor.fragments.flatMap { fragment ->
fragment.getMemberScope().getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS)
.filterIsInstance<ClassDescriptor>()
@@ -99,10 +98,12 @@ internal class WorkspaceMetaModelProviderImpl(
return objModule.types.find { it.name == entityInterfaceName } ?: error("Cannot find $entityInterfaceName in $objModule")
}
private inner class ObjModuleStub(val module: CompiledObjModuleImpl,
val types: List<Pair<ClassDescriptor, ObjClassImpl<Obj>>>,
val moduleAbstractTypes: List<ClassDescriptor>,
val moduleDescriptor: ModuleDescriptor) {
private inner class ObjModuleStub(
val module: CompiledObjModuleImpl,
val types: List<Pair<ClassDescriptor, ObjClassImpl<Obj>>>,
val moduleAbstractTypes: List<ClassDescriptor>,
val moduleDescriptor: ModuleDescriptor,
) {
fun registerContent(extProperties: List<Pair<PropertyDescriptor, ClassDescriptor>>): CompiledObjModule {
var extPropertyId = 0
for ((classDescriptor, objType) in types) {
@@ -111,10 +112,11 @@ internal class WorkspaceMetaModelProviderImpl(
.filter { it.kind.isReal }
.filter { it.module == moduleDescriptor }
for ((propertyId, property) in properties.withIndex()) {
val kind = computeKind(property)
val kind = property.computeKind()
if (kind !is ObjProperty.ValueKind.Computable ||
// We can't simply skip all `Computable` because some of them are SymbolicIds
property.overriddenDescriptors.isNotEmpty()) {
property.overriddenDescriptors.isNotEmpty()
) {
objType.addField(createOwnProperty(property, propertyId, objType))
}
}
@@ -151,14 +153,16 @@ internal class WorkspaceMetaModelProviderImpl(
}
private fun createOwnProperty(property: PropertyDescriptor, propertyId: Int,
receiver: ObjClassImpl<Obj>): OwnProperty<Obj, *> {
val valueType = convertType(property.type, hashMapOf(), property.isAnnotatedBy (StandardNames.CHILD_ANNOTATION))
private fun createOwnProperty(
property: PropertyDescriptor, propertyId: Int,
receiver: ObjClassImpl<Obj>,
): OwnProperty<Obj, *> {
val valueType = convertType(property.type, hashMapOf(), property.isAnnotatedBy(WorkspaceModelDefaults.CHILD_ANNOTATION.fqName))
return OwnPropertyImpl(
receiver, property.name.identifier, valueType, computeKind(property),
property.isAnnotatedBy(StandardNames.OPEN_ANNOTATION), property.isVar,
receiver, property.name.identifier, valueType, property.computeKind(),
property.isAnnotatedBy(WorkspaceModelDefaults.OPEN_ANNOTATION.fqName), property.isVar,
false, false, propertyId,
property.isAnnotatedBy(StandardNames.EQUALS_BY_ANNOTATION), property.source
property.isAnnotatedBy(WorkspaceModelDefaults.EQUALS_BY_ANNOTATION.fqName), property.source.getPsi()
)
}
@@ -170,13 +174,17 @@ internal class WorkspaceMetaModelProviderImpl(
?: emptyList()
return ExtPropertyImpl(
findObjClass(receiverClass), extProperty.name.identifier, valueType,
computeKind(extProperty), extProperty.isAnnotatedBy(StandardNames.OPEN_ANNOTATION),
extProperty.isVar, false, module, extPropertyId, propertyAnnotations, extProperty.source
extProperty.computeKind(), extProperty.isAnnotatedBy(WorkspaceModelDefaults.OPEN_ANNOTATION.fqName),
extProperty.isVar, false, module, extPropertyId, propertyAnnotations, extProperty.source.getPsi()
)
}
private fun convertType(type: KotlinType, knownTypes: MutableMap<String, ValueType.Blob<*>>, hasChildAnnotation: Boolean): ValueType<*> {
private fun convertType(
type: KotlinType,
knownTypes: MutableMap<String, ValueType.Blob<*>>,
hasChildAnnotation: Boolean,
): ValueType<*> {
if (type.isMarkedNullable) {
return ValueType.Optional(convertType(type.makeNotNullable(), knownTypes, hasChildAnnotation))
}
@@ -185,7 +193,7 @@ internal class WorkspaceMetaModelProviderImpl(
if (descriptor is ClassDescriptor) {
val fqName = descriptor.fqNameSafe
val primitive = ObjTypeConverter.findPrimitive(fqName)
val primitive = ObjTypeConverter[fqName]
if (primitive != null) return primitive
if (fqName.isCollection) {
@@ -199,7 +207,8 @@ internal class WorkspaceMetaModelProviderImpl(
}
if (descriptor.isEntityInterface) {
return ValueType.ObjRef(type.isAnnotatedBy(StandardNames.CHILD_ANNOTATION) || hasChildAnnotation, //todo leave only one target for @Child annotation
return ValueType.ObjRef(type.isAnnotatedBy(
WorkspaceModelDefaults.CHILD_ANNOTATION.fqName) || hasChildAnnotation, //todo leave only one target for @Child annotation
findObjClass(descriptor))
}
return descriptor.toValueType(knownTypes, processAbstractTypes)
@@ -208,7 +217,10 @@ internal class WorkspaceMetaModelProviderImpl(
return unsupportedType(type.toString())
}
private fun ClassDescriptor.toValueType(knownTypes: MutableMap<String, ValueType.Blob<*>>, processAbstractTypes: Boolean): ValueType.JvmClass<*> {
private fun ClassDescriptor.toValueType(
knownTypes: MutableMap<String, ValueType.Blob<*>>,
processAbstractTypes: Boolean,
): ValueType.JvmClass<*> {
val javaClassFqn = javaClassFqn
val superTypes = superTypesJavaFqns
@@ -243,16 +255,21 @@ internal class WorkspaceMetaModelProviderImpl(
}
}
private fun createProperties(descriptor: ClassDescriptor, knownTypes: MutableMap<String, ValueType.Blob<*>>): List<ValueType.ClassProperty<*>> {
private fun createProperties(
descriptor: ClassDescriptor,
knownTypes: MutableMap<String, ValueType.Blob<*>>,
): List<ValueType.ClassProperty<*>> {
return descriptor.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES)
.filterIsInstance<PropertyDescriptor>()
.sortedBy { it.name.identifier }
.map { ValueType.ClassProperty(it.name.identifier, convertType(it.type, knownTypes, false)) }
}
private fun findObjClass(descriptor: ClassDescriptor): ObjClass<*> {
if (descriptor.packageOrDie.asString() == module.name) {
return types.find { it.first.typeConstructor == descriptor.typeConstructor }?.second ?: error("Cannot find ${descriptor.fqNameSafe} in $module")
return types.find { it.first.typeConstructor == descriptor.typeConstructor }?.second ?: error(
"Cannot find ${descriptor.fqNameSafe} in $module")
}
return getObjClass(descriptor)
}
@@ -262,77 +279,3 @@ internal class WorkspaceMetaModelProviderImpl(
}
}
}
internal fun Annotated.isAnnotatedBy(fqName: FqName) = annotations.hasAnnotation(fqName)
private val FqName.isCollection: Boolean
get() = isList || isSet || isMap
private val FqName.isList: Boolean
get() = this == StandardNames.LIST_INTERFACE
private val FqName.isSet: Boolean
get() = this == StandardNames.SET_INTERFACE
private val FqName.isMap: Boolean
get() = this == StandardNames.MAP_INTERFACE
private object ObjTypeConverter {
private val javaPrimitiveTypes = mapOf(
CommonClassNames.JAVA_LANG_BOOLEAN to ValueType.Boolean,
CommonClassNames.JAVA_LANG_BYTE to ValueType.Byte,
CommonClassNames.JAVA_LANG_SHORT to ValueType.Short,
CommonClassNames.JAVA_LANG_INTEGER to ValueType.Int,
CommonClassNames.JAVA_LANG_LONG to ValueType.Long,
CommonClassNames.JAVA_LANG_FLOAT to ValueType.Float,
CommonClassNames.JAVA_LANG_DOUBLE to ValueType.Double,
CommonClassNames.JAVA_LANG_CHARACTER to ValueType.Char,
CommonClassNames.JAVA_LANG_STRING to ValueType.String,
)
private val kotlinPrimitiveTypes = mapOf(
"kotlin.Boolean" to ValueType.Boolean,
"kotlin.Byte" to ValueType.Byte,
"kotlin.Short" to ValueType.Short,
"kotlin.Int" to ValueType.Int,
"kotlin.Long" to ValueType.Long,
"kotlin.Float" to ValueType.Float,
"kotlin.Double" to ValueType.Double,
"kotlin.UByte" to ValueType.UByte,
"kotlin.UShort" to ValueType.UShort,
"kotlin.UInt" to ValueType.UInt,
"kotlin.ULong" to ValueType.ULong,
"kotlin.Char" to ValueType.Char,
"kotlin.String" to ValueType.String,
)
fun findPrimitive(fqName: FqName): ValueType.Primitive<*>? =
kotlinPrimitiveTypes[fqName.asString()] ?: javaPrimitiveTypes[fqName.asString()]
}
internal object StandardNames {
val DEFAULT_ANNOTATION = FqName(Default::class.qualifiedName!!)
val OPEN_ANNOTATION = FqName(Open::class.qualifiedName!!)
val ABSTRACT_ANNOTATION = FqName(Abstract::class.qualifiedName!!)
val CHILD_ANNOTATION = FqName(Child::class.qualifiedName!!)
val EQUALS_BY_ANNOTATION = FqName(EqualsBy::class.qualifiedName!!)
val LIST_INTERFACE = FqName(List::class.qualifiedName!!)
val SET_INTERFACE = FqName(Set::class.qualifiedName!!)
val MAP_INTERFACE = FqName(Map::class.qualifiedName!!)
val WORKSPACE_ENTITY = FqName(WorkspaceEntity::class.qualifiedName!!)
val ENTITY_SOURCE = FqName(EntitySource::class.qualifiedName!!)
val VIRTUAL_FILE_URL = FqName(VirtualFileUrl::class.qualifiedName!!)
val SYMBOLIC_ENTITY_ID = FqName(SymbolicEntityId::class.qualifiedName!!)
val ENTITY_POINTER = FqName(EntityPointer::class.qualifiedName!!)
}
internal val standardTypes = setOf(Any::class.qualifiedName, CommonClassNames.JAVA_LANG_OBJECT, CommonClassNames.JAVA_LANG_ENUM)
private fun unsupportedType(type: String?): ValueType<*> {
throw IncorrectObjInterfaceException("Unsupported type '$type'")
}
@@ -0,0 +1,25 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k1.metaModel
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceMetaModelProvider
import com.intellij.openapi.module.Module
import com.intellij.workspaceModel.codegen.deft.meta.CompiledObjModule
import org.jetbrains.kotlin.psi.KtClass
internal class WorkspaceMetaModelProviderImpl : WorkspaceMetaModelProvider {
override fun loadObjModules(
ktClasses: HashMap<String, KtClass>,
module: Module,
processAbstractTypes: Boolean,
isTestSourceFolder: Boolean,
): List<CompiledObjModule> {
val packages = ktClasses.values.mapTo(LinkedHashSet()) { it.containingKtFile.packageFqName.asString() }
val metaModelProvider = WorkspaceMetaModelBuilder(
processAbstractTypes = processAbstractTypes,
module.project
)
return packages.filter { it != "" }.map { metaModelProvider.getObjModule(it, module, isTestSourceFolder) }
}
}
@@ -0,0 +1,10 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k1
import com.intellij.devkit.workspaceModel.AbstractAllIntellijEntitiesGenerationTest
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode
class AllIntellijEntitiesGenerationTest : AbstractAllIntellijEntitiesGenerationTest() {
override val pluginMode: KotlinPluginMode
get() = KotlinPluginMode.K1
}
@@ -0,0 +1,10 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k1
import com.intellij.devkit.workspaceModel.AbstractEntityCodeGenTest
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode
class EntityCodeGenTest : AbstractEntityCodeGenTest() {
override val pluginMode: KotlinPluginMode
get() = KotlinPluginMode.K1
}
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="5" platform="JVM 17" allPlatforms="JVM [17]" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-Xjvm-default=all -opt-in=com.intellij.openapi.util.IntellijInternalApi -opt-in=org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction -opt-in=org.jetbrains.kotlin.analysis.api.KaIdeApi -opt-in=org.jetbrains.kotlin.analysis.api.KaNonPublicApi -opt-in=org.jetbrains.kotlin.analysis.api.permissions.KaAllowProhibitedAnalyzeFromWriteAction" />
</compilerSettings>
<compilerArguments>
<stringArguments>
<stringArg name="jvmTarget" arg="17" />
<stringArg name="apiVersion" arg="2.0" />
<stringArg name="languageVersion" arg="2.0" />
</stringArguments>
</compilerArguments>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="com.intellij.devkit.workspaceModel.k2" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" packagePrefix="com.intellij.devkit.workspaceModel.k2" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="intellij.devkit.workspaceModel" />
<orderEntry type="module" module-name="kotlin.base.indices" />
<orderEntry type="module" module-name="kotlin.base.project-structure" />
<orderEntry type="module" module-name="intellij.java.indexing" />
<orderEntry type="module" module-name="intellij.platform.workspace.storage" />
<orderEntry type="library" name="kotlin-stdlib" level="project" />
<orderEntry type="library" scope="PROVIDED" name="kotlinc.analysis-api" level="project" />
<orderEntry type="library" scope="PROVIDED" name="kotlinc.kotlin-compiler-common" level="project" />
<orderEntry type="library" name="workspace-model-codegen" level="project" />
<orderEntry type="module" module-name="intellij.platform.core.impl" />
<orderEntry type="module" module-name="intellij.java" />
<orderEntry type="module" module-name="kotlin.base.psi" />
<orderEntry type="module" module-name="intellij.devkit.workspaceModel.tests" scope="TEST" />
<orderEntry type="module" module-name="kotlin.test-framework" scope="TEST" />
<orderEntry type="module" module-name="kotlin.base.plugin" scope="TEST" />
<orderEntry type="module" module-name="kotlin.tests-common" scope="TEST" />
<orderEntry type="module" module-name="kotlin.plugin.k2" scope="TEST" />
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
<orderEntry type="module" module-name="kotlin.base.test" scope="TEST" />
</component>
</module>
@@ -0,0 +1,13 @@
<idea-plugin package="com.intellij.devkit.workspaceModel.k2">
<dependencies>
<plugin id="com.intellij.modules.kotlin.k2"/>
<module name="intellij.devkit.workspaceModel"/>
</dependencies>
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceInterface="com.intellij.devkit.workspaceModel.metaModel.WorkspaceMetaModelProvider"
serviceImplementation="com.intellij.devkit.workspaceModel.k2.metaModel.WorkspaceMetaModelProviderImpl"
/>
</extensions>
</idea-plugin>
@@ -0,0 +1,143 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k2.metaModel
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceModelDefaults
import com.intellij.devkit.workspaceModel.metaModel.impl.CompiledObjModuleImpl
import com.intellij.devkit.workspaceModel.metaModel.impl.ObjAnnotationImpl
import com.intellij.devkit.workspaceModel.metaModel.impl.ObjClassImpl
import com.intellij.psi.CommonClassNames
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiClass
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.searches.ClassInheritorsSearch
import com.intellij.workspaceModel.codegen.deft.meta.Obj
import com.intellij.workspaceModel.codegen.deft.meta.ObjClass
import com.intellij.workspaceModel.codegen.deft.meta.ObjProperty
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.annotations.KaAnnotated
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.types.symbol
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
internal fun KaAnnotated.isAnnotatedBy(classId: ClassId) = annotations.contains(classId)
private val moduleAbstractTypesClassIds: List<ClassId> = listOf(
WorkspaceModelDefaults.ENTITY_SOURCE.classId,
WorkspaceModelDefaults.SYMBOLIC_ENTITY_ID.classId,
)
internal fun KaSession.inheritors(
classSymbol: KaClassSymbol, javaPsiFacade: JavaPsiFacade, scope: GlobalSearchScope,
): List<KtClassOrObject> {
// can be rewritten using org.jetbrains.kotlin.idea.searching.inheritors.KotlinSearchUtilKt.findAllInheritors
val psiClass = javaPsiFacade.findClass(classSymbol.javaClassFqn, scope) ?: return emptyList()
return ClassInheritorsSearch.search(psiClass, scope, true, true, false)
.filterNot { it.isAnonymous }
.sortedBy { it.qualifiedName } // Sorting is needed for consistency in case of regeneration
.mapNotNull {
KotlinFullClassNameIndex[it.qualifiedName!!, it.project, scope].firstOrNull()
}
}
private val standardTypes = setOf(Any::class.qualifiedName, CommonClassNames.JAVA_LANG_OBJECT, CommonClassNames.JAVA_LANG_ENUM)
internal fun KaSession.superTypesJavaFqns(
classSymbol: KaClassSymbol, javaPsiFacade: JavaPsiFacade, scope: GlobalSearchScope,
): List<String> {
// FIXME: There's definitely smth wrong with AA
val kaSuperTypes1 = classSymbol.defaultType.allSupertypes
.mapNotNull { it.expandedSymbol?.javaClassFqn }
.toList()
val kaSuperTypes2 = classSymbol.superTypes.flatMap { listOf(it) + it.allSupertypes }
.mapNotNull { it.expandedSymbol?.javaClassFqn }
.toList()
val psiSuperTypes = javaPsiFacade.findClass(classSymbol.javaClassFqn, scope)?.supers?.mapNotNull { it.qualifiedName }
?: emptyList()
val mergedSuperTypes = (psiSuperTypes + kaSuperTypes1 + kaSuperTypes2).distinct()
return mergedSuperTypes.withoutStandardTypes().sorted()
}
// TODO: merge with above?
internal val KaClassSymbol.superTypesJavaFqns: List<String>
get() = superTypes.mapNotNull { it.symbol?.javaClassFqn }.withoutStandardTypes().sorted()
private val PsiClass.isAnonymous: Boolean
get() = qualifiedName == null
internal val KaClassLikeSymbol.javaClassFqn: String
get() {
val nameWithoutPackage = classId?.asSingleFqName()?.asString()
?.substringAfter("$packageName.")
?.replace(".", "$")
return "$packageName.$nameWithoutPackage"
}
internal val KaClassLikeSymbol.packageName: String
get() = packageOrDie.asString()
internal val KaClassLikeSymbol.packageOrDie: FqName
get() = classId?.packageFqName ?: error("$name has no package")
internal fun KaSession.getPackageSymbol(classSymbol: KaClassSymbol): KaPackageSymbol? =
classSymbol.classId?.packageFqName?.let { findPackage(it) }
private val blobClasses: List<ClassId> = arrayListOf(
WorkspaceModelDefaults.VIRTUAL_FILE_URL.classId,
WorkspaceModelDefaults.ENTITY_POINTER.classId,
)
internal fun KaSession.isBlob(classSymbol: KaClassSymbol): Boolean {
val classId = classSymbol.classId ?: return false
return blobClasses.any { blobClass -> classSymbol.defaultType.isSubtypeOf(blobClass) } ||
classId in moduleAbstractTypesClassIds ||
classId.packageFqName.asString().startsWith("java.") ||
classId.packageFqName.asString().startsWith("kotlin.")
}
private fun Iterable<String>.withoutStandardTypes(): List<String> {
return filterNot { standardTypes.contains(it) }
}
internal fun KaSession.moduleAbstractTypes(): List<KaClassSymbol> {
return moduleAbstractTypesClassIds.mapNotNull { classId -> findClass(classId) }
}
internal fun KaSession.isEntityInterface(classSymbol: KaClassSymbol): Boolean =
classSymbol.classKind == KaClassKind.INTERFACE && classSymbol.defaultType.isSubtypeOf(WorkspaceModelDefaults.WORKSPACE_ENTITY.classId)
internal fun KaSession.isEntityBuilderInterface(classSymbol: KaClassSymbol): Boolean =
isEntityInterface(classSymbol) && classSymbol.name?.identifier == "Builder" // TODO: improve
internal fun KaSession.computeKind(property: KaPropertySymbol): ObjProperty.ValueKind {
val getter = property.getter ?: return ObjProperty.ValueKind.Plain
if (!getter.hasBody) return ObjProperty.ValueKind.Plain
val declaration = getter.psi as? KtDeclarationWithBody ?: return ObjProperty.ValueKind.Plain
val getterText = (declaration.bodyExpression ?: declaration.bodyBlockExpression)?.text
return when {
getterText == null -> ObjProperty.ValueKind.Plain
getter.isAnnotatedBy(WorkspaceModelDefaults.DEFAULT_ANNOTATION.classId) -> ObjProperty.ValueKind.WithDefault(getterText)
else -> ObjProperty.ValueKind.Computable(getterText)
}
}
internal fun KaSession.createObjTypeStub(symbol: KaClassSymbol, module: CompiledObjModuleImpl): ObjClassImpl<Obj> {
val openness = when {
symbol.isAnnotatedBy(WorkspaceModelDefaults.ABSTRACT_ANNOTATION.classId) -> ObjClass.Openness.abstract
symbol.isAnnotatedBy(WorkspaceModelDefaults.OPEN_ANNOTATION.classId) -> ObjClass.Openness.open
else -> ObjClass.Openness.final
}
val propertyAnnotations = symbol.annotations
.mapNotNull { it.classId?.asSingleFqName() }
.map { ObjAnnotationImpl(it.asString(), it.pathSegments().map { segment -> segment.asString() }) }
return ObjClassImpl(module, symbol.name?.identifier!!, openness, symbol.sourcePsi(), propertyAnnotations)
}
internal fun KaSession.isChild(kaType: KaAnnotated) =
kaType.isAnnotatedBy(WorkspaceModelDefaults.CHILD_ANNOTATION.classId)
@@ -0,0 +1,27 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k2.metaModel
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
import org.jetbrains.kotlin.analysis.api.components.DefaultTypeClassIds
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.name.ClassId
internal object ObjTypeConverter {
private val kotlinDefaultTypeToValueType = mapOf(
DefaultTypeClassIds.BOOLEAN to ValueType.Boolean,
DefaultTypeClassIds.BYTE to ValueType.Byte,
DefaultTypeClassIds.SHORT to ValueType.Short,
DefaultTypeClassIds.INT to ValueType.Int,
DefaultTypeClassIds.LONG to ValueType.Long,
DefaultTypeClassIds.FLOAT to ValueType.Float,
DefaultTypeClassIds.DOUBLE to ValueType.Double,
DefaultTypeClassIds.CHAR to ValueType.Char,
DefaultTypeClassIds.STRING to ValueType.String,
StandardNames.FqNames.uByte to ValueType.UByte,
StandardNames.FqNames.uShort to ValueType.UShort,
StandardNames.FqNames.uInt to ValueType.UInt,
StandardNames.FqNames.uLong to ValueType.ULong,
)
operator fun get(classId: ClassId?): ValueType.Primitive<*>? = classId?.let { kotlinDefaultTypeToValueType[it] }
}
@@ -0,0 +1,9 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k2.metaModel
import com.intellij.workspaceModel.codegen.deft.meta.CompiledObjModule
import org.jetbrains.kotlin.analysis.api.projectStructure.KaModule
internal data class CompiledObjModuleAndK2Module(val compiledObjModule: CompiledObjModule, val kotlinModule: KaModule)
internal infix fun CompiledObjModule.and(kaModule: KaModule) = CompiledObjModuleAndK2Module(this, kaModule)
@@ -0,0 +1,311 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k2.metaModel
import com.intellij.devkit.workspaceModel.metaModel.IncorrectObjInterfaceException
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceModelDefaults
import com.intellij.devkit.workspaceModel.metaModel.impl.*
import com.intellij.devkit.workspaceModel.metaModel.unsupportedType
import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.concurrency.annotations.RequiresReadLock
import com.intellij.workspaceModel.codegen.deft.meta.*
import org.jetbrains.kotlin.analysis.api.KaSession
import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.analysis.api.projectStructure.KaModule
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.types.KaClassType
import org.jetbrains.kotlin.analysis.api.types.KaType
import org.jetbrains.kotlin.analysis.api.types.KaTypeNullability
import org.jetbrains.kotlin.idea.stubindex.KotlinExactPackagesIndex
import org.jetbrains.kotlin.name.StandardClassIds
import java.util.concurrent.ConcurrentHashMap
internal class WorkspaceMetaModelBuilder(
private val processAbstractTypes: Boolean,
private val project: Project,
) {
private val objModuleByName = ConcurrentHashMap<String, CompiledObjModuleAndK2Module>()
private val javaPsiFacade = JavaPsiFacade.getInstance(project)
private val allProjectScope = GlobalSearchScope.allScope(project)
@RequiresReadLock
fun getObjModule(
packageName: String,
kaModule: KaModule,
): CompiledObjModule = analyze(kaModule) {
val ktFile = KotlinExactPackagesIndex.get(packageName, project, kaModule.contentScope).firstOrNull()
?: error("Cannot find any files with package $packageName in module ${kaModule}")
val packageSymbol = findPackage(ktFile.packageFqName) ?: error("Could not find package $packageName in module ${kaModule}")
getObjModule(packageName, packageSymbol, kaModule)
}
private fun KaSession.getObjModule(
packageName: String,
packageSymbol: KaPackageSymbol,
kaModule: KaModule,
): CompiledObjModule {
val cached = objModuleByName[packageName]
if (cached != null && cached.kotlinModule == kaModule) return cached.compiledObjModule
val objModuleStub = createObjModuleStub(packageName, packageSymbol, kaModule)
val compiledObjModule = registerObjModuleContent(packageSymbol, objModuleStub, kaModule)
objModuleByName[packageName] = compiledObjModule and kaModule
return compiledObjModule
}
private fun KaSession.registerObjModuleContent(
packageSymbol: KaPackageSymbol,
objModuleStub: ObjModuleStub,
kaModule: KaModule,
): CompiledObjModule {
val extensionProperties = packageSymbol.packageScope.callables
.filterIsInstance<KaPropertySymbol>()
.filter { it.isExtension }
.filter { it.containingModule == kaModule }
.mapNotNull { propertySymbol ->
propertySymbol.receiverType?.expandedSymbol
?.takeIf { receiverClassSymbol -> isEntityInterface(receiverClassSymbol) && !isEntityBuilderInterface(receiverClassSymbol) }
?.let { propertySymbol to it }
}
return objModuleStub.registerContent(this@registerObjModuleContent, extensionProperties.toList())
}
private fun KaSession.createObjModuleStub(
packageName: String,
packageSymbol: KaPackageSymbol,
kaModule: KaModule,
): ObjModuleStub {
val module = CompiledObjModuleImpl(packageName)
val types = packageSymbol.packageScope.declarations
.filterIsInstance<KaClassSymbol>()
.filter(::isEntityInterface)
.filter { it.containingModule == kaModule }
.sortedBy { it.name }
.map { it to createObjTypeStub(it, module) }
.toList()
val moduleAbstractTypes = moduleAbstractTypes()
return ObjModuleStub(module, types, moduleAbstractTypes, kaModule)
}
private fun KaSession.getObjClass(entityInterface: KaClassSymbol): ObjClass<*> {
val containingPackage = getPackageSymbol(entityInterface) ?: error("Cannot find package for ${entityInterface.name ?: entityInterface}")
val objModule = getObjModule(entityInterface.packageName, containingPackage, entityInterface.containingModule)
val entityInterfaceName = entityInterface.name?.identifier ?: error("Too many errors")
return objModule.types.find { it.name == entityInterfaceName } ?: error("Cannot find $entityInterfaceName in $objModule")
}
private inner class ObjModuleStub(
val module: CompiledObjModuleImpl,
// TODO: storing KaClassSymbol is unsafe, ObjModuleStub should inherit from KaLifetimeOwner
val types: List<Pair<KaClassSymbol, ObjClassImpl<Obj>>>,
val moduleAbstractTypes: List<KaClassSymbol>,
val kaModule: KaModule,
) /* : KaLifetimeOwner */ {
@RequiresReadLock
fun registerContent(kaSession: KaSession, extProperties: List<Pair<KaPropertySymbol, KaClassSymbol>>): CompiledObjModule =
with(kaSession) {
var extPropertyId = 0
for ((classSymbol, objType) in types) {
val properties = classSymbol.declaredMemberScope.callables
.filterIsInstance<KaPropertySymbol>().toList()
.filter { it.containingModule == kaModule }
for ((propertyId, propertySymbol) in properties.withIndex()) {
val kind = computeKind(propertySymbol)
if (kind !is ObjProperty.ValueKind.Computable ||
// We can't simply skip all `Computable` because some of them are SymbolicIds
// propertySymbol.overriddenDescriptors.isNotEmpty()
propertySymbol.allOverriddenSymbols.any()
) {
objType.addField(createOwnProperty(propertySymbol, propertyId, objType))
}
}
classSymbol.superTypes.forEach { superType ->
val superSymbol = superType.expandedSymbol
if (superSymbol is KaClassSymbol && isEntityInterface(superSymbol)) {
val superClass = findObjClass(superSymbol)
objType.addSuperType(superClass)
}
}
module.addType(objType)
}
registerModuleAbstractTypes()
for ((extProperty, receiverClass) in extProperties) {
module.addExtension(createExtProperty(extProperty, receiverClass, extPropertyId++))
}
module
}
private fun KaSession.registerModuleAbstractTypes() {
for (abstractTypeClassSymbol in moduleAbstractTypes) {
val javaClassFqn = abstractTypeClassSymbol.javaClassFqn
val superTypes = abstractTypeClassSymbol.superTypesJavaFqns
val blobType = ValueType.Blob<Any>(javaClassFqn, superTypes)
val inheritors = mutableListOf<ValueType.JvmClass<*>>()
val inheritorsKtClasses = inheritors(abstractTypeClassSymbol, javaPsiFacade, allProjectScope)
for (inheritor in inheritorsKtClasses) {
analyze(inheritor) {
val inheritorSymbol = inheritor.namedClassSymbol
if (inheritorSymbol != null && inheritorSymbol.packageName == module.name && inheritorSymbol.containingModule == kaModule) {
val inheritorValueType = classSymbolToValueType(inheritorSymbol, hashMapOf(javaClassFqn to blobType), true)
inheritors.add(inheritorValueType)
}
}
}
if (inheritors.isNotEmpty()) {
module.addAbstractType(ValueType.AbstractClass<Any>(javaClassFqn, superTypes, inheritors))
}
}
}
private fun KaSession.createOwnProperty(
property: KaPropertySymbol,
propertyId: Int,
receiver: ObjClassImpl<Obj>,
): OwnProperty<Obj, *> {
val valueType = convertType(property.returnType, hashMapOf(), isChild(property))
return OwnPropertyImpl(receiver, property.name.identifier, valueType, computeKind(property),
property.isAnnotatedBy(WorkspaceModelDefaults.OPEN_ANNOTATION.classId), !property.isVal, false, false,
propertyId, property.isAnnotatedBy(WorkspaceModelDefaults.EQUALS_BY_ANNOTATION.classId),
property.sourcePsiSafe())
}
private fun KaSession.createExtProperty(
extProperty: KaPropertySymbol,
receiverClass: KaClassSymbol,
extPropertyId: Int,
): ExtProperty<*, *> {
val valueType = convertType(extProperty.returnType, hashMapOf(), false)
val propertyAnnotations = extProperty.getter?.annotations?.mapNotNull { annotation ->
annotation.classId?.asSingleFqName()?.let {
ObjAnnotationImpl(it.asString(), it.pathSegments().map { segment -> segment.asString() })
}
} ?: emptyList()
return ExtPropertyImpl(findObjClass(receiverClass), extProperty.name.identifier, valueType, computeKind(extProperty),
extProperty.isAnnotatedBy(WorkspaceModelDefaults.OPEN_ANNOTATION.classId), !extProperty.isVal, false, module,
extPropertyId, propertyAnnotations, extProperty.sourcePsiSafe())
}
private fun KaSession.convertType(
type: KaType,
knownTypes: MutableMap<String, ValueType.Blob<*>>,
hasChildAnnotation: Boolean,
): ValueType<*> {
if (type !is KaClassType) error("$type is not a class")
if (type.nullability == KaTypeNullability.NULLABLE) {
val nonNullableType = type.withNullability(KaTypeNullability.NON_NULLABLE)
return ValueType.Optional(convertType(nonNullableType, knownTypes, hasChildAnnotation))
}
val symbol = type.expandedSymbol
if (symbol is KaClassSymbol) {
val kotlinDefaultValueType = ObjTypeConverter[type.symbol.classId]
if (kotlinDefaultValueType != null) return kotlinDefaultValueType
if (type.isSubtypeOf(StandardClassIds.Collection)) {
val typeArguments = type.typeArguments.mapNotNull { it.type }
val genericType = convertType(typeArguments.first(), knownTypes, hasChildAnnotation)
when {
type.isSubtypeOf(StandardClassIds.List) -> return ValueType.List(genericType)
type.isSubtypeOf(StandardClassIds.Set) -> return ValueType.Set(genericType)
else -> return unsupportedType(type.toString())
}
}
if (type.isSubtypeOf(StandardClassIds.Map)) {
val (keyType, valueType) = type.typeArguments.mapNotNull { it.type }
val convertedKeyType = convertType(keyType, knownTypes, hasChildAnnotation)
val convertedValueType = convertType(valueType, knownTypes, hasChildAnnotation)
return ValueType.Map(convertedKeyType, convertedValueType)
}
if (symbol.classKind == KaClassKind.INTERFACE && type.isSubtypeOf(WorkspaceModelDefaults.WORKSPACE_ENTITY.classId)) {
// TODO IJPL-600 Replace @Child annotation to @Parent annotation and not for the type, but for the field
return ValueType.ObjRef(isChild(type) || hasChildAnnotation, findObjClass(symbol))
}
return classSymbolToValueType(symbol, knownTypes, processAbstractTypes)
}
return unsupportedType(type.toString())
}
private fun KaSession.findObjClass(classSymbol: KaClassSymbol): ObjClass<*> {
if (classSymbol.packageOrDie.asString() == module.name) {
return types.find { it.first.classId == classSymbol.classId }?.second
?: error("Cannot find ${classSymbol.name} in $module")
}
return getObjClass(classSymbol)
}
private fun KaSession.classSymbolToValueType(
classSymbol: KaClassSymbol,
knownTypes: MutableMap<String, ValueType.Blob<*>>,
processAbstractTypes: Boolean,
): ValueType.JvmClass<*> {
val javaClassFqn = classSymbol.javaClassFqn
val superTypesJavaFqns = superTypesJavaFqns(classSymbol, javaPsiFacade, allProjectScope)
val blobType = ValueType.Blob<Any>(javaClassFqn, superTypesJavaFqns)
if (knownTypes.containsKey(javaClassFqn) || isBlob(classSymbol)) {
return blobType
}
knownTypes[javaClassFqn] = blobType
return when {
classSymbol.classKind == KaClassKind.OBJECT -> ValueType.Object<Any>(javaClassFqn, superTypesJavaFqns,
createProperties(classSymbol, knownTypes).toList())
classSymbol.classKind == KaClassKind.ENUM_CLASS -> {
val enumEntries = classSymbol.staticMemberScope.callables.filterIsInstance<KaEnumEntrySymbol>().map { it.name.asString() }
ValueType.Enum<Any>(javaClassFqn, superTypesJavaFqns, enumEntries.toList(),
createProperties(classSymbol, knownTypes).asSequence().withoutEnumFields().toList())
}
classSymbol.modality == KaSymbolModality.SEALED && classSymbol is KaNamedClassSymbol -> {
val subclasses = classSymbol.sealedClassInheritors
.map { convertType(it.defaultType, knownTypes, false) as ValueType.JvmClass<*> }
ValueType.AbstractClass<Any>(javaClassFqn, superTypesJavaFqns, subclasses)
}
classSymbol.classKind == KaClassKind.INTERFACE || classSymbol.modality == KaSymbolModality.ABSTRACT -> {
if (!processAbstractTypes) {
throw IncorrectObjInterfaceException("$javaClassFqn is abstract type. Abstract types are not supported in generator")
}
val inheritors = inheritors(classSymbol, javaPsiFacade, allProjectScope)
.mapNotNull { ktClassOrObject ->
analyze(ktClassOrObject) {
val inheritorSymbol = ktClassOrObject.namedClassSymbol
if (inheritorSymbol != null) {
classSymbolToValueType(inheritorSymbol, knownTypes, processAbstractTypes)
}
else null
}
}
ValueType.AbstractClass<Any>(javaClassFqn, superTypesJavaFqns, inheritors)
}
else -> ValueType.FinalClass<Any>(javaClassFqn, superTypesJavaFqns, createProperties(classSymbol, knownTypes).toList())
}
}
private fun KaSession.createProperties(classSymbol: KaClassSymbol, knownTypes: MutableMap<String, ValueType.Blob<*>>) =
classSymbol.memberScope.callables
.filterIsInstance<KaPropertySymbol>()
.sortedBy { symbol -> symbol.name }
.map { propertySymbol ->
propertySymbol.location
ValueType.ClassProperty(propertySymbol.name.identifier, convertType(propertySymbol.returnType, knownTypes, false))
}
}
// TODO: Kirill does not understand why it exists
private fun Sequence<ValueType.ClassProperty<*>>.withoutEnumFields() = filterNot { it.name == "name" || it.name == "ordinal" }
}
@@ -0,0 +1,49 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k2.metaModel
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceMetaModelProvider
import com.intellij.openapi.module.Module
import com.intellij.workspaceModel.codegen.deft.meta.CompiledObjModule
import org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisFromWriteAction
import org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisOnEdt
import org.jetbrains.kotlin.analysis.api.permissions.allowAnalysisFromWriteAction
import org.jetbrains.kotlin.analysis.api.permissions.allowAnalysisOnEdt
import org.jetbrains.kotlin.idea.base.projectStructure.toKaSourceModuleForProduction
import org.jetbrains.kotlin.idea.base.projectStructure.toKaSourceModuleForTest
import org.jetbrains.kotlin.psi.KtClass
internal class WorkspaceMetaModelProviderImpl : WorkspaceMetaModelProvider {
@OptIn(KaAllowAnalysisFromWriteAction::class, KaAllowAnalysisOnEdt::class)
override fun loadObjModules(
ktClasses: HashMap<String, KtClass>,
module: Module,
processAbstractTypes: Boolean,
isTestSourceFolder: Boolean,
): List<CompiledObjModule> {
val packages = ktClasses.values.mapTo(LinkedHashSet()) { it.containingKtFile.packageFqName.asString() }
val metaModelProvider = WorkspaceMetaModelBuilder(
processAbstractTypes,
module.project
)
val compiledObjModule = allowAnalysisOnEdt {
allowAnalysisFromWriteAction {
packages
.filter { it != "" }
.mapNotNull { packageName ->
if (!isTestSourceFolder) {
module.toKaSourceModuleForProduction()
}
else {
module.toKaSourceModuleForTest()
}
?.let { kaModule ->
metaModelProvider.getObjModule(packageName, kaModule)
}
}
}
}
return compiledObjModule
}
}
@@ -0,0 +1,10 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k2
import com.intellij.devkit.workspaceModel.AbstractAllIntellijEntitiesGenerationTest
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode
class AllIntellijEntitiesGenerationTest : AbstractAllIntellijEntitiesGenerationTest() {
override val pluginMode: KotlinPluginMode
get() = KotlinPluginMode.K2
}
@@ -0,0 +1,10 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.k2
import com.intellij.devkit.workspaceModel.AbstractEntityCodeGenTest
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode
class EntityCodeGenTest : AbstractEntityCodeGenTest() {
override val pluginMode: KotlinPluginMode
get() = KotlinPluginMode.K2
}
@@ -1,10 +1,13 @@
<idea-plugin package="com.intellij.devkit.workspaceModel">
<dependencies>
<plugin id="com.intellij.java"/>
<plugin id="org.jetbrains.kotlin"/>
<module name="intellij.devkit.core"/>
</dependencies>
<resource-bundle>messages.DevKitWorkspaceModelBundle</resource-bundle>
<actions>
<group id="WorkspaceModel" popup="true">
<action id="WorkspaceEntitiesJsonClipboard" internal="true"
@@ -11,9 +11,9 @@ private const val BUNDLE_FQN = "messages.DevKitWorkspaceModelBundle"
object DevKitWorkspaceModelBundle {
private val BUNDLE = DynamicBundle(DevKitWorkspaceModelBundle::class.java, BUNDLE_FQN)
fun message(@NonNls @PropertyKey(resourceBundle = BUNDLE_FQN) key: String, vararg params: Any): @Nls String {
@Nls
fun message(@NonNls @PropertyKey(resourceBundle = BUNDLE_FQN) key: String, vararg params: Any): String {
return BUNDLE.getMessage(key, *params)
}
}
}
@@ -4,13 +4,14 @@ package com.intellij.devkit.workspaceModel.codegen.writer
import com.intellij.application.options.CodeStyle
import com.intellij.devkit.workspaceModel.CodegenJarLoader
import com.intellij.devkit.workspaceModel.DevKitWorkspaceModelBundle
import com.intellij.devkit.workspaceModel.codegen.writer.CodeWriter.addGeneratedObjModuleFile
import com.intellij.devkit.workspaceModel.metaModel.WorkspaceMetaModelProvider
import com.intellij.devkit.workspaceModel.metaModel.impl.WorkspaceMetaModelProviderImpl
import com.intellij.lang.ASTNode
import com.intellij.notification.NotificationGroupManager
import com.intellij.notification.NotificationType
import com.intellij.openapi.application.ex.ApplicationManagerEx
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.command.executeCommand
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.DumbService
@@ -21,7 +22,7 @@ import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.*
import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil
import com.intellij.util.concurrency.annotations.RequiresEdt
import com.intellij.util.containers.FactoryMap
@@ -31,7 +32,7 @@ import com.intellij.workspaceModel.codegen.engine.*
import kotlinx.coroutines.delay
import org.jetbrains.io.JsonReaderEx
import org.jetbrains.io.JsonUtil
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.children
@@ -42,6 +43,7 @@ import java.util.*
import java.util.jar.Manifest
import kotlin.time.Duration.Companion.seconds
private val LOG = logger<CodeWriter>()
object CodeWriter {
@@ -51,7 +53,7 @@ object CodeWriter {
processAbstractTypes: Boolean, explicitApiEnabled: Boolean,
isTestSourceFolder: Boolean, isTestModule: Boolean,
targetFolderGenerator: () -> VirtualFile?,
existingTargetFolder: () -> VirtualFile?
existingTargetFolder: () -> VirtualFile?,
) {
val sourceFilePerObjModule = HashMap<String, VirtualFile>()
val ktClasses = HashMap<String, KtClass>()
@@ -59,15 +61,23 @@ object CodeWriter {
if (it.extension == "kt") {
val ktFile = PsiManager.getInstance(project).findFile(it) as? KtFile?
ktFile?.declarations?.filterIsInstance<KtClass>()?.filter { clazz -> clazz.name != null }?.forEach { clazz ->
val fqName = clazz.fqName!!.asString()
val objModuleName = fqName.replace(clazz.name!!, "").substringBeforeLast(".")
ktFile?.declarations
?.filterIsInstance<KtClass>()
?.filter { it.name != null }
?.forEach { ktClass ->
val fqName = ktClass.fqName!!.asString()
val objModuleName = fqName
.replace(ktClass.name!!, "")
.substringBeforeLast(".")
/* We find one virtual file for each module. This is necessary to find the relative path for the generated GeneratedObjModuleFile.
See [addGeneratedObjModuleFile] method */
sourceFilePerObjModule[objModuleName] = it
ktClasses[fqName] = clazz
}
/**
* We find one virtual file for each module.
* This is necessary to find the relative path for the generated GeneratedObjModuleFile.
* See [addGeneratedObjModuleFile] method.
*/
sourceFilePerObjModule[objModuleName] = it
ktClasses[fqName] = ktClass
}
}
return@processFilesRecursively true
}
@@ -83,11 +93,12 @@ object CodeWriter {
return
}
CommandProcessor.getInstance().executeCommand(project, Runnable {
executeCommand(project, DevKitWorkspaceModelBundle.message("command.name.generate.code.for.workspace.entities.in", sourceFolder.name)) {
val title = DevKitWorkspaceModelBundle.message("progress.title.generating.code")
ApplicationManagerEx.getApplicationEx().runWriteActionWithCancellableProgressInDispatchThread(title, project, null) { indicator ->
indicator.text = DevKitWorkspaceModelBundle.message("progress.text.collecting.classes.metadata")
val objModules = loadObjModules(ktClasses, module, processAbstractTypes, isTestSourceFolder)
val metaLoader: WorkspaceMetaModelProvider = service<WorkspaceMetaModelProvider>()
val objModules = metaLoader.loadObjModules(ktClasses, module, processAbstractTypes, isTestSourceFolder)
val results = generate(codeGenerator, objModules, explicitApiEnabled, isTestModule)
val generatedCode = results.flatMap { it.generatedCode }
@@ -120,12 +131,6 @@ object CodeWriter {
indicator.text = DevKitWorkspaceModelBundle.message("progress.text.writing.code")
indicator.isIndeterminate = false
val settings = CodeStyle.getSettings(project)
val kotlinSettings = settings.getCustomSettings(KotlinCodeStyleSettings::class.java)
val oldValue = kotlinSettings.NAME_COUNT_TO_USE_STAR_IMPORT
kotlinSettings.NAME_COUNT_TO_USE_STAR_IMPORT = Int.MAX_VALUE
CodeStyleSettingsManager.getInstance(project).notifyCodeStyleSettingsChanged()
generatedCode.forEachIndexed { i, code ->
val psiFactory = KtPsiFactory(project)
indicator.fraction = 0.15 + 0.1 * i / generatedCode.size
@@ -146,40 +151,47 @@ object CodeWriter {
}
}
indicator.text = DevKitWorkspaceModelBundle.message("progress.text.formatting.generated.code")
importsByFile.forEach { (file, imports) ->
addImports(file, imports.set)
addImports(file, imports)
}
generatedFiles.withoutBigFiles().forEachIndexed { i, file ->
indicator.fraction = 0.25 + 0.7 * i / generatedFiles.size
CodeStyleManager.getInstance(project).reformat(file)
}
topLevelDeclarations.entrySet().forEach { (file, placeAndDeclarations) ->
val addedElements = ArrayList<KtDeclaration>()
for ((place, declarations) in placeAndDeclarations) {
var nextPlace: PsiElement = place
val newElements = ArrayList<KtDeclaration>()
for (declaration in declarations) {
val added = file.addAfter(declaration, nextPlace) as KtDeclaration
newElements.add(added)
nextPlace = added
CodeStyle.runWithLocalSettings(project, CodeStyle.getSettings(project)) { localSettings ->
localSettings.setUpCodeStyle()
generatedFiles.withoutBigFiles().forEachIndexed { i, file ->
indicator.fraction = 0.25 + 0.7 * i / generatedFiles.size
CodeStyleManager.getInstance(project).reformat(file)
file.apiFileNameForImplFile?.let { ktClasses[it] }?.containingKtFile?.let { apiFile -> copyHeaderComment(apiFile, file) }
}
topLevelDeclarations.entrySet().forEach { (file, placeAndDeclarations) ->
val addedElements = ArrayList<KtDeclaration>()
for ((place, declarations) in placeAndDeclarations) {
var nextPlace: PsiElement = place
val newElements = ArrayList<KtDeclaration>()
for (declaration in declarations) {
val added = file.addAfter(declaration, nextPlace) as KtDeclaration
newElements.add(added)
nextPlace = added
}
addGeneratedRegionStartComment(file, newElements.first())
addGeneratedRegionEndComment(file, newElements.last())
addedElements.addAll(newElements)
}
addGeneratedRegionStartComment(file, newElements.first())
addGeneratedRegionEndComment(file, newElements.last())
addedElements.addAll(newElements)
}
}
val filesWithGeneratedRegions = ktClasses.values.groupBy { it.containingFile }.toList()
filesWithGeneratedRegions.forEachIndexed { i, (file, classes) ->
indicator.fraction = 0.95 + 0.05 * i / filesWithGeneratedRegions.size
reformatCodeInGeneratedRegions(file, classes.mapNotNull { it.body?.node } + listOf(file.node))
}
val filesWithGeneratedRegions = ktClasses.values.groupBy { it.containingFile }.toList()
filesWithGeneratedRegions.forEachIndexed { i, (file, classes) ->
indicator.fraction = 0.95 + 0.05 * i / filesWithGeneratedRegions.size
reformatCodeInGeneratedRegions(file, classes.mapNotNull { it.body?.node } + listOf(file.node))
}
kotlinSettings.NAME_COUNT_TO_USE_STAR_IMPORT = oldValue
CodeStyleSettingsManager.getInstance(project).notifyCodeStyleSettingsChanged()
}
}
}, DevKitWorkspaceModelBundle.message("command.name.generate.code.for.workspace.entities.in", sourceFolder.name), null)
}
}
private fun CodeStyleSettings.setUpCodeStyle() {
val kotlinCustomSettings = this.kotlinCustomSettings
kotlinCustomSettings.NAME_COUNT_TO_USE_STAR_IMPORT = Int.MAX_VALUE
}
// Documentation for IndexNotReadyException says that it's enough to run completeJustSubmittedTasks only once
@@ -205,7 +217,8 @@ object CodeWriter {
val message = if (apiVersionFromDownloadedJar == CodegenApiVersion.UNKNOWN_VERSION || apiVersionInDevkit > apiVersionFromDownloadedJar) {
DevKitWorkspaceModelBundle.message("notification.workspace.incompatible.codegen.api.versions.content.newer", apiVersionInDevkit, apiVersionFromDownloadedJar)
} else {
}
else {
DevKitWorkspaceModelBundle.message("notification.workspace.incompatible.codegen.api.versions.content.older", apiVersionInDevkit, apiVersionFromDownloadedJar)
}
@@ -248,7 +261,8 @@ object CodeWriter {
val apiVersion: String?
try {
apiVersion = readApiVersionFromFile(fileAbsolutePath)
} catch (e: IOException) {
}
catch (e: IOException) {
LOG.info("Failed to read codegen-api version from file \"$fileAbsolutePath\": " + e.message)
return CodegenApiVersion.UNKNOWN_VERSION
}
@@ -256,18 +270,10 @@ object CodeWriter {
return apiVersion ?: CodegenApiVersion.UNKNOWN_VERSION
}
private fun loadObjModules(ktClasses: HashMap<String, KtClass>, module: Module, processAbstractTypes: Boolean, isTestSourceFolder: Boolean): List<CompiledObjModule> {
val packages = ktClasses.values.mapTo(LinkedHashSet()) { it.containingKtFile.packageFqName.asString() }
val metaModelProvider: WorkspaceMetaModelProvider = WorkspaceMetaModelProviderImpl(
processAbstractTypes = processAbstractTypes,
module.project
)
return packages.filter { it != "" }.map { metaModelProvider.getObjModule(it, module, isTestSourceFolder) }
}
private fun generate(codeGenerator: CodeGenerator, objModules: List<CompiledObjModule>,
explicitApiEnabled: Boolean, isTestModule: Boolean): List<GenerationResult> {
private fun generate(
codeGenerator: CodeGenerator, objModules: List<CompiledObjModule>,
explicitApiEnabled: Boolean, isTestModule: Boolean,
): List<GenerationResult> {
val generatorSettings = GeneratorSettings(explicitApiEnabled = explicitApiEnabled, testModeEnabled = isTestModule)
val entitiesImplementations = objModules.map { codeGenerator.generateEntitiesImplementation(it, generatorSettings) }
val metadataStorageImplementation = codeGenerator.generateMetadataStoragesImplementation(objModules, generatorSettings)
@@ -303,10 +309,12 @@ object CodeWriter {
filesToRemove.forEach { it.delete(CodeWriter) }
}
private fun addGeneratedObjModuleFile(code: ObjModuleFileGeneratedCode, generatedFiles: MutableList<KtFile>,
project: Project, sourceFolder: VirtualFile, genFolder: VirtualFile,
sourceFilePerObjModule: Map<String, VirtualFile>,
importsByFile: MutableMap<KtFile, Imports>, psiFactory: KtPsiFactory) {
private fun addGeneratedObjModuleFile(
code: ObjModuleFileGeneratedCode, generatedFiles: MutableList<KtFile>,
project: Project, sourceFolder: VirtualFile, genFolder: VirtualFile,
sourceFilePerObjModule: Map<String, VirtualFile>,
importsByFile: MutableMap<KtFile, Imports>, psiFactory: KtPsiFactory,
) {
val packageFqnName = code.objModuleName
val sourceFile = sourceFilePerObjModule[packageFqnName]!!
@@ -323,10 +331,12 @@ object CodeWriter {
importsByFile[addedFile] = implImports
}
private fun addGeneratedObjClassFile(code: ObjClassGeneratedCode, generatedFiles: MutableList<KtFile>,
project: Project, sourceFolder: VirtualFile, genFolder: VirtualFile,
ktClasses: Map<String, KtClass>, importsByFile: MutableMap<KtFile, Imports>,
topLevelDeclarations: MultiMap<KtFile, Pair<KtClass, List<KtDeclaration>>>, psiFactory: KtPsiFactory) {
private fun addGeneratedObjClassFile(
code: ObjClassGeneratedCode, generatedFiles: MutableList<KtFile>,
project: Project, sourceFolder: VirtualFile, genFolder: VirtualFile,
ktClasses: Map<String, KtClass>, importsByFile: MutableMap<KtFile, Imports>,
topLevelDeclarations: MultiMap<KtFile, Pair<KtClass, List<KtDeclaration>>>, psiFactory: KtPsiFactory,
) {
if (code.target.name in SKIPPED_TYPES) return
@@ -349,7 +359,6 @@ object CodeWriter {
val implPackageFqnName = "${apiFile.packageFqName.asString()}.impl"
val implImports = Imports(implPackageFqnName)
val implFile = psiFactory.createFile("${code.target.name}Impl.kt", implImports.findAndRemoveFqns(implementationClassText))
copyHeaderComment(apiFile, implFile)
apiClass.containingKtFile.importDirectives.mapNotNull { it.importPath }.forEach { import ->
implImports.add(import.pathStr)
}
@@ -381,21 +390,20 @@ object CodeWriter {
}
}
private fun addImports(file: KtFile, imports: Collection<String>) {
private fun addImports(file: KtFile, imports: Imports) {
val psiFactory = KtPsiFactory(file.project)
val importList = file.importList ?: error("no imports in ${file.name}")
val existingImports = importList.imports.mapNotNullTo(HashSet()) { it.importedFqName?.asString() }
imports.sorted().filterNot { it in existingImports }.forEach { imported ->
val place = importList.imports.find { imported < (it.importedFqName?.asString() ?: "") }
val importDirective = psiFactory.createImportDirective(ImportPath.fromString(imported))
if (place != null) {
val added = importList.addBefore(importDirective, place)
importList.addAfter(psiFactory.createNewLine(), added)
}
else {
val added = importList.add(importDirective)
importList.addBefore(psiFactory.createNewLine(), added)
}
importList.imports.asSequence().mapNotNull { it.importPath?.pathStr }.forEach { imports.add(it) }
if (importList.children.isNotEmpty()) {
importList.deleteChildRange(importList.firstChild, importList.lastChild)
}
imports.imports.sorted().forEach {
val importDirective = psiFactory.createImportDirective(ImportPath.fromString(it))
importList.add(importDirective)
importList.add(psiFactory.createNewLine())
}
if (imports.isNotEmpty()) {
importList.lastChild.delete()
}
}
@@ -454,13 +462,19 @@ object CodeWriter {
if (child.isGeneratedRegionStart) {
regionStart = if (child.treePrev?.elementType == KtTokens.WHITE_SPACE) child.treePrev else child
}
else if (regionStart != null && child.isGeneratedRegionEnd) {
generatedRegions.add(regionStart!! to child)
else if (child.isGeneratedRegionEnd) {
regionStart?.let { generatedRegions.add(it to child) }
}
}
return generatedRegions
}
private val KtFile.apiFileNameForImplFile: String?
get() {
val packageName = packageFqName.asString()
if (!packageName.endsWith(".impl") || !name.endsWith("Impl.kt")) return null
return "${packageFqName.asString().dropLast(4)}${name.dropLast(7)}"
}
private const val GENERATED_REGION_START = "//region generated code"
@@ -492,9 +506,8 @@ object CodeWriter {
const val UNKNOWN_VERSION = "unknown version"
}
//Function was added because CodeStyleManager throws an exception for big MetadataStorageImpl files
// This function was added because CodeStyleManager throws an exception for big MetadataStorageImpl files
private fun Iterable<KtFile>.withoutBigFiles(): Iterable<KtFile> {
return filterNot { it.name == GENERATED_METADATA_STORAGE_FILE }
}
}
@@ -19,7 +19,13 @@ private val packagesImportedByDefault = setOf(
)
class Imports(private val scopeFqn: String?) {
val set = mutableSetOf<String>()
fun isNotEmpty(): Boolean = set.isNotEmpty() || wildcardImports.isNotEmpty()
val imports: Set<String>
get() = set + wildcardImports.map { "$it.*" }
private val set = mutableSetOf<String>()
private val wildcardImports = mutableSetOf<String>()
fun findAndRemoveFqns(str: String): String {
val res = StringBuilder()
@@ -43,11 +49,28 @@ class Imports(private val scopeFqn: String?) {
}
fun add(import: String) {
set.add(import)
val importSegments = import.split('.')
if (importSegments.size < 2) set.add(import)
else {
val (packageName, name) = import
.split('.')
.let {
it.dropLast(1).joinToString(".") to it.last()
}
add(packageName, name)
}
}
private fun String.packageRegex() = Regex("^${replace(".", "\\.")}\\.[^.]*$")
private fun add(packageName: String, name: String) {
if (packageName != scopeFqn && packageName !in packagesImportedByDefault) {
if (packageName == scopeFqn || packageName in packagesImportedByDefault || packageName in wildcardImports) {
return
} else if (name == "*") {
val packageRegex = packageName.packageRegex()
set.removeIf { it.matches(packageRegex) }
wildcardImports.add(packageName)
} else {
set.add("$packageName.$name")
}
}
@@ -7,7 +7,7 @@ import com.intellij.analysis.problemsView.ProblemsCollector
import com.intellij.analysis.problemsView.ProblemsProvider
import com.intellij.analysis.problemsView.toolWindow.ProblemsViewToolWindowUtils.selectProjectErrorsTab
import com.intellij.codeHighlighting.HighlightDisplayLevel
import com.intellij.devkit.workspaceModel.metaModel.ObjMetaElementWithSource
import com.intellij.devkit.workspaceModel.metaModel.ObjMetaElementWithPsi
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
@@ -18,7 +18,6 @@ import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.util.startOffset
import com.intellij.workspaceModel.codegen.engine.GenerationProblem
import com.intellij.workspaceModel.codegen.engine.ProblemLocation
import org.jetbrains.kotlin.resolve.source.getPsi
import javax.swing.Icon
@Service(Service.Level.PROJECT)
@@ -49,11 +48,10 @@ class WorkspaceCodegenProblemsProvider(override val project: Project): ProblemsP
}
private fun GenerationProblem.toProblem(): WorkspaceModelCodeGenerationProblem {
val sourceElement = when (val problemLocation = location) {
is ProblemLocation.Class -> (problemLocation.objClass as ObjMetaElementWithSource).sourceElement
is ProblemLocation.Property -> (problemLocation.property as ObjMetaElementWithSource).sourceElement
}
val psiElement = sourceElement.getPsi() ?: return WorkspaceModelCodeGenerationProblem(this)
val psiElement = when (val problemLocation = location) {
is ProblemLocation.Class -> (problemLocation.objClass as ObjMetaElementWithPsi).sourcePsi
is ProblemLocation.Property -> (problemLocation.property as ObjMetaElementWithPsi).sourcePsi
} ?: return WorkspaceModelCodeGenerationProblem(this)
val psiToHighlight = (psiElement as? PsiNameIdentifierOwner)?.nameIdentifier ?: psiElement
val file = psiToHighlight.containingFile.virtualFile
val document = FileDocumentManager.getInstance().getDocument(file) ?: return WorkspaceModelCodeGenerationProblem(this)
@@ -84,4 +82,3 @@ class WorkspaceCodegenProblemsProvider(override val project: Project): ProblemsP
override val column: Int
) : WorkspaceModelCodeGenerationProblem(originalProblem), FileProblem
}
@@ -0,0 +1,15 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.metaModel
import com.intellij.psi.PsiElement
import com.intellij.workspaceModel.codegen.deft.meta.ValueType
class IncorrectObjInterfaceException(errorMessage: String) : RuntimeException(errorMessage)
interface ObjMetaElementWithPsi {
val sourcePsi: PsiElement?
}
fun unsupportedType(type: String?): ValueType<*> {
throw IncorrectObjInterfaceException("Unsupported type '$type'")
}
@@ -1,16 +1,15 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.metaModel
import com.intellij.openapi.module.Module
import com.intellij.workspaceModel.codegen.deft.meta.CompiledObjModule
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.psi.KtClass
interface WorkspaceMetaModelProvider {
fun getObjModule(packageName: String, module: Module, isTestSourceFolder: Boolean): CompiledObjModule
fun loadObjModules(
ktClasses: HashMap<String, KtClass>,
module: Module,
processAbstractTypes: Boolean,
isTestSourceFolder: Boolean,
): List<CompiledObjModule>
}
class IncorrectObjInterfaceException(errorMessage: String): RuntimeException(errorMessage)
interface ObjMetaElementWithSource {
val sourceElement: SourceElement
}
@@ -0,0 +1,32 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.metaModel
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.annotations.Abstract
import com.intellij.platform.workspace.storage.annotations.Child
import com.intellij.platform.workspace.storage.annotations.Default
import com.intellij.platform.workspace.storage.annotations.Open
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.StandardClassIds
enum class WorkspaceModelDefaults(val fqName: FqName, val classId: ClassId) {
DEFAULT_ANNOTATION(FqName(Default::class.qualifiedName!!), ClassId.topLevel(FqName(Default::class.qualifiedName!!))),
OPEN_ANNOTATION(FqName(Open::class.qualifiedName!!), ClassId.topLevel(FqName(Open::class.qualifiedName!!))),
ABSTRACT_ANNOTATION(FqName(Abstract::class.qualifiedName!!), ClassId.topLevel(FqName(Abstract::class.qualifiedName!!))),
CHILD_ANNOTATION(FqName(Child::class.qualifiedName!!), ClassId.topLevel(FqName(Child::class.qualifiedName!!))),
EQUALS_BY_ANNOTATION(FqName(EqualsBy::class.qualifiedName!!), ClassId.topLevel(FqName(EqualsBy::class.qualifiedName!!))),
LIST_INTERFACE(StandardNames.FqNames.list, StandardClassIds.List),
SET_INTERFACE(StandardNames.FqNames.set, StandardClassIds.Set),
MAP_INTERFACE(StandardNames.FqNames.map, StandardClassIds.Map),
WORKSPACE_ENTITY(FqName(WorkspaceEntity::class.qualifiedName!!), ClassId.topLevel(FqName(WorkspaceEntity::class.qualifiedName!!))),
ENTITY_SOURCE(FqName(EntitySource::class.qualifiedName!!), ClassId.topLevel(FqName(EntitySource::class.qualifiedName!!))),
VIRTUAL_FILE_URL(FqName(VirtualFileUrl::class.qualifiedName!!), ClassId.topLevel(FqName(VirtualFileUrl::class.qualifiedName!!))),
SYMBOLIC_ENTITY_ID(FqName(SymbolicEntityId::class.qualifiedName!!), ClassId.topLevel(FqName(SymbolicEntityId::class.qualifiedName!!))),
ENTITY_POINTER(FqName(EntityPointer::class.qualifiedName!!), ClassId.topLevel(FqName(EntityPointer::class.qualifiedName!!)))
;
}
@@ -1,9 +1,9 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.metaModel.impl
import com.intellij.devkit.workspaceModel.metaModel.ObjMetaElementWithSource
import com.intellij.devkit.workspaceModel.metaModel.ObjMetaElementWithPsi
import com.intellij.psi.PsiElement
import com.intellij.workspaceModel.codegen.deft.meta.*
import org.jetbrains.kotlin.descriptors.SourceElement
private val fieldObjType = ObjTypeImpl<ObjProperty<*, *>>()
@@ -15,8 +15,8 @@ sealed class ObjPropertyBase<T : Obj, V>(
override val open: Boolean,
override val mutable: Boolean,
override val content: Boolean,
override val sourceElement: SourceElement
) : ObjProperty<T, V>, ObjMetaElementWithSource {
override val sourcePsi: PsiElement?
) : ObjProperty<T, V>, ObjMetaElementWithPsi {
private val mutableOverrides: MutableList<ObjProperty<T, V>> = ArrayList()
private val mutableOverriddenBy: MutableList<ObjProperty<T, V>> = ArrayList()
@@ -39,8 +39,8 @@ class OwnPropertyImpl<T : Obj, V>(
override val constructorParameter: Boolean,
override val classLocalId: Int,
override val isKey: Boolean,
sourceElement: SourceElement
) : ObjPropertyBase<T, V>(receiver, name, valueType, valueKind, open, mutable, content, sourceElement), OwnProperty<T, V> {
sourcePsi: PsiElement?
) : ObjPropertyBase<T, V>(receiver, name, valueType, valueKind, open, mutable, content, sourcePsi), OwnProperty<T, V> {
override fun toString(): String = "$name (${receiver.name})"
}
@@ -56,7 +56,7 @@ class ExtPropertyImpl<T : Obj, V>(
override val module: ObjModule,
override val moduleLocalId: Int,
override val annotations: List<ObjAnnotation>,
sourceElement: SourceElement,
) : ObjPropertyBase<T, V>(receiver, name, valueType, valueKind, open, mutable, content, sourceElement), ExtProperty<T, V> {
sourcePsi: PsiElement?
) : ObjPropertyBase<T, V>(receiver, name, valueType, valueKind, open, mutable, content, sourcePsi), ExtProperty<T, V> {
override fun toString(): String = "$name (${receiver.name})"
}
}
@@ -1,9 +1,9 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.workspaceModel.metaModel.impl
import com.intellij.devkit.workspaceModel.metaModel.ObjMetaElementWithSource
import com.intellij.devkit.workspaceModel.metaModel.ObjMetaElementWithPsi
import com.intellij.psi.PsiElement
import com.intellij.workspaceModel.codegen.deft.meta.*
import org.jetbrains.kotlin.descriptors.SourceElement
object ObjTypeType : ObjType<ObjType<*>> {
override val classifier: ObjType<ObjType<*>>
@@ -27,9 +27,9 @@ class ObjClassImpl<T : Obj>(
override val module: ObjModule,
override val name: String,
override val openness: ObjClass.Openness,
override val sourceElement: SourceElement,
override val sourcePsi: PsiElement?,
override val annotations: List<ObjAnnotation>
) : ObjClass<T>, ObjTypeImpl<T>(), ObjMetaElementWithSource {
) : ObjClass<T>, ObjTypeImpl<T>(), ObjMetaElementWithPsi {
override var parentField: OwnProperty<T, *>? = null
override var nameField: OwnProperty<T, *>? = null
private val mutableFields: MutableList<OwnProperty<T, *>> = ArrayList()
@@ -69,4 +69,4 @@ class ObjClassImpl<T : Obj>(
class ObjAnnotationImpl(override val fqName: String, override val pathSegments: List<String>) : ObjAnnotation {
override fun toString(): String = fqName
}
}
@@ -3,7 +3,7 @@
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" packagePrefix="com.intellij.devkit.workspaceModel" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
@@ -14,8 +14,7 @@
<orderEntry type="module" module-name="intellij.devkit.workspaceModel" scope="TEST" />
<orderEntry type="module" module-name="kotlin.test-framework" scope="TEST" />
<orderEntry type="module" module-name="kotlin.formatter" scope="TEST" />
<orderEntry type="module" module-name="kotlin.tests-common" scope="TEST" />
<orderEntry type="module" module-name="kotlin.plugin.k1" scope="TEST" />
<orderEntry type="module" module-name="kotlin.base.plugin" scope="TEST" />
<orderEntry type="library" scope="TEST" name="kotlinc.kotlin-compiler-common" level="project" />
<orderEntry type="module" module-name="kotlin.base.test" scope="TEST" />
<orderEntry type="module" module-name="intellij.devkit" scope="RUNTIME" />
@@ -29,5 +28,6 @@
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5" scope="TEST" />
<orderEntry type="library" scope="TEST" name="kotlinx-serialization-core" level="project" />
<orderEntry type="library" scope="TEST" name="kotlinx-serialization-json" level="project" />
<orderEntry type="module" module-name="kotlin.tests-common" />
</component>
</module>
@@ -4,8 +4,8 @@ import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.EntityType
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.annotations.Default
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.annotations.Default
interface DefaultFieldEntity : WorkspaceEntity {
val version: Int
@@ -18,8 +18,8 @@ internal object MetadataStorageImpl: MetadataStorageBase() {
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.DefaultFieldEntity", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.DefaultFieldEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "version", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "data", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.TestData", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "description", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf())), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "data", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.TestData", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "description", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf())), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "anotherVersion", valueType = primitiveTypeIntNotNullable, withDefault = true),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "description", valueType = primitiveTypeStringNotNullable, withDefault = true)), extProperties = listOf(), isAbstract = false)
@@ -27,8 +27,8 @@ OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name =
}
override fun initializeMetadataHash() {
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.DefaultFieldEntity", metadataHash = 124467804)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.TestData", metadataHash = 589453437)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.DefaultFieldEntity", metadataHash = -1646169674)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.TestData", metadataHash = -898117917)
}
}
@@ -0,0 +1,96 @@
package com.intellij.workspaceModel.test.api
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.EntityType
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.annotations.Child
interface ChildrenCollectionFieldEntity : WorkspaceEntity {
val name: String
val childrenEntitiesCollection: List<@Child SimpleEntity>
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<ChildrenCollectionFieldEntity> {
override var entitySource: EntitySource
var name: String
var childrenEntitiesCollection: List<SimpleEntity.Builder>
}
companion object : EntityType<ChildrenCollectionFieldEntity, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
name: String,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.name = name
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
}
//endregion
}
//region generated code
fun MutableEntityStorage.modifyChildrenCollectionFieldEntity(
entity: ChildrenCollectionFieldEntity,
modification: ChildrenCollectionFieldEntity.Builder.() -> Unit,
): ChildrenCollectionFieldEntity {
return modifyEntity(ChildrenCollectionFieldEntity.Builder::class.java, entity, modification)
}
//endregion
interface SimpleEntity : WorkspaceEntity {
val version: Int
val name: String
val isSimple: Boolean
val parent: ChildrenCollectionFieldEntity
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<SimpleEntity> {
override var entitySource: EntitySource
var version: Int
var name: String
var isSimple: Boolean
var parent: ChildrenCollectionFieldEntity.Builder
}
companion object : EntityType<SimpleEntity, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
version: Int,
name: String,
isSimple: Boolean,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.version = version
builder.name = name
builder.isSimple = isSimple
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
}
//endregion
}
//region generated code
fun MutableEntityStorage.modifySimpleEntity(
entity: SimpleEntity,
modification: SimpleEntity.Builder.() -> Unit,
): SimpleEntity {
return modifyEntity(SimpleEntity.Builder::class.java, entity, modification)
}
//endregion
@@ -0,0 +1,267 @@
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.GeneratedCodeImplVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.annotations.Child
import com.intellij.platform.workspace.storage.impl.EntityLink
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityData
import com.intellij.platform.workspace.storage.impl.extractOneToManyChildren
import com.intellij.platform.workspace.storage.impl.updateOneToManyChildrenOfParent
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentation
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentationApi
import com.intellij.platform.workspace.storage.instrumentation.MutableEntityStorageInstrumentation
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.workspaceModel.test.api.ChildrenCollectionFieldEntity
import com.intellij.workspaceModel.test.api.SimpleEntity
@GeneratedCodeApiVersion(3)
@GeneratedCodeImplVersion(6)
@OptIn(WorkspaceEntityInternalApi::class)
internal class ChildrenCollectionFieldEntityImpl(private val dataSource: ChildrenCollectionFieldEntityData) : ChildrenCollectionFieldEntity,
WorkspaceEntityBase(
dataSource
) {
private companion object {
internal val CHILDRENENTITIESCOLLECTION_CONNECTION_ID: ConnectionId = ConnectionId.create(
ChildrenCollectionFieldEntity::class.java, SimpleEntity::class.java, ConnectionId.ConnectionType.ONE_TO_MANY, false
)
private val connections = listOf<ConnectionId>(
CHILDRENENTITIESCOLLECTION_CONNECTION_ID,
)
}
override val name: String
get() {
readField("name")
return dataSource.name
}
override val childrenEntitiesCollection: List<SimpleEntity>
get() = snapshot.extractOneToManyChildren<SimpleEntity>(CHILDRENENTITIESCOLLECTION_CONNECTION_ID, this)!!.toList()
override val entitySource: EntitySource
get() {
readField("entitySource")
return dataSource.entitySource
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
internal class Builder(result: ChildrenCollectionFieldEntityData?) :
ModifiableWorkspaceEntityBase<ChildrenCollectionFieldEntity, ChildrenCollectionFieldEntityData>(result),
ChildrenCollectionFieldEntity.Builder {
internal constructor() : this(ChildrenCollectionFieldEntityData())
override fun applyToBuilder(builder: MutableEntityStorage) {
if (this.diff != null) {
if (existsInBuilder(builder)) {
this.diff = builder
return
}
else {
error("Entity ChildrenCollectionFieldEntity is already created in a different builder")
}
}
this.diff = builder
addToBuilder()
this.id = getEntityData().createEntityId()
// After adding entity data to the builder, we need to unbind it and move the control over entity data to builder
// Builder may switch to snapshot at any moment and lock entity data to modification
this.currentEntityData = null
// Process linked entities that are connected without a builder
processLinkedEntities(builder)
checkInitialization() // TODO uncomment and check failed tests
}
private fun checkInitialization() {
val _diff = diff
if (!getEntityData().isEntitySourceInitialized()) {
error("Field WorkspaceEntity#entitySource should be initialized")
}
if (!getEntityData().isNameInitialized()) {
error("Field ChildrenCollectionFieldEntity#name should be initialized")
}
// Check initialization for list with ref type
if (_diff != null) {
if (_diff.extractOneToManyChildren<WorkspaceEntityBase>(CHILDRENENTITIESCOLLECTION_CONNECTION_ID, this) == null) {
error("Field ChildrenCollectionFieldEntity#childrenEntitiesCollection should be initialized")
}
}
else {
if (this.entityLinks[EntityLink(true, CHILDRENENTITIESCOLLECTION_CONNECTION_ID)] == null) {
error("Field ChildrenCollectionFieldEntity#childrenEntitiesCollection should be initialized")
}
}
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
// Relabeling code, move information from dataSource to this builder
override fun relabel(dataSource: WorkspaceEntity, parents: Set<WorkspaceEntity>?) {
dataSource as ChildrenCollectionFieldEntity
if (this.entitySource != dataSource.entitySource) this.entitySource = dataSource.entitySource
if (this.name != dataSource.name) this.name = dataSource.name
updateChildToParentReferences(parents)
}
override var entitySource: EntitySource
get() = getEntityData().entitySource
set(value) {
checkModificationAllowed()
getEntityData(true).entitySource = value
changedProperty.add("entitySource")
}
override var name: String
get() = getEntityData().name
set(value) {
checkModificationAllowed()
getEntityData(true).name = value
changedProperty.add("name")
}
// List of non-abstract referenced types
var _childrenEntitiesCollection: List<SimpleEntity>? = emptyList()
override var childrenEntitiesCollection: List<SimpleEntity.Builder>
get() {
// Getter of the list of non-abstract referenced types
val _diff = diff
return if (_diff != null) {
@OptIn(EntityStorageInstrumentationApi::class)
((_diff as MutableEntityStorageInstrumentation).getManyChildrenBuilders(CHILDRENENTITIESCOLLECTION_CONNECTION_ID, this)!!
.toList() as List<SimpleEntity.Builder>) +
(this.entityLinks[EntityLink(true, CHILDRENENTITIESCOLLECTION_CONNECTION_ID)] as? List<SimpleEntity.Builder> ?: emptyList())
}
else {
this.entityLinks[EntityLink(true, CHILDRENENTITIESCOLLECTION_CONNECTION_ID)] as? List<SimpleEntity.Builder> ?: emptyList()
}
}
set(value) {
// Setter of the list of non-abstract referenced types
checkModificationAllowed()
val _diff = diff
if (_diff != null) {
for (item_value in value) {
if (item_value is ModifiableWorkspaceEntityBase<*, *> && (item_value as? ModifiableWorkspaceEntityBase<*, *>)?.diff == null) {
// Backref setup before adding to store
if (item_value is ModifiableWorkspaceEntityBase<*, *>) {
item_value.entityLinks[EntityLink(false, CHILDRENENTITIESCOLLECTION_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
_diff.addEntity(item_value as ModifiableWorkspaceEntityBase<WorkspaceEntity, *>)
}
}
_diff.updateOneToManyChildrenOfParent(CHILDRENENTITIESCOLLECTION_CONNECTION_ID, this, value)
}
else {
for (item_value in value) {
if (item_value is ModifiableWorkspaceEntityBase<*, *>) {
item_value.entityLinks[EntityLink(false, CHILDRENENTITIESCOLLECTION_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
}
this.entityLinks[EntityLink(true, CHILDRENENTITIESCOLLECTION_CONNECTION_ID)] = value
}
changedProperty.add("childrenEntitiesCollection")
}
override fun getEntityClass(): Class<ChildrenCollectionFieldEntity> = ChildrenCollectionFieldEntity::class.java
}
}
@OptIn(WorkspaceEntityInternalApi::class)
internal class ChildrenCollectionFieldEntityData : WorkspaceEntityData<ChildrenCollectionFieldEntity>() {
lateinit var name: String
internal fun isNameInitialized(): Boolean = ::name.isInitialized
override fun wrapAsModifiable(diff: MutableEntityStorage): WorkspaceEntity.Builder<ChildrenCollectionFieldEntity> {
val modifiable = ChildrenCollectionFieldEntityImpl.Builder(null)
modifiable.diff = diff
modifiable.id = createEntityId()
return modifiable
}
@OptIn(EntityStorageInstrumentationApi::class)
override fun createEntity(snapshot: EntityStorageInstrumentation): ChildrenCollectionFieldEntity {
val entityId = createEntityId()
return snapshot.initializeEntity(entityId) {
val entity = ChildrenCollectionFieldEntityImpl(this)
entity.snapshot = snapshot
entity.id = entityId
entity
}
}
override fun getMetadata(): EntityMetadata {
return MetadataStorageImpl.getMetadataByTypeFqn("com.intellij.workspaceModel.test.api.ChildrenCollectionFieldEntity") as EntityMetadata
}
override fun getEntityInterface(): Class<out WorkspaceEntity> {
return ChildrenCollectionFieldEntity::class.java
}
override fun createDetachedEntity(parents: List<WorkspaceEntity.Builder<*>>): WorkspaceEntity.Builder<*> {
return ChildrenCollectionFieldEntity(name, entitySource) {
}
}
override fun getRequiredParents(): List<Class<out WorkspaceEntity>> {
val res = mutableListOf<Class<out WorkspaceEntity>>()
return res
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as ChildrenCollectionFieldEntityData
if (this.entitySource != other.entitySource) return false
if (this.name != other.name) return false
return true
}
override fun equalsIgnoringEntitySource(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as ChildrenCollectionFieldEntityData
if (this.name != other.name) return false
return true
}
override fun hashCode(): Int {
var result = entitySource.hashCode()
result = 31 * result + name.hashCode()
return result
}
override fun hashCodeIgnoringEntitySource(): Int {
var result = javaClass.hashCode()
result = 31 * result + name.hashCode()
return result
}
}
@@ -0,0 +1,41 @@
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.metadata.impl.MetadataStorageBase
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.platform.workspace.storage.metadata.model.FinalClassMetadata
import com.intellij.platform.workspace.storage.metadata.model.OwnPropertyMetadata
import com.intellij.platform.workspace.storage.metadata.model.StorageTypeMetadata
import com.intellij.platform.workspace.storage.metadata.model.ValueTypeMetadata
@OptIn(WorkspaceEntityInternalApi::class)
internal object MetadataStorageImpl: MetadataStorageBase() {
override fun initializeMetadata() {
val primitiveTypeStringNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "String")
val primitiveTypeIntNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Int")
val primitiveTypeBooleanNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Boolean")
var typeMetadata: StorageTypeMetadata
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.ChildrenCollectionFieldEntity", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.ChildrenCollectionFieldEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "childrenEntitiesCollection", valueType = ValueTypeMetadata.EntityReference(connectionType = ConnectionId.ConnectionType.ONE_TO_MANY, entityFqName = "com.intellij.workspaceModel.test.api.SimpleEntity", isChild = true, isNullable = false), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleEntity", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.SimpleEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "version", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "isSimple", valueType = primitiveTypeBooleanNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "parent", valueType = ValueTypeMetadata.EntityReference(connectionType = ConnectionId.ConnectionType.ONE_TO_MANY, entityFqName = "com.intellij.workspaceModel.test.api.ChildrenCollectionFieldEntity", isChild = false, isNullable = false), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
}
override fun initializeMetadataHash() {
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.ChildrenCollectionFieldEntity", metadataHash = -454547805)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SimpleEntity", metadataHash = -41718252)
}
}
@@ -0,0 +1,299 @@
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.GeneratedCodeImplVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.annotations.Child
import com.intellij.platform.workspace.storage.impl.EntityLink
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityData
import com.intellij.platform.workspace.storage.impl.extractOneToManyParent
import com.intellij.platform.workspace.storage.impl.updateOneToManyParentOfChild
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentation
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentationApi
import com.intellij.platform.workspace.storage.instrumentation.MutableEntityStorageInstrumentation
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.workspaceModel.test.api.ChildrenCollectionFieldEntity
import com.intellij.workspaceModel.test.api.SimpleEntity
@GeneratedCodeApiVersion(3)
@GeneratedCodeImplVersion(6)
@OptIn(WorkspaceEntityInternalApi::class)
internal class SimpleEntityImpl(private val dataSource: SimpleEntityData) : SimpleEntity, WorkspaceEntityBase(dataSource) {
private companion object {
internal val PARENT_CONNECTION_ID: ConnectionId = ConnectionId.create(
ChildrenCollectionFieldEntity::class.java, SimpleEntity::class.java, ConnectionId.ConnectionType.ONE_TO_MANY, false
)
private val connections = listOf<ConnectionId>(
PARENT_CONNECTION_ID,
)
}
override val version: Int
get() {
readField("version")
return dataSource.version
}
override val name: String
get() {
readField("name")
return dataSource.name
}
override val isSimple: Boolean
get() {
readField("isSimple")
return dataSource.isSimple
}
override val parent: ChildrenCollectionFieldEntity
get() = snapshot.extractOneToManyParent(PARENT_CONNECTION_ID, this)!!
override val entitySource: EntitySource
get() {
readField("entitySource")
return dataSource.entitySource
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
internal class Builder(result: SimpleEntityData?) : ModifiableWorkspaceEntityBase<SimpleEntity, SimpleEntityData>(result),
SimpleEntity.Builder {
internal constructor() : this(SimpleEntityData())
override fun applyToBuilder(builder: MutableEntityStorage) {
if (this.diff != null) {
if (existsInBuilder(builder)) {
this.diff = builder
return
}
else {
error("Entity SimpleEntity is already created in a different builder")
}
}
this.diff = builder
addToBuilder()
this.id = getEntityData().createEntityId()
// After adding entity data to the builder, we need to unbind it and move the control over entity data to builder
// Builder may switch to snapshot at any moment and lock entity data to modification
this.currentEntityData = null
// Process linked entities that are connected without a builder
processLinkedEntities(builder)
checkInitialization() // TODO uncomment and check failed tests
}
private fun checkInitialization() {
val _diff = diff
if (!getEntityData().isEntitySourceInitialized()) {
error("Field WorkspaceEntity#entitySource should be initialized")
}
if (!getEntityData().isNameInitialized()) {
error("Field SimpleEntity#name should be initialized")
}
if (_diff != null) {
if (_diff.extractOneToManyParent<WorkspaceEntityBase>(PARENT_CONNECTION_ID, this) == null) {
error("Field SimpleEntity#parent should be initialized")
}
}
else {
if (this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)] == null) {
error("Field SimpleEntity#parent should be initialized")
}
}
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
// Relabeling code, move information from dataSource to this builder
override fun relabel(dataSource: WorkspaceEntity, parents: Set<WorkspaceEntity>?) {
dataSource as SimpleEntity
if (this.entitySource != dataSource.entitySource) this.entitySource = dataSource.entitySource
if (this.version != dataSource.version) this.version = dataSource.version
if (this.name != dataSource.name) this.name = dataSource.name
if (this.isSimple != dataSource.isSimple) this.isSimple = dataSource.isSimple
updateChildToParentReferences(parents)
}
override var entitySource: EntitySource
get() = getEntityData().entitySource
set(value) {
checkModificationAllowed()
getEntityData(true).entitySource = value
changedProperty.add("entitySource")
}
override var version: Int
get() = getEntityData().version
set(value) {
checkModificationAllowed()
getEntityData(true).version = value
changedProperty.add("version")
}
override var name: String
get() = getEntityData().name
set(value) {
checkModificationAllowed()
getEntityData(true).name = value
changedProperty.add("name")
}
override var isSimple: Boolean
get() = getEntityData().isSimple
set(value) {
checkModificationAllowed()
getEntityData(true).isSimple = value
changedProperty.add("isSimple")
}
override var parent: ChildrenCollectionFieldEntity.Builder
get() {
val _diff = diff
return if (_diff != null) {
@OptIn(EntityStorageInstrumentationApi::class)
((_diff as MutableEntityStorageInstrumentation).getParentBuilder(
PARENT_CONNECTION_ID, this
) as? ChildrenCollectionFieldEntity.Builder)
?: (this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)]!! as ChildrenCollectionFieldEntity.Builder)
}
else {
this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)]!! as ChildrenCollectionFieldEntity.Builder
}
}
set(value) {
checkModificationAllowed()
val _diff = diff
if (_diff != null && value is ModifiableWorkspaceEntityBase<*, *> && value.diff == null) {
// Setting backref of the list
if (value is ModifiableWorkspaceEntityBase<*, *>) {
val data = (value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] as? List<Any> ?: emptyList()) + this
value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] = data
}
// else you're attaching a new entity to an existing entity that is not modifiable
_diff.addEntity(value as ModifiableWorkspaceEntityBase<WorkspaceEntity, *>)
}
if (_diff != null && (value !is ModifiableWorkspaceEntityBase<*, *> || value.diff != null)) {
_diff.updateOneToManyParentOfChild(PARENT_CONNECTION_ID, this, value)
}
else {
// Setting backref of the list
if (value is ModifiableWorkspaceEntityBase<*, *>) {
val data = (value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] as? List<Any> ?: emptyList()) + this
value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] = data
}
// else you're attaching a new entity to an existing entity that is not modifiable
this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)] = value
}
changedProperty.add("parent")
}
override fun getEntityClass(): Class<SimpleEntity> = SimpleEntity::class.java
}
}
@OptIn(WorkspaceEntityInternalApi::class)
internal class SimpleEntityData : WorkspaceEntityData<SimpleEntity>() {
var version: Int = 0
lateinit var name: String
var isSimple: Boolean = false
internal fun isNameInitialized(): Boolean = ::name.isInitialized
override fun wrapAsModifiable(diff: MutableEntityStorage): WorkspaceEntity.Builder<SimpleEntity> {
val modifiable = SimpleEntityImpl.Builder(null)
modifiable.diff = diff
modifiable.id = createEntityId()
return modifiable
}
@OptIn(EntityStorageInstrumentationApi::class)
override fun createEntity(snapshot: EntityStorageInstrumentation): SimpleEntity {
val entityId = createEntityId()
return snapshot.initializeEntity(entityId) {
val entity = SimpleEntityImpl(this)
entity.snapshot = snapshot
entity.id = entityId
entity
}
}
override fun getMetadata(): EntityMetadata {
return MetadataStorageImpl.getMetadataByTypeFqn("com.intellij.workspaceModel.test.api.SimpleEntity") as EntityMetadata
}
override fun getEntityInterface(): Class<out WorkspaceEntity> {
return SimpleEntity::class.java
}
override fun createDetachedEntity(parents: List<WorkspaceEntity.Builder<*>>): WorkspaceEntity.Builder<*> {
return SimpleEntity(version, name, isSimple, entitySource) {
parents.filterIsInstance<ChildrenCollectionFieldEntity.Builder>().singleOrNull()?.let { this.parent = it }
}
}
override fun getRequiredParents(): List<Class<out WorkspaceEntity>> {
val res = mutableListOf<Class<out WorkspaceEntity>>()
res.add(ChildrenCollectionFieldEntity::class.java)
return res
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as SimpleEntityData
if (this.entitySource != other.entitySource) return false
if (this.version != other.version) return false
if (this.name != other.name) return false
if (this.isSimple != other.isSimple) return false
return true
}
override fun equalsIgnoringEntitySource(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as SimpleEntityData
if (this.version != other.version) return false
if (this.name != other.name) return false
if (this.isSimple != other.isSimple) return false
return true
}
override fun hashCode(): Int {
var result = entitySource.hashCode()
result = 31 * result + version.hashCode()
result = 31 * result + name.hashCode()
result = 31 * result + isSimple.hashCode()
return result
}
override fun hashCodeIgnoringEntitySource(): Int {
var result = javaClass.hashCode()
result = 31 * result + version.hashCode()
result = 31 * result + name.hashCode()
result = 31 * result + isSimple.hashCode()
return result
}
}
@@ -0,0 +1,16 @@
package com.intellij.workspaceModel.test.api
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.annotations.Child
interface ChildrenCollectionFieldEntity : WorkspaceEntity {
val name: String
val childrenEntitiesCollection: List<@Child SimpleEntity>
}
interface SimpleEntity : WorkspaceEntity {
val version: Int
val name: String
val isSimple: Boolean
val parent: ChildrenCollectionFieldEntity
}
@@ -11,6 +11,7 @@ import com.intellij.platform.workspace.storage.impl.containers.toMutableWorkspac
interface CollectionFieldEntity : WorkspaceEntity {
val versions: Set<Int>
val names: List<String>
val manifestAttributes: Map<String, String>
//region generated code
@GeneratedCodeApiVersion(3)
@@ -18,6 +19,7 @@ interface CollectionFieldEntity : WorkspaceEntity {
override var entitySource: EntitySource
var versions: MutableSet<Int>
var names: MutableList<String>
var manifestAttributes: Map<String, String>
}
companion object : EntityType<CollectionFieldEntity, Builder>() {
@@ -27,12 +29,14 @@ interface CollectionFieldEntity : WorkspaceEntity {
operator fun invoke(
versions: Set<Int>,
names: List<String>,
manifestAttributes: Map<String, String>,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.versions = versions.toMutableWorkspaceSet()
builder.names = names.toMutableWorkspaceList()
builder.manifestAttributes = manifestAttributes
builder.entitySource = entitySource
init?.invoke(builder)
return builder
@@ -45,6 +45,12 @@ internal class CollectionFieldEntityImpl(private val dataSource: CollectionField
return dataSource.names
}
override val manifestAttributes: Map<String, String>
get() {
readField("manifestAttributes")
return dataSource.manifestAttributes
}
override val entitySource: EntitySource
get() {
readField("entitySource")
@@ -94,6 +100,9 @@ internal class CollectionFieldEntityImpl(private val dataSource: CollectionField
if (!getEntityData().isNamesInitialized()) {
error("Field CollectionFieldEntity#names should be initialized")
}
if (!getEntityData().isManifestAttributesInitialized()) {
error("Field CollectionFieldEntity#manifestAttributes should be initialized")
}
}
override fun connectionIdList(): List<ConnectionId> {
@@ -117,6 +126,7 @@ internal class CollectionFieldEntityImpl(private val dataSource: CollectionField
if (this.entitySource != dataSource.entitySource) this.entitySource = dataSource.entitySource
if (this.versions != dataSource.versions) this.versions = dataSource.versions.toMutableSet()
if (this.names != dataSource.names) this.names = dataSource.names.toMutableList()
if (this.manifestAttributes != dataSource.manifestAttributes) this.manifestAttributes = dataSource.manifestAttributes.toMutableMap()
updateChildToParentReferences(parents)
}
@@ -174,6 +184,14 @@ internal class CollectionFieldEntityImpl(private val dataSource: CollectionField
namesUpdater.invoke(value)
}
override var manifestAttributes: Map<String, String>
get() = getEntityData().manifestAttributes
set(value) {
checkModificationAllowed()
getEntityData(true).manifestAttributes = value
changedProperty.add("manifestAttributes")
}
override fun getEntityClass(): Class<CollectionFieldEntity> = CollectionFieldEntity::class.java
}
}
@@ -182,9 +200,11 @@ internal class CollectionFieldEntityImpl(private val dataSource: CollectionField
internal class CollectionFieldEntityData : WorkspaceEntityData<CollectionFieldEntity>() {
lateinit var versions: MutableSet<Int>
lateinit var names: MutableList<String>
lateinit var manifestAttributes: Map<String, String>
internal fun isVersionsInitialized(): Boolean = ::versions.isInitialized
internal fun isNamesInitialized(): Boolean = ::names.isInitialized
internal fun isManifestAttributesInitialized(): Boolean = ::manifestAttributes.isInitialized
override fun wrapAsModifiable(diff: MutableEntityStorage): WorkspaceEntity.Builder<CollectionFieldEntity> {
val modifiable = CollectionFieldEntityImpl.Builder(null)
@@ -221,7 +241,7 @@ internal class CollectionFieldEntityData : WorkspaceEntityData<CollectionFieldEn
}
override fun createDetachedEntity(parents: List<WorkspaceEntity.Builder<*>>): WorkspaceEntity.Builder<*> {
return CollectionFieldEntity(versions, names, entitySource) {
return CollectionFieldEntity(versions, names, manifestAttributes, entitySource) {
}
}
@@ -239,6 +259,7 @@ internal class CollectionFieldEntityData : WorkspaceEntityData<CollectionFieldEn
if (this.entitySource != other.entitySource) return false
if (this.versions != other.versions) return false
if (this.names != other.names) return false
if (this.manifestAttributes != other.manifestAttributes) return false
return true
}
@@ -250,6 +271,7 @@ internal class CollectionFieldEntityData : WorkspaceEntityData<CollectionFieldEn
if (this.versions != other.versions) return false
if (this.names != other.names) return false
if (this.manifestAttributes != other.manifestAttributes) return false
return true
}
@@ -257,6 +279,7 @@ internal class CollectionFieldEntityData : WorkspaceEntityData<CollectionFieldEn
var result = entitySource.hashCode()
result = 31 * result + versions.hashCode()
result = 31 * result + names.hashCode()
result = 31 * result + manifestAttributes.hashCode()
return result
}
@@ -264,6 +287,7 @@ internal class CollectionFieldEntityData : WorkspaceEntityData<CollectionFieldEn
var result = javaClass.hashCode()
result = 31 * result + versions.hashCode()
result = 31 * result + names.hashCode()
result = 31 * result + manifestAttributes.hashCode()
return result
}
}
@@ -15,18 +15,21 @@ internal object MetadataStorageImpl: MetadataStorageBase() {
val primitiveTypeSetNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Set")
val primitiveTypeStringNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "String")
val primitiveTypeListNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "List")
val primitiveTypeMapNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Map")
var typeMetadata: StorageTypeMetadata
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.CollectionFieldEntity", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.CollectionFieldEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "versions", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(primitiveTypeIntNotNullable), primitive = primitiveTypeSetNotNullable), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "names", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(primitiveTypeStringNotNullable), primitive = primitiveTypeListNotNullable), withDefault = false)), extProperties = listOf(), isAbstract = false)
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "names", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(primitiveTypeStringNotNullable), primitive = primitiveTypeListNotNullable), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "manifestAttributes", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(primitiveTypeStringNotNullable,
primitiveTypeStringNotNullable), primitive = primitiveTypeMapNotNullable), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
}
override fun initializeMetadataHash() {
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.CollectionFieldEntity", metadataHash = 1735861848)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.CollectionFieldEntity", metadataHash = 1555273165)
}
}
@@ -5,4 +5,5 @@ import com.intellij.platform.workspace.storage.WorkspaceEntity
interface CollectionFieldEntity : WorkspaceEntity {
val versions: Set<Int>
val names: List<String>
}
val manifestAttributes: Map<String, String>
}
@@ -0,0 +1,130 @@
package com.intellij.workspaceModel.test.api
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.EntityType
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.annotations.Child
interface EntityWithChildren : WorkspaceEntity {
val name: String
val propertyChild: @Child ChildEntityType1?
@Child val typeChild: ChildEntityType2?
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<EntityWithChildren> {
override var entitySource: EntitySource
var name: String
var propertyChild: ChildEntityType1.Builder?
var typeChild: ChildEntityType2.Builder?
}
companion object : EntityType<EntityWithChildren, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
name: String,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.name = name
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
}
//endregion
}
//region generated code
fun MutableEntityStorage.modifyEntityWithChildren(
entity: EntityWithChildren,
modification: EntityWithChildren.Builder.() -> Unit,
): EntityWithChildren {
return modifyEntity(EntityWithChildren.Builder::class.java, entity, modification)
}
//endregion
interface ChildEntityType1 : WorkspaceEntity {
val version: Int
val parent: EntityWithChildren
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<ChildEntityType1> {
override var entitySource: EntitySource
var version: Int
var parent: EntityWithChildren.Builder
}
companion object : EntityType<ChildEntityType1, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
version: Int,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.version = version
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
}
//endregion
}
//region generated code
fun MutableEntityStorage.modifyChildEntityType1(
entity: ChildEntityType1,
modification: ChildEntityType1.Builder.() -> Unit,
): ChildEntityType1 {
return modifyEntity(ChildEntityType1.Builder::class.java, entity, modification)
}
//endregion
interface ChildEntityType2 : WorkspaceEntity {
val version: Int
val parent: EntityWithChildren
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<ChildEntityType2> {
override var entitySource: EntitySource
var version: Int
var parent: EntityWithChildren.Builder
}
companion object : EntityType<ChildEntityType2, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
version: Int,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.version = version
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
}
//endregion
}
//region generated code
fun MutableEntityStorage.modifyChildEntityType2(
entity: ChildEntityType2,
modification: ChildEntityType2.Builder.() -> Unit,
): ChildEntityType2 {
return modifyEntity(ChildEntityType2.Builder::class.java, entity, modification)
}
//endregion
@@ -0,0 +1,247 @@
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.GeneratedCodeImplVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.annotations.Child
import com.intellij.platform.workspace.storage.impl.EntityLink
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityData
import com.intellij.platform.workspace.storage.impl.extractOneToOneParent
import com.intellij.platform.workspace.storage.impl.updateOneToOneParentOfChild
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentation
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentationApi
import com.intellij.platform.workspace.storage.instrumentation.MutableEntityStorageInstrumentation
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.workspaceModel.test.api.ChildEntityType1
import com.intellij.workspaceModel.test.api.EntityWithChildren
@GeneratedCodeApiVersion(3)
@GeneratedCodeImplVersion(6)
@OptIn(WorkspaceEntityInternalApi::class)
internal class ChildEntityType1Impl(private val dataSource: ChildEntityType1Data) : ChildEntityType1, WorkspaceEntityBase(dataSource) {
private companion object {
internal val PARENT_CONNECTION_ID: ConnectionId =
ConnectionId.create(EntityWithChildren::class.java, ChildEntityType1::class.java, ConnectionId.ConnectionType.ONE_TO_ONE, false)
private val connections = listOf<ConnectionId>(
PARENT_CONNECTION_ID,
)
}
override val version: Int
get() {
readField("version")
return dataSource.version
}
override val parent: EntityWithChildren
get() = snapshot.extractOneToOneParent(PARENT_CONNECTION_ID, this)!!
override val entitySource: EntitySource
get() {
readField("entitySource")
return dataSource.entitySource
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
internal class Builder(result: ChildEntityType1Data?) : ModifiableWorkspaceEntityBase<ChildEntityType1, ChildEntityType1Data>(result),
ChildEntityType1.Builder {
internal constructor() : this(ChildEntityType1Data())
override fun applyToBuilder(builder: MutableEntityStorage) {
if (this.diff != null) {
if (existsInBuilder(builder)) {
this.diff = builder
return
}
else {
error("Entity ChildEntityType1 is already created in a different builder")
}
}
this.diff = builder
addToBuilder()
this.id = getEntityData().createEntityId()
// After adding entity data to the builder, we need to unbind it and move the control over entity data to builder
// Builder may switch to snapshot at any moment and lock entity data to modification
this.currentEntityData = null
// Process linked entities that are connected without a builder
processLinkedEntities(builder)
checkInitialization() // TODO uncomment and check failed tests
}
private fun checkInitialization() {
val _diff = diff
if (!getEntityData().isEntitySourceInitialized()) {
error("Field WorkspaceEntity#entitySource should be initialized")
}
if (_diff != null) {
if (_diff.extractOneToOneParent<WorkspaceEntityBase>(PARENT_CONNECTION_ID, this) == null) {
error("Field ChildEntityType1#parent should be initialized")
}
}
else {
if (this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)] == null) {
error("Field ChildEntityType1#parent should be initialized")
}
}
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
// Relabeling code, move information from dataSource to this builder
override fun relabel(dataSource: WorkspaceEntity, parents: Set<WorkspaceEntity>?) {
dataSource as ChildEntityType1
if (this.entitySource != dataSource.entitySource) this.entitySource = dataSource.entitySource
if (this.version != dataSource.version) this.version = dataSource.version
updateChildToParentReferences(parents)
}
override var entitySource: EntitySource
get() = getEntityData().entitySource
set(value) {
checkModificationAllowed()
getEntityData(true).entitySource = value
changedProperty.add("entitySource")
}
override var version: Int
get() = getEntityData().version
set(value) {
checkModificationAllowed()
getEntityData(true).version = value
changedProperty.add("version")
}
override var parent: EntityWithChildren.Builder
get() {
val _diff = diff
return if (_diff != null) {
@OptIn(EntityStorageInstrumentationApi::class)
((_diff as MutableEntityStorageInstrumentation).getParentBuilder(PARENT_CONNECTION_ID, this) as? EntityWithChildren.Builder)
?: (this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)]!! as EntityWithChildren.Builder)
}
else {
this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)]!! as EntityWithChildren.Builder
}
}
set(value) {
checkModificationAllowed()
val _diff = diff
if (_diff != null && value is ModifiableWorkspaceEntityBase<*, *> && value.diff == null) {
if (value is ModifiableWorkspaceEntityBase<*, *>) {
value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
_diff.addEntity(value as ModifiableWorkspaceEntityBase<WorkspaceEntity, *>)
}
if (_diff != null && (value !is ModifiableWorkspaceEntityBase<*, *> || value.diff != null)) {
_diff.updateOneToOneParentOfChild(PARENT_CONNECTION_ID, this, value)
}
else {
if (value is ModifiableWorkspaceEntityBase<*, *>) {
value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)] = value
}
changedProperty.add("parent")
}
override fun getEntityClass(): Class<ChildEntityType1> = ChildEntityType1::class.java
}
}
@OptIn(WorkspaceEntityInternalApi::class)
internal class ChildEntityType1Data : WorkspaceEntityData<ChildEntityType1>() {
var version: Int = 0
override fun wrapAsModifiable(diff: MutableEntityStorage): WorkspaceEntity.Builder<ChildEntityType1> {
val modifiable = ChildEntityType1Impl.Builder(null)
modifiable.diff = diff
modifiable.id = createEntityId()
return modifiable
}
@OptIn(EntityStorageInstrumentationApi::class)
override fun createEntity(snapshot: EntityStorageInstrumentation): ChildEntityType1 {
val entityId = createEntityId()
return snapshot.initializeEntity(entityId) {
val entity = ChildEntityType1Impl(this)
entity.snapshot = snapshot
entity.id = entityId
entity
}
}
override fun getMetadata(): EntityMetadata {
return MetadataStorageImpl.getMetadataByTypeFqn("com.intellij.workspaceModel.test.api.ChildEntityType1") as EntityMetadata
}
override fun getEntityInterface(): Class<out WorkspaceEntity> {
return ChildEntityType1::class.java
}
override fun createDetachedEntity(parents: List<WorkspaceEntity.Builder<*>>): WorkspaceEntity.Builder<*> {
return ChildEntityType1(version, entitySource) {
parents.filterIsInstance<EntityWithChildren.Builder>().singleOrNull()?.let { this.parent = it }
}
}
override fun getRequiredParents(): List<Class<out WorkspaceEntity>> {
val res = mutableListOf<Class<out WorkspaceEntity>>()
res.add(EntityWithChildren::class.java)
return res
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as ChildEntityType1Data
if (this.entitySource != other.entitySource) return false
if (this.version != other.version) return false
return true
}
override fun equalsIgnoringEntitySource(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as ChildEntityType1Data
if (this.version != other.version) return false
return true
}
override fun hashCode(): Int {
var result = entitySource.hashCode()
result = 31 * result + version.hashCode()
return result
}
override fun hashCodeIgnoringEntitySource(): Int {
var result = javaClass.hashCode()
result = 31 * result + version.hashCode()
return result
}
}
@@ -0,0 +1,247 @@
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.GeneratedCodeImplVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.annotations.Child
import com.intellij.platform.workspace.storage.impl.EntityLink
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityData
import com.intellij.platform.workspace.storage.impl.extractOneToOneParent
import com.intellij.platform.workspace.storage.impl.updateOneToOneParentOfChild
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentation
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentationApi
import com.intellij.platform.workspace.storage.instrumentation.MutableEntityStorageInstrumentation
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.workspaceModel.test.api.ChildEntityType2
import com.intellij.workspaceModel.test.api.EntityWithChildren
@GeneratedCodeApiVersion(3)
@GeneratedCodeImplVersion(6)
@OptIn(WorkspaceEntityInternalApi::class)
internal class ChildEntityType2Impl(private val dataSource: ChildEntityType2Data) : ChildEntityType2, WorkspaceEntityBase(dataSource) {
private companion object {
internal val PARENT_CONNECTION_ID: ConnectionId =
ConnectionId.create(EntityWithChildren::class.java, ChildEntityType2::class.java, ConnectionId.ConnectionType.ONE_TO_ONE, false)
private val connections = listOf<ConnectionId>(
PARENT_CONNECTION_ID,
)
}
override val version: Int
get() {
readField("version")
return dataSource.version
}
override val parent: EntityWithChildren
get() = snapshot.extractOneToOneParent(PARENT_CONNECTION_ID, this)!!
override val entitySource: EntitySource
get() {
readField("entitySource")
return dataSource.entitySource
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
internal class Builder(result: ChildEntityType2Data?) : ModifiableWorkspaceEntityBase<ChildEntityType2, ChildEntityType2Data>(result),
ChildEntityType2.Builder {
internal constructor() : this(ChildEntityType2Data())
override fun applyToBuilder(builder: MutableEntityStorage) {
if (this.diff != null) {
if (existsInBuilder(builder)) {
this.diff = builder
return
}
else {
error("Entity ChildEntityType2 is already created in a different builder")
}
}
this.diff = builder
addToBuilder()
this.id = getEntityData().createEntityId()
// After adding entity data to the builder, we need to unbind it and move the control over entity data to builder
// Builder may switch to snapshot at any moment and lock entity data to modification
this.currentEntityData = null
// Process linked entities that are connected without a builder
processLinkedEntities(builder)
checkInitialization() // TODO uncomment and check failed tests
}
private fun checkInitialization() {
val _diff = diff
if (!getEntityData().isEntitySourceInitialized()) {
error("Field WorkspaceEntity#entitySource should be initialized")
}
if (_diff != null) {
if (_diff.extractOneToOneParent<WorkspaceEntityBase>(PARENT_CONNECTION_ID, this) == null) {
error("Field ChildEntityType2#parent should be initialized")
}
}
else {
if (this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)] == null) {
error("Field ChildEntityType2#parent should be initialized")
}
}
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
// Relabeling code, move information from dataSource to this builder
override fun relabel(dataSource: WorkspaceEntity, parents: Set<WorkspaceEntity>?) {
dataSource as ChildEntityType2
if (this.entitySource != dataSource.entitySource) this.entitySource = dataSource.entitySource
if (this.version != dataSource.version) this.version = dataSource.version
updateChildToParentReferences(parents)
}
override var entitySource: EntitySource
get() = getEntityData().entitySource
set(value) {
checkModificationAllowed()
getEntityData(true).entitySource = value
changedProperty.add("entitySource")
}
override var version: Int
get() = getEntityData().version
set(value) {
checkModificationAllowed()
getEntityData(true).version = value
changedProperty.add("version")
}
override var parent: EntityWithChildren.Builder
get() {
val _diff = diff
return if (_diff != null) {
@OptIn(EntityStorageInstrumentationApi::class)
((_diff as MutableEntityStorageInstrumentation).getParentBuilder(PARENT_CONNECTION_ID, this) as? EntityWithChildren.Builder)
?: (this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)]!! as EntityWithChildren.Builder)
}
else {
this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)]!! as EntityWithChildren.Builder
}
}
set(value) {
checkModificationAllowed()
val _diff = diff
if (_diff != null && value is ModifiableWorkspaceEntityBase<*, *> && value.diff == null) {
if (value is ModifiableWorkspaceEntityBase<*, *>) {
value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
_diff.addEntity(value as ModifiableWorkspaceEntityBase<WorkspaceEntity, *>)
}
if (_diff != null && (value !is ModifiableWorkspaceEntityBase<*, *> || value.diff != null)) {
_diff.updateOneToOneParentOfChild(PARENT_CONNECTION_ID, this, value)
}
else {
if (value is ModifiableWorkspaceEntityBase<*, *>) {
value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)] = value
}
changedProperty.add("parent")
}
override fun getEntityClass(): Class<ChildEntityType2> = ChildEntityType2::class.java
}
}
@OptIn(WorkspaceEntityInternalApi::class)
internal class ChildEntityType2Data : WorkspaceEntityData<ChildEntityType2>() {
var version: Int = 0
override fun wrapAsModifiable(diff: MutableEntityStorage): WorkspaceEntity.Builder<ChildEntityType2> {
val modifiable = ChildEntityType2Impl.Builder(null)
modifiable.diff = diff
modifiable.id = createEntityId()
return modifiable
}
@OptIn(EntityStorageInstrumentationApi::class)
override fun createEntity(snapshot: EntityStorageInstrumentation): ChildEntityType2 {
val entityId = createEntityId()
return snapshot.initializeEntity(entityId) {
val entity = ChildEntityType2Impl(this)
entity.snapshot = snapshot
entity.id = entityId
entity
}
}
override fun getMetadata(): EntityMetadata {
return MetadataStorageImpl.getMetadataByTypeFqn("com.intellij.workspaceModel.test.api.ChildEntityType2") as EntityMetadata
}
override fun getEntityInterface(): Class<out WorkspaceEntity> {
return ChildEntityType2::class.java
}
override fun createDetachedEntity(parents: List<WorkspaceEntity.Builder<*>>): WorkspaceEntity.Builder<*> {
return ChildEntityType2(version, entitySource) {
parents.filterIsInstance<EntityWithChildren.Builder>().singleOrNull()?.let { this.parent = it }
}
}
override fun getRequiredParents(): List<Class<out WorkspaceEntity>> {
val res = mutableListOf<Class<out WorkspaceEntity>>()
res.add(EntityWithChildren::class.java)
return res
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as ChildEntityType2Data
if (this.entitySource != other.entitySource) return false
if (this.version != other.version) return false
return true
}
override fun equalsIgnoringEntitySource(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as ChildEntityType2Data
if (this.version != other.version) return false
return true
}
override fun hashCode(): Int {
var result = entitySource.hashCode()
result = 31 * result + version.hashCode()
return result
}
override fun hashCodeIgnoringEntitySource(): Int {
var result = javaClass.hashCode()
result = 31 * result + version.hashCode()
return result
}
}
@@ -0,0 +1,286 @@
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.GeneratedCodeImplVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.annotations.Child
import com.intellij.platform.workspace.storage.impl.EntityLink
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityData
import com.intellij.platform.workspace.storage.impl.extractOneToOneChild
import com.intellij.platform.workspace.storage.impl.updateOneToOneChildOfParent
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentation
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentationApi
import com.intellij.platform.workspace.storage.instrumentation.MutableEntityStorageInstrumentation
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.workspaceModel.test.api.ChildEntityType1
import com.intellij.workspaceModel.test.api.ChildEntityType2
import com.intellij.workspaceModel.test.api.EntityWithChildren
@GeneratedCodeApiVersion(3)
@GeneratedCodeImplVersion(6)
@OptIn(WorkspaceEntityInternalApi::class)
internal class EntityWithChildrenImpl(private val dataSource: EntityWithChildrenData) : EntityWithChildren,
WorkspaceEntityBase(dataSource) {
private companion object {
internal val PROPERTYCHILD_CONNECTION_ID: ConnectionId =
ConnectionId.create(EntityWithChildren::class.java, ChildEntityType1::class.java, ConnectionId.ConnectionType.ONE_TO_ONE, false)
internal val TYPECHILD_CONNECTION_ID: ConnectionId =
ConnectionId.create(EntityWithChildren::class.java, ChildEntityType2::class.java, ConnectionId.ConnectionType.ONE_TO_ONE, false)
private val connections = listOf<ConnectionId>(
PROPERTYCHILD_CONNECTION_ID,
TYPECHILD_CONNECTION_ID,
)
}
override val name: String
get() {
readField("name")
return dataSource.name
}
override val propertyChild: ChildEntityType1?
get() = snapshot.extractOneToOneChild(PROPERTYCHILD_CONNECTION_ID, this)
override val typeChild: ChildEntityType2?
get() = snapshot.extractOneToOneChild(TYPECHILD_CONNECTION_ID, this)
override val entitySource: EntitySource
get() {
readField("entitySource")
return dataSource.entitySource
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
internal class Builder(result: EntityWithChildrenData?) :
ModifiableWorkspaceEntityBase<EntityWithChildren, EntityWithChildrenData>(result), EntityWithChildren.Builder {
internal constructor() : this(EntityWithChildrenData())
override fun applyToBuilder(builder: MutableEntityStorage) {
if (this.diff != null) {
if (existsInBuilder(builder)) {
this.diff = builder
return
}
else {
error("Entity EntityWithChildren is already created in a different builder")
}
}
this.diff = builder
addToBuilder()
this.id = getEntityData().createEntityId()
// After adding entity data to the builder, we need to unbind it and move the control over entity data to builder
// Builder may switch to snapshot at any moment and lock entity data to modification
this.currentEntityData = null
// Process linked entities that are connected without a builder
processLinkedEntities(builder)
checkInitialization() // TODO uncomment and check failed tests
}
private fun checkInitialization() {
val _diff = diff
if (!getEntityData().isEntitySourceInitialized()) {
error("Field WorkspaceEntity#entitySource should be initialized")
}
if (!getEntityData().isNameInitialized()) {
error("Field EntityWithChildren#name should be initialized")
}
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
// Relabeling code, move information from dataSource to this builder
override fun relabel(dataSource: WorkspaceEntity, parents: Set<WorkspaceEntity>?) {
dataSource as EntityWithChildren
if (this.entitySource != dataSource.entitySource) this.entitySource = dataSource.entitySource
if (this.name != dataSource.name) this.name = dataSource.name
updateChildToParentReferences(parents)
}
override var entitySource: EntitySource
get() = getEntityData().entitySource
set(value) {
checkModificationAllowed()
getEntityData(true).entitySource = value
changedProperty.add("entitySource")
}
override var name: String
get() = getEntityData().name
set(value) {
checkModificationAllowed()
getEntityData(true).name = value
changedProperty.add("name")
}
override var propertyChild: ChildEntityType1.Builder?
get() {
val _diff = diff
return if (_diff != null) {
@OptIn(EntityStorageInstrumentationApi::class)
((_diff as MutableEntityStorageInstrumentation).getOneChildBuilder(
PROPERTYCHILD_CONNECTION_ID, this
) as? ChildEntityType1.Builder)
?: (this.entityLinks[EntityLink(true, PROPERTYCHILD_CONNECTION_ID)] as? ChildEntityType1.Builder)
}
else {
this.entityLinks[EntityLink(true, PROPERTYCHILD_CONNECTION_ID)] as? ChildEntityType1.Builder
}
}
set(value) {
checkModificationAllowed()
val _diff = diff
if (_diff != null && value is ModifiableWorkspaceEntityBase<*, *> && value.diff == null) {
if (value is ModifiableWorkspaceEntityBase<*, *>) {
value.entityLinks[EntityLink(false, PROPERTYCHILD_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
_diff.addEntity(value as ModifiableWorkspaceEntityBase<WorkspaceEntity, *>)
}
if (_diff != null && (value !is ModifiableWorkspaceEntityBase<*, *> || value.diff != null)) {
_diff.updateOneToOneChildOfParent(PROPERTYCHILD_CONNECTION_ID, this, value)
}
else {
if (value is ModifiableWorkspaceEntityBase<*, *>) {
value.entityLinks[EntityLink(false, PROPERTYCHILD_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
this.entityLinks[EntityLink(true, PROPERTYCHILD_CONNECTION_ID)] = value
}
changedProperty.add("propertyChild")
}
override var typeChild: ChildEntityType2.Builder?
get() {
val _diff = diff
return if (_diff != null) {
@OptIn(EntityStorageInstrumentationApi::class)
((_diff as MutableEntityStorageInstrumentation).getOneChildBuilder(TYPECHILD_CONNECTION_ID, this) as? ChildEntityType2.Builder)
?: (this.entityLinks[EntityLink(true, TYPECHILD_CONNECTION_ID)] as? ChildEntityType2.Builder)
}
else {
this.entityLinks[EntityLink(true, TYPECHILD_CONNECTION_ID)] as? ChildEntityType2.Builder
}
}
set(value) {
checkModificationAllowed()
val _diff = diff
if (_diff != null && value is ModifiableWorkspaceEntityBase<*, *> && value.diff == null) {
if (value is ModifiableWorkspaceEntityBase<*, *>) {
value.entityLinks[EntityLink(false, TYPECHILD_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
_diff.addEntity(value as ModifiableWorkspaceEntityBase<WorkspaceEntity, *>)
}
if (_diff != null && (value !is ModifiableWorkspaceEntityBase<*, *> || value.diff != null)) {
_diff.updateOneToOneChildOfParent(TYPECHILD_CONNECTION_ID, this, value)
}
else {
if (value is ModifiableWorkspaceEntityBase<*, *>) {
value.entityLinks[EntityLink(false, TYPECHILD_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
this.entityLinks[EntityLink(true, TYPECHILD_CONNECTION_ID)] = value
}
changedProperty.add("typeChild")
}
override fun getEntityClass(): Class<EntityWithChildren> = EntityWithChildren::class.java
}
}
@OptIn(WorkspaceEntityInternalApi::class)
internal class EntityWithChildrenData : WorkspaceEntityData<EntityWithChildren>() {
lateinit var name: String
internal fun isNameInitialized(): Boolean = ::name.isInitialized
override fun wrapAsModifiable(diff: MutableEntityStorage): WorkspaceEntity.Builder<EntityWithChildren> {
val modifiable = EntityWithChildrenImpl.Builder(null)
modifiable.diff = diff
modifiable.id = createEntityId()
return modifiable
}
@OptIn(EntityStorageInstrumentationApi::class)
override fun createEntity(snapshot: EntityStorageInstrumentation): EntityWithChildren {
val entityId = createEntityId()
return snapshot.initializeEntity(entityId) {
val entity = EntityWithChildrenImpl(this)
entity.snapshot = snapshot
entity.id = entityId
entity
}
}
override fun getMetadata(): EntityMetadata {
return MetadataStorageImpl.getMetadataByTypeFqn("com.intellij.workspaceModel.test.api.EntityWithChildren") as EntityMetadata
}
override fun getEntityInterface(): Class<out WorkspaceEntity> {
return EntityWithChildren::class.java
}
override fun createDetachedEntity(parents: List<WorkspaceEntity.Builder<*>>): WorkspaceEntity.Builder<*> {
return EntityWithChildren(name, entitySource) {
}
}
override fun getRequiredParents(): List<Class<out WorkspaceEntity>> {
val res = mutableListOf<Class<out WorkspaceEntity>>()
return res
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as EntityWithChildrenData
if (this.entitySource != other.entitySource) return false
if (this.name != other.name) return false
return true
}
override fun equalsIgnoringEntitySource(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as EntityWithChildrenData
if (this.name != other.name) return false
return true
}
override fun hashCode(): Int {
var result = entitySource.hashCode()
result = 31 * result + name.hashCode()
return result
}
override fun hashCodeIgnoringEntitySource(): Int {
var result = javaClass.hashCode()
result = 31 * result + name.hashCode()
return result
}
}
@@ -0,0 +1,46 @@
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.metadata.impl.MetadataStorageBase
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.platform.workspace.storage.metadata.model.FinalClassMetadata
import com.intellij.platform.workspace.storage.metadata.model.OwnPropertyMetadata
import com.intellij.platform.workspace.storage.metadata.model.StorageTypeMetadata
import com.intellij.platform.workspace.storage.metadata.model.ValueTypeMetadata
@OptIn(WorkspaceEntityInternalApi::class)
internal object MetadataStorageImpl: MetadataStorageBase() {
override fun initializeMetadata() {
val primitiveTypeIntNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Int")
val primitiveTypeStringNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "String")
var typeMetadata: StorageTypeMetadata
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.ChildEntityType1", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.ChildEntityType1Data", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "version", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "parent", valueType = ValueTypeMetadata.EntityReference(connectionType = ConnectionId.ConnectionType.ONE_TO_ONE, entityFqName = "com.intellij.workspaceModel.test.api.EntityWithChildren", isChild = false, isNullable = false), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.ChildEntityType2", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.ChildEntityType2Data", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "version", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "parent", valueType = ValueTypeMetadata.EntityReference(connectionType = ConnectionId.ConnectionType.ONE_TO_ONE, entityFqName = "com.intellij.workspaceModel.test.api.EntityWithChildren", isChild = false, isNullable = false), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.EntityWithChildren", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.EntityWithChildrenData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "propertyChild", valueType = ValueTypeMetadata.EntityReference(connectionType = ConnectionId.ConnectionType.ONE_TO_ONE, entityFqName = "com.intellij.workspaceModel.test.api.ChildEntityType1", isChild = true, isNullable = true), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "typeChild", valueType = ValueTypeMetadata.EntityReference(connectionType = ConnectionId.ConnectionType.ONE_TO_ONE, entityFqName = "com.intellij.workspaceModel.test.api.ChildEntityType2", isChild = true, isNullable = true), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
}
override fun initializeMetadataHash() {
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.ChildEntityType1", metadataHash = 1430777503)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.ChildEntityType2", metadataHash = -1568141121)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.EntityWithChildren", metadataHash = 104242451)
}
}
@@ -0,0 +1,20 @@
package com.intellij.workspaceModel.test.api
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.annotations.Child
interface EntityWithChildren : WorkspaceEntity {
val name: String
val propertyChild: @Child ChildEntityType1?
@Child val typeChild: ChildEntityType2?
}
interface ChildEntityType1 : WorkspaceEntity {
val version: Int
val parent: EntityWithChildren
}
interface ChildEntityType2 : WorkspaceEntity {
val version: Int
val parent: EntityWithChildren
}
@@ -1,12 +1,12 @@
package com.intellij.workspaceModel.test.api
import com.intellij.platform.workspace.storage.EntityType
import com.intellij.platform.workspace.storage.annotations.Default
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.EntityType
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.ModifiableWorkspaceEntity
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.annotations.Default
interface FinalFieldsEntity : WorkspaceEntity {
@@ -11,27 +11,27 @@ import com.intellij.platform.workspace.storage.metadata.model.ValueTypeMetadata
@OptIn(WorkspaceEntityInternalApi::class)
internal object MetadataStorageImpl: MetadataStorageBase() {
override fun initializeMetadata() {
val primitiveTypeStringNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "String")
val primitiveTypeIntNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Int")
val primitiveTypeBooleanNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Boolean")
val primitiveTypeStringNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = true, type = "String")
val primitiveTypeStringNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "String")
val primitiveTypeBooleanNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Boolean")
val primitiveTypeIntNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Int")
var typeMetadata: StorageTypeMetadata
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.FinalFieldsEntity", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.FinalFieldsEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "descriptor", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.AnotherDataClass", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "version", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "descriptor", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.AnotherDataClass", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "displayName", valueType = primitiveTypeStringNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "revision", valueType = primitiveTypeStringNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "source", valueType = primitiveTypeBooleanNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "displayName", valueType = primitiveTypeStringNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "url", valueType = primitiveTypeStringNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "revision", valueType = primitiveTypeStringNullable, withDefault = false)), supertypes = listOf())), withDefault = false)), extProperties = listOf(), isAbstract = false)
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "version", valueType = primitiveTypeIntNotNullable, withDefault = false)), supertypes = listOf())), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
}
override fun initializeMetadataHash() {
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.FinalFieldsEntity", metadataHash = 1499543638)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.AnotherDataClass", metadataHash = -1492715258)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.FinalFieldsEntity", metadataHash = -241552936)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.AnotherDataClass", metadataHash = 1379646916)
}
}
@@ -0,0 +1,108 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.test.api
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.annotations.Child
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import java.net.URL
interface EntityWithManyImports : WorkspaceEntityWithSymbolicId {
val version: Int
val name: String
val files: List<@Child SimpleEntity>
val pointer: EntityPointer<SimpleEntity>
override val symbolicId: SimpleId
get() = SimpleId(name)
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<EntityWithManyImports> {
override var entitySource: EntitySource
var version: Int
var name: String
var files: List<SimpleEntity.Builder>
var pointer: EntityPointer
}
companion object : EntityType<EntityWithManyImports, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
version: Int,
name: String,
pointer: EntityPointer,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.version = version
builder.name = name
builder.pointer = pointer
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
}
//endregion
}
//region generated code
fun MutableEntityStorage.modifyEntityWithManyImports(
entity: EntityWithManyImports,
modification: EntityWithManyImports.Builder.() -> Unit,
): EntityWithManyImports {
return modifyEntity(EntityWithManyImports.Builder::class.java, entity, modification)
}
//endregion
data class SimpleId(val name: String) : SymbolicEntityId<EntityWithManyImports> {
override val presentableName: String
get() = name
}
interface SimpleEntity : WorkspaceEntity {
val url: VirtualFileUrl
val parent: EntityWithManyImports
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<SimpleEntity> {
override var entitySource: EntitySource
var url: VirtualFileUrl
var parent: EntityWithManyImports.Builder
}
companion object : EntityType<SimpleEntity, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
url: VirtualFileUrl,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.url = url
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
}
//endregion
}
//region generated code
fun MutableEntityStorage.modifySimpleEntity(
entity: SimpleEntity,
modification: SimpleEntity.Builder.() -> Unit,
): SimpleEntity {
return modifyEntity(SimpleEntity.Builder::class.java, entity, modification)
}
//endregion
data class UnrelatedToEntities(val name: String, val data: EntityPointer<SimpleEntity>) {
fun doSomething(src: EntitySource) {
}
}
@@ -0,0 +1,308 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.annotations.Child
import com.intellij.platform.workspace.storage.impl.EntityLink
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityData
import com.intellij.platform.workspace.storage.impl.extractOneToManyChildren
import com.intellij.platform.workspace.storage.impl.updateOneToManyChildrenOfParent
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentation
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentationApi
import com.intellij.platform.workspace.storage.instrumentation.MutableEntityStorageInstrumentation
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import com.intellij.workspaceModel.test.api.EntityWithManyImports
import com.intellij.workspaceModel.test.api.SimpleEntity
import com.intellij.workspaceModel.test.api.SimpleId
import java.net.URL
@GeneratedCodeApiVersion(3)
@GeneratedCodeImplVersion(6)
@OptIn(WorkspaceEntityInternalApi::class)
internal class EntityWithManyImportsImpl(private val dataSource: EntityWithManyImportsData) : EntityWithManyImports,
WorkspaceEntityBase(dataSource) {
private companion object {
internal val FILES_CONNECTION_ID: ConnectionId =
ConnectionId.create(EntityWithManyImports::class.java, SimpleEntity::class.java, ConnectionId.ConnectionType.ONE_TO_MANY, false)
private val connections = listOf<ConnectionId>(
FILES_CONNECTION_ID,
)
}
override val symbolicId: SimpleId = super.symbolicId
override val version: Int
get() {
readField("version")
return dataSource.version
}
override val name: String
get() {
readField("name")
return dataSource.name
}
override val files: List<SimpleEntity>
get() = snapshot.extractOneToManyChildren<SimpleEntity>(FILES_CONNECTION_ID, this)!!.toList()
override val pointer: EntityPointer
get() {
readField("pointer")
return dataSource.pointer
}
override val entitySource: EntitySource
get() {
readField("entitySource")
return dataSource.entitySource
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
internal class Builder(result: EntityWithManyImportsData?) :
ModifiableWorkspaceEntityBase<EntityWithManyImports, EntityWithManyImportsData>(result), EntityWithManyImports.Builder {
internal constructor() : this(EntityWithManyImportsData())
override fun applyToBuilder(builder: MutableEntityStorage) {
if (this.diff != null) {
if (existsInBuilder(builder)) {
this.diff = builder
return
}
else {
error("Entity EntityWithManyImports is already created in a different builder")
}
}
this.diff = builder
addToBuilder()
this.id = getEntityData().createEntityId()
// After adding entity data to the builder, we need to unbind it and move the control over entity data to builder
// Builder may switch to snapshot at any moment and lock entity data to modification
this.currentEntityData = null
// Process linked entities that are connected without a builder
processLinkedEntities(builder)
checkInitialization() // TODO uncomment and check failed tests
}
private fun checkInitialization() {
val _diff = diff
if (!getEntityData().isEntitySourceInitialized()) {
error("Field WorkspaceEntity#entitySource should be initialized")
}
if (!getEntityData().isNameInitialized()) {
error("Field EntityWithManyImports#name should be initialized")
}
// Check initialization for list with ref type
if (_diff != null) {
if (_diff.extractOneToManyChildren<WorkspaceEntityBase>(FILES_CONNECTION_ID, this) == null) {
error("Field EntityWithManyImports#files should be initialized")
}
}
else {
if (this.entityLinks[EntityLink(true, FILES_CONNECTION_ID)] == null) {
error("Field EntityWithManyImports#files should be initialized")
}
}
if (!getEntityData().isPointerInitialized()) {
error("Field EntityWithManyImports#pointer should be initialized")
}
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
// Relabeling code, move information from dataSource to this builder
override fun relabel(dataSource: WorkspaceEntity, parents: Set<WorkspaceEntity>?) {
dataSource as EntityWithManyImports
if (this.entitySource != dataSource.entitySource) this.entitySource = dataSource.entitySource
if (this.version != dataSource.version) this.version = dataSource.version
if (this.name != dataSource.name) this.name = dataSource.name
if (this.pointer != dataSource.pointer) this.pointer = dataSource.pointer
updateChildToParentReferences(parents)
}
override var entitySource: EntitySource
get() = getEntityData().entitySource
set(value) {
checkModificationAllowed()
getEntityData(true).entitySource = value
changedProperty.add("entitySource")
}
override var version: Int
get() = getEntityData().version
set(value) {
checkModificationAllowed()
getEntityData(true).version = value
changedProperty.add("version")
}
override var name: String
get() = getEntityData().name
set(value) {
checkModificationAllowed()
getEntityData(true).name = value
changedProperty.add("name")
}
// List of non-abstract referenced types
var _files: List<SimpleEntity>? = emptyList()
override var files: List<SimpleEntity.Builder>
get() {
// Getter of the list of non-abstract referenced types
val _diff = diff
return if (_diff != null) {
@OptIn(EntityStorageInstrumentationApi::class)
((_diff as MutableEntityStorageInstrumentation).getManyChildrenBuilders(FILES_CONNECTION_ID, this)!!
.toList() as List<SimpleEntity.Builder>) +
(this.entityLinks[EntityLink(true, FILES_CONNECTION_ID)] as? List<SimpleEntity.Builder> ?: emptyList())
}
else {
this.entityLinks[EntityLink(true, FILES_CONNECTION_ID)] as? List<SimpleEntity.Builder> ?: emptyList()
}
}
set(value) {
// Setter of the list of non-abstract referenced types
checkModificationAllowed()
val _diff = diff
if (_diff != null) {
for (item_value in value) {
if (item_value is ModifiableWorkspaceEntityBase<*, *> && (item_value as? ModifiableWorkspaceEntityBase<*, *>)?.diff == null) {
// Backref setup before adding to store
if (item_value is ModifiableWorkspaceEntityBase<*, *>) {
item_value.entityLinks[EntityLink(false, FILES_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
_diff.addEntity(item_value as ModifiableWorkspaceEntityBase<WorkspaceEntity, *>)
}
}
_diff.updateOneToManyChildrenOfParent(FILES_CONNECTION_ID, this, value)
}
else {
for (item_value in value) {
if (item_value is ModifiableWorkspaceEntityBase<*, *>) {
item_value.entityLinks[EntityLink(false, FILES_CONNECTION_ID)] = this
}
// else you're attaching a new entity to an existing entity that is not modifiable
}
this.entityLinks[EntityLink(true, FILES_CONNECTION_ID)] = value
}
changedProperty.add("files")
}
override var pointer: EntityPointer
get() = getEntityData().pointer
set(value) {
checkModificationAllowed()
getEntityData(true).pointer = value
changedProperty.add("pointer")
}
override fun getEntityClass(): Class<EntityWithManyImports> = EntityWithManyImports::class.java
}
}
@OptIn(WorkspaceEntityInternalApi::class)
internal class EntityWithManyImportsData : WorkspaceEntityData<EntityWithManyImports>() {
var version: Int = 0
lateinit var name: String
lateinit var pointer: EntityPointer
internal fun isNameInitialized(): Boolean = ::name.isInitialized
internal fun isPointerInitialized(): Boolean = ::pointer.isInitialized
override fun wrapAsModifiable(diff: MutableEntityStorage): WorkspaceEntity.Builder<EntityWithManyImports> {
val modifiable = EntityWithManyImportsImpl.Builder(null)
modifiable.diff = diff
modifiable.id = createEntityId()
return modifiable
}
@OptIn(EntityStorageInstrumentationApi::class)
override fun createEntity(snapshot: EntityStorageInstrumentation): EntityWithManyImports {
val entityId = createEntityId()
return snapshot.initializeEntity(entityId) {
val entity = EntityWithManyImportsImpl(this)
entity.snapshot = snapshot
entity.id = entityId
entity
}
}
override fun getMetadata(): EntityMetadata {
return MetadataStorageImpl.getMetadataByTypeFqn("com.intellij.workspaceModel.test.api.EntityWithManyImports") as EntityMetadata
}
override fun getEntityInterface(): Class<out WorkspaceEntity> {
return EntityWithManyImports::class.java
}
override fun createDetachedEntity(parents: List<WorkspaceEntity.Builder<*>>): WorkspaceEntity.Builder<*> {
return EntityWithManyImports(version, name, pointer, entitySource) {
}
}
override fun getRequiredParents(): List<Class<out WorkspaceEntity>> {
val res = mutableListOf<Class<out WorkspaceEntity>>()
return res
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as EntityWithManyImportsData
if (this.entitySource != other.entitySource) return false
if (this.version != other.version) return false
if (this.name != other.name) return false
if (this.pointer != other.pointer) return false
return true
}
override fun equalsIgnoringEntitySource(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as EntityWithManyImportsData
if (this.version != other.version) return false
if (this.name != other.name) return false
if (this.pointer != other.pointer) return false
return true
}
override fun hashCode(): Int {
var result = entitySource.hashCode()
result = 31 * result + version.hashCode()
result = 31 * result + name.hashCode()
result = 31 * result + pointer.hashCode()
return result
}
override fun hashCodeIgnoringEntitySource(): Int {
var result = javaClass.hashCode()
result = 31 * result + version.hashCode()
result = 31 * result + name.hashCode()
result = 31 * result + pointer.hashCode()
return result
}
}
@@ -0,0 +1,50 @@
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.ConnectionId
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.metadata.impl.MetadataStorageBase
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.platform.workspace.storage.metadata.model.FinalClassMetadata
import com.intellij.platform.workspace.storage.metadata.model.OwnPropertyMetadata
import com.intellij.platform.workspace.storage.metadata.model.StorageTypeMetadata
import com.intellij.platform.workspace.storage.metadata.model.ValueTypeMetadata
@OptIn(WorkspaceEntityInternalApi::class)
internal object MetadataStorageImpl: MetadataStorageBase() {
override fun initializeMetadata() {
val primitiveTypeStringNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "String")
val primitiveTypeIntNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Int")
var typeMetadata: StorageTypeMetadata
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))
addMetadata(typeMetadata)
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.EntityWithManyImports", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.EntityWithManyImportsData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity",
"com.intellij.platform.workspace.storage.WorkspaceEntityWithSymbolicId"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "version", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "files", valueType = ValueTypeMetadata.EntityReference(connectionType = ConnectionId.ConnectionType.ONE_TO_MANY, entityFqName = "com.intellij.workspaceModel.test.api.SimpleEntity", isChild = true, isNullable = false), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "pointer", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntityPointer")), withDefault = false),
OwnPropertyMetadata(isComputable = true, isKey = false, isOpen = false, name = "symbolicId", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleEntity", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.SimpleEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "url", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.url.VirtualFileUrl")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "parent", valueType = ValueTypeMetadata.EntityReference(connectionType = ConnectionId.ConnectionType.ONE_TO_MANY, entityFqName = "com.intellij.workspaceModel.test.api.EntityWithManyImports", isChild = false, isNullable = false), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
}
override fun initializeMetadataHash() {
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.EntityWithManyImports", metadataHash = 279598191)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SimpleEntity", metadataHash = 8198385)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SimpleId", metadataHash = 1096965603)
addMetadataHash(typeFqn = "com.intellij.platform.workspace.storage.SymbolicEntityId", metadataHash = -1044278955)
}
}
@@ -0,0 +1,256 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.annotations.Child
import com.intellij.platform.workspace.storage.impl.EntityLink
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityData
import com.intellij.platform.workspace.storage.impl.extractOneToManyParent
import com.intellij.platform.workspace.storage.impl.updateOneToManyParentOfChild
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentation
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentationApi
import com.intellij.platform.workspace.storage.instrumentation.MutableEntityStorageInstrumentation
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
import com.intellij.workspaceModel.test.api.EntityWithManyImports
import com.intellij.workspaceModel.test.api.SimpleEntity
import java.net.URL
@GeneratedCodeApiVersion(3)
@GeneratedCodeImplVersion(6)
@OptIn(WorkspaceEntityInternalApi::class)
internal class SimpleEntityImpl(private val dataSource: SimpleEntityData) : SimpleEntity, WorkspaceEntityBase(dataSource) {
private companion object {
internal val PARENT_CONNECTION_ID: ConnectionId =
ConnectionId.create(EntityWithManyImports::class.java, SimpleEntity::class.java, ConnectionId.ConnectionType.ONE_TO_MANY, false)
private val connections = listOf<ConnectionId>(
PARENT_CONNECTION_ID,
)
}
override val url: VirtualFileUrl
get() {
readField("url")
return dataSource.url
}
override val parent: EntityWithManyImports
get() = snapshot.extractOneToManyParent(PARENT_CONNECTION_ID, this)!!
override val entitySource: EntitySource
get() {
readField("entitySource")
return dataSource.entitySource
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
internal class Builder(result: SimpleEntityData?) : ModifiableWorkspaceEntityBase<SimpleEntity, SimpleEntityData>(result),
SimpleEntity.Builder {
internal constructor() : this(SimpleEntityData())
override fun applyToBuilder(builder: MutableEntityStorage) {
if (this.diff != null) {
if (existsInBuilder(builder)) {
this.diff = builder
return
}
else {
error("Entity SimpleEntity is already created in a different builder")
}
}
this.diff = builder
addToBuilder()
this.id = getEntityData().createEntityId()
// After adding entity data to the builder, we need to unbind it and move the control over entity data to builder
// Builder may switch to snapshot at any moment and lock entity data to modification
this.currentEntityData = null
index(this, "url", this.url)
// Process linked entities that are connected without a builder
processLinkedEntities(builder)
checkInitialization() // TODO uncomment and check failed tests
}
private fun checkInitialization() {
val _diff = diff
if (!getEntityData().isEntitySourceInitialized()) {
error("Field WorkspaceEntity#entitySource should be initialized")
}
if (!getEntityData().isUrlInitialized()) {
error("Field SimpleEntity#url should be initialized")
}
if (_diff != null) {
if (_diff.extractOneToManyParent<WorkspaceEntityBase>(PARENT_CONNECTION_ID, this) == null) {
error("Field SimpleEntity#parent should be initialized")
}
}
else {
if (this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)] == null) {
error("Field SimpleEntity#parent should be initialized")
}
}
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
// Relabeling code, move information from dataSource to this builder
override fun relabel(dataSource: WorkspaceEntity, parents: Set<WorkspaceEntity>?) {
dataSource as SimpleEntity
if (this.entitySource != dataSource.entitySource) this.entitySource = dataSource.entitySource
if (this.url != dataSource.url) this.url = dataSource.url
updateChildToParentReferences(parents)
}
override var entitySource: EntitySource
get() = getEntityData().entitySource
set(value) {
checkModificationAllowed()
getEntityData(true).entitySource = value
changedProperty.add("entitySource")
}
override var url: VirtualFileUrl
get() = getEntityData().url
set(value) {
checkModificationAllowed()
getEntityData(true).url = value
changedProperty.add("url")
val _diff = diff
if (_diff != null) index(this, "url", value)
}
override var parent: EntityWithManyImports.Builder
get() {
val _diff = diff
return if (_diff != null) {
@OptIn(EntityStorageInstrumentationApi::class)
((_diff as MutableEntityStorageInstrumentation).getParentBuilder(PARENT_CONNECTION_ID, this) as? EntityWithManyImports.Builder)
?: (this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)]!! as EntityWithManyImports.Builder)
}
else {
this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)]!! as EntityWithManyImports.Builder
}
}
set(value) {
checkModificationAllowed()
val _diff = diff
if (_diff != null && value is ModifiableWorkspaceEntityBase<*, *> && value.diff == null) {
// Setting backref of the list
if (value is ModifiableWorkspaceEntityBase<*, *>) {
val data = (value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] as? List<Any> ?: emptyList()) + this
value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] = data
}
// else you're attaching a new entity to an existing entity that is not modifiable
_diff.addEntity(value as ModifiableWorkspaceEntityBase<WorkspaceEntity, *>)
}
if (_diff != null && (value !is ModifiableWorkspaceEntityBase<*, *> || value.diff != null)) {
_diff.updateOneToManyParentOfChild(PARENT_CONNECTION_ID, this, value)
}
else {
// Setting backref of the list
if (value is ModifiableWorkspaceEntityBase<*, *>) {
val data = (value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] as? List<Any> ?: emptyList()) + this
value.entityLinks[EntityLink(true, PARENT_CONNECTION_ID)] = data
}
// else you're attaching a new entity to an existing entity that is not modifiable
this.entityLinks[EntityLink(false, PARENT_CONNECTION_ID)] = value
}
changedProperty.add("parent")
}
override fun getEntityClass(): Class<SimpleEntity> = SimpleEntity::class.java
}
}
@OptIn(WorkspaceEntityInternalApi::class)
internal class SimpleEntityData : WorkspaceEntityData<SimpleEntity>() {
lateinit var url: VirtualFileUrl
internal fun isUrlInitialized(): Boolean = ::url.isInitialized
override fun wrapAsModifiable(diff: MutableEntityStorage): WorkspaceEntity.Builder<SimpleEntity> {
val modifiable = SimpleEntityImpl.Builder(null)
modifiable.diff = diff
modifiable.id = createEntityId()
return modifiable
}
@OptIn(EntityStorageInstrumentationApi::class)
override fun createEntity(snapshot: EntityStorageInstrumentation): SimpleEntity {
val entityId = createEntityId()
return snapshot.initializeEntity(entityId) {
val entity = SimpleEntityImpl(this)
entity.snapshot = snapshot
entity.id = entityId
entity
}
}
override fun getMetadata(): EntityMetadata {
return MetadataStorageImpl.getMetadataByTypeFqn("com.intellij.workspaceModel.test.api.SimpleEntity") as EntityMetadata
}
override fun getEntityInterface(): Class<out WorkspaceEntity> {
return SimpleEntity::class.java
}
override fun createDetachedEntity(parents: List<WorkspaceEntity.Builder<*>>): WorkspaceEntity.Builder<*> {
return SimpleEntity(url, entitySource) {
parents.filterIsInstance<EntityWithManyImports.Builder>().singleOrNull()?.let { this.parent = it }
}
}
override fun getRequiredParents(): List<Class<out WorkspaceEntity>> {
val res = mutableListOf<Class<out WorkspaceEntity>>()
res.add(EntityWithManyImports::class.java)
return res
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as SimpleEntityData
if (this.entitySource != other.entitySource) return false
if (this.url != other.url) return false
return true
}
override fun equalsIgnoringEntitySource(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as SimpleEntityData
if (this.url != other.url) return false
return true
}
override fun hashCode(): Int {
var result = entitySource.hashCode()
result = 31 * result + url.hashCode()
return result
}
override fun hashCodeIgnoringEntitySource(): Int {
var result = javaClass.hashCode()
result = 31 * result + url.hashCode()
return result
}
}
@@ -0,0 +1,33 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.test.api
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.WorkspaceEntityWithSymbolicId // stoopid and unnecessary
import java.net.URL // stoopid but necessary (user-added)
import com.intellij.platform.workspace.storage.annotations.Child
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
interface EntityWithManyImports : WorkspaceEntityWithSymbolicId {
val version: Int
val name: String
val files: List<@Child SimpleEntity>
val pointer: EntityPointer<SimpleEntity>
override val symbolicId: SimpleId
get() = SimpleId(name)
}
data class SimpleId(val name: String) : SymbolicEntityId<EntityWithManyImports> {
override val presentableName: String
get() = name
}
interface SimpleEntity : WorkspaceEntity {
val url: VirtualFileUrl
val parent: EntityWithManyImports
}
data class UnrelatedToEntities(val name: String, val data: EntityPointer<SimpleEntity>) {
fun doSomething(src: EntitySource) {
}
}
@@ -0,0 +1,181 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.test.api
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.annotations.Abstract
interface SimpleEntity : WorkspaceEntityWithSymbolicId {
override val symbolicId: SimpleId
get() = SimpleId(name)
val name: String
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<SimpleEntity> {
override var entitySource: EntitySource
var name: String
}
companion object : EntityType<SimpleEntity, Builder>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
name: String,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.name = name
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
}
//endregion
}
//region generated code
fun MutableEntityStorage.modifySimpleEntity(
entity: SimpleEntity,
modification: SimpleEntity.Builder.() -> Unit,
): SimpleEntity {
return modifyEntity(SimpleEntity.Builder::class.java, entity, modification)
}
//endregion
data class SimpleId(val name: String) : SymbolicEntityId<SimpleEntity> {
override val presentableName: String
get() = name
}
// partial copy of org.jetbrains.kotlin.idea.workspaceModel.KotlinSettingsEntity
@Abstract
interface BaseEntity : WorkspaceEntity {
val name: String
val moduleId: SimpleId
val aBaseEntityProperty: String
val dBaseEntityProperty: String
val bBaseEntityProperty: String
val sealedDataClassProperty: BaseDataClass
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder<T : BaseEntity> : WorkspaceEntity.Builder<T> {
override var entitySource: EntitySource
var name: String
var moduleId: SimpleId
var aBaseEntityProperty: String
var dBaseEntityProperty: String
var bBaseEntityProperty: String
var sealedDataClassProperty: BaseDataClass
}
companion object : EntityType<BaseEntity, Builder<BaseEntity>>() {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
name: String,
moduleId: SimpleId,
aBaseEntityProperty: String,
dBaseEntityProperty: String,
bBaseEntityProperty: String,
sealedDataClassProperty: BaseDataClass,
entitySource: EntitySource,
init: (Builder<BaseEntity>.() -> Unit)? = null,
): Builder<BaseEntity> {
val builder = builder()
builder.name = name
builder.moduleId = moduleId
builder.aBaseEntityProperty = aBaseEntityProperty
builder.dBaseEntityProperty = dBaseEntityProperty
builder.bBaseEntityProperty = bBaseEntityProperty
builder.sealedDataClassProperty = sealedDataClassProperty
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
}
//endregion
}
interface ChildEntity : BaseEntity {
val cChildEntityProperty: String
//region generated code
@GeneratedCodeApiVersion(3)
interface Builder : WorkspaceEntity.Builder<ChildEntity>, BaseEntity.Builder<ChildEntity> {
override var entitySource: EntitySource
override var name: String
override var moduleId: SimpleId
override var aBaseEntityProperty: String
override var dBaseEntityProperty: String
override var bBaseEntityProperty: String
override var sealedDataClassProperty: BaseDataClass
var cChildEntityProperty: String
}
companion object : EntityType<ChildEntity, Builder>(BaseEntity) {
@JvmOverloads
@JvmStatic
@JvmName("create")
operator fun invoke(
name: String,
moduleId: SimpleId,
aBaseEntityProperty: String,
dBaseEntityProperty: String,
bBaseEntityProperty: String,
sealedDataClassProperty: BaseDataClass,
cChildEntityProperty: String,
entitySource: EntitySource,
init: (Builder.() -> Unit)? = null,
): Builder {
val builder = builder()
builder.name = name
builder.moduleId = moduleId
builder.aBaseEntityProperty = aBaseEntityProperty
builder.dBaseEntityProperty = dBaseEntityProperty
builder.bBaseEntityProperty = bBaseEntityProperty
builder.sealedDataClassProperty = sealedDataClassProperty
builder.cChildEntityProperty = cChildEntityProperty
builder.entitySource = entitySource
init?.invoke(builder)
return builder
}
}
//endregion
}
//region generated code
fun MutableEntityStorage.modifyChildEntity(
entity: ChildEntity,
modification: ChildEntity.Builder.() -> Unit,
): ChildEntity {
return modifyEntity(ChildEntity.Builder::class.java, entity, modification)
}
//endregion
sealed class BaseDataClass(val baseConstructorProperty: String) {
open val baseBodyProperty: Int = 15
val anotherBaseBodyProperty: Int = 16
}
sealed class DerivedDataClass(
baseConstructorPropertyValue: String,
val derivedConstructorProperty: String
) : BaseDataClass(baseConstructorPropertyValue) {
val derivedBodyProperty: Int = 23
}
class DerivedDerivedDataClass(
baseConstructorPropertyValue: String,
override val baseBodyProperty: Int,
derivedConstructorPropertyValue: String,
val derivedDerivedConstructorProperty: String
) : DerivedDataClass(baseConstructorPropertyValue, derivedConstructorPropertyValue) {
val deriveDerivedBodyProperty: Int = 42
}
@@ -0,0 +1,427 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.annotations.Abstract
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.SoftLinkable
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityData
import com.intellij.platform.workspace.storage.impl.indices.WorkspaceMutableIndex
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentation
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentationApi
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.workspaceModel.test.api.BaseDataClass
import com.intellij.workspaceModel.test.api.ChildEntity
import com.intellij.workspaceModel.test.api.DerivedDataClass
import com.intellij.workspaceModel.test.api.DerivedDerivedDataClass
import com.intellij.workspaceModel.test.api.SimpleId
@GeneratedCodeApiVersion(3)
@GeneratedCodeImplVersion(6)
@OptIn(WorkspaceEntityInternalApi::class)
internal class ChildEntityImpl(private val dataSource: ChildEntityData) : ChildEntity, WorkspaceEntityBase(dataSource) {
private companion object {
private val connections = listOf<ConnectionId>(
)
}
override val name: String
get() {
readField("name")
return dataSource.name
}
override val moduleId: SimpleId
get() {
readField("moduleId")
return dataSource.moduleId
}
override val aBaseEntityProperty: String
get() {
readField("aBaseEntityProperty")
return dataSource.aBaseEntityProperty
}
override val dBaseEntityProperty: String
get() {
readField("dBaseEntityProperty")
return dataSource.dBaseEntityProperty
}
override val bBaseEntityProperty: String
get() {
readField("bBaseEntityProperty")
return dataSource.bBaseEntityProperty
}
override val sealedDataClassProperty: BaseDataClass
get() {
readField("sealedDataClassProperty")
return dataSource.sealedDataClassProperty
}
override val cChildEntityProperty: String
get() {
readField("cChildEntityProperty")
return dataSource.cChildEntityProperty
}
override val entitySource: EntitySource
get() {
readField("entitySource")
return dataSource.entitySource
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
internal class Builder(result: ChildEntityData?) : ModifiableWorkspaceEntityBase<ChildEntity, ChildEntityData>(result),
ChildEntity.Builder {
internal constructor() : this(ChildEntityData())
override fun applyToBuilder(builder: MutableEntityStorage) {
if (this.diff != null) {
if (existsInBuilder(builder)) {
this.diff = builder
return
}
else {
error("Entity ChildEntity is already created in a different builder")
}
}
this.diff = builder
addToBuilder()
this.id = getEntityData().createEntityId()
// After adding entity data to the builder, we need to unbind it and move the control over entity data to builder
// Builder may switch to snapshot at any moment and lock entity data to modification
this.currentEntityData = null
// Process linked entities that are connected without a builder
processLinkedEntities(builder)
checkInitialization() // TODO uncomment and check failed tests
}
private fun checkInitialization() {
val _diff = diff
if (!getEntityData().isEntitySourceInitialized()) {
error("Field WorkspaceEntity#entitySource should be initialized")
}
if (!getEntityData().isNameInitialized()) {
error("Field BaseEntity#name should be initialized")
}
if (!getEntityData().isModuleIdInitialized()) {
error("Field BaseEntity#moduleId should be initialized")
}
if (!getEntityData().isABaseEntityPropertyInitialized()) {
error("Field BaseEntity#aBaseEntityProperty should be initialized")
}
if (!getEntityData().isDBaseEntityPropertyInitialized()) {
error("Field BaseEntity#dBaseEntityProperty should be initialized")
}
if (!getEntityData().isBBaseEntityPropertyInitialized()) {
error("Field BaseEntity#bBaseEntityProperty should be initialized")
}
if (!getEntityData().isSealedDataClassPropertyInitialized()) {
error("Field BaseEntity#sealedDataClassProperty should be initialized")
}
if (!getEntityData().isCChildEntityPropertyInitialized()) {
error("Field ChildEntity#cChildEntityProperty should be initialized")
}
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
// Relabeling code, move information from dataSource to this builder
override fun relabel(dataSource: WorkspaceEntity, parents: Set<WorkspaceEntity>?) {
dataSource as ChildEntity
if (this.entitySource != dataSource.entitySource) this.entitySource = dataSource.entitySource
if (this.name != dataSource.name) this.name = dataSource.name
if (this.moduleId != dataSource.moduleId) this.moduleId = dataSource.moduleId
if (this.aBaseEntityProperty != dataSource.aBaseEntityProperty) this.aBaseEntityProperty = dataSource.aBaseEntityProperty
if (this.dBaseEntityProperty != dataSource.dBaseEntityProperty) this.dBaseEntityProperty = dataSource.dBaseEntityProperty
if (this.bBaseEntityProperty != dataSource.bBaseEntityProperty) this.bBaseEntityProperty = dataSource.bBaseEntityProperty
if (this.sealedDataClassProperty != dataSource.sealedDataClassProperty) this.sealedDataClassProperty =
dataSource.sealedDataClassProperty
if (this.cChildEntityProperty != dataSource.cChildEntityProperty) this.cChildEntityProperty = dataSource.cChildEntityProperty
updateChildToParentReferences(parents)
}
override var entitySource: EntitySource
get() = getEntityData().entitySource
set(value) {
checkModificationAllowed()
getEntityData(true).entitySource = value
changedProperty.add("entitySource")
}
override var name: String
get() = getEntityData().name
set(value) {
checkModificationAllowed()
getEntityData(true).name = value
changedProperty.add("name")
}
override var moduleId: SimpleId
get() = getEntityData().moduleId
set(value) {
checkModificationAllowed()
getEntityData(true).moduleId = value
changedProperty.add("moduleId")
}
override var aBaseEntityProperty: String
get() = getEntityData().aBaseEntityProperty
set(value) {
checkModificationAllowed()
getEntityData(true).aBaseEntityProperty = value
changedProperty.add("aBaseEntityProperty")
}
override var dBaseEntityProperty: String
get() = getEntityData().dBaseEntityProperty
set(value) {
checkModificationAllowed()
getEntityData(true).dBaseEntityProperty = value
changedProperty.add("dBaseEntityProperty")
}
override var bBaseEntityProperty: String
get() = getEntityData().bBaseEntityProperty
set(value) {
checkModificationAllowed()
getEntityData(true).bBaseEntityProperty = value
changedProperty.add("bBaseEntityProperty")
}
override var sealedDataClassProperty: BaseDataClass
get() = getEntityData().sealedDataClassProperty
set(value) {
checkModificationAllowed()
getEntityData(true).sealedDataClassProperty = value
changedProperty.add("sealedDataClassProperty")
}
override var cChildEntityProperty: String
get() = getEntityData().cChildEntityProperty
set(value) {
checkModificationAllowed()
getEntityData(true).cChildEntityProperty = value
changedProperty.add("cChildEntityProperty")
}
override fun getEntityClass(): Class<ChildEntity> = ChildEntity::class.java
}
}
@OptIn(WorkspaceEntityInternalApi::class)
internal class ChildEntityData : WorkspaceEntityData<ChildEntity>(), SoftLinkable {
lateinit var name: String
lateinit var moduleId: SimpleId
lateinit var aBaseEntityProperty: String
lateinit var dBaseEntityProperty: String
lateinit var bBaseEntityProperty: String
lateinit var sealedDataClassProperty: BaseDataClass
lateinit var cChildEntityProperty: String
internal fun isNameInitialized(): Boolean = ::name.isInitialized
internal fun isModuleIdInitialized(): Boolean = ::moduleId.isInitialized
internal fun isABaseEntityPropertyInitialized(): Boolean = ::aBaseEntityProperty.isInitialized
internal fun isDBaseEntityPropertyInitialized(): Boolean = ::dBaseEntityProperty.isInitialized
internal fun isBBaseEntityPropertyInitialized(): Boolean = ::bBaseEntityProperty.isInitialized
internal fun isSealedDataClassPropertyInitialized(): Boolean = ::sealedDataClassProperty.isInitialized
internal fun isCChildEntityPropertyInitialized(): Boolean = ::cChildEntityProperty.isInitialized
override fun getLinks(): Set<SymbolicEntityId<*>> {
val result = HashSet<SymbolicEntityId<*>>()
result.add(moduleId)
val _sealedDataClassProperty = sealedDataClassProperty
when (_sealedDataClassProperty) {
is DerivedDataClass -> {
val __sealedDataClassProperty = _sealedDataClassProperty
when (__sealedDataClassProperty) {
is DerivedDerivedDataClass -> {
}
}
}
}
return result
}
override fun index(index: WorkspaceMutableIndex<SymbolicEntityId<*>>) {
index.index(this, moduleId)
val _sealedDataClassProperty = sealedDataClassProperty
when (_sealedDataClassProperty) {
is DerivedDataClass -> {
val __sealedDataClassProperty = _sealedDataClassProperty
when (__sealedDataClassProperty) {
is DerivedDerivedDataClass -> {
}
}
}
}
}
override fun updateLinksIndex(prev: Set<SymbolicEntityId<*>>, index: WorkspaceMutableIndex<SymbolicEntityId<*>>) {
// TODO verify logic
val mutablePreviousSet = HashSet(prev)
val removedItem_moduleId = mutablePreviousSet.remove(moduleId)
if (!removedItem_moduleId) {
index.index(this, moduleId)
}
val _sealedDataClassProperty = sealedDataClassProperty
when (_sealedDataClassProperty) {
is DerivedDataClass -> {
val __sealedDataClassProperty = _sealedDataClassProperty
when (__sealedDataClassProperty) {
is DerivedDerivedDataClass -> {
}
}
}
}
for (removed in mutablePreviousSet) {
index.remove(this, removed)
}
}
override fun updateLink(oldLink: SymbolicEntityId<*>, newLink: SymbolicEntityId<*>): Boolean {
var changed = false
val moduleId_data = if (moduleId == oldLink) {
changed = true
newLink as SimpleId
}
else {
null
}
if (moduleId_data != null) {
moduleId = moduleId_data
}
val _sealedDataClassProperty = sealedDataClassProperty
val res_sealedDataClassProperty = when (_sealedDataClassProperty) {
is DerivedDataClass -> {
val __sealedDataClassProperty = _sealedDataClassProperty
val res__sealedDataClassProperty = when (__sealedDataClassProperty) {
is DerivedDerivedDataClass -> {
__sealedDataClassProperty
}
}
res__sealedDataClassProperty
}
}
if (res_sealedDataClassProperty != null) {
sealedDataClassProperty = res_sealedDataClassProperty
}
return changed
}
override fun wrapAsModifiable(diff: MutableEntityStorage): WorkspaceEntity.Builder<ChildEntity> {
val modifiable = ChildEntityImpl.Builder(null)
modifiable.diff = diff
modifiable.id = createEntityId()
return modifiable
}
@OptIn(EntityStorageInstrumentationApi::class)
override fun createEntity(snapshot: EntityStorageInstrumentation): ChildEntity {
val entityId = createEntityId()
return snapshot.initializeEntity(entityId) {
val entity = ChildEntityImpl(this)
entity.snapshot = snapshot
entity.id = entityId
entity
}
}
override fun getMetadata(): EntityMetadata {
return MetadataStorageImpl.getMetadataByTypeFqn("com.intellij.workspaceModel.test.api.ChildEntity") as EntityMetadata
}
override fun getEntityInterface(): Class<out WorkspaceEntity> {
return ChildEntity::class.java
}
override fun createDetachedEntity(parents: List<WorkspaceEntity.Builder<*>>): WorkspaceEntity.Builder<*> {
return ChildEntity(
name, moduleId, aBaseEntityProperty, dBaseEntityProperty, bBaseEntityProperty, sealedDataClassProperty, cChildEntityProperty,
entitySource
) {
}
}
override fun getRequiredParents(): List<Class<out WorkspaceEntity>> {
val res = mutableListOf<Class<out WorkspaceEntity>>()
return res
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as ChildEntityData
if (this.entitySource != other.entitySource) return false
if (this.name != other.name) return false
if (this.moduleId != other.moduleId) return false
if (this.aBaseEntityProperty != other.aBaseEntityProperty) return false
if (this.dBaseEntityProperty != other.dBaseEntityProperty) return false
if (this.bBaseEntityProperty != other.bBaseEntityProperty) return false
if (this.sealedDataClassProperty != other.sealedDataClassProperty) return false
if (this.cChildEntityProperty != other.cChildEntityProperty) return false
return true
}
override fun equalsIgnoringEntitySource(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as ChildEntityData
if (this.name != other.name) return false
if (this.moduleId != other.moduleId) return false
if (this.aBaseEntityProperty != other.aBaseEntityProperty) return false
if (this.dBaseEntityProperty != other.dBaseEntityProperty) return false
if (this.bBaseEntityProperty != other.bBaseEntityProperty) return false
if (this.sealedDataClassProperty != other.sealedDataClassProperty) return false
if (this.cChildEntityProperty != other.cChildEntityProperty) return false
return true
}
override fun hashCode(): Int {
var result = entitySource.hashCode()
result = 31 * result + name.hashCode()
result = 31 * result + moduleId.hashCode()
result = 31 * result + aBaseEntityProperty.hashCode()
result = 31 * result + dBaseEntityProperty.hashCode()
result = 31 * result + bBaseEntityProperty.hashCode()
result = 31 * result + sealedDataClassProperty.hashCode()
result = 31 * result + cChildEntityProperty.hashCode()
return result
}
override fun hashCodeIgnoringEntitySource(): Int {
var result = javaClass.hashCode()
result = 31 * result + name.hashCode()
result = 31 * result + moduleId.hashCode()
result = 31 * result + aBaseEntityProperty.hashCode()
result = 31 * result + dBaseEntityProperty.hashCode()
result = 31 * result + bBaseEntityProperty.hashCode()
result = 31 * result + sealedDataClassProperty.hashCode()
result = 31 * result + cChildEntityProperty.hashCode()
return result
}
}
@@ -0,0 +1,83 @@
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.metadata.impl.MetadataStorageBase
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.platform.workspace.storage.metadata.model.ExtendableClassMetadata
import com.intellij.platform.workspace.storage.metadata.model.FinalClassMetadata
import com.intellij.platform.workspace.storage.metadata.model.OwnPropertyMetadata
import com.intellij.platform.workspace.storage.metadata.model.StorageTypeMetadata
import com.intellij.platform.workspace.storage.metadata.model.ValueTypeMetadata
@OptIn(WorkspaceEntityInternalApi::class)
internal object MetadataStorageImpl: MetadataStorageBase() {
override fun initializeMetadata() {
val primitiveTypeStringNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "String")
val primitiveTypeIntNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Int")
var typeMetadata: StorageTypeMetadata
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))
addMetadata(typeMetadata)
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.BaseEntity", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.BaseEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "moduleId", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "aBaseEntityProperty", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "dBaseEntityProperty", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "bBaseEntityProperty", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "sealedDataClassProperty", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = ExtendableClassMetadata.AbstractClassMetadata(fqName = "com.intellij.workspaceModel.test.api.BaseDataClass", subclasses = listOf(FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.DerivedDerivedDataClass", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "anotherBaseBodyProperty", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "baseBodyProperty", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "baseConstructorProperty", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "deriveDerivedBodyProperty", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "derivedBodyProperty", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "derivedConstructorProperty", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "derivedDerivedConstructorProperty", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.workspaceModel.test.api.BaseDataClass",
"com.intellij.workspaceModel.test.api.DerivedDataClass"))), supertypes = listOf())), withDefault = false)), extProperties = listOf(), isAbstract = true)
addMetadata(typeMetadata)
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.ChildEntity", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.ChildEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity",
"com.intellij.workspaceModel.test.api.BaseEntity"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "moduleId", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "aBaseEntityProperty", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "dBaseEntityProperty", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "bBaseEntityProperty", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "sealedDataClassProperty", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = ExtendableClassMetadata.AbstractClassMetadata(fqName = "com.intellij.workspaceModel.test.api.BaseDataClass", subclasses = listOf(FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.DerivedDerivedDataClass", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "anotherBaseBodyProperty", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "baseBodyProperty", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "baseConstructorProperty", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "deriveDerivedBodyProperty", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "derivedBodyProperty", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "derivedConstructorProperty", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "derivedDerivedConstructorProperty", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.workspaceModel.test.api.BaseDataClass",
"com.intellij.workspaceModel.test.api.DerivedDataClass"))), supertypes = listOf())), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "cChildEntityProperty", valueType = primitiveTypeStringNotNullable, withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleEntity", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.SimpleEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity",
"com.intellij.platform.workspace.storage.WorkspaceEntityWithSymbolicId"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = true, isKey = false, isOpen = false, name = "symbolicId", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
}
override fun initializeMetadataHash() {
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.BaseEntity", metadataHash = -433943746)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.ChildEntity", metadataHash = -296025373)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SimpleEntity", metadataHash = -2018622680)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SimpleId", metadataHash = 1096965603)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.BaseDataClass", metadataHash = 937384310)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.DerivedDataClass", metadataHash = 1525344553)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.DerivedDerivedDataClass", metadataHash = -597612584)
addMetadataHash(typeFqn = "com.intellij.platform.workspace.storage.SymbolicEntityId", metadataHash = -1044278955)
}
}
@@ -0,0 +1,192 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.test.api.impl
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.annotations.Abstract
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityData
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentation
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentationApi
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
import com.intellij.workspaceModel.test.api.SimpleEntity
import com.intellij.workspaceModel.test.api.SimpleId
@GeneratedCodeApiVersion(3)
@GeneratedCodeImplVersion(6)
@OptIn(WorkspaceEntityInternalApi::class)
internal class SimpleEntityImpl(private val dataSource: SimpleEntityData) : SimpleEntity, WorkspaceEntityBase(dataSource) {
private companion object {
private val connections = listOf<ConnectionId>(
)
}
override val symbolicId: SimpleId = super.symbolicId
override val name: String
get() {
readField("name")
return dataSource.name
}
override val entitySource: EntitySource
get() {
readField("entitySource")
return dataSource.entitySource
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
internal class Builder(result: SimpleEntityData?) : ModifiableWorkspaceEntityBase<SimpleEntity, SimpleEntityData>(result),
SimpleEntity.Builder {
internal constructor() : this(SimpleEntityData())
override fun applyToBuilder(builder: MutableEntityStorage) {
if (this.diff != null) {
if (existsInBuilder(builder)) {
this.diff = builder
return
}
else {
error("Entity SimpleEntity is already created in a different builder")
}
}
this.diff = builder
addToBuilder()
this.id = getEntityData().createEntityId()
// After adding entity data to the builder, we need to unbind it and move the control over entity data to builder
// Builder may switch to snapshot at any moment and lock entity data to modification
this.currentEntityData = null
// Process linked entities that are connected without a builder
processLinkedEntities(builder)
checkInitialization() // TODO uncomment and check failed tests
}
private fun checkInitialization() {
val _diff = diff
if (!getEntityData().isEntitySourceInitialized()) {
error("Field WorkspaceEntity#entitySource should be initialized")
}
if (!getEntityData().isNameInitialized()) {
error("Field SimpleEntity#name should be initialized")
}
}
override fun connectionIdList(): List<ConnectionId> {
return connections
}
// Relabeling code, move information from dataSource to this builder
override fun relabel(dataSource: WorkspaceEntity, parents: Set<WorkspaceEntity>?) {
dataSource as SimpleEntity
if (this.entitySource != dataSource.entitySource) this.entitySource = dataSource.entitySource
if (this.name != dataSource.name) this.name = dataSource.name
updateChildToParentReferences(parents)
}
override var entitySource: EntitySource
get() = getEntityData().entitySource
set(value) {
checkModificationAllowed()
getEntityData(true).entitySource = value
changedProperty.add("entitySource")
}
override var name: String
get() = getEntityData().name
set(value) {
checkModificationAllowed()
getEntityData(true).name = value
changedProperty.add("name")
}
override fun getEntityClass(): Class<SimpleEntity> = SimpleEntity::class.java
}
}
@OptIn(WorkspaceEntityInternalApi::class)
internal class SimpleEntityData : WorkspaceEntityData<SimpleEntity>() {
lateinit var name: String
internal fun isNameInitialized(): Boolean = ::name.isInitialized
override fun wrapAsModifiable(diff: MutableEntityStorage): WorkspaceEntity.Builder<SimpleEntity> {
val modifiable = SimpleEntityImpl.Builder(null)
modifiable.diff = diff
modifiable.id = createEntityId()
return modifiable
}
@OptIn(EntityStorageInstrumentationApi::class)
override fun createEntity(snapshot: EntityStorageInstrumentation): SimpleEntity {
val entityId = createEntityId()
return snapshot.initializeEntity(entityId) {
val entity = SimpleEntityImpl(this)
entity.snapshot = snapshot
entity.id = entityId
entity
}
}
override fun getMetadata(): EntityMetadata {
return MetadataStorageImpl.getMetadataByTypeFqn("com.intellij.workspaceModel.test.api.SimpleEntity") as EntityMetadata
}
override fun getEntityInterface(): Class<out WorkspaceEntity> {
return SimpleEntity::class.java
}
override fun createDetachedEntity(parents: List<WorkspaceEntity.Builder<*>>): WorkspaceEntity.Builder<*> {
return SimpleEntity(name, entitySource) {
}
}
override fun getRequiredParents(): List<Class<out WorkspaceEntity>> {
val res = mutableListOf<Class<out WorkspaceEntity>>()
return res
}
override fun equals(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as SimpleEntityData
if (this.entitySource != other.entitySource) return false
if (this.name != other.name) return false
return true
}
override fun equalsIgnoringEntitySource(other: Any?): Boolean {
if (other == null) return false
if (this.javaClass != other.javaClass) return false
other as SimpleEntityData
if (this.name != other.name) return false
return true
}
override fun hashCode(): Int {
var result = entitySource.hashCode()
result = 31 * result + name.hashCode()
return result
}
override fun hashCodeIgnoringEntitySource(): Int {
var result = javaClass.hashCode()
result = 31 * result + name.hashCode()
return result
}
}
@@ -0,0 +1,55 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.workspaceModel.test.api
import com.intellij.platform.workspace.storage.*
import com.intellij.platform.workspace.storage.annotations.Abstract
interface SimpleEntity : WorkspaceEntityWithSymbolicId {
override val symbolicId: SimpleId
get() = SimpleId(name)
val name: String
}
data class SimpleId(val name: String) : SymbolicEntityId<SimpleEntity> {
override val presentableName: String
get() = name
}
// partial copy of org.jetbrains.kotlin.idea.workspaceModel.KotlinSettingsEntity
@Abstract
interface BaseEntity : WorkspaceEntity {
val name: String
val moduleId: SimpleId
val aBaseEntityProperty: String
val dBaseEntityProperty: String
val bBaseEntityProperty: String
val sealedDataClassProperty: BaseDataClass
}
interface ChildEntity : BaseEntity {
val cChildEntityProperty: String
}
sealed class BaseDataClass(val baseConstructorProperty: String) {
open val baseBodyProperty: Int = 15
val anotherBaseBodyProperty: Int = 16
}
sealed class DerivedDataClass(
baseConstructorPropertyValue: String,
val derivedConstructorProperty: String
) : BaseDataClass(baseConstructorPropertyValue) {
val derivedBodyProperty: Int = 23
}
class DerivedDerivedDataClass(
baseConstructorPropertyValue: String,
override val baseBodyProperty: Int,
derivedConstructorPropertyValue: String,
val derivedDerivedConstructorProperty: String
) : DerivedDataClass(baseConstructorPropertyValue, derivedConstructorPropertyValue) {
val deriveDerivedBodyProperty: Int = 42
}
@@ -1,11 +1,11 @@
package com.intellij.workspaceModel.test.api
import com.intellij.platform.workspace.jps.entities.ContentRootEntity
import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.EntityType
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.jps.entities.ContentRootEntity
import com.intellij.platform.workspace.storage.annotations.Child
interface ReferredEntity : WorkspaceEntity {
@@ -4,8 +4,7 @@ import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.EntityType
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.annotations.Default
import com.intellij.platform.workspace.storage.PersistentEntityId
import com.intellij.platform.workspace.storage.SymbolicEntityId
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.WorkspaceEntityWithSymbolicId
@@ -75,5 +74,4 @@ sealed class SealedClassWithLinks {
data class Ordered(val list: List<SimpleId>) : Many()
data class Unordered(val set: Set<SimpleId>) : Many()
}
}
}
@@ -12,41 +12,47 @@ import com.intellij.platform.workspace.storage.metadata.model.ValueTypeMetadata
@OptIn(WorkspaceEntityInternalApi::class)
internal object MetadataStorageImpl: MetadataStorageBase() {
override fun initializeMetadata() {
val primitiveTypeIntNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Int")
val primitiveTypeStringNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "String")
val primitiveTypeIntNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Int")
val primitiveTypeListNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "List")
val primitiveTypeSetNotNullable = ValueTypeMetadata.SimpleType.PrimitiveType(isNullable = false, type = "Set")
var typeMetadata: StorageTypeMetadata
typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))
addMetadata(typeMetadata)
typeMetadata = EntityMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleSymbolicIdEntity", entityDataFqName = "com.intellij.workspaceModel.test.api.impl.SimpleSymbolicIdEntityData", supertypes = listOf("com.intellij.platform.workspace.storage.WorkspaceEntity",
"com.intellij.platform.workspace.storage.WorkspaceEntityWithSymbolicId"), properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "entitySource", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.platform.workspace.storage.EntitySource")), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "version", valueType = primitiveTypeIntNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "related", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf())), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "sealedClassWithLinks", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = ExtendableClassMetadata.AbstractClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SealedClassWithLinks", subclasses = listOf(FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many\$Ordered", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "list", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf()))), primitive = primitiveTypeListNotNullable), withDefault = false)), supertypes = listOf("com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many",
"com.intellij.workspaceModel.test.api.SealedClassWithLinks")),
FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many\$Unordered", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "set", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.workspaceModel.test.api.SimpleId"))), primitive = primitiveTypeSetNotNullable), withDefault = false)), supertypes = listOf("com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many",
"com.intellij.workspaceModel.test.api.SealedClassWithLinks")),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "related", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))), withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "sealedClassWithLinks", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = ExtendableClassMetadata.AbstractClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SealedClassWithLinks", subclasses = listOf(FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many\$Ordered", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "list", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId")))), primitive = primitiveTypeListNotNullable), withDefault = false)), supertypes = listOf("com.intellij.workspaceModel.test.api.SealedClassWithLinks",
"com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many")),
FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many\$Unordered", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "set", valueType = ValueTypeMetadata.ParameterizedType(generics = listOf(ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.workspaceModel.test.api.SimpleId"))), primitive = primitiveTypeSetNotNullable), withDefault = false)), supertypes = listOf("com.intellij.workspaceModel.test.api.SealedClassWithLinks",
"com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many")),
FinalClassMetadata.ObjectMetadata(fqName = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Nothing", properties = listOf(), supertypes = listOf("com.intellij.workspaceModel.test.api.SealedClassWithLinks")),
FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Single", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "id", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.KnownClass(fqName = "com.intellij.workspaceModel.test.api.SimpleId")), withDefault = false)), supertypes = listOf("com.intellij.workspaceModel.test.api.SealedClassWithLinks"))), supertypes = listOf())), withDefault = false),
OwnPropertyMetadata(isComputable = true, isKey = false, isOpen = false, name = "symbolicId", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf())), withDefault = false)), extProperties = listOf(), isAbstract = false)
OwnPropertyMetadata(isComputable = true, isKey = false, isOpen = false, name = "symbolicId", valueType = ValueTypeMetadata.SimpleType.CustomType(isNullable = false, typeMetadata = FinalClassMetadata.ClassMetadata(fqName = "com.intellij.workspaceModel.test.api.SimpleId", properties = listOf(OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "name", valueType = primitiveTypeStringNotNullable, withDefault = false),
OwnPropertyMetadata(isComputable = false, isKey = false, isOpen = false, name = "presentableName", valueType = primitiveTypeStringNotNullable, withDefault = false)), supertypes = listOf("com.intellij.platform.workspace.storage.SymbolicEntityId"))), withDefault = false)), extProperties = listOf(), isAbstract = false)
addMetadata(typeMetadata)
}
override fun initializeMetadataHash() {
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SimpleSymbolicIdEntity", metadataHash = 920886074)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SimpleId", metadataHash = 503726574)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SealedClassWithLinks", metadataHash = 869203958)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many", metadataHash = 1388134395)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many\$Ordered", metadataHash = -2032838886)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many\$Unordered", metadataHash = -1543556527)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SimpleSymbolicIdEntity", metadataHash = -99546289)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SimpleId", metadataHash = 1096965603)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SealedClassWithLinks", metadataHash = 229222369)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many", metadataHash = 372382182)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many\$Ordered", metadataHash = -1632944095)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Many\$Unordered", metadataHash = -585653981)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Nothing", metadataHash = 1541593304)
addMetadataHash(typeFqn = "com.intellij.workspaceModel.test.api.SealedClassWithLinks\$Single", metadataHash = -800484835)
addMetadataHash(typeFqn = "com.intellij.platform.workspace.storage.SymbolicEntityId", metadataHash = -1044278955)
}
}
@@ -5,14 +5,15 @@ import com.intellij.platform.workspace.storage.EntitySource
import com.intellij.platform.workspace.storage.GeneratedCodeApiVersion
import com.intellij.platform.workspace.storage.GeneratedCodeImplVersion
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.platform.workspace.storage.PersistentEntityId
import com.intellij.platform.workspace.storage.SymbolicEntityId
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.WorkspaceEntityInternalApi
import com.intellij.platform.workspace.storage.WorkspaceEntityWithSymbolicId
import com.intellij.platform.workspace.storage.annotations.Default
import com.intellij.platform.workspace.storage.impl.ModifiableWorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.SoftLinkable
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityBase
import com.intellij.platform.workspace.storage.impl.WorkspaceEntityData
import com.intellij.platform.workspace.storage.impl.indices.WorkspaceMutableIndex
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentation
import com.intellij.platform.workspace.storage.instrumentation.EntityStorageInstrumentationApi
import com.intellij.platform.workspace.storage.metadata.model.EntityMetadata
@@ -177,7 +178,7 @@ internal class SimpleSymbolicIdEntityImpl(private val dataSource: SimpleSymbolic
}
@OptIn(WorkspaceEntityInternalApi::class)
internal class SimpleSymbolicIdEntityData : WorkspaceEntityData<SimpleSymbolicIdEntity>() {
internal class SimpleSymbolicIdEntityData : WorkspaceEntityData<SimpleSymbolicIdEntity>(), SoftLinkable {
var version: Int = 0
lateinit var name: String
lateinit var related: SimpleId
@@ -188,6 +189,194 @@ internal class SimpleSymbolicIdEntityData : WorkspaceEntityData<SimpleSymbolicId
internal fun isRelatedInitialized(): Boolean = ::related.isInitialized
internal fun isSealedClassWithLinksInitialized(): Boolean = ::sealedClassWithLinks.isInitialized
override fun getLinks(): Set<SymbolicEntityId<*>> {
val result = HashSet<SymbolicEntityId<*>>()
result.add(related)
val _sealedClassWithLinks = sealedClassWithLinks
when (_sealedClassWithLinks) {
is SealedClassWithLinks.Many -> {
val __sealedClassWithLinks = _sealedClassWithLinks
when (__sealedClassWithLinks) {
is SealedClassWithLinks.Many.Ordered -> {
for (item in __sealedClassWithLinks.list) {
result.add(item)
}
}
is SealedClassWithLinks.Many.Unordered -> {
for (item in __sealedClassWithLinks.set) {
result.add(item)
}
}
}
}
is SealedClassWithLinks.Nothing -> {
}
is SealedClassWithLinks.Single -> {
result.add(_sealedClassWithLinks.id)
}
}
return result
}
override fun index(index: WorkspaceMutableIndex<SymbolicEntityId<*>>) {
index.index(this, related)
val _sealedClassWithLinks = sealedClassWithLinks
when (_sealedClassWithLinks) {
is SealedClassWithLinks.Many -> {
val __sealedClassWithLinks = _sealedClassWithLinks
when (__sealedClassWithLinks) {
is SealedClassWithLinks.Many.Ordered -> {
for (item in __sealedClassWithLinks.list) {
index.index(this, item)
}
}
is SealedClassWithLinks.Many.Unordered -> {
for (item in __sealedClassWithLinks.set) {
index.index(this, item)
}
}
}
}
is SealedClassWithLinks.Nothing -> {
}
is SealedClassWithLinks.Single -> {
index.index(this, _sealedClassWithLinks.id)
}
}
}
override fun updateLinksIndex(prev: Set<SymbolicEntityId<*>>, index: WorkspaceMutableIndex<SymbolicEntityId<*>>) {
// TODO verify logic
val mutablePreviousSet = HashSet(prev)
val removedItem_related = mutablePreviousSet.remove(related)
if (!removedItem_related) {
index.index(this, related)
}
val _sealedClassWithLinks = sealedClassWithLinks
when (_sealedClassWithLinks) {
is SealedClassWithLinks.Many -> {
val __sealedClassWithLinks = _sealedClassWithLinks
when (__sealedClassWithLinks) {
is SealedClassWithLinks.Many.Ordered -> {
for (item in __sealedClassWithLinks.list) {
val removedItem_item = mutablePreviousSet.remove(item)
if (!removedItem_item) {
index.index(this, item)
}
}
}
is SealedClassWithLinks.Many.Unordered -> {
for (item in __sealedClassWithLinks.set) {
val removedItem_item = mutablePreviousSet.remove(item)
if (!removedItem_item) {
index.index(this, item)
}
}
}
}
}
is SealedClassWithLinks.Nothing -> {
}
is SealedClassWithLinks.Single -> {
val removedItem__sealedClassWithLinks_id = mutablePreviousSet.remove(_sealedClassWithLinks.id)
if (!removedItem__sealedClassWithLinks_id) {
index.index(this, _sealedClassWithLinks.id)
}
}
}
for (removed in mutablePreviousSet) {
index.remove(this, removed)
}
}
override fun updateLink(oldLink: SymbolicEntityId<*>, newLink: SymbolicEntityId<*>): Boolean {
var changed = false
val related_data = if (related == oldLink) {
changed = true
newLink as SimpleId
}
else {
null
}
if (related_data != null) {
related = related_data
}
val _sealedClassWithLinks = sealedClassWithLinks
val res_sealedClassWithLinks = when (_sealedClassWithLinks) {
is SealedClassWithLinks.Many -> {
val __sealedClassWithLinks = _sealedClassWithLinks
val res__sealedClassWithLinks = when (__sealedClassWithLinks) {
is SealedClassWithLinks.Many.Ordered -> {
val __sealedClassWithLinks_list_data = __sealedClassWithLinks.list.map {
val it_data = if (it == oldLink) {
changed = true
newLink as SimpleId
}
else {
null
}
if (it_data != null) {
it_data
}
else {
it
}
}
var __sealedClassWithLinks_data = __sealedClassWithLinks
if (__sealedClassWithLinks_list_data != null) {
__sealedClassWithLinks_data = __sealedClassWithLinks_data.copy(list = __sealedClassWithLinks_list_data)
}
__sealedClassWithLinks_data
}
is SealedClassWithLinks.Many.Unordered -> {
val __sealedClassWithLinks_set_data = __sealedClassWithLinks.set.map {
val it_data = if (it == oldLink) {
changed = true
newLink as SimpleId
}
else {
null
}
if (it_data != null) {
it_data
}
else {
it
}
}
var __sealedClassWithLinks_data = __sealedClassWithLinks
if (__sealedClassWithLinks_set_data != null) {
__sealedClassWithLinks_data = __sealedClassWithLinks_data.copy(set = __sealedClassWithLinks_set_data)
}
__sealedClassWithLinks_data
}
}
res__sealedClassWithLinks
}
is SealedClassWithLinks.Nothing -> {
_sealedClassWithLinks
}
is SealedClassWithLinks.Single -> {
val _sealedClassWithLinks_id_data = if (_sealedClassWithLinks.id == oldLink) {
changed = true
newLink as SimpleId
}
else {
null
}
var _sealedClassWithLinks_data = _sealedClassWithLinks
if (_sealedClassWithLinks_id_data != null) {
_sealedClassWithLinks_data = _sealedClassWithLinks_data.copy(id = _sealedClassWithLinks_id_data)
}
_sealedClassWithLinks_data
}
}
if (res_sealedClassWithLinks != null) {
sealedClassWithLinks = res_sealedClassWithLinks
}
return changed
}
override fun wrapAsModifiable(diff: MutableEntityStorage): WorkspaceEntity.Builder<SimpleSymbolicIdEntity> {
val modifiable = SimpleSymbolicIdEntityImpl.Builder(null)
modifiable.diff = diff
@@ -1,8 +1,6 @@
package com.intellij.workspaceModel.test.api
import com.intellij.platform.workspace.storage.annotations.Default
import com.intellij.platform.workspace.storage.PersistentEntityId
import com.intellij.platform.workspace.storage.WorkspaceEntity
import com.intellij.platform.workspace.storage.SymbolicEntityId
import com.intellij.platform.workspace.storage.WorkspaceEntityWithSymbolicId
interface SimpleSymbolicIdEntity : WorkspaceEntityWithSymbolicId {
@@ -28,5 +26,4 @@ sealed class SealedClassWithLinks {
data class Ordered(val list: List<SimpleId>) : Many()
data class Unordered(val set: Set<SimpleId>) : Many()
}
}
}
@@ -8,6 +8,7 @@ import com.intellij.java.workspace.entities.JavaSourceRootPropertiesEntity
import com.intellij.java.workspace.entities.javaSourceRoots
import com.intellij.openapi.application.runWriteActionAndWait
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.fileTypes.LanguageFileType
import com.intellij.openapi.roots.ModifiableRootModel
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.util.io.FileUtil
@@ -46,8 +47,8 @@ import java.nio.file.Paths
import kotlin.io.path.invariantSeparatorsPathString
import kotlin.io.path.pathString
class AllIntellijEntitiesGenerationTest : CodeGenerationTestBase() {
private val LOG = logger<AllIntellijEntitiesGenerationTest>()
abstract class AbstractAllIntellijEntitiesGenerationTest : CodeGenerationTestBase() {
private val LOG = logger<AbstractAllIntellijEntitiesGenerationTest>()
private val virtualFileManager = IdeVirtualFileUrlManagerImpl()
@@ -75,6 +76,7 @@ class AllIntellijEntitiesGenerationTest : CodeGenerationTestBase() {
override val testDataDirectory: File
get() = File(IdeaTestExecutionPolicy.getHomePathWithPolicy())
// IJPL-895
fun `_test generation of all entities in intellij codebase`() {
executeEntitiesGeneration(::generateAndCompare)
}
@@ -148,8 +150,10 @@ class AllIntellijEntitiesGenerationTest : CodeGenerationTestBase() {
modulesToCheck.forEach { (moduleEntity, sourceRoot), pathToPackages ->
val isTestModule = sourceRoot.rootTypeId == JAVA_TEST_ROOT_ENTITY_TYPE_ID
fun generateForSpecificModule(processAbstractTypes: Boolean, beforeGeneration: (ModifiableRootModel) -> Unit,
afterGeneration: (ModifiableRootModel) -> Unit) {
fun generateForSpecificModule(
processAbstractTypes: Boolean, beforeGeneration: (ModifiableRootModel) -> Unit,
afterGeneration: (ModifiableRootModel) -> Unit,
) {
runWriteActionAndWait {
val modifiableModel = ModuleRootManager.getInstance(module).modifiableModel
beforeGeneration(modifiableModel)
@@ -165,11 +169,11 @@ class AllIntellijEntitiesGenerationTest : CodeGenerationTestBase() {
}
when (moduleEntity.name) {
"intellij.platform.workspace.storage"-> {
"intellij.platform.workspace.storage" -> {
generateForSpecificModule(false, { modifiableModel -> removeWorkspaceStorageLibrary(modifiableModel) },
{ modifiableModel -> addWorkspaceStorageLibrary(modifiableModel) })
}
"intellij.platform.workspace.jps"-> {
"intellij.platform.workspace.jps" -> {
generateForSpecificModule(false, { modifiableModel -> removeWorkspaceJpsEntitiesLibrary(modifiableModel) },
{ modifiableModel -> addWorkspaceJpsEntitiesLibrary(modifiableModel) })
}
@@ -191,9 +195,9 @@ class AllIntellijEntitiesGenerationTest : CodeGenerationTestBase() {
addIntellijJavaLibrary(modifiableModel)
addKotlinJpsCommonJar(modifiableModel)
}, { modifiableModel ->
removeIntellijJavaLibrary(modifiableModel)
removeKotlinJpsCommonJar(modifiableModel)
})
removeIntellijJavaLibrary(modifiableModel)
removeKotlinJpsCommonJar(modifiableModel)
})
}
in modulesWithAbstractTypes -> {
val projectModelUpdateResult = generationFunction(storage, moduleEntity, sourceRoot, pathToPackages, true, false, isTestModule)
@@ -216,7 +220,7 @@ class AllIntellijEntitiesGenerationTest : CodeGenerationTestBase() {
storage: MutableEntityStorage, moduleEntity: ModuleEntity,
sourceRoot: SourceRootEntity, pathToPackages: Set<String>,
processAbstractTypes: Boolean, explicitApiEnabled: Boolean,
isTestModule: Boolean
isTestModule: Boolean,
): Boolean {
val relativize = Path.of(IdeaTestExecutionPolicy.getHomePathWithPolicy()).relativize(Path.of(sourceRoot.url.presentableUrl))
myFixture.copyDirectoryToProject(relativize.invariantSeparatorsPathString, "")
@@ -272,7 +276,7 @@ class AllIntellijEntitiesGenerationTest : CodeGenerationTestBase() {
storage: MutableEntityStorage, moduleEntity: ModuleEntity,
sourceRoot: SourceRootEntity, pathToPackages: Set<String>,
processAbstractTypes: Boolean, explicitApiEnabled: Boolean,
isTestModule: Boolean
isTestModule: Boolean,
): Boolean {
val genSourceRoots = sourceRoot.contentRoot.sourceRoots.flatMap { it.javaSourceRoots }.filter { it.generated }
val relativize = Path.of(IdeaTestExecutionPolicy.getHomePathWithPolicy()).relativize(Path.of(sourceRoot.url.presentableUrl))
@@ -314,7 +318,8 @@ class AllIntellijEntitiesGenerationTest : CodeGenerationTestBase() {
private fun setupCustomIndent(moduleEntity: ModuleEntity) {
val indent = modulesWithCustomIndentSize[moduleEntity.name] ?: return
val settings = CodeStyle.getSettings(project)
val indentOptions = settings.getIndentOptions(KotlinFileType.INSTANCE)
val kotlinFileType: LanguageFileType? = KotlinFileType.INSTANCE
val indentOptions = settings.getIndentOptions(kotlinFileType)
indentOptions.INDENT_SIZE = indent
indentOptions.TAB_SIZE = indent
indentOptions.CONTINUATION_INDENT_SIZE = indent
@@ -323,7 +328,8 @@ class AllIntellijEntitiesGenerationTest : CodeGenerationTestBase() {
private fun resetCustomIndent(moduleEntity: ModuleEntity) {
modulesWithCustomIndentSize[moduleEntity.name] ?: return
val settings = CodeStyle.getSettings(project)
val indentOptions = settings.getIndentOptions(KotlinFileType.INSTANCE)
val kotlinFileType: LanguageFileType? = KotlinFileType.INSTANCE
val indentOptions = settings.getIndentOptions(kotlinFileType)
indentOptions.INDENT_SIZE = INDENT_SIZE
indentOptions.TAB_SIZE = TAB_SIZE
indentOptions.CONTINUATION_INDENT_SIZE = CONTINUATION_INDENT_SIZE
@@ -348,14 +354,11 @@ class AllIntellijEntitiesGenerationTest : CodeGenerationTestBase() {
return filter { path -> none { anotherPath -> anotherPath != path && anotherPath.isSubPathOf(path) } }
}
private fun Path.isSubPathOf(anotherPath: Path): Boolean
= anotherPath.startsWith(this)
private fun Path.isSubPathOf(anotherPath: Path): Boolean = anotherPath.startsWith(this)
internal object TestErrorReporter : ErrorReporter {
override fun reportError(message: String, file: VirtualFileUrl) {
throw AssertionFailedError("Failed to load ${file.url}: $message")
}
}
}
}
@@ -2,11 +2,11 @@
package com.intellij.devkit.workspaceModel
import com.intellij.openapi.application.ex.PathManagerEx
import org.junit.jupiter.api.Assertions
import java.io.File
import java.nio.file.Path
import org.junit.jupiter.api.Assertions
class EntityCodeGenTest : CodeGenerationTestBase() {
abstract class AbstractEntityCodeGenTest : CodeGenerationTestBase() {
override val testDataDirectory: File
get() = File(PathManagerEx.getCommunityHomePath() + "/plugins/devkit/intellij.devkit.workspaceModel/tests/testData/codeGen/$testDirectoryName")
@@ -39,6 +39,14 @@ class EntityCodeGenTest : CodeGenerationTestBase() {
doTest()
}
fun testEntityWithChildrenCollection() {
doTest()
}
fun testEntityWithDifferentChildrenTargets() {
doTest()
}
fun testRefsFromAnotherModule() {
doTest()
}
@@ -63,6 +71,14 @@ class EntityCodeGenTest : CodeGenerationTestBase() {
doTest(processAbstractTypes = true)
}
fun testImports() {
doTest()
}
fun testPropertiesOrder() {
doTest()
}
fun testBothLinksAreParents() {
doTestAndCheckErrorMessage("Both fields MainEntity#secondaryEntities and SecondaryEntity#mainEntity are marked as parent. Did you forget to add @Child annotation?")
}
@@ -97,8 +113,7 @@ class EntityCodeGenTest : CodeGenerationTestBase() {
)
}
private fun getExpectedDir(): Path {
return testDataDirectory.toPath().resolve("after")
}
}
}
@@ -22,6 +22,8 @@
- name: intellij.devkit.themes
- name: intellij.devkit.uiDesigner
- name: intellij.devkit.workspaceModel
- name: intellij.devkit.workspaceModel.k1
- name: intellij.devkit.workspaceModel.k2
- name: intellij.kotlin.devkit
- name: intellij.kotlin.devkit.k1
- name: intellij.kotlin.devkit.k2
@@ -26,6 +26,8 @@
<module name="intellij.devkit.themes"/>
<module name="intellij.devkit.uiDesigner"/>
<module name="intellij.devkit.workspaceModel"/>
<module name="intellij.devkit.workspaceModel.k1"/>
<module name="intellij.devkit.workspaceModel.k2"/>
<module name="intellij.kotlin.devkit"/>
<module name="intellij.kotlin.devkit.k1"/>
<module name="intellij.kotlin.devkit.k2"/>