Add cache to KLightClassForFacade

This commit is contained in:
Igor Yakovlev
2019-05-24 18:28:08 +03:00
parent 24253e21d0
commit fa6b21357b
9 changed files with 128 additions and 99 deletions
@@ -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<PsiClass> {
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<PsiClass> {
@@ -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())
}
}
@@ -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<StubCacheKey, ValueWrapper>(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<FacadeCacheData> = 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)
}
}
}
@@ -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<LightClassDataHolder.ForFacade>,
files: Collection<KtFile>
) : 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<StubCacheKey, CachedValue<LightClassDataHolder.ForFacade>>(20, 30) {
override fun createValue(key: StubCacheKey): CachedValue<LightClassDataHolder.ForFacade> {
val stubProvider = LightClassDataProviderForFileFacade.ByProjectSource(project, key.fqName, key.searchScope)
return CachedValuesManager.getManager(project)
.createCachedValue<LightClassDataHolder.ForFacade>(stubProvider, false)
}
}
}
private val cachedValue: CachedValue<FacadeCacheData> = CachedValuesManager.getManager(project).createCachedValue<FacadeCacheData>(
{ CachedValueProvider.Result.create(FacadeCacheData(), OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) }, false
)
operator fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue<LightClassDataHolder.ForFacade> {
synchronized(cachedValue) {
return cachedValue.value.cache.get(StubCacheKey(qualifiedName, searchScope))
}
}
companion object {
fun getInstance(project: Project): FacadeStubCache {
return ServiceManager.getService<FacadeStubCache>(project, FacadeStubCache::class.java)
}
}
}
val files: Collection<KtFile> = 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<KtFile>
): 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<LightClassDataHolder.ForFacade>(
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))
}
}
}
@@ -69,7 +69,7 @@ class KtUltraLightClassForFacade(
private val ownFieldsForNotTooComplex: List<KtLightField> by lazyPub {
hashSetOf<String>().let { nameCache ->
filesToSupportsToMemberCreators.flatMap { (file, support, creator) ->
filesToSupportsToMemberCreators.flatMap { (file, _, creator) ->
file.declarations.filterIsInstance<KtProperty>().mapNotNull {
creator.createPropertyField(it, nameCache, forceStatic = true)
}
@@ -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 {
@@ -142,7 +142,8 @@ sealed class LazyLightClassDataHolder(
}
private fun <T : PsiMember> 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
@@ -143,13 +143,12 @@ class IDEKotlinAsJavaSupport(private val project: Project) : KotlinAsJavaSupport
KtLightClassForScript.create(script)
private fun withFakeLightClasses(
lightClassForFacade: KtLightClassForFacade,
facadeFiles: List<KtFile>
lightClassForFacade: KtLightClassForFacade
): List<PsiClass> {
val lightClasses = ArrayList<PsiClass>()
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<KtFile>,
moduleInfo: IdeaModuleInfo
): List<PsiClass> {
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<KtFile>,
facadeFqName: FqName
): List<PsiClass> {
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<KtFile> {
+2 -2
View File
@@ -307,8 +307,8 @@
<projectService serviceImplementation="org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerWorkspaceSettings"/>
<projectService serviceInterface="org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade$FacadeStubCache"
serviceImplementation="org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade$FacadeStubCache"/>
<projectService serviceInterface="org.jetbrains.kotlin.asJava.classes.FacadeCache"
serviceImplementation="org.jetbrains.kotlin.asJava.classes.FacadeCache"/>
<projectService serviceInterface="org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService"
serviceImplementation="org.jetbrains.kotlin.idea.stubindex.resolve.PluginDeclarationProviderFactoryService"/>