Allow only one invoke to be a target for smart step into (KT-18632)
It's difficult to distinguish such calls reliably in debug session #KT-18632 Fixed
This commit is contained in:
+6
-24
@@ -72,12 +72,14 @@ class KotlinBasicStepMethodFilter(
|
|||||||
if (currentDescriptor !is CallableMemberDescriptor) return false
|
if (currentDescriptor !is CallableMemberDescriptor) return false
|
||||||
if (currentDescriptor.kind != DECLARATION) return false
|
if (currentDescriptor.kind != DECLARATION) return false
|
||||||
|
|
||||||
if (compareDescriptors(currentDescriptor, targetDescriptor)) return true
|
if (targetDescriptor is FunctionInvokeDescriptor) {
|
||||||
|
// There can be only one 'invoke' target at the moment so consider position as expected.
|
||||||
if (targetDescriptor is FunctionInvokeDescriptor && currentDescriptor is FunctionDescriptor) {
|
// Descriptors can be not-equal, say when parameter has type `(T) -> T` and lambda is `Int.() -> Int`.
|
||||||
return isCompatibleSignatures(targetDescriptor, currentDescriptor)
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (compareDescriptors(currentDescriptor, targetDescriptor)) return true
|
||||||
|
|
||||||
// We should stop if current descriptor overrides the target one or some base descriptor of target
|
// We should stop if current descriptor overrides the target one or some base descriptor of target
|
||||||
// (if target descriptor is delegation or fake override)
|
// (if target descriptor is delegation or fake override)
|
||||||
|
|
||||||
@@ -101,23 +103,3 @@ class KotlinBasicStepMethodFilter(
|
|||||||
private fun compareDescriptors(d1: DeclarationDescriptor, d2: DeclarationDescriptor): Boolean {
|
private fun compareDescriptors(d1: DeclarationDescriptor, d2: DeclarationDescriptor): Boolean {
|
||||||
return d1 == d2 || d1.original == d2.original
|
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
|
|
||||||
}
|
|
||||||
+13
-1
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.idea.debugger.stepping
|
|||||||
import com.intellij.debugger.actions.SmartStepTarget
|
import com.intellij.debugger.actions.SmartStepTarget
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.util.Range
|
import com.intellij.util.Range
|
||||||
|
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||||
@@ -43,8 +44,19 @@ class KotlinMethodSmartStepTarget(
|
|||||||
|
|
||||||
if (other == null || other !is KotlinMethodSmartStepTarget) return false
|
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
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+17
-4
@@ -14,11 +14,12 @@ fun defaultParameter(f: (String) -> Int = { it.toInt() }) {
|
|||||||
f("12")
|
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
|
// SMART_STEP_INTO_BY_INDEX: 0
|
||||||
// RESUME: 1
|
// RESUME: 1
|
||||||
//Breakpoint!
|
//Breakpoint!
|
||||||
paramFun(f("12"))
|
paramFun(f("12")) + ii()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun nonDefaultWithAnonymousFun(paramFun: (Int) -> Int) {
|
fun nonDefaultWithAnonymousFun(paramFun: (Int) -> Int) {
|
||||||
@@ -35,16 +36,28 @@ fun withExtensionParameters(paramFun: Int.() -> Int) {
|
|||||||
12.paramFun()
|
12.paramFun()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> genericSignatureAndExtensionArgument(v: T, paramFun: (T) -> T) {
|
||||||
|
// SMART_STEP_INTO_BY_INDEX: 0
|
||||||
|
// RESUME: 1
|
||||||
|
//Breakpoint!
|
||||||
|
paramFun(v)
|
||||||
|
}
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val localFun : (Int) -> Int = { it + 1 }
|
val localFun: (Int) -> Int = { it + 1 }
|
||||||
|
|
||||||
nonDefaultParameter(localFun)
|
nonDefaultParameter(localFun)
|
||||||
|
|
||||||
defaultParameter()
|
defaultParameter()
|
||||||
|
|
||||||
badSignatureIsSkipped { it + 1 }
|
firstInvokeIsCalled { it + 1 }
|
||||||
|
|
||||||
nonDefaultWithAnonymousFun(fun (i: Int): Int { return i })
|
nonDefaultWithAnonymousFun(fun (i: Int): Int { return i })
|
||||||
|
|
||||||
withExtensionParameters { this }
|
withExtensionParameters { this }
|
||||||
|
|
||||||
|
val ext: Int.() -> Int = { this }
|
||||||
|
genericSignatureAndExtensionArgument(15, ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ii() = 12
|
||||||
+13
-10
@@ -1,20 +1,23 @@
|
|||||||
LineBreakpoint created at smartStepIntoToLambdaParameter.kt:7
|
LineBreakpoint created at smartStepIntoToLambdaParameter.kt:7
|
||||||
LineBreakpoint created at smartStepIntoToLambdaParameter.kt:14
|
LineBreakpoint created at smartStepIntoToLambdaParameter.kt:14
|
||||||
LineBreakpoint created at smartStepIntoToLambdaParameter.kt:21
|
LineBreakpoint created at smartStepIntoToLambdaParameter.kt:22
|
||||||
LineBreakpoint created at smartStepIntoToLambdaParameter.kt:28
|
LineBreakpoint created at smartStepIntoToLambdaParameter.kt:29
|
||||||
LineBreakpoint created at smartStepIntoToLambdaParameter.kt:35
|
LineBreakpoint created at smartStepIntoToLambdaParameter.kt:36
|
||||||
|
LineBreakpoint created at smartStepIntoToLambdaParameter.kt:43
|
||||||
Run Java
|
Run Java
|
||||||
Connected to the target VM
|
Connected to the target VM
|
||||||
smartStepIntoToLambdaParameter.kt:7
|
smartStepIntoToLambdaParameter.kt:7
|
||||||
smartStepIntoToLambdaParameter.kt:39
|
smartStepIntoToLambdaParameter.kt:47
|
||||||
smartStepIntoToLambdaParameter.kt:14
|
smartStepIntoToLambdaParameter.kt:14
|
||||||
smartStepIntoToLambdaParameter.kt:10
|
smartStepIntoToLambdaParameter.kt:10
|
||||||
smartStepIntoToLambdaParameter.kt:21
|
smartStepIntoToLambdaParameter.kt:22
|
||||||
smartStepIntoToLambdaParameter.kt:45
|
smartStepIntoToLambdaParameter.kt:18
|
||||||
smartStepIntoToLambdaParameter.kt:28
|
smartStepIntoToLambdaParameter.kt:29
|
||||||
smartStepIntoToLambdaParameter.kt:47
|
smartStepIntoToLambdaParameter.kt:55
|
||||||
smartStepIntoToLambdaParameter.kt:35
|
smartStepIntoToLambdaParameter.kt:36
|
||||||
smartStepIntoToLambdaParameter.kt:49
|
smartStepIntoToLambdaParameter.kt:57
|
||||||
|
smartStepIntoToLambdaParameter.kt:43
|
||||||
|
smartStepIntoToLambdaParameter.kt:59
|
||||||
Disconnected from the target VM
|
Disconnected from the target VM
|
||||||
|
|
||||||
Process finished with exit code 0
|
Process finished with exit code 0
|
||||||
|
|||||||
Reference in New Issue
Block a user