Fix smart step into functions call with suspend lambdas (KT-14700)

#KT-14700 Fixed
This commit is contained in:
Nikolay Krasko
2017-01-26 16:08:19 +03:00
parent 2add36ef32
commit 4a4a8250fd
7 changed files with 62 additions and 14 deletions
@@ -21,6 +21,7 @@ import com.intellij.debugger.engine.BreakpointStepMethodFilter
import com.intellij.debugger.engine.DebugProcessImpl
import com.intellij.util.Range
import com.sun.jdi.Location
import org.jetbrains.kotlin.codegen.coroutines.DO_RESUME_METHOD_NAME
import org.jetbrains.kotlin.idea.refactoring.isMultiLine
import org.jetbrains.kotlin.idea.debugger.isInsideInlineArgument
import org.jetbrains.kotlin.psi.KtBlockExpression
@@ -30,7 +31,8 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
class KotlinLambdaMethodFilter(
private val lambda: KtFunction,
private val myCallingExpressionLines: Range<Int>,
private val isInline: Boolean
private val isInline: Boolean,
private val isSuspend: Boolean
): BreakpointStepMethodFilter {
private val myFirstStatementPosition: SourcePosition?
private val myLastStatementLine: Int
@@ -72,9 +74,12 @@ class KotlinLambdaMethodFilter(
override fun getCallingExpressionLines() = if (isInline) Range(0, 999) else myCallingExpressionLines
companion object {
fun isLambdaName(name: String?): Boolean {
return name == OperatorNameConventions.INVOKE.asString()
private fun isLambdaName(name: String?): Boolean {
if (isSuspend) {
return name == DO_RESUME_METHOD_NAME
}
return name == OperatorNameConventions.INVOKE.asString()
}
}
@@ -23,14 +23,16 @@ import org.jetbrains.kotlin.idea.KotlinIcons
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.util.OperatorNameConventions
import javax.swing.Icon
class KotlinLambdaSmartStepTarget(
label: String,
highlightElement: KtFunction,
lines: Range<Int>,
val isInline: Boolean
val isInline: Boolean,
val isSuspend: Boolean
): SmartStepTarget(label, highlightElement, true, lines) {
override fun getIcon() = KotlinIcons.LAMBDA
override fun getIcon(): Icon = KotlinIcons.LAMBDA
fun getLambda() = highlightElement as KtFunction
@@ -25,6 +25,7 @@ import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiMethod
import com.intellij.util.Range
import com.intellij.util.containers.OrderedSet
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
@@ -50,8 +51,8 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
val elementAtOffset = position.elementAt ?: return emptyList()
val element = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, elementAtOffset.textRange.startOffset)
if (element !is KtElement) return emptyList()
val element = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, elementAtOffset.textRange.startOffset) as? KtElement ?:
return emptyList()
val elementTextRange = element.textRange ?: return emptyList()
@@ -80,8 +81,10 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
val arguments = resolvedCall.valueArguments
for ((param, argument) in arguments) {
if (argument.arguments.any { getArgumentExpression(it) == function }) {
val label = KotlinLambdaSmartStepTarget.calcLabel(resolvedCall.resultingDescriptor, param.name)
result.add(KotlinLambdaSmartStepTarget(label, function, lines, InlineUtil.isInline(resolvedCall.resultingDescriptor)))
val resultingDescriptor = resolvedCall.resultingDescriptor
val label = KotlinLambdaSmartStepTarget.calcLabel(resultingDescriptor, param.name)
result.add(KotlinLambdaSmartStepTarget(
label, function, lines, InlineUtil.isInline(resultingDescriptor), param.type.isSuspendFunctionType))
return true
}
}
@@ -195,8 +198,11 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
override fun createMethodFilter(stepTarget: SmartStepTarget?): MethodFilter? {
return when (stepTarget) {
is KotlinMethodSmartStepTarget -> KotlinBasicStepMethodFilter(stepTarget.descriptor, stepTarget.callingExpressionLines!!)
is KotlinLambdaSmartStepTarget -> KotlinLambdaMethodFilter(stepTarget.getLambda(), stepTarget.callingExpressionLines!!, stepTarget.isInline)
is KotlinMethodSmartStepTarget ->
KotlinBasicStepMethodFilter(stepTarget.descriptor, stepTarget.callingExpressionLines!!)
is KotlinLambdaSmartStepTarget ->
KotlinLambdaMethodFilter(
stepTarget.getLambda(), stepTarget.callingExpressionLines!!, stepTarget.isInline, stepTarget.isSuspend)
else -> super.createMethodFilter(stepTarget)
}
}
+8
View File
@@ -0,0 +1,8 @@
LineBreakpoint created at coroutine.kt:15
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! coroutine.CoroutineKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
coroutine.kt:15
coroutine.kt:16
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,18 @@
package coroutine
import forTests.builder
suspend fun second() {
}
suspend fun first() {
second()
}
fun main(args: Array<String>) {
// SMART_STEP_INTO_BY_INDEX: 2
//Breakpoint!
builder {
first()
}
}
@@ -213,8 +213,11 @@ abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() {
stepTargets.filterIsInstance<SmartStepTarget>().mapNotNull {
stepTarget ->
when (stepTarget) {
is KotlinLambdaSmartStepTarget -> KotlinLambdaMethodFilter(stepTarget.getLambda(), stepTarget.getCallingExpressionLines()!!, stepTarget.isInline)
is KotlinMethodSmartStepTarget -> KotlinBasicStepMethodFilter(stepTarget.descriptor, stepTarget.getCallingExpressionLines()!!)
is KotlinLambdaSmartStepTarget ->
KotlinLambdaMethodFilter(
stepTarget.getLambda(), stepTarget.getCallingExpressionLines()!!, stepTarget.isInline, stepTarget.isSuspend)
is KotlinMethodSmartStepTarget ->
KotlinBasicStepMethodFilter(stepTarget.descriptor, stepTarget.getCallingExpressionLines()!!)
is MethodSmartStepTarget -> BasicStepMethodFilter(stepTarget.method, stepTarget.getCallingExpressionLines())
else -> null
}
@@ -944,6 +944,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/stepping/custom"), Pattern.compile("^([^.]+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("coroutine.kt")
public void testCoroutine() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/coroutine.kt");
doCustomTest(fileName);
}
@TestMetadata("crossinlineLiteral.kt")
public void testCrossinlineLiteral() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/crossinlineLiteral.kt");