From 94ee78c0ca321274cf87f81bf74e8eefde1ddcf1 Mon Sep 17 00:00:00 2001 From: Renaud Paquay Date: Wed, 28 Feb 2018 00:56:52 +0300 Subject: [PATCH] Hitting breakpoint in Kotlin sometimes doesn't work (KT-22205) Fix KT-22205 and https://issuetracker.google.com/issues/71556313 Hitting breakpoints in Kotlin JUnit test with an Android Gradle project sometimes(*) does not work in Android Studio 3.1 beta. (*) The issue is related to various threads running concurrently with "dumb" mode background code, so the issue reproduces only on certain configurations. In a nutshell, the issue is as follows * On one hand, gradle build finishes, fires an event ("buildFinished") that is processed "later" and that causes the IDE to enter "dumb" mode for a shot amount of time (about 300-500 msec on a somewhat up to date multi-core computer). * On the other hand, once the JVM of the debuggee is started, breakpoints need to be resolved (on the debugger thread, through a call to com.intellij.debugger.engine.CompoundPositionManager.createPrepareRequests. This code calls into the "KotlinPositionManager.createPrepareRequests", which in turns calls into "PerFileAnalysisCache.analyze". That method returns "AnalysisResult.EMPTY" is the project is in dumb mode. This return value prevents callers from successfully resolving the source location into a breakpoint. Given that the 2 code paths above execute on separate threads without explicit synchronization, the "failed to resolve breakpoint" issue occurs sporadically, to the point it happens 100% of the time on certain configuration. The fix is so wrap the kotlin breakpoint resolution code inside a "runReadActionInSmartMode" so that the debugger thread "waits" for "dumb" mode to terminates before trying to resolve breakpoint locations. #KT-22205 Fixed --- .../idea/debugger/KotlinPositionManager.kt | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt index 24372130d84..13b9be57fc9 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt @@ -26,7 +26,9 @@ import com.intellij.debugger.engine.evaluation.EvaluationContext import com.intellij.debugger.impl.DebuggerUtilsEx import com.intellij.debugger.jdi.StackFrameProxyImpl import com.intellij.debugger.requests.ClassPrepareRequestor +import com.intellij.openapi.project.DumbService import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.util.Computable import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiFile @@ -342,13 +344,15 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq throw NoDataException.INSTANCE } - val classNames = DebuggerClassNameProvider(myDebugProcess).getOuterClassNamesForPosition(position) - return classNames.flatMap { name -> - listOfNotNull( - myDebugProcess.requestsManager.createClassPrepareRequest(requestor, name), - myDebugProcess.requestsManager.createClassPrepareRequest(requestor, "$name$*") - ) - } + return DumbService.getInstance(myDebugProcess.project).runReadActionInSmartMode(Computable { + val classNames = DebuggerClassNameProvider(myDebugProcess).getOuterClassNamesForPosition(position) + classNames.flatMap { name -> + listOfNotNull( + myDebugProcess.requestsManager.createClassPrepareRequest(requestor, name), + myDebugProcess.requestsManager.createClassPrepareRequest(requestor, "$name$*") + ) + } + }) } private fun ReferenceType.containsKotlinStrata() = availableStrata().contains(KOTLIN_STRATA_NAME)