Trying to work around: ProhibitedAnalysisException: Analysis is not allowed: Called in the EDT thread

I have a plugin that needs to get the full list of supertypes (so supers of supers etc) of a given KtClassOrObject. Using k2 mode and the new analysis API, I get the exception:

ProhibitedAnalysisException: Analysis is not allowed: Called in the EDT thread

I have been unsuccessful in trying to work around this. I’ve tried various combinations of runReadAction, readAction, ReadAction.compute and so on.

Ultimately, this is what I currently have, which is still failing with the above exception:

@RequiresReadLock
fun KtClassOrObject.getAllSuperClasses(): List<FqName> {
   return if (ApplicationManager.getApplication().isDispatchThread) {
      ReadAction.compute<List<FqName>, Throwable> {
         getAllSuperClassesInternal()
      }
   } else {
      getAllSuperClassesInternal()
   }
}

fun KtClassOrObject.getAllSuperClassesInternal(): List<FqName> {
   return superTypeListEntries
      .mapNotNull { it.typeReference }
      .flatMap { ref ->
         analyze(this) {
            val kaType = ref.type
            val superTypes = (kaType.allSupertypes(shouldApproximate = false) + kaType).toList()
            superTypes.mapNotNull { it.symbol?.classId?.asSingleFqName() }
         }
      }
}

For further context, I am calling this method in several places where I cannot just run it as a background process, eg TestFinder.isTest and StructureViewExtension.getChildren

Thanks!

1 Like

Hi Stephen, you can wrap analyze call with org.jetbrains.kotlin.analysis.api.permissions.PermissionsKt#allowAnalysisOnEdt if you can’t move to BGT in your plugin
Anna

Thanks for reply.
Added allowAnalysisOnEdt before the analysis call, and am now getting:
ProhibitedAnalysisException: Analysis is not allowed: Called from a write action.

@OptIn(KaAllowAnalysisOnEdt::class)
@RequiresReadLock
fun KtClassOrObject.getAllSuperClasses(): List<FqName> {
   return superTypeListEntries.mapNotNull { it.typeReference }
      .flatMap { ref ->
         allowAnalysisOnEdt {
            ReadAction.compute<List<FqName>, Throwable> {
               analyze(this@getAllSuperClasses) {
                  val kaType: KaType = ref.type
                  val superTypes: List<KaType> = (kaType.allSupertypes(shouldApproximate = false) + kaType).toList()
                  superTypes.mapNotNull {
                     // don't include the Any supertype that is the root of all types
                     val classId: ClassId? = it.symbol?.classId?.takeIf { id -> id != StandardClassIds.Any }
                     classId?.asSingleFqName()
                  }
               }
            }
         }
      }
}

isTest or StructureViewExtension definitely should not start write action. Are you sure you can’t avoid surrounding WA? If absolutely necessary, you can wrap with allowFromWriteAction but this is an invitation for a freeze.

I am not sure if it’s me starting the write action?
The code is triggered inside a StructureViewExtension here:

Which then just calls the code I pasted above:

Any advice on how to avoid a write action here ?

Could you please provide the full stacktrace with the WA?

Stack trace:

