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
This commit is contained in:
Renaud Paquay
2018-02-28 00:56:52 +03:00
committed by Nikolay Krasko
parent b1bcadd762
commit 94ee78c0ca
@@ -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)