From 3e9765f5bb108ea7cc277ac3548c392efc84deb3 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Sat, 13 Jul 2019 01:03:30 +0300 Subject: [PATCH] Don't over-cache own methods list in KtUltraLightClass The might be code that stores light class references (for example ChangeMethodSignatureFromUsageFix) and tries to find methods after invalidating. Internal class caches has an additional assert that methods obtained are valid and this assert can be violated if the list of methods was cached before some method invalidation. This a major problem of current light-classes implementation. Other places should be checked and fixed as well. Check test: QuickFixMultiFileTestGenerated$ChangeSignature$Jk.testJkKeepValOnAddingParameter1 Caused by: java.lang.AssertionError: Element: class org.jetbrains.kotlin.asJava.classes.KtUltraLightMethodForSourceDeclaration #kotlin because: File language:Language: JAVA != Provider base language:Language: kotlin invalidated at: no info Attachments: at com.intellij.testFramework.LoggedErrorProcessor.processError(LoggedErrorProcessor.java:61) at org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase$setUp$1.processError(KotlinLightCodeInsightFixtureTestCase.kt:84) at com.intellij.testFramework.TestLogger.error(TestLogger.java:40) at com.intellij.openapi.diagnostic.Logger.error(Logger.java:170) at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$null$1(PassExecutorService.java:442) at com.intellij.openapi.application.impl.ApplicationImpl.tryRunReadAction(ApplicationImpl.java:1166) at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$doRun$2(PassExecutorService.java:423) at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:586) at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:532) at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:86) at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.doRun(PassExecutorService.java:422) at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$run$0(PassExecutorService.java:398) at com.intellij.openapi.application.impl.ReadMostlyRWLock.executeByImpatientReader(ReadMostlyRWLock.java:164) at com.intellij.openapi.application.impl.ApplicationImpl.executeByImpatientReader(ApplicationImpl.java:218) at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.run(PassExecutorService.java:396) at com.intellij.concurrency.JobLauncherImpl$VoidForkJoinTask$1.exec(JobLauncherImpl.java:174) at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289) at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056) at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692) at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157) Caused by: com.intellij.psi.PsiInvalidElementAccessException: Element: class org.jetbrains.kotlin.asJava.classes.KtUltraLightMethodForSourceDeclaration #kotlin because: File language:Language: JAVA != Provider base language:Language: kotlin invalidated at: no info at com.intellij.psi.util.PsiUtilCore.ensureValid(PsiUtilCore.java:482) at com.intellij.psi.impl.PsiClassImplUtil$1.add(PsiClassImplUtil.java:380) at com.intellij.psi.scope.processor.FilterScopeProcessor.execute(FilterScopeProcessor.java:59) at com.intellij.psi.impl.PsiClassImplUtil.processDeclarationsInClassNotCached(PsiClassImplUtil.java:684) at com.intellij.psi.impl.PsiClassImplUtil.lambda$createMembersMap$2(PsiClassImplUtil.java:395) at com.intellij.util.containers.ConcurrentFactoryMap$2.create(ConcurrentFactoryMap.java:181) at com.intellij.util.containers.ConcurrentFactoryMap.get(ConcurrentFactoryMap.java:45) at com.intellij.psi.impl.PsiClassImplUtil$MembersMap.get(PsiClassImplUtil.java:357) at com.intellij.psi.impl.PsiClassImplUtil$MembersMap.access$000(PsiClassImplUtil.java:349) at com.intellij.psi.impl.PsiClassImplUtil.getMap(PsiClassImplUtil.java:207) at com.intellij.psi.impl.PsiClassImplUtil.findByMap(PsiClassImplUtil.java:153) at com.intellij.psi.impl.PsiClassImplUtil.findMethodsByName(PsiClassImplUtil.java:96) at com.intellij.psi.impl.source.ClassInnerStuffCache.findMethodsByName(ClassInnerStuffCache.java:67) at org.jetbrains.kotlin.asJava.classes.KtLightClassBase.findMethodsByName(KtLightClassBase.kt:52) at com.intellij.codeInsight.daemon.impl.quickfix.ChangeMethodSignatureFromUsageFix.getShortText(ChangeMethodSignatureFromUsageFix.java:94) at com.intellij.codeInsight.daemon.impl.quickfix.ChangeMethodSignatureFromUsageFix.isAvailable(ChangeMethodSignatureFromUsageFix.java:152) at com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler.availableFor(ShowIntentionActionsHandler.java:127) at com.intellij.codeInsight.intention.impl.CachedIntentions.wrapActionsTo(CachedIntentions.java:183) at com.intellij.codeInsight.intention.impl.CachedIntentions.wrapAndUpdateActions(CachedIntentions.java:135) at com.intellij.codeInsight.daemon.impl.ShowIntentionsPass.doCollectInformation(ShowIntentionsPass.java:222) at com.intellij.codeHighlighting.TextEditorHighlightingPass.collectInformation(TextEditorHighlightingPass.java:69) at com.intellij.codeInsight.daemon.impl.PassExecutorService$ScheduledPass.lambda$null$1(PassExecutorService.java:430) ... 15 more --- .../kotlin/asJava/classes/ultraLightClass.kt | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) 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 f3c3847ff7b..664d4287c44 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 @@ -11,6 +11,10 @@ import com.intellij.psi.impl.InheritanceImplUtil import com.intellij.psi.impl.PsiClassImplUtil import com.intellij.psi.impl.PsiSuperMethodImplUtil import com.intellij.psi.impl.light.LightMethodBuilder +import com.intellij.psi.util.CachedValue +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService import org.jetbrains.kotlin.asJava.builder.LightClassData import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightMethod @@ -242,8 +246,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor private fun propertyParameters() = classOrObject.primaryConstructorParameters.filter { it.hasValOrVar() } - private val _ownMethods: List by lazyPub { - + private fun ownMethods(): List { val result = arrayListOf() for (declaration in this.classOrObject.declarations.filterNot { it.isHiddenByDeprecation(support) }) { @@ -292,9 +295,18 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor addMethodsFromDataClass(result) addDelegatesToInterfaceMethods(result) - result + return result } + private val _ownMethods: CachedValue> = CachedValuesManager.getManager(project).createCachedValue( + { + CachedValueProvider.Result.create( + ownMethods(), + KotlinModificationTrackerService.getInstance(project).outOfBlockModificationTracker + ) + }, false + ) + private fun addMethodsFromDataClass(result: MutableList) { if (!classOrObject.hasModifier(DATA_KEYWORD)) return val descriptor = classOrObject.resolve() as? ClassDescriptor ?: return @@ -409,7 +421,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor private fun isJvmStatic(declaration: KtAnnotated): Boolean = declaration.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) - override fun getOwnMethods(): List = if (tooComplex) super.getOwnMethods() else _ownMethods + override fun getOwnMethods(): List = if (tooComplex) super.getOwnMethods() else _ownMethods.value private fun KtAnnotated.hasAnnotation(name: FqName) = support.findAnnotation(this, name) != null