Use lazySync instead of lazyPub to avoid raise on creation LightClasses

This commit is contained in:
Vladimir Dolzhenko
2019-08-29 17:51:09 +02:00
parent b856d60575
commit d6c54b845b
5 changed files with 23 additions and 15 deletions
@@ -56,13 +56,10 @@ class LightClassDataProviderForClassOrObject(
} }
override fun compute(): CachedValueProvider.Result<LightClassDataHolder.ForClass>? { override fun compute(): CachedValueProvider.Result<LightClassDataHolder.ForClass>? {
val trackerService = KotlinModificationTrackerService.getInstance(classOrObject.project)
return CachedValueProvider.Result.create( return CachedValueProvider.Result.create(
computeLightClassData(), computeLightClassData(),
if (classOrObject.isLocal()) { if (classOrObject.isLocal) trackerService.modificationTracker else trackerService.outOfBlockModificationTracker
KotlinModificationTrackerService.getInstance(classOrObject.project).modificationTracker
} else {
KotlinModificationTrackerService.getInstance(classOrObject.project).outOfBlockModificationTracker
}
) )
} }
@@ -19,12 +19,17 @@ package org.jetbrains.kotlin.asJava.classes
import com.intellij.psi.PsiClass import com.intellij.psi.PsiClass
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.asJava.builder.LightClassData import org.jetbrains.kotlin.asJava.builder.LightClassData
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
abstract class KtLazyLightClass(manager: PsiManager) : KtLightClassBase(manager) { abstract class KtLazyLightClass(manager: PsiManager) : KtLightClassBase(manager) {
abstract val lightClassData: LightClassData abstract val lightClassData: LightClassData
override val clsDelegate: PsiClass by lazyPub { lightClassData.clsDelegate } override val clsDelegate: PsiClass by lazyPub { lightClassData.clsDelegate }
override fun getOwnFields() = lightClassData.getOwnFields(this) private val _getOwnFields: List<KtLightField> by lazySync { lightClassData.getOwnFields(this) }
override fun getOwnMethods() = lightClassData.getOwnMethods(this) override fun getOwnFields() = _getOwnFields
private val _getOwnMethods: List<KtLightMethod> by lazySync { lightClassData.getOwnMethods(this) }
override fun getOwnMethods() = _getOwnMethods
} }
@@ -97,7 +97,9 @@ abstract class KtLightClassForSourceDeclaration(
abstract override fun getQualifiedName(): String? abstract override fun getQualifiedName(): String?
override val lightClassData: LightClassData override val lightClassData: LightClassData
get() = findLightClassData() get() = _findLightClassData
private val _findLightClassData: LightClassData by lazySync { findLightClassData() }
protected open fun findLightClassData() = getLightClassDataHolder().findDataForClassOrObject(classOrObject) protected open fun findLightClassData() = getLightClassDataHolder().findDataForClassOrObject(classOrObject)
@@ -20,6 +20,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
// NOTE: avoid using blocking lazy in light classes, it leads to deadlocks // NOTE: avoid using blocking lazy in light classes, it leads to deadlocks
fun <T> lazyPub(initializer: () -> T) = lazy(LazyThreadSafetyMode.PUBLICATION, initializer) fun <T> lazyPub(initializer: () -> T) = lazy(LazyThreadSafetyMode.PUBLICATION, initializer)
fun <T> lazySync(initializer: () -> T) = lazy(LazyThreadSafetyMode.SYNCHRONIZED, initializer)
fun LightElement.cannotModify(): Nothing { fun LightElement.cannotModify(): Nothing {
throw IncorrectOperationException("Modification not implemented.") throw IncorrectOperationException("Modification not implemented.")
} }
@@ -14,7 +14,7 @@ import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import org.jetbrains.kotlin.asJava.LightClassBuilder import org.jetbrains.kotlin.asJava.LightClassBuilder
import org.jetbrains.kotlin.asJava.builder.* import org.jetbrains.kotlin.asJava.builder.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.asJava.classes.lazySync
import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl
import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.elements.KtLightMethod
@@ -43,9 +43,11 @@ sealed class LazyLightClassDataHolder(
cache.computeIfAbsent(lazyLightClassDataHolder, diagnostics) cache.computeIfAbsent(lazyLightClassDataHolder, diagnostics)
} }
private val exactResultLazyValue = lazyPub { builder(exactContextProvider()).stub } private val _builderExactContextProvider: LightClassBuilderResult by lazySync { builder(exactContextProvider()) }
private val lazyInexactStub by lazyPub { private val exactResultLazyValue = lazySync { _builderExactContextProvider.stub }
private val lazyInexactStub by lazySync {
dummyContextProvider?.let { provider -> provider()?.let { context -> builder.invoke(context).stub } } dummyContextProvider?.let { provider -> provider()?.let { context -> builder.invoke(context).stub } }
} }
@@ -56,7 +58,7 @@ sealed class LazyLightClassDataHolder(
override val extraDiagnostics: Diagnostics override val extraDiagnostics: Diagnostics
get() = diagnosticsHolderProvider().getOrCompute(this) { get() = diagnosticsHolderProvider().getOrCompute(this) {
builder(exactContextProvider()).diagnostics _builderExactContextProvider.diagnostics
// Force lazy diagnostics computation because otherwise a lot of memory is retained by computation. // Force lazy diagnostics computation because otherwise a lot of memory is retained by computation.
// NB: Laziness here is not crucial anyway since somebody already has requested diagnostics and we hope one will use them // NB: Laziness here is not crucial anyway since somebody already has requested diagnostics and we hope one will use them
.takeUnless { it.isEmpty() } ?: Diagnostics.EMPTY .takeUnless { it.isEmpty() } ?: Diagnostics.EMPTY
@@ -100,9 +102,9 @@ sealed class LazyLightClassDataHolder(
private inner class LazyLightClassData( private inner class LazyLightClassData(
findDelegate: (PsiJavaFileStub) -> PsiClass findDelegate: (PsiJavaFileStub) -> PsiClass
) : LightClassData { ) : LightClassData {
override val clsDelegate: PsiClass by lazyPub { findDelegate(javaFileStub) } override val clsDelegate: PsiClass by lazySync { findDelegate(javaFileStub) }
private val dummyDelegate: PsiClass? by lazyPub { inexactStub?.let(findDelegate) } private val dummyDelegate: PsiClass? by lazySync { inexactStub?.let(findDelegate) }
override fun getOwnFields(containingClass: KtLightClass): List<KtLightField> { override fun getOwnFields(containingClass: KtLightClass): List<KtLightField> {
if (dummyDelegate == null) return KtLightFieldImpl.fromClsFields(clsDelegate, containingClass) if (dummyDelegate == null) return KtLightFieldImpl.fromClsFields(clsDelegate, containingClass)