org.jetbrains.kotlin.analysis.api.impl.base.sessions.ProhibitedAnalysisException: Analysis is not allowed: Called from a write action.
	at org.jetbrains.kotlin.analysis.api.impl.base.sessions.KaBaseSessionProvider.beforeEnteringAnalysis(KaBaseSessionProvider.kt:56)
	at org.jetbrains.kotlin.analysis.api.impl.base.sessions.KaBaseSessionProvider.beforeEnteringAnalysis(KaBaseSessionProvider.kt:47)
	at io.kotest.plugin.intellij.psi.SuperClassesKt.getAllSuperClasses$lambda$6$lambda$5(superClasses.kt:64)
	at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runReadAction(AnyThreadWriteThreadingSupport.kt:272)
	at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runReadAction(AnyThreadWriteThreadingSupport.kt:262)
	at com.intellij.openapi.application.impl.ApplicationImpl.runReadAction(ApplicationImpl.java:863)
	at com.intellij.openapi.application.ReadAction.compute(ReadAction.java:66)
	at io.kotest.plugin.intellij.psi.SuperClassesKt.getAllSuperClasses(superClasses.kt:23)
	at io.kotest.plugin.intellij.psi.SpecsKt.specStyle(specs.kt:52)
	at io.kotest.plugin.intellij.structure.KotestStructureViewExtension.getChildren(KotestStructureViewExtension.kt:50)
	at com.intellij.ide.structureView.impl.common.PsiTreeElementBase.mergeWithExtensions(PsiTreeElementBase.java:146)
	at com.intellij.ide.structureView.impl.common.PsiTreeElementBase.doGetChildren(PsiTreeElementBase.java:89)
	at com.intellij.ide.structureView.impl.common.PsiTreeElementBase.getChildren(PsiTreeElementBase.java:74)
	at com.intellij.ide.structureView.impl.common.PsiTreeElementBase.getChildren(PsiTreeElementBase.java:23)
	at com.intellij.codeInsight.navigation.MethodUpDownUtil.addStructureViewElements(MethodUpDownUtil.java:62)
	at com.intellij.codeInsight.navigation.MethodUpDownUtil.addStructureViewElements(MethodUpDownUtil.java:68)
	at com.intellij.codeInsight.navigation.MethodUpDownUtil.addNavigationElements(MethodUpDownUtil.java:53)
	at com.intellij.codeInsight.navigation.MethodUpDownUtil.getNavigationOffsets(MethodUpDownUtil.java:33)
	at com.intellij.codeInsight.navigation.MethodDownHandler.invoke(MethodDownHandler.java:25)
	at com.intellij.codeInsight.actions.CodeInsightAction.lambda$actionPerformedImpl$0(CodeInsightAction.java:73)
	at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runWriteAction$lambda$5(AnyThreadWriteThreadingSupport.kt:379)
	at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runWriteAction(AnyThreadWriteThreadingSupport.kt:389)
	at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runWriteAction(AnyThreadWriteThreadingSupport.kt:379)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:896)
	at com.intellij.codeInsight.actions.CodeInsightAction.lambda$actionPerformedImpl$1(CodeInsightAction.java:76)
	at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:226)
	at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:178)
	at com.intellij.openapi.command.impl.CoreCommandProcessor.executeCommand(CoreCommandProcessor.java:159)
	at com.intellij.codeInsight.actions.CodeInsightAction.actionPerformedImpl(CodeInsightAction.java:70)
	at com.intellij.codeInsight.actions.CodeInsightAction.actionPerformed(CodeInsightAction.java:41)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.doPerformActionOrShowPopup(ActionUtil.kt:374)
	at com.intellij.openapi.keymap.impl.ActionProcessor.performAction(ActionProcessor.java:32)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher$actionProcessor$1.performAction(IdeKeyEventDispatcher.kt:499)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcherKt.doPerformActionInner$lambda$8$lambda$7(IdeKeyEventDispatcher.kt:850)
	at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:109)
	at com.intellij.openapi.application.TransactionGuardImpl.performUserActivity(TransactionGuardImpl.java:98)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcherKt.doPerformActionInner$lambda$8(IdeKeyEventDispatcher.kt:850)
	at com.intellij.openapi.actionSystem.impl.ActionManagerImpl.performWithActionCallbacks(ActionManagerImpl.kt:1173)
	at com.intellij.openapi.actionSystem.ex.ActionUtil.performDumbAwareWithCallbacks(ActionUtil.kt:396)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcherKt.doPerformActionInner(IdeKeyEventDispatcher.kt:848)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcherKt.access$doPerformActionInner(IdeKeyEventDispatcher.kt:1)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processAction(IdeKeyEventDispatcher.kt:577)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processAction(IdeKeyEventDispatcher.kt:512)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processActionOrWaitSecondStroke(IdeKeyEventDispatcher.kt:451)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.inInitState(IdeKeyEventDispatcher.kt:444)
	at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.dispatchKeyEvent(IdeKeyEventDispatcher.kt:306)
	at com.intellij.ide.IdeEventQueue.dispatchKeyEvent(IdeEventQueue.kt:606)
	at com.intellij.ide.IdeEventQueue._dispatchEvent$lambda$22(IdeEventQueue.kt:565)
	at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runWriteIntentReadAction(AnyThreadWriteThreadingSupport.kt:128)
	at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.kt:565)
	at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$18$lambda$17$lambda$16$lambda$15(IdeEventQueue.kt:355)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:857)
	at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$18$lambda$17$lambda$16(IdeEventQueue.kt:354)
	at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$2$lambda$1(IdeEventQueue.kt:1045)
	at com.intellij.openapi.application.WriteIntentReadAction.lambda$run$0(WriteIntentReadAction.java:24)
	at com.intellij.openapi.application.impl.AnyThreadWriteThreadingSupport.runWriteIntentReadAction(AnyThreadWriteThreadingSupport.kt:128)
	at com.intellij.openapi.application.impl.ApplicationImpl.runWriteIntentReadAction(ApplicationImpl.java:916)
	at com.intellij.openapi.application.WriteIntentReadAction.compute(WriteIntentReadAction.java:55)
	at com.intellij.openapi.application.WriteIntentReadAction.run(WriteIntentReadAction.java:23)
	at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$2(IdeEventQueue.kt:1045)
	at com.intellij.ide.IdeEventQueueKt.performActivity$lambda$3(IdeEventQueue.kt:1054)
	at com.intellij.openapi.application.TransactionGuardImpl.performActivity(TransactionGuardImpl.java:117)
	at com.intellij.ide.IdeEventQueueKt.performActivity(IdeEventQueue.kt:1054)
	at com.intellij.ide.IdeEventQueue.dispatchEvent$lambda$18(IdeEventQueue.kt:349)
	at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.kt:395)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:207)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:92)

