From e57ddfb4e3365d715b19eef4da7d7be78d646638 Mon Sep 17 00:00:00 2001 From: Alex Plate Date: Fri, 8 May 2020 18:05:05 +0300 Subject: [PATCH] [Workspace Model] EntityData should calculate PersistentId if TypedEntity has it GitOrigin-RevId: d0b3d356ce71b194e34c1c2bc22175c80e96f1f7 --- .../EntityWithPersistentIdInPStorageTest.kt | 6 ++-- .../api/pstorage/PersistentIdIndexTest.kt | 9 ++++-- .../workspace/api/pstorage/SoftLinksTest.kt | 4 ++- .../src/ImlModelEntities.kt | 14 ++++++--- .../src/pstorage/Entities.kt | 19 +++++++++++- .../src/pstorage/PEntityStorage.kt | 30 +++++++------------ 6 files changed, 53 insertions(+), 29 deletions(-) diff --git a/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/EntityWithPersistentIdInPStorageTest.kt b/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/EntityWithPersistentIdInPStorageTest.kt index b7bd0277f1b3..3f84c8b04eeb 100644 --- a/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/EntityWithPersistentIdInPStorageTest.kt +++ b/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/EntityWithPersistentIdInPStorageTest.kt @@ -8,12 +8,14 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Test -internal class PNamedSampleEntityData : PEntityData() { +internal class PNamedSampleEntityData : PEntityData.WithCalculatablePersistentId() { lateinit var name: String lateinit var next: PSampleEntityId override fun createEntity(snapshot: TypedEntityStorage): PNamedSampleEntity { return PNamedSampleEntity(name, next).also { addMetaData(it, snapshot) } } + + override fun persistentId(): PSampleEntityId = PSampleEntityId(name) } internal class PNamedSampleEntity( @@ -42,7 +44,7 @@ internal data class PChildEntityId(val childName: String, get() = childName } -internal class PChildWithPersistentIdEntityData : PEntityData() { +internal class PChildWithPersistentIdEntityData : PEntityData.WithPersistentId() { lateinit var parent: PNamedSampleEntity lateinit var childName: String override fun createEntity(snapshot: TypedEntityStorage): PChildWithPersistentIdEntity { diff --git a/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/PersistentIdIndexTest.kt b/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/PersistentIdIndexTest.kt index a391f15f6b06..b5853cce15ea 100644 --- a/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/PersistentIdIndexTest.kt +++ b/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/PersistentIdIndexTest.kt @@ -1,15 +1,20 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.workspace.api.pstorage -import com.intellij.workspace.api.* +import com.intellij.workspace.api.EntitySource +import com.intellij.workspace.api.TypedEntityStorage +import com.intellij.workspace.api.TypedEntityStorageBuilder +import com.intellij.workspace.api.TypedEntityWithPersistentId import org.junit.Assert import org.junit.Test -internal class PPersistentIdEntityData : PEntityData() { +internal class PPersistentIdEntityData : PEntityData.WithCalculatablePersistentId() { lateinit var data: String override fun createEntity(snapshot: TypedEntityStorage): PPersistentIdEntity { return PPersistentIdEntity(data).also { addMetaData(it, snapshot) } } + + override fun persistentId(): PSampleEntityId = PSampleEntityId(data) } internal class PPersistentIdEntity(val data: String) : TypedEntityWithPersistentId, PTypedEntity() { diff --git a/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/SoftLinksTest.kt b/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/SoftLinksTest.kt index 33d54478e9da..a78aecdac30f 100644 --- a/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/SoftLinksTest.kt +++ b/platform/workspaceModel-core-tests/test/com/intellij/workspace/api/pstorage/SoftLinksTest.kt @@ -19,11 +19,13 @@ internal data class NameId(private val name: String) : PersistentEntityId() { +internal class NamedEntityData : PEntityData.WithCalculatablePersistentId() { lateinit var name: String override fun createEntity(snapshot: TypedEntityStorage): NamedEntity { return NamedEntity(name).also { addMetaData(it, snapshot) } } + + override fun persistentId(): PersistentEntityId<*> = NameId(name) } internal class NamedEntity( diff --git a/platform/workspaceModel-core/src/ImlModelEntities.kt b/platform/workspaceModel-core/src/ImlModelEntities.kt index 0699b369eb58..2b6a167e33e1 100644 --- a/platform/workspaceModel-core/src/ImlModelEntities.kt +++ b/platform/workspaceModel-core/src/ImlModelEntities.kt @@ -15,7 +15,7 @@ import java.io.Serializable */ @Suppress("unused") -class ModuleEntityData : PEntityData(), PSoftLinkable { +class ModuleEntityData : PEntityData.WithCalculatablePersistentId(), PSoftLinkable { lateinit var name: String var type: String? = null lateinit var dependencies: List @@ -65,6 +65,8 @@ class ModuleEntityData : PEntityData(), PSoftLinkable { override fun createEntity(snapshot: TypedEntityStorage): ModuleEntity = ModuleEntity(name, type, dependencies.toList()).also { addMetaData(it, snapshot) } + + override fun persistentId(): ModuleId = ModuleId(name) } class ModuleEntity( @@ -325,7 +327,7 @@ sealed class LibraryTableId : Serializable { } @Suppress("unused") -class LibraryEntityData : PEntityData(), PSoftLinkable { +class LibraryEntityData : PEntityData.WithCalculatablePersistentId(), PSoftLinkable { lateinit var tableId: LibraryTableId lateinit var name: String lateinit var roots: List @@ -350,6 +352,8 @@ class LibraryEntityData : PEntityData(), PSoftLinkable { override fun createEntity(snapshot: TypedEntityStorage): LibraryEntity { return LibraryEntity(tableId, name, roots.toList(), excludedRoots.toList()).also { addMetaData(it, snapshot) } } + + override fun persistentId(): LibraryId = LibraryId(name, tableId) } open class LibraryEntity( @@ -450,7 +454,7 @@ val ModuleEntity.externalSystemOptions: ExternalSystemModuleOptionsEntity? get() = referrers(ExternalSystemModuleOptionsEntity::module).firstOrNull() @Suppress("unused") -class FacetEntityData : PEntityData() { +class FacetEntityData : PEntityData.WithPersistentId() { lateinit var name: String lateinit var facetType: String var configurationXmlTag: String? = null @@ -490,7 +494,7 @@ data class ArtifactId(val name: String) : PersistentEntityId() { } @Suppress("unused") -class ArtifactEntityData : PEntityData() { +class ArtifactEntityData : PEntityData.WithCalculatablePersistentId() { lateinit var name: String lateinit var artifactType: String var includeInProjectBuild: Boolean = false @@ -499,6 +503,8 @@ class ArtifactEntityData : PEntityData() { override fun createEntity(snapshot: TypedEntityStorage): ArtifactEntity { return ArtifactEntity(name, artifactType, includeInProjectBuild, outputUrl).also { addMetaData(it, snapshot) } } + + override fun persistentId(): ArtifactId = ArtifactId(name) } class ArtifactEntity( diff --git a/platform/workspaceModel-core/src/pstorage/Entities.kt b/platform/workspaceModel-core/src/pstorage/Entities.kt index 555c029f818a..10ba35f2a327 100644 --- a/platform/workspaceModel-core/src/pstorage/Entities.kt +++ b/platform/workspaceModel-core/src/pstorage/Entities.kt @@ -6,7 +6,6 @@ import kotlin.properties.ReadWriteProperty import kotlin.reflect.KClass import kotlin.reflect.KProperty import kotlin.reflect.KProperty1 -import kotlin.reflect.KType import kotlin.reflect.full.memberProperties abstract class PTypedEntity : ReferableTypedEntity, Any() { @@ -150,6 +149,24 @@ abstract class PEntityData: Cloneable { .mapNotNull { it.get(this)?.hashCode() } .fold(31) { acc, i -> acc * 17 + i } } + + /** + * Temporally solution. + * Get persistent Id without creating of TypedEntity. Should be in sync with TypedEntityWithPersistentId. + * But it doesn't everywhere. E.g. FacetEntity where we should resolve module before creating persistent id. + */ + abstract class WithCalculatablePersistentId : PEntityData() { + abstract fun persistentId(): PersistentEntityId<*> + } + + abstract class WithPersistentId : PEntityData() { + } +} + +fun PEntityData<*>.persistentId(snapshot: TypedEntityStorage): PersistentEntityId<*>? = when (this) { + is PEntityData.WithCalculatablePersistentId -> this.persistentId() + is PEntityData.WithPersistentId -> (this.createEntity(snapshot) as TypedEntityWithPersistentId).persistentId() + else -> null } class EntityDataDelegation, B> : ReadWriteProperty { diff --git a/platform/workspaceModel-core/src/pstorage/PEntityStorage.kt b/platform/workspaceModel-core/src/pstorage/PEntityStorage.kt index 17ef99e1659f..51bcdf176ef8 100644 --- a/platform/workspaceModel-core/src/pstorage/PEntityStorage.kt +++ b/platform/workspaceModel-core/src/pstorage/PEntityStorage.kt @@ -158,7 +158,7 @@ internal class PEntityStorageBuilder( // Restore links to soft references if (cloned is PSoftLinkable) { for (link in cloned.getLinks()) { - softLinks.put(link, cloned.createPid()) + softLinks.put(link, replaceToPid) } } @@ -205,8 +205,7 @@ internal class PEntityStorageBuilder( val id = newEntity.createPid() val existingEntityData = entityDataById(id) - val existingEntity = existingEntityData?.createEntity(this) - val beforePersistentId = if (existingEntity is TypedEntityWithPersistentId) existingEntity.persistentId() else null + val beforePersistentId = existingEntityData?.persistentId(this) val beforeSoftLinks = if (existingEntityData is PSoftLinkable) existingEntityData.getLinks() else null /// Replace entity data. id should not be changed @@ -257,10 +256,9 @@ internal class PEntityStorageBuilder( private fun updateSoftReferences(beforePersistentId: PersistentEntityId<*>?, beforeSoftLinks: List>?, copiedData: PEntityData) { - val updatedEntity = copiedData.createEntity(this) - val pid = (updatedEntity as PTypedEntity).id + val pid = copiedData.createPid() if (beforePersistentId != null) { - val afterPersistentId = (updatedEntity as TypedEntityWithPersistentId).persistentId() + val afterPersistentId = copiedData.persistentId(this) ?: error("Persistent id expected") if (beforePersistentId != afterPersistentId) { val updatedIds = mutableListOf(beforePersistentId to afterPersistentId) while (updatedIds.isNotEmpty()) { @@ -415,23 +413,15 @@ internal class PEntityStorageBuilder( } private fun PEntityData<*>.identificator(storage: AbstractPEntityStorage): Any { - val entity = this.createEntity(storage) - return if (entity is TypedEntityWithPersistentId) { - entity.persistentId() - } - else { - this.hashCode() - } + return this.persistentId(storage) ?: this.hashCode() } private fun ArrayListMultimap>.find(entity: PEntityData, storage: AbstractPEntityStorage): PEntityData? { val possibleValues = this[entity.identificator(storage)] - return if (entity.hasPersistentId()) { - possibleValues.find { - (it.createEntity(this@PEntityStorageBuilder) as TypedEntityWithPersistentId).persistentId() == - (entity.createEntity(this@PEntityStorageBuilder) as TypedEntityWithPersistentId).persistentId() - } + val persistentId = entity.persistentId(storage) + return if (persistentId != null) { + possibleValues.find { it.persistentId(this@PEntityStorageBuilder) == persistentId } } else { possibleValues.find { it == entity } @@ -753,7 +743,9 @@ internal class PEntityStorageBuilder( // TODO: 27.03.2020 Here should be consistency check val res = HashMap() replaceMap.forEach { (oldId, newId) -> - res[diff.entityDataByIdOrDie(oldId).createEntity(diff)] = this.entityDataByIdOrDie(newId).createEntity(this) + if (oldId != newId) { + res[diff.entityDataByIdOrDie(oldId).createEntity(diff)] = this.entityDataByIdOrDie(newId).createEntity(this) + } } return res }