diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt index e6818aa8953..23799777df8 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/CliLightClassGenerationSupport.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.cli.jvm.compiler import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.CachedValue import org.jetbrains.kotlin.asJava.LightClassBuilder import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.builder.InvalidLightClassDataHolder @@ -45,7 +46,7 @@ class CliLightClassGenerationSupport(private val traceHolder: CliTraceHolder) : override fun createUltraLightClassForFacade( facadeClassFqName: FqName, - searchScope: GlobalSearchScope, + lightClassDataCache: CachedValue, facadeFile: KtFile ): KtUltraLightClassForFacade? = null diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt index f2d5587627f..1dffa29b290 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/LightClassGenerationSupport.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.asJava import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.CachedValue import org.jetbrains.kotlin.asJava.builder.LightClassBuilderResult import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder @@ -50,7 +51,7 @@ abstract class LightClassGenerationSupport { abstract fun createUltraLightClassForFacade( facadeClassFqName: FqName, - searchScope: GlobalSearchScope, + lightClassDataCache: CachedValue, facadeFile: KtFile ): KtUltraLightClassForFacade? 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 07c05ea71c4..46a69278f7a 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 @@ -19,6 +19,7 @@ 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 @@ -27,7 +28,7 @@ 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.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 @@ -62,13 +63,13 @@ open class KtLightClassForFacade protected constructor( override fun createValue(key: StubCacheKey): CachedValue { val stubProvider = LightClassDataProviderForFileFacade.ByProjectSource(project, key.fqName, key.searchScope) return CachedValuesManager.getManager(project) - .createCachedValue(stubProvider, /*trackValue = */false) + .createCachedValue(stubProvider, false) } } } private val cachedValue: CachedValue = CachedValuesManager.getManager(project).createCachedValue( - { CachedValueProvider.Result.create(FacadeCacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) }, false + { CachedValueProvider.Result.create(FacadeCacheData(), OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) }, false ) operator fun get(qualifiedName: FqName, searchScope: GlobalSearchScope): CachedValue { @@ -86,6 +87,8 @@ open class KtLightClassForFacade protected constructor( val files: Collection = files.toSet() // needed for hashCode + private val firstFileInFacade by lazyPub { files.iterator().next() } + private val hashCode: Int = computeHashCode() @@ -199,7 +202,7 @@ open class KtLightClassForFacade protected constructor( override val lightClassData get() = lightClassDataCache.value.findDataForFacade(facadeClassFqName) - override fun getNavigationElement() = files.iterator().next() + override fun getNavigationElement() = firstFileInFacade override fun isEquivalentTo(another: PsiElement?): Boolean { return another is KtLightClassForFacade && Comparing.equal(another.qualifiedName, qualifiedName) @@ -251,6 +254,7 @@ open class KtLightClassForFacade protected constructor( override fun toString() = "${KtLightClassForFacade::class.java.simpleName}:$facadeClassFqName" companion object { + fun createForFacade( manager: PsiManager, facadeClassFqName: FqName, @@ -264,8 +268,17 @@ open class KtLightClassForFacade protected constructor( if (ultraLightEnabled && files.count() == 1) { val facadeFile = files.first() - LightClassGenerationSupport.getInstance(facadeFile.project) - .createUltraLightClassForFacade(facadeClassFqName, searchScope, facadeFile)?.let { return it } + + return CachedValuesManager.getCachedValue(facadeFile) { + + val lightClassDataCache = FacadeStubCache.getInstance(manager.project).get(facadeClassFqName, searchScope) + + val classForFacade = LightClassGenerationSupport.getInstance(facadeFile.project) + .createUltraLightClassForFacade(facadeClassFqName, lightClassDataCache, facadeFile) + ?: KtLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, files) + + CachedValueProvider.Result.create(classForFacade, OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) + } } val lightClassDataCache = FacadeStubCache.getInstance(manager.project).get(facadeClassFqName, searchScope) @@ -287,4 +300,14 @@ open class KtLightClassForFacade protected constructor( override val originKind: LightClassOriginKind get() = LightClassOriginKind.SOURCE + + override fun getText() = firstFileInFacade.text ?: "" + + override fun getTextRange(): TextRange = firstFileInFacade.textRange ?: TextRange.EMPTY_RANGE + + override fun getTextOffset() = firstFileInFacade.textOffset + + override fun getStartOffsetInParent() = firstFileInFacade.startOffsetInParent + + override fun isWritable() = firstFileInFacade.isWritable } 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 758148f67ce..1a26042e496 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 @@ -5,9 +5,7 @@ package org.jetbrains.kotlin.asJava.classes -import com.intellij.psi.PsiClass -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiManager +import com.intellij.psi.* import com.intellij.psi.util.CachedValue import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder import org.jetbrains.kotlin.asJava.elements.KtLightField @@ -26,7 +24,7 @@ class KtUltraLightClassForFacade( private val support: KtUltraLightSupport ) : KtLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, listOf(file)) { - private val methodsBuilder by lazyPub { UltraLightMembersCreator(this, false, true, support) } + private val membersBuilder by lazyPub { UltraLightMembersCreator(this, false, true, support) } private inline fun forTooComplex(getter: () -> T): T { check(tooComplex) { @@ -50,8 +48,8 @@ class KtUltraLightClassForFacade( for (declaration in file.declarations.filterNot { it.isHiddenByDeprecation(support) }) { if (declaration.hasModifier(KtTokens.PRIVATE_KEYWORD)) continue when (declaration) { - is KtNamedFunction -> result.addAll(methodsBuilder.createMethods(declaration, true)) - is KtProperty -> result.addAll(methodsBuilder.propertyAccessors(declaration, declaration.isVar, true, false)) + is KtNamedFunction -> result.addAll(membersBuilder.createMethods(declaration, true)) + is KtProperty -> result.addAll(membersBuilder.propertyAccessors(declaration, declaration.isVar, true, false)) } } @@ -61,7 +59,7 @@ class KtUltraLightClassForFacade( private val ownFieldsForNotTooComplex: List by lazyPub { hashSetOf().run { file.declarations.filterIsInstance().mapNotNull { - methodsBuilder.createPropertyField(it, this, forceStatic = true) + membersBuilder.createPropertyField(it, this, forceStatic = true) } } } @@ -70,13 +68,8 @@ class KtUltraLightClassForFacade( override fun getOwnMethods() = if (!tooComplex) ownMethodsForNotTooComplex else super.getOwnMethods() - override fun hashCode(): Int = file.hashCode() - override fun toString(): String = "UltraLight class for file facade" - override fun equals(other: Any?): Boolean = this === other - override fun copy(): KtLightClassForFacade = KtUltraLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, file, support) - override fun setName(name: String): PsiElement? = this } \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt index 54f8b42dd6e..65c6d657f84 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt @@ -39,7 +39,7 @@ import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val support: KtUltraLightSupport) : KtLightClassImpl(classOrObject) { - private val methodsBuilder by lazyPub { + private val membersBuilder by lazyPub { UltraLightMembersCreator(this, isNamedObject(), classOrObject.hasModifier(SEALED_KEYWORD), support) } @@ -128,14 +128,14 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor val usedNames = hashSetOf() for (parameter in propertyParameters()) { - methodsBuilder.createPropertyField(parameter, usedNames, forceStatic = false)?.let(result::add) + membersBuilder.createPropertyField(parameter, usedNames, forceStatic = false)?.let(result::add) } this.classOrObject.companionObjects.firstOrNull()?.let { companion -> result.add( KtUltraLightField( companion, - methodsBuilder.generateUniqueFieldName(companion.name.orEmpty(), usedNames), + membersBuilder.generateUniqueFieldName(companion.name.orEmpty(), usedNames), this, support, setOf(PsiModifier.STATIC, PsiModifier.FINAL, PsiModifier.PUBLIC) @@ -144,7 +144,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor for (property in companion.declarations.filterIsInstance()) { if (isInterface && !property.isConstOrJvmField()) continue - methodsBuilder.createPropertyField(property, usedNames, true)?.let(result::add) + membersBuilder.createPropertyField(property, usedNames, true)?.let(result::add) } } @@ -156,7 +156,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor // Probably, the same should work for const vals but it doesn't at the moment (see KT-28294) if (isCompanion && (containingClass?.isInterface == false || property.isJvmField())) continue - methodsBuilder.createPropertyField(property, usedNames, forceStatic = this.classOrObject is KtObjectDeclaration)?.let(result::add) + membersBuilder.createPropertyField(property, usedNames, forceStatic = this.classOrObject is KtObjectDeclaration)?.let(result::add) } } @@ -200,13 +200,13 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor for (declaration in this.classOrObject.declarations.filterNot { it.isHiddenByDeprecation(support) }) { if (declaration.hasModifier(PRIVATE_KEYWORD) && isInterface) continue when (declaration) { - is KtNamedFunction -> result.addAll(methodsBuilder.createMethods(declaration, false)) - is KtProperty -> result.addAll(methodsBuilder.propertyAccessors(declaration, declaration.isVar, false,false)) + is KtNamedFunction -> result.addAll(membersBuilder.createMethods(declaration, false)) + is KtProperty -> result.addAll(membersBuilder.propertyAccessors(declaration, declaration.isVar, false, false)) } } for (parameter in propertyParameters()) { - result.addAll(methodsBuilder.propertyAccessors(parameter, parameter.isMutable, false,false)) + result.addAll(membersBuilder.propertyAccessors(parameter, parameter.isMutable, false, false)) } if (!isInterface) { @@ -216,8 +216,8 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor this.classOrObject.companionObjects.firstOrNull()?.let { companion -> for (declaration in companion.declarations.filterNot { isHiddenByDeprecation(it) }) { when (declaration) { - is KtNamedFunction -> if (isJvmStatic(declaration)) result.addAll(methodsBuilder.createMethods(declaration, true)) - is KtProperty -> result.addAll(methodsBuilder.propertyAccessors(declaration, declaration.isVar, false,true)) + is KtNamedFunction -> if (isJvmStatic(declaration)) result.addAll(membersBuilder.createMethods(declaration, true)) + is KtProperty -> result.addAll(membersBuilder.propertyAccessors(declaration, declaration.isVar, false, true)) } } } @@ -298,7 +298,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor result.add(defaultConstructor()) } for (constructor in constructors.filterNot { isHiddenByDeprecation(it) }) { - result.addAll(methodsBuilder.createMethods(constructor, false, forcePrivate = isEnum)) + result.addAll(membersBuilder.createMethods(constructor, false, forcePrivate = isEnum)) } val primary = classOrObject.primaryConstructor if (primary != null && shouldGenerateNoArgOverload(primary)) { diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt index 1d0109c1749..24e29af4114 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.asJava.classes +import com.intellij.openapi.util.registry.Registry import com.intellij.psi.* import com.intellij.psi.impl.cache.ModifierFlags import com.intellij.psi.impl.cache.TypeInfo @@ -312,4 +313,4 @@ internal fun KtDeclaration.simpleVisibility(): String = when { hasModifier(KtTokens.PRIVATE_KEYWORD) -> PsiModifier.PRIVATE hasModifier(KtTokens.PROTECTED_KEYWORD) -> PsiModifier.PROTECTED else -> PsiModifier.PUBLIC -} \ No newline at end of file +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt index 8c04ae41635..9cd8ae6fbf0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt @@ -24,6 +24,7 @@ import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiElement 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 @@ -178,13 +179,10 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG override fun createUltraLightClassForFacade( facadeClassFqName: FqName, - searchScope: GlobalSearchScope, + lightClassDataCache: CachedValue, facadeFile: KtFile ): KtUltraLightClassForFacade? { - val lightClassDataCache = - KtLightClassForFacade.FacadeStubCache.getInstance(project).get(facadeClassFqName, searchScope) - if (facadeFile.isScript()) return null val module = ModuleUtilCore.findModuleForPsiElement(facadeFile) ?: return null diff --git a/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt b/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt index db583a99b5b..9b01486c143 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt @@ -12,6 +12,7 @@ import com.intellij.testFramework.UsefulTestCase import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass +import org.jetbrains.kotlin.asJava.classes.KtUltraLightSupport import org.jetbrains.kotlin.asJava.classes.isPrivateOrParameterInPrivateMethod import org.jetbrains.kotlin.asJava.elements.KtLightNullabilityAnnotation import org.jetbrains.kotlin.load.kotlin.NON_EXISTENT_CLASS_NAME @@ -20,9 +21,9 @@ import org.jetbrains.kotlin.psi.KtFile import org.junit.Assert fun UsefulTestCase.forceUsingOldLightClassesForTest() { - KtUltraLightClass.forceUsingOldLightClasses = true + KtUltraLightSupport.forceUsingOldLightClasses = true Disposer.register(testRootDisposable, Disposable { - KtUltraLightClass.forceUsingOldLightClasses = false + KtUltraLightSupport.forceUsingOldLightClasses = false }) }