diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinBasicStepMethodFilter.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinBasicStepMethodFilter.kt index d22ee3c5386..6ed96a32b4d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinBasicStepMethodFilter.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinBasicStepMethodFilter.kt @@ -72,12 +72,14 @@ class KotlinBasicStepMethodFilter( if (currentDescriptor !is CallableMemberDescriptor) return false if (currentDescriptor.kind != DECLARATION) return false - if (compareDescriptors(currentDescriptor, targetDescriptor)) return true - - if (targetDescriptor is FunctionInvokeDescriptor && currentDescriptor is FunctionDescriptor) { - return isCompatibleSignatures(targetDescriptor, currentDescriptor) + if (targetDescriptor is FunctionInvokeDescriptor) { + // There can be only one 'invoke' target at the moment so consider position as expected. + // Descriptors can be not-equal, say when parameter has type `(T) -> T` and lambda is `Int.() -> Int`. + return true } + if (compareDescriptors(currentDescriptor, targetDescriptor)) return true + // We should stop if current descriptor overrides the target one or some base descriptor of target // (if target descriptor is delegation or fake override) @@ -100,24 +102,4 @@ class KotlinBasicStepMethodFilter( private fun compareDescriptors(d1: DeclarationDescriptor, d2: DeclarationDescriptor): Boolean { return d1 == d2 || d1.original == d2.original -} - -private fun isCompatibleSignatures(target: FunctionDescriptor, current: FunctionDescriptor): Boolean { - // A very primitive approximation - if (target.valueParameters.size != current.valueParameters.size) { - return false - } - - if (target.returnType != current.returnType) { - return false - } - - for ((i, targetParam) in target.valueParameters.withIndex()) { - val currentParam = current.valueParameters[i] - if (targetParam.type != currentParam.type) { - return false - } - } - - return true } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinMethodSmartStepIntoTarget.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinMethodSmartStepIntoTarget.kt index d47398bc72a..41e8fd96cb8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinMethodSmartStepIntoTarget.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinMethodSmartStepIntoTarget.kt @@ -3,6 +3,7 @@ package org.jetbrains.kotlin.idea.debugger.stepping import com.intellij.debugger.actions.SmartStepTarget import com.intellij.psi.PsiElement import com.intellij.util.Range +import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.idea.KotlinIcons @@ -43,8 +44,19 @@ class KotlinMethodSmartStepTarget( if (other == null || other !is KotlinMethodSmartStepTarget) return false + if (descriptor is FunctionInvokeDescriptor && other.descriptor is FunctionInvokeDescriptor) { + // Don't allow to choose several invoke targets in smart step into as we can't distinguish them reliably during debug + return true + } + return descriptor == other.descriptor } - override fun hashCode() = descriptor.hashCode() + override fun hashCode(): Int { + if (descriptor is FunctionInvokeDescriptor) { + // Predefined value to make all FunctionInvokeDescriptor targets equal + return 42 + } + return descriptor.hashCode() + } } \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/stepping/custom/smartStepIntoToLambdaParameter.kt b/idea/testData/debugger/tinyApp/src/stepping/custom/smartStepIntoToLambdaParameter.kt index c49c0b8658a..553b5dcc38f 100644 --- a/idea/testData/debugger/tinyApp/src/stepping/custom/smartStepIntoToLambdaParameter.kt +++ b/idea/testData/debugger/tinyApp/src/stepping/custom/smartStepIntoToLambdaParameter.kt @@ -14,11 +14,12 @@ fun defaultParameter(f: (String) -> Int = { it.toInt() }) { f("12") } -fun badSignatureIsSkipped(f: (String) -> Int = { it.toInt() }, paramFun: (Int) -> Int) { +// Minor bug is here. During selection paramFun() is shown as a target, but f is called instead. +fun firstInvokeIsCalled(f: (String) -> Int = { it.toInt() }, paramFun: (Int) -> Int) { // SMART_STEP_INTO_BY_INDEX: 0 // RESUME: 1 //Breakpoint! - paramFun(f("12")) + paramFun(f("12")) + ii() } fun nonDefaultWithAnonymousFun(paramFun: (Int) -> Int) { @@ -35,16 +36,28 @@ fun withExtensionParameters(paramFun: Int.() -> Int) { 12.paramFun() } +fun genericSignatureAndExtensionArgument(v: T, paramFun: (T) -> T) { + // SMART_STEP_INTO_BY_INDEX: 0 + // RESUME: 1 + //Breakpoint! + paramFun(v) +} + fun main(args: Array) { - val localFun : (Int) -> Int = { it + 1 } + val localFun: (Int) -> Int = { it + 1 } nonDefaultParameter(localFun) defaultParameter() - badSignatureIsSkipped { it + 1 } + firstInvokeIsCalled { it + 1 } nonDefaultWithAnonymousFun(fun (i: Int): Int { return i }) withExtensionParameters { this } -} \ No newline at end of file + + val ext: Int.() -> Int = { this } + genericSignatureAndExtensionArgument(15, ext) +} + +fun ii() = 12 \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/stepping/custom/smartStepIntoToLambdaParameter.out b/idea/testData/debugger/tinyApp/src/stepping/custom/smartStepIntoToLambdaParameter.out index e8f001bec24..9c17753a22d 100644 --- a/idea/testData/debugger/tinyApp/src/stepping/custom/smartStepIntoToLambdaParameter.out +++ b/idea/testData/debugger/tinyApp/src/stepping/custom/smartStepIntoToLambdaParameter.out @@ -1,20 +1,23 @@ LineBreakpoint created at smartStepIntoToLambdaParameter.kt:7 LineBreakpoint created at smartStepIntoToLambdaParameter.kt:14 -LineBreakpoint created at smartStepIntoToLambdaParameter.kt:21 -LineBreakpoint created at smartStepIntoToLambdaParameter.kt:28 -LineBreakpoint created at smartStepIntoToLambdaParameter.kt:35 +LineBreakpoint created at smartStepIntoToLambdaParameter.kt:22 +LineBreakpoint created at smartStepIntoToLambdaParameter.kt:29 +LineBreakpoint created at smartStepIntoToLambdaParameter.kt:36 +LineBreakpoint created at smartStepIntoToLambdaParameter.kt:43 Run Java Connected to the target VM smartStepIntoToLambdaParameter.kt:7 -smartStepIntoToLambdaParameter.kt:39 +smartStepIntoToLambdaParameter.kt:47 smartStepIntoToLambdaParameter.kt:14 smartStepIntoToLambdaParameter.kt:10 -smartStepIntoToLambdaParameter.kt:21 -smartStepIntoToLambdaParameter.kt:45 -smartStepIntoToLambdaParameter.kt:28 -smartStepIntoToLambdaParameter.kt:47 -smartStepIntoToLambdaParameter.kt:35 -smartStepIntoToLambdaParameter.kt:49 +smartStepIntoToLambdaParameter.kt:22 +smartStepIntoToLambdaParameter.kt:18 +smartStepIntoToLambdaParameter.kt:29 +smartStepIntoToLambdaParameter.kt:55 +smartStepIntoToLambdaParameter.kt:36 +smartStepIntoToLambdaParameter.kt:57 +smartStepIntoToLambdaParameter.kt:43 +smartStepIntoToLambdaParameter.kt:59 Disconnected from the target VM Process finished with exit code 0