From fa6b21357b781db444d85143fabd0f9670e3d168 Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Fri, 24 May 2019 18:28:08 +0300 Subject: [PATCH] Add cache to KLightClassForFacade --- .../jvm/compiler/CliKotlinAsJavaSupport.kt | 9 +- .../cli/jvm/compiler/KotlinCoreEnvironment.kt | 3 +- .../kotlin/asJava/classes/FacadeCache.kt | 79 +++++++++++++++ .../asJava/classes/KtLightClassForFacade.kt | 98 +++++-------------- .../classes/ultraKtLightClassForFacade.kt | 2 +- .../asJava/duplicateJvmSignatureUtil.kt | 11 ++- .../lightClasses/LazyLightClassDataHolder.kt | 3 +- .../caches/resolve/IDEKotlinAsJavaSupport.kt | 18 ++-- idea/resources/META-INF/plugin-common.xml | 4 +- 9 files changed, 128 insertions(+), 99 deletions(-) create mode 100644 compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FacadeCache.kt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliKotlinAsJavaSupport.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliKotlinAsJavaSupport.kt index 19d7a9e149f..b8b8106b1c6 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliKotlinAsJavaSupport.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliKotlinAsJavaSupport.kt @@ -39,7 +39,7 @@ class CliKotlinAsJavaSupport( return findFacadeFilesInPackage(packageFqName, scope) .groupBy { it.javaFileFacadeFqName } .mapNotNull { (facadeClassFqName, files) -> - KtLightClassForFacade.createForFacade(psiManager, facadeClassFqName, scope, files) + KtLightClassForFacade.createForFacade(psiManager, facadeClassFqName, scope) } } @@ -56,12 +56,7 @@ class CliKotlinAsJavaSupport( .orEmpty() override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection { - val filesForFacade = findFilesForFacade(facadeFqName, scope) - if (filesForFacade.isEmpty()) return emptyList() - - return listOfNotNull( - KtLightClassForFacade.createForFacade(psiManager, facadeFqName, scope, filesForFacade) - ) + return listOfNotNull(KtLightClassForFacade.createForFacade(psiManager, facadeFqName, scope)) } override fun getScriptClasses(scriptFqName: FqName, scope: GlobalSearchScope): Collection { diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt index 66253391b98..58697fcb2e7 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt @@ -65,6 +65,7 @@ import com.intellij.util.lang.UrlClassLoader import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.classes.FacadeCache import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade import org.jetbrains.kotlin.asJava.finder.JavaElementFinder import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension @@ -679,7 +680,7 @@ class KotlinCoreEnvironment private constructor( fun registerProjectServices(project: MockProject) { with(project) { registerService(KotlinJavaPsiFacade::class.java, KotlinJavaPsiFacade(this)) - registerService(KtLightClassForFacade.FacadeStubCache::class.java, KtLightClassForFacade.FacadeStubCache(this)) + registerService(FacadeCache::class.java, FacadeCache(this)) registerService(ModuleAnnotationsResolver::class.java, CliModuleAnnotationsResolver()) } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FacadeCache.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FacadeCache.kt new file mode 100644 index 00000000000..eed58eea194 --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FacadeCache.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2010-2019 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.asJava.classes + +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.registry.Registry +import com.intellij.psi.PsiManager +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.CachedValue +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import com.intellij.util.containers.SLRUCache +import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport +import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForFileFacade +import org.jetbrains.kotlin.name.FqName + +private data class StubCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope) + +private data class ValueWrapper(val value: KtLightClassForFacade?) { + companion object { + val Null = ValueWrapper(null) + } +} + +class FacadeCache(private val project: Project) { + private inner class FacadeCacheData { + val cache = object : SLRUCache(20, 30) { + override fun createValue(key: StubCacheKey): ValueWrapper { + + val (fqName, searchScope) = key + + val sources = KotlinAsJavaSupport.getInstance(project).findFilesForFacade(key.fqName, key.searchScope) + .filterNot { it.isCompiled } + + if (sources.isEmpty()) return ValueWrapper.Null + + val ultraLightEnabled = + !KtUltraLightSupport.forceUsingOldLightClasses && Registry.`is`("kotlin.use.ultra.light.classes", true) + + val stubProvider = LightClassDataProviderForFileFacade.ByProjectSource(project, fqName, searchScope) + val stubValue = CachedValuesManager.getManager(project) + .createCachedValue(stubProvider, false) + + val manager = PsiManager.getInstance(project) + + val ultraLightClass = if (ultraLightEnabled) + LightClassGenerationSupport.getInstance(project) + .createUltraLightClassForFacade(manager, fqName, stubValue, sources) + else null + + val result = ultraLightClass ?: KtLightClassForFacade(manager, fqName, stubValue, sources) + + return ValueWrapper(result) + } + } + } + + private val cachedValue: CachedValue = CachedValuesManager.getManager(project).createCachedValue( + { CachedValueProvider.Result.create(FacadeCacheData(), PsiModificationTracker.MODIFICATION_COUNT) }, false + ) + + operator fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): KtLightClassForFacade? { + synchronized(cachedValue) { + return cachedValue.value.cache.get(StubCacheKey(qualifiedName, searchScope)).value + } + } + + companion object { + fun getInstance(project: Project): FacadeCache { + return ServiceManager.getService(project, FacadeCache::class.java) + } + } +} \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt index 3075eccf966..f4c44f33c91 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt @@ -16,26 +16,18 @@ package org.jetbrains.kotlin.asJava.classes -import com.intellij.openapi.components.ServiceManager -import com.intellij.openapi.project.Project import com.intellij.openapi.util.Comparing import com.intellij.openapi.util.TextRange -import com.intellij.openapi.util.registry.Registry import com.intellij.psi.* import com.intellij.psi.impl.light.LightEmptyImplementsList import com.intellij.psi.impl.light.LightModifierList import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.CachedValue -import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager -import com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT -import com.intellij.util.containers.SLRUCache import org.jetbrains.annotations.NonNls -import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForFileFacade import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass -import org.jetbrains.kotlin.codegen.inline.getOrPut import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName import org.jetbrains.kotlin.idea.KotlinLanguage @@ -49,43 +41,13 @@ import org.jetbrains.kotlin.psi.KtStringTemplateExpression import org.jetbrains.kotlin.psi.psiUtil.siblings import javax.swing.Icon -open class KtLightClassForFacade protected constructor( +open class KtLightClassForFacade constructor( manager: PsiManager, protected val facadeClassFqName: FqName, protected open val lightClassDataCache: CachedValue, files: Collection ) : KtLazyLightClass(manager) { - private data class StubCacheKey(val fqName: FqName, val searchScope: GlobalSearchScope) - - class FacadeStubCache(private val project: Project) { - private inner class FacadeCacheData { - val cache = object : SLRUCache>(20, 30) { - override fun createValue(key: StubCacheKey): CachedValue { - val stubProvider = LightClassDataProviderForFileFacade.ByProjectSource(project, key.fqName, key.searchScope) - return CachedValuesManager.getManager(project) - .createCachedValue(stubProvider, false) - } - } - } - - private val cachedValue: CachedValue = CachedValuesManager.getManager(project).createCachedValue( - { CachedValueProvider.Result.create(FacadeCacheData(), OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) }, false - ) - - operator fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue { - synchronized(cachedValue) { - return cachedValue.value.cache.get(StubCacheKey(qualifiedName, searchScope)) - } - } - - companion object { - fun getInstance(project: Project): FacadeStubCache { - return ServiceManager.getService(project, FacadeStubCache::class.java) - } - } - } - val files: Collection = files.toSet() // needed for hashCode private val firstFileInFacade by lazyPub { files.iterator().next() } @@ -254,42 +216,6 @@ open class KtLightClassForFacade protected constructor( override fun toString() = "${KtLightClassForFacade::class.java.simpleName}:$facadeClassFqName" - companion object { - - fun createForFacade( - manager: PsiManager, - facadeClassFqName: FqName, - searchScope: GlobalSearchScope, - files: Collection - ): KtLightClassForFacade { - assert(files.isNotEmpty()) { "No files for facade $facadeClassFqName" } - - val ultraLightEnabled = - !KtUltraLightSupport.forceUsingOldLightClasses && Registry.`is`("kotlin.use.ultra.light.classes", true) - - val lightClassDataCache = FacadeStubCache.getInstance(manager.project).get(facadeClassFqName, searchScope) - - val ultraLightClass = if (ultraLightEnabled) - LightClassGenerationSupport.getInstance(manager.project) - .createUltraLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, files) - else null - - return ultraLightClass ?: KtLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, files) - } - - fun createForSyntheticFile( - manager: PsiManager, - facadeClassFqName: FqName, - file: KtFile - ): KtLightClassForFacade { - // TODO: refactor, using cached value doesn't make sense for this case - val cachedValue = CachedValuesManager.getManager(manager.project).createCachedValue( - LightClassDataProviderForFileFacade.ByFile(manager.project, facadeClassFqName, file), /*trackValue = */false - ) - return KtLightClassForFacade(manager, facadeClassFqName, cachedValue, listOf(file)) - } - } - override val originKind: LightClassOriginKind get() = LightClassOriginKind.SOURCE @@ -302,4 +228,26 @@ open class KtLightClassForFacade protected constructor( override fun getStartOffsetInParent() = firstFileInFacade.startOffsetInParent override fun isWritable() = firstFileInFacade.isWritable + + companion object { + fun createForFacade( + manager: PsiManager, + facadeClassFqName: FqName, + searchScope: GlobalSearchScope + ): KtLightClassForFacade? { + return FacadeCache.getInstance(manager.project).get(facadeClassFqName, searchScope) + } + + fun createForSyntheticFile( + manager: PsiManager, + facadeClassFqName: FqName, + file: KtFile + ): KtLightClassForFacade { + // TODO: refactor, using cached value doesn't make sense for this case + val cachedValue = CachedValuesManager.getManager(manager.project).createCachedValue( + LightClassDataProviderForFileFacade.ByFile(manager.project, facadeClassFqName, file), false + ) + return KtLightClassForFacade(manager, facadeClassFqName, cachedValue, listOf(file)) + } + } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraKtLightClassForFacade.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraKtLightClassForFacade.kt index 671709a3e62..c5eea320377 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraKtLightClassForFacade.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraKtLightClassForFacade.kt @@ -69,7 +69,7 @@ class KtUltraLightClassForFacade( private val ownFieldsForNotTooComplex: List by lazyPub { hashSetOf().let { nameCache -> - filesToSupportsToMemberCreators.flatMap { (file, support, creator) -> + filesToSupportsToMemberCreators.flatMap { (file, _, creator) -> file.declarations.filterIsInstance().mapNotNull { creator.createPropertyField(it, nameCache, forceStatic = true) } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/duplicateJvmSignatureUtil.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/duplicateJvmSignatureUtil.kt index 6007b930cb3..8680b7253fd 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/duplicateJvmSignatureUtil.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/duplicateJvmSignatureUtil.kt @@ -18,7 +18,9 @@ package org.jetbrains.kotlin.asJava import com.intellij.psi.PsiElement import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.CachedValuesManager import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder +import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForFileFacade import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration import org.jetbrains.kotlin.diagnostics.Diagnostic @@ -36,9 +38,14 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.* fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Diagnostics, moduleScope: GlobalSearchScope): Diagnostics? { fun getDiagnosticsForFileFacade(file: KtFile): Diagnostics? { val project = file.project - val cache = KtLightClassForFacade.FacadeStubCache.getInstance(project) + val facadeFqName = JvmFileClassUtil.getFileClassInfoNoResolve(file).facadeClassFqName - return cache[facadeFqName, moduleScope].value?.extraDiagnostics + + //TODO Maybe it is better to cache this item + return LightClassDataProviderForFileFacade.ByProjectSource(project, facadeFqName, moduleScope) + .compute() + ?.value + ?.extraDiagnostics } fun getDiagnosticsForClass(ktClassOrObject: KtClassOrObject): Diagnostics { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/LazyLightClassDataHolder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/LazyLightClassDataHolder.kt index c29f7258746..ad37bbbb26b 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/LazyLightClassDataHolder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/LazyLightClassDataHolder.kt @@ -142,7 +142,8 @@ sealed class LazyLightClassDataHolder( } private fun T?.assertMatches(dummyMember: T, containingClass: KtLightClass): T { - if (this == null) throw LazyLightClassMemberMatchingError.NoMatch(dummyMember, containingClass) + if (this == null) + throw LazyLightClassMemberMatchingError.NoMatch(dummyMember, containingClass) val parameterCountMatches = (this as? PsiMethod)?.parameterList?.parametersCount ?: 0 == (dummyMember as? PsiMethod)?.parameterList?.parametersCount ?: 0 diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt index 9fec7d220fe..a024b89bace 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDEKotlinAsJavaSupport.kt @@ -143,13 +143,12 @@ class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport KtLightClassForScript.create(script) private fun withFakeLightClasses( - lightClassForFacade: KtLightClassForFacade, - facadeFiles: List + lightClassForFacade: KtLightClassForFacade ): List { val lightClasses = ArrayList() lightClasses.add(lightClassForFacade) - if (facadeFiles.size > 1) { - lightClasses.addAll(facadeFiles.map { + if (lightClassForFacade.files.size > 1) { + lightClasses.addAll(lightClassForFacade.files.map { FakeLightClassForFileOfPackage(lightClassForFacade, it) }) } @@ -208,24 +207,23 @@ class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport facadeFiles: List, moduleInfo: IdeaModuleInfo ): List { - val (clsFiles, sourceFiles) = facadeFiles.partition { it is KtClsFile } + val (clsFiles, _) = facadeFiles.partition { it is KtClsFile } val facadesFromCls = clsFiles.mapNotNull { createLightClassForDecompiledKotlinFile(it as KtClsFile) } - val facadesFromSources = createFacadesForSourceFiles(moduleInfo, sourceFiles, facadeFqName) + val facadesFromSources = createFacadesForSourceFiles(moduleInfo, facadeFqName) return facadesFromSources + facadesFromCls } private fun createFacadesForSourceFiles( moduleInfo: IdeaModuleInfo, - sourceFiles: List, facadeFqName: FqName ): List { - if (sourceFiles.isEmpty()) return listOf() if (moduleInfo !is ModuleSourceInfo && moduleInfo !is PlatformModuleInfo) return listOf() val lightClassForFacade = KtLightClassForFacade.createForFacade( - psiManager, facadeFqName, moduleInfo.contentScope(), sourceFiles + psiManager, facadeFqName, moduleInfo.contentScope() ) - return withFakeLightClasses(lightClassForFacade, sourceFiles) + + return if (lightClassForFacade !== null) withFakeLightClasses(lightClassForFacade) else emptyList() } override fun findFilesForFacade(facadeFqName: FqName, scope: GlobalSearchScope): Collection { diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml index a6c06a09262..107b2da98f1 100644 --- a/idea/resources/META-INF/plugin-common.xml +++ b/idea/resources/META-INF/plugin-common.xml @@ -307,8 +307,8 @@ - +