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:
Nikolay Krasko
2017-06-23 15:59:41 +03:00
parent 247c0497b1
commit 87889904ee
4 changed files with 50 additions and 40 deletions
@@ -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
}
@@ -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()
}
} }
@@ -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
@@ -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