Oh, move methods up/down. Then indeed you don’t have a choice and need to suppress an error as I suggested above.

So try both allowFromWriteAction and allowAnalysisOnEdt ?
I can try that.

Yes, you need both. When you need to run under WA, you run in EDT now but that might be changed in the future.

I cannot find allowFromWriteAction. Can you tell me where the import is?
I can find allowAnalysisFromWriteAction but that requires a private opt in annotation.

yes, right, another one is specific to monorepo, sorry. You have to add OptIn annotation. It should not look right by design to avoid resolve in EDT and under WA as much as possible.

allowAnalysisFromWriteAction is annotated with KaAllowProhibitedAnalyzeFromWriteAction which is a private annotation, so I cannot opt-in in my code.

Any suggestions?

You have to have something like this now:

@OptIn(
     KaAllowAnalysisOnEdt::class,
     KaAllowAnalysisFromWriteAction::class
 )
fun KtClassOrObject.getAllSuperClasses(): List<FqName> {}

Yeah but the annotation requires two opt ins:

@org.jetbrains.kotlin.analysis.api.permissions.KaAllowAnalysisFromWriteAction @org.jetbrains.kotlin.analysis.api.permissions.KaAllowProhibitedAnalyzeFromWriteAction public inline fun allowAnalysisFromWriteAction(action: () → T): T

and KaAllowProhibitedAnalyzeFromWriteAction is private.

Any workaround?

You need to specify compiler option as well: -opt-in=org.jetbrains.kotlin.analysis.api.permissions.KaAllowProhibitedAnalyzeFromWriteAction. Sorry, it’s mentioned in my kdoc, probably it’s newer than one you use

Looks like it works! I’ll release an updated kotest plugin now and see if it fixes it for all users.