From 2eaea66a0cdcec8a1621e6973caa31a83bec2dc2 Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Tue, 28 Jun 2022 17:57:31 +0200 Subject: [PATCH] Revert "Revert "[light classes] drop old light classes and backend: iteration #4"" This reverts commit 3d9a58627f075a5172258188b012d1596109fb81. --- .../compiler/CliExtraDiagnosticsProvider.kt | 109 ++++++++-- .../jvm/compiler/LightClassDataProvider.kt | 150 ++++++++++++++ .../asJava/builder/LightClassDataProvider.kt | 186 ------------------ .../asJava/classes/KtLightClassForScript.kt | 19 -- .../KtLightClassForSourceDeclaration.kt | 72 ------- 5 files changed, 248 insertions(+), 288 deletions(-) create mode 100644 compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/LightClassDataProvider.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliExtraDiagnosticsProvider.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliExtraDiagnosticsProvider.kt index 328602d35dc..862896b760d 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliExtraDiagnosticsProvider.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliExtraDiagnosticsProvider.kt @@ -5,33 +5,120 @@ package org.jetbrains.kotlin.cli.jvm.compiler +import com.intellij.openapi.util.Key import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.CachedValue +import com.intellij.psi.util.CachedValuesManager +import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport import org.jetbrains.kotlin.asJava.KotlinExtraDiagnosticsProvider -import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder -import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForFileFacade -import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration +import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder +import org.jetbrains.kotlin.asJava.builder.buildLightClass +import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject +import org.jetbrains.kotlin.asJava.classes.safeIsLocal +import org.jetbrains.kotlin.asJava.classes.safeScript +import org.jetbrains.kotlin.asJava.classes.shouldNotBeVisibleAsLightClass import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtScript import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics +private val JAVA_API_STUB_FOR_SCRIPT = Key.create>("JAVA_API_STUB_FOR_SCRIPT") +private val JAVA_API_STUB = Key.create>("JAVA_API_STUB") +private val JAVA_API_STUB_LOCK = Key.create("JAVA_API_STUB_LOCK") + +private val javaApiStubInitIsRunning: ThreadLocal = ThreadLocal.withInitial { false } + class CliExtraDiagnosticsProvider : KotlinExtraDiagnosticsProvider { override fun forClassOrObject(kclass: KtClassOrObject): Diagnostics { - val lightClassDataHolder = KtLightClassForSourceDeclaration.getLightClassDataHolder(kclass) - if (lightClassDataHolder is InvalidLightClassDataHolder) { + if (kclass.shouldNotBeVisibleAsLightClass()) { return Diagnostics.EMPTY } - return lightClassDataHolder.extraDiagnostics + val containingScript = kclass.containingKtFile.safeScript() + return when { + !kclass.safeIsLocal() && containingScript != null -> getLightClassCachedValue(containingScript).value + else -> getLightClassCachedValue(kclass).value + }.extraDiagnostics } override fun forFacade(file: KtFile, moduleScope: GlobalSearchScope): Diagnostics { val project = file.project val facadeFqName = JvmFileClassUtil.getFileClassInfoNoResolve(file).facadeClassFqName - return LightClassDataProviderForFileFacade(project, facadeFqName, moduleScope) - .compute() - ?.value - ?.extraDiagnostics - ?: Diagnostics.EMPTY + val files = KotlinAsJavaSupport.getInstance(project) + .findFilesForFacade(facadeFqName, moduleScope) + .ifEmpty { return Diagnostics.EMPTY } + + return LightClassGenerationSupport.getInstance(project).createDataHolderForFacade(files) { constructionContext -> + buildLightClass(facadeFqName.parent(), files, ClassFilterForFacade, constructionContext) generate@{ state, files -> + val representativeFile = files.first() + val fileClassInfo = JvmFileClassUtil.getFileClassInfoNoResolve(representativeFile) + if (!fileClassInfo.withJvmMultifileClass) { + val codegen = state.factory.forPackage(representativeFile.packageFqName, files) + codegen.generate() + state.factory.done() + return@generate + } + + val codegen = state.factory.forMultifileClass(facadeFqName, files) + codegen.generate() + state.factory.done() + } + }.extraDiagnostics } +} + +private fun getLightClassCachedValue(script: KtScript): CachedValue { + return script.getUserData(JAVA_API_STUB_FOR_SCRIPT) ?: createCachedValueForScript(script).also { + script.putUserData(JAVA_API_STUB_FOR_SCRIPT, it) + } +} + +private fun createCachedValueForScript(script: KtScript): CachedValue = + CachedValuesManager.getManager(script.project).createCachedValue(LightClassDataProviderForScript(script), false) + +private fun getLightClassCachedValue(classOrObject: KtClassOrObject): CachedValue { + val outerClassValue = getOutermostClassOrObject(classOrObject).getUserData(JAVA_API_STUB) + outerClassValue?.let { + // stub computed for outer class can be used for inner/nested + return it + } + // the idea behind this locking approach: + // Thread T1 starts to calculate value for A it acquires lock for A + // + // Assumption 1: Lets say A calculation requires another value e.g. B to be calculated + // Assumption 2: Thread T2 wants to calculate value for B + + // to avoid dead-lock case we mark thread as doing calculation and acquire lock only once per thread + // as a trade-off to prevent dependent value could be calculated several time + // due to CAS (within putUserDataIfAbsent etc) the same instance of calculated value will be used + val value: CachedValue = if (!javaApiStubInitIsRunning.get()) { + classOrObject.getUserData(JAVA_API_STUB) ?: run { + val lock = classOrObject.putUserDataIfAbsent(JAVA_API_STUB_LOCK, Object()) + synchronized(lock) { + try { + javaApiStubInitIsRunning.set(true) + computeLightClassCachedValue(classOrObject) + } finally { + javaApiStubInitIsRunning.set(false) + } + } + } + } else { + computeLightClassCachedValue(classOrObject) + } + + return value +} + +private fun computeLightClassCachedValue(classOrObject: KtClassOrObject): CachedValue { + val value = classOrObject.getUserData(JAVA_API_STUB) ?: run { + val manager = CachedValuesManager.getManager(classOrObject.project) + val cachedValue = manager.createCachedValue( + LightClassDataProviderForClassOrObject(classOrObject), false + ) + classOrObject.putUserDataIfAbsent(JAVA_API_STUB, cachedValue) + } + return value } \ No newline at end of file diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/LightClassDataProvider.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/LightClassDataProvider.kt new file mode 100644 index 00000000000..92ce93de6f0 --- /dev/null +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/LightClassDataProvider.kt @@ -0,0 +1,150 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.cli.jvm.compiler + +import com.intellij.psi.PsiFile +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService +import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder +import org.jetbrains.kotlin.asJava.builder.buildLightClass +import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject +import org.jetbrains.kotlin.asJava.classes.safeIsLocal +import org.jetbrains.kotlin.codegen.MemberCodegen +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.isAncestor +import org.jetbrains.org.objectweb.asm.Type + +internal class LightClassDataProviderForClassOrObject( + private val classOrObject: KtClassOrObject +) : CachedValueProvider { + private fun computeLightClassData(): LightClassDataHolder.ForClass { + val file = classOrObject.containingKtFile + val packageFqName = file.packageFqName + return LightClassGenerationSupport.getInstance(classOrObject.project) + .createDataHolderForClass(classOrObject) { constructionContext -> + buildLightClass( + packageFqName, + listOf(file), + ClassFilterForClassOrObject(classOrObject), + constructionContext + ) { state, files -> + val packageCodegen = state.factory.forPackage(packageFqName, files) + val packagePartType = Type.getObjectType(JvmFileClassUtil.getFileClassInternalName(file)) + val context = state.rootContext.intoPackagePart(packageCodegen.packageFragment, packagePartType, file) + MemberCodegen.genClassOrObject(context, getOutermostClassOrObject(classOrObject), state, null) + state.factory.done() + } + } + } + + override fun compute(): CachedValueProvider.Result? { + val trackerService = KotlinModificationTrackerService.getInstance(classOrObject.project) + return CachedValueProvider.Result.create( + computeLightClassData(), + if (classOrObject.safeIsLocal()) trackerService.modificationTracker else trackerService.outOfBlockModificationTracker + ) + } + + override fun toString(): String { + return this::class.java.name + " for " + classOrObject.name + } +} + +private class ClassFilterForClassOrObject(private val classOrObject: KtClassOrObject) : GenerationState.GenerateClassFilter() { + + override fun shouldGeneratePackagePart(ktFile: KtFile) = true + override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject) = shouldGenerateClass(processingClassOrObject) + + override fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject): Boolean { + if (classOrObject === processingClassOrObject) return true + + // process all children + if (classOrObject.isAncestor(processingClassOrObject, true)) { + return true + } + + // Local classes should be process by CodegenAnnotatingVisitor to + // decide what class they should be placed in. + // + // Example: + // class A + // fun foo() { + // trait Z: A {} + // fun bar() { + // class O2: Z {} + // } + // } + // TODO: current method will process local classes in irrelevant declarations, it should be fixed. + // We generate all enclosing classes + + if (classOrObject.safeIsLocal() && processingClassOrObject.safeIsLocal()) { + val commonParent = PsiTreeUtil.findCommonParent(classOrObject, processingClassOrObject) + return commonParent != null && commonParent !is PsiFile + } + + return false + } + + override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject) + // generate outer classes but not their members + = shouldGenerateClassMembers(processingClassOrObject) || processingClassOrObject.isAncestor(classOrObject, true) + + override fun shouldGenerateScript(script: KtScript) = PsiTreeUtil.isAncestor(script, classOrObject, false) + override fun shouldGenerateCodeFragment(script: KtCodeFragment) = false +} + +internal class LightClassDataProviderForScript(private val script: KtScript) : CachedValueProvider { + private fun computeLightClassData(): LightClassDataHolder.ForScript { + return LightClassGenerationSupport.getInstance(script.project).createDataHolderForScript(script) { constructionContext -> + buildLightClass( + script.fqName.parent(), + listOf(script.containingKtFile), + ClassFilterForScript(script), + constructionContext + ) generate@{ state, files -> + val scriptFile = files.first() + val codegen = state.factory.forPackage(scriptFile.packageFqName, files) + codegen.generate() + state.factory.done() + } + } + } + + override fun compute(): CachedValueProvider.Result = + CachedValueProvider.Result.create( + computeLightClassData(), + KotlinModificationTrackerService.getInstance(script.project).outOfBlockModificationTracker + ) + + override fun toString(): String = this::class.java.name + " for ${script.fqName}" +} + +private class ClassFilterForScript(val script: KtScript) : GenerationState.GenerateClassFilter() { + override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean = + shouldGenerateClass(processingClassOrObject) + + override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean = + processingClassOrObject.isAncestor(script, true) + + override fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject): Boolean = true + + override fun shouldGeneratePackagePart(ktFile: KtFile): Boolean = script.containingKtFile === ktFile + + override fun shouldGenerateScript(script: KtScript): Boolean = this.script === script + override fun shouldGenerateCodeFragment(script: KtCodeFragment) = false +} + +internal object ClassFilterForFacade : GenerationState.GenerateClassFilter() { + override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject) = shouldGenerateClass(processingClassOrObject) + override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject) = KtPsiUtil.isLocal(processingClassOrObject) + override fun shouldGeneratePackagePart(ktFile: KtFile) = true + override fun shouldGenerateScript(script: KtScript) = false + override fun shouldGenerateCodeFragment(script: KtCodeFragment) = false +} \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt index 272078e6c12..a914c6c7c79 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt @@ -5,195 +5,9 @@ package org.jetbrains.kotlin.asJava.builder -import com.intellij.openapi.project.Project -import com.intellij.psi.PsiFile import com.intellij.psi.impl.java.stubs.PsiJavaFileStub -import com.intellij.psi.search.GlobalSearchScope -import com.intellij.psi.util.CachedValueProvider -import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService -import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport -import org.jetbrains.kotlin.asJava.LightClassGenerationSupport -import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject -import org.jetbrains.kotlin.asJava.classes.safeIsLocal -import org.jetbrains.kotlin.codegen.MemberCodegen -import org.jetbrains.kotlin.codegen.state.GenerationState -import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.isAncestor -import org.jetbrains.org.objectweb.asm.Type -class LightClassDataProviderForClassOrObject( - private val classOrObject: KtClassOrObject -) : CachedValueProvider { - - private fun computeLightClassData(): LightClassDataHolder.ForClass { - val file = classOrObject.containingKtFile - val packageFqName = file.packageFqName - return LightClassGenerationSupport.getInstance(classOrObject.project) - .createDataHolderForClass(classOrObject) { constructionContext -> - buildLightClass( - packageFqName, - listOf(file), - ClassFilterForClassOrObject(classOrObject), - constructionContext - ) { state, files -> - val packageCodegen = state.factory.forPackage(packageFqName, files) - val packagePartType = Type.getObjectType(JvmFileClassUtil.getFileClassInternalName(file)) - val context = state.rootContext.intoPackagePart(packageCodegen.packageFragment, packagePartType, file) - MemberCodegen.genClassOrObject(context, getOutermostClassOrObject(classOrObject), state, null) - state.factory.done() - } - } - } - - override fun compute(): CachedValueProvider.Result? { - val trackerService = KotlinModificationTrackerService.getInstance(classOrObject.project) - return CachedValueProvider.Result.create( - computeLightClassData(), - if (classOrObject.safeIsLocal()) trackerService.modificationTracker else trackerService.outOfBlockModificationTracker - ) - } - - override fun toString(): String { - return this::class.java.name + " for " + classOrObject.name - } -} - -class LightClassDataProviderForFileFacade constructor( - private val project: Project, private val facadeFqName: FqName, private val searchScope: GlobalSearchScope -) : CachedValueProvider { - fun findFiles(): Collection = KotlinAsJavaSupport.getInstance(project).findFilesForFacade(facadeFqName, searchScope) - - private fun computeLightClassData(files: Collection): LightClassDataHolder.ForFacade { - return LightClassGenerationSupport.getInstance(project).createDataHolderForFacade(files) { constructionContext -> - buildLightClass(facadeFqName.parent(), files, ClassFilterForFacade, constructionContext) generate@{ state, files -> - val representativeFile = files.first() - val fileClassInfo = JvmFileClassUtil.getFileClassInfoNoResolve(representativeFile) - if (!fileClassInfo.withJvmMultifileClass) { - val codegen = state.factory.forPackage(representativeFile.packageFqName, files) - codegen.generate() - state.factory.done() - return@generate - } - - val codegen = state.factory.forMultifileClass(facadeFqName, files) - codegen.generate() - state.factory.done() - } - } - } - - override fun compute(): CachedValueProvider.Result? { - val files = findFiles() - if (files.isEmpty()) return null - - return CachedValueProvider.Result.create( - computeLightClassData(files), - KotlinModificationTrackerService.getInstance(project).outOfBlockModificationTracker - ) - } - - override fun toString(): String { - return this::class.java.name + " for $facadeFqName" - } -} - - -class LightClassDataProviderForScript(private val script: KtScript) : CachedValueProvider { - private fun computeLightClassData(): LightClassDataHolder.ForScript { - return LightClassGenerationSupport.getInstance(script.project).createDataHolderForScript(script) { constructionContext -> - buildLightClass( - script.fqName.parent(), - listOf(script.containingKtFile), - ClassFilterForScript(script), - constructionContext - ) generate@{ state, files -> - val scriptFile = files.first() - val codegen = state.factory.forPackage(scriptFile.packageFqName, files) - codegen.generate() - state.factory.done() - } - } - } - - override fun compute(): CachedValueProvider.Result? = - CachedValueProvider.Result.create( - computeLightClassData(), - KotlinModificationTrackerService.getInstance(script.project).outOfBlockModificationTracker - ) - - override fun toString(): String = this::class.java.name + " for ${script.fqName}" -} interface StubComputationTracker { fun onStubComputed(javaFileStub: PsiJavaFileStub, context: LightClassConstructionContext) } - - -private class ClassFilterForClassOrObject(private val classOrObject: KtClassOrObject) : GenerationState.GenerateClassFilter() { - - override fun shouldGeneratePackagePart(ktFile: KtFile) = true - override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject) = shouldGenerateClass(processingClassOrObject) - - override fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject): Boolean { - if (classOrObject === processingClassOrObject) return true - - // process all children - if (classOrObject.isAncestor(processingClassOrObject, true)) { - return true - } - - // Local classes should be process by CodegenAnnotatingVisitor to - // decide what class they should be placed in. - // - // Example: - // class A - // fun foo() { - // trait Z: A {} - // fun bar() { - // class O2: Z {} - // } - // } - // TODO: current method will process local classes in irrelevant declarations, it should be fixed. - // We generate all enclosing classes - - if (classOrObject.safeIsLocal() && processingClassOrObject.safeIsLocal()) { - val commonParent = PsiTreeUtil.findCommonParent(classOrObject, processingClassOrObject) - return commonParent != null && commonParent !is PsiFile - } - - return false - } - - override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject) - // generate outer classes but not their members - = shouldGenerateClassMembers(processingClassOrObject) || processingClassOrObject.isAncestor(classOrObject, true) - - override fun shouldGenerateScript(script: KtScript) = PsiTreeUtil.isAncestor(script, classOrObject, false) - override fun shouldGenerateCodeFragment(script: KtCodeFragment) = false -} - -object ClassFilterForFacade : GenerationState.GenerateClassFilter() { - override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject) = shouldGenerateClass(processingClassOrObject) - override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject) = KtPsiUtil.isLocal(processingClassOrObject) - override fun shouldGeneratePackagePart(ktFile: KtFile) = true - override fun shouldGenerateScript(script: KtScript) = false - override fun shouldGenerateCodeFragment(script: KtCodeFragment) = false -} - -private class ClassFilterForScript(val script: KtScript) : GenerationState.GenerateClassFilter() { - override fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean = - shouldGenerateClass(processingClassOrObject) - - override fun shouldGenerateClass(processingClassOrObject: KtClassOrObject): Boolean = - processingClassOrObject.isAncestor(script, true) - - override fun shouldGenerateClassMembers(processingClassOrObject: KtClassOrObject): Boolean = true - - override fun shouldGeneratePackagePart(ktFile: KtFile): Boolean = script.containingKtFile === ktFile - - override fun shouldGenerateScript(script: KtScript): Boolean = this.script === script - override fun shouldGenerateCodeFragment(script: KtCodeFragment) = false -} diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForScript.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForScript.kt index abacc5244c2..26fbbaf52aa 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForScript.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForScript.kt @@ -5,20 +5,16 @@ package org.jetbrains.kotlin.asJava.classes -import com.intellij.openapi.util.Key import com.intellij.psi.* import com.intellij.psi.impl.PsiSuperMethodImplUtil import com.intellij.psi.impl.light.LightEmptyImplementsList import com.intellij.psi.impl.light.LightModifierList -import com.intellij.psi.util.CachedValue import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.util.IncorrectOperationException import org.jetbrains.annotations.NonNls import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService import org.jetbrains.kotlin.asJava.LightClassGenerationSupport -import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder -import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForScript import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind @@ -163,9 +159,6 @@ abstract class KtLightClassForScript(val script: KtScript) : KtLazyLightClass(sc override fun toString() = "${KtLightClassForScript::class.java.simpleName}:${script.fqName}" companion object { - - private val JAVA_API_STUB_FOR_SCRIPT = Key.create>("JAVA_API_STUB_FOR_SCRIPT") - fun create(script: KtScript): KtLightClassForScript? = CachedValuesManager.getCachedValue(script) { CachedValueProvider.Result @@ -186,17 +179,5 @@ abstract class KtLightClassForScript(val script: KtScript) : KtLazyLightClass(sc createUltraLightClassForScript(script) } } - - fun getLightClassCachedValue(script: KtScript): CachedValue { - return script.getUserData(JAVA_API_STUB_FOR_SCRIPT) ?: createCachedValueForScript(script).also { - script.putUserData( - JAVA_API_STUB_FOR_SCRIPT, - it, - ) - } - } - - private fun createCachedValueForScript(script: KtScript): CachedValue = - CachedValuesManager.getManager(script.project).createCachedValue(LightClassDataProviderForScript(script), false) } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt index aabff8542b4..7fa99a085ff 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.asJava.classes import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project -import com.intellij.openapi.util.Key import com.intellij.openapi.util.TextRange import com.intellij.psi.* import com.intellij.psi.impl.InheritanceImplUtil @@ -18,7 +17,6 @@ import com.intellij.psi.scope.PsiScopeProcessor import com.intellij.psi.search.SearchScope import com.intellij.psi.stubs.IStubElementType import com.intellij.psi.stubs.StubElement -import com.intellij.psi.util.CachedValue import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiUtilCore @@ -28,9 +26,6 @@ import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService import org.jetbrains.kotlin.asJava.ImpreciseResolveResult import org.jetbrains.kotlin.asJava.ImpreciseResolveResult.UNSURE import org.jetbrains.kotlin.asJava.LightClassGenerationSupport -import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder -import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder -import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForClassOrObject import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier import org.jetbrains.kotlin.asJava.elements.KtLightModifierList @@ -310,12 +305,6 @@ abstract class KtLightClassForSourceDeclaration( override fun getImplementsList(): PsiReferenceList? = _implementsList companion object { - private val JAVA_API_STUB = Key.create>("JAVA_API_STUB") - private val JAVA_API_STUB_LOCK = Key.create("JAVA_API_STUB_LOCK") - - @JvmStatic - private val javaApiStubInitIsRunning: ThreadLocal = ThreadLocal.withInitial { false } - private val jetTokenToPsiModifier = listOf( PUBLIC_KEYWORD to PsiModifier.PUBLIC, INTERNAL_KEYWORD to PsiModifier.PUBLIC, @@ -347,67 +336,6 @@ abstract class KtLightClassForSourceDeclaration( } } - fun getLightClassDataHolder(classOrObject: KtClassOrObject): LightClassDataHolder.ForClass { - if (classOrObject.shouldNotBeVisibleAsLightClass()) { - return InvalidLightClassDataHolder - } - - val containingScript = classOrObject.containingKtFile.safeScript() - return when { - !classOrObject.safeIsLocal() && containingScript != null -> - KtLightClassForScript.getLightClassCachedValue(containingScript).value - - else -> - getLightClassCachedValue(classOrObject).value - } - } - - private fun getLightClassCachedValue(classOrObject: KtClassOrObject): CachedValue { - val outerClassValue = getOutermostClassOrObject(classOrObject).getUserData(JAVA_API_STUB) - outerClassValue?.let { - // stub computed for outer class can be used for inner/nested - return it - } - // the idea behind this locking approach: - // Thread T1 starts to calculate value for A it acquires lock for A - // - // Assumption 1: Lets say A calculation requires another value e.g. B to be calculated - // Assumption 2: Thread T2 wants to calculate value for B - - // to avoid dead-lock case we mark thread as doing calculation and acquire lock only once per thread - // as a trade-off to prevent dependent value could be calculated several time - // due to CAS (within putUserDataIfAbsent etc) the same instance of calculated value will be used - val value: CachedValue = if (!javaApiStubInitIsRunning.get()) { - classOrObject.getUserData(JAVA_API_STUB) ?: run { - val lock = classOrObject.putUserDataIfAbsent(JAVA_API_STUB_LOCK, Object()) - synchronized(lock) { - try { - javaApiStubInitIsRunning.set(true) - computeLightClassCachedValue(classOrObject) - } finally { - javaApiStubInitIsRunning.set(false) - } - } - } - } else { - computeLightClassCachedValue(classOrObject) - } - return value - } - - private fun computeLightClassCachedValue( - classOrObject: KtClassOrObject - ): CachedValue { - val value = classOrObject.getUserData(JAVA_API_STUB) ?: run { - val manager = CachedValuesManager.getManager(classOrObject.project) - val cachedValue = manager.createCachedValue( - LightClassDataProviderForClassOrObject(classOrObject), false - ) - classOrObject.putUserDataIfAbsent(JAVA_API_STUB, cachedValue) - } - return value - } - private fun checkSuperTypeByFQName(classDescriptor: ClassDescriptor, qualifiedName: String, deep: Boolean): Boolean { if (CommonClassNames.JAVA_LANG_OBJECT == qualifiedName) return true