Debugger: Fix method evaluation on arrays (KT-11706)
This commit is contained in:
@@ -219,13 +219,33 @@ class JDIEval(
|
|||||||
mayThrow { _class.setValue(field, jdiValue) }.ifFail(field)
|
mayThrow { _class.setValue(field, jdiValue) }.ifFail(field)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findMethod(methodDesc: MethodDescription, _class: ReferenceType = methodDesc.ownerType.asReferenceType()): Method {
|
private fun findMethod(methodDesc: MethodDescription, clazz: ReferenceType = methodDesc.ownerType.asReferenceType()): Method {
|
||||||
|
val method = findMethodOrNull(methodDesc, clazz)
|
||||||
|
if (method != null) {
|
||||||
|
return method
|
||||||
|
}
|
||||||
|
|
||||||
|
throwBrokenCodeException(NoSuchMethodError("Method not found: $methodDesc"))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findMethodOrNull(methodDesc: MethodDescription, clazz: ReferenceType): Method? {
|
||||||
val methodName = methodDesc.name
|
val methodName = methodDesc.name
|
||||||
val method = when (_class) {
|
|
||||||
is ClassType ->
|
var method: Method?
|
||||||
_class.concreteMethodByName(methodName, methodDesc.desc)
|
when (clazz) {
|
||||||
else ->
|
is ClassType -> {
|
||||||
_class.methodsByName(methodName, methodDesc.desc).firstOrNull()
|
method = clazz.concreteMethodByName(methodName, methodDesc.desc)
|
||||||
|
}
|
||||||
|
is ArrayType -> { // Copied from com.intellij.debugger.engine.DebuggerUtils.findMethod
|
||||||
|
val objectType = OBJECT.asReferenceType()
|
||||||
|
method = findMethodOrNull(methodDesc, objectType)
|
||||||
|
if (method == null && methodDesc.name == "clone" && methodDesc.desc == "()[Ljava/lang/Object;") {
|
||||||
|
method = findMethodOrNull(MethodDescription(OBJECT.internalName, "clone", "()[Ljava/lang/Object;", false), objectType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
method = clazz.methodsByName(methodName, methodDesc.desc).firstOrNull()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
@@ -235,7 +255,7 @@ class JDIEval(
|
|||||||
// Module name can be different for internal functions during evaluation and compilation
|
// Module name can be different for internal functions during evaluation and compilation
|
||||||
val internalNameWithoutSuffix = internalNameWithoutModuleSuffix(methodName)
|
val internalNameWithoutSuffix = internalNameWithoutModuleSuffix(methodName)
|
||||||
if (internalNameWithoutSuffix != null) {
|
if (internalNameWithoutSuffix != null) {
|
||||||
val internalMethods = _class.visibleMethods().filter {
|
val internalMethods = clazz.visibleMethods().filter {
|
||||||
val name = it.name()
|
val name = it.name()
|
||||||
name.startsWith(internalNameWithoutSuffix) && canBeMangledInternalName(name) && it.signature() == methodDesc.desc
|
name.startsWith(internalNameWithoutSuffix) && canBeMangledInternalName(name) && it.signature() == methodDesc.desc
|
||||||
}
|
}
|
||||||
@@ -246,7 +266,7 @@ class JDIEval(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throwBrokenCodeException(NoSuchMethodError("Method not found: $methodDesc"))
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun invokeStaticMethod(methodDesc: MethodDescription, arguments: List<Value>): Value {
|
override fun invokeStaticMethod(methodDesc: MethodDescription, arguments: List<Value>): Value {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package arrayMethods
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPRESSION: args.toString().length > 0
|
||||||
|
// RESULT: 1: Z
|
||||||
|
|
||||||
|
// EXPRESSION: args.hashCode() and 0
|
||||||
|
// RESULT: 0: I
|
||||||
|
|
||||||
|
// EXPRESSION: args.clone()
|
||||||
|
// RESULT: instance of java.lang.String[0] (id=ID): [Ljava/lang/String;
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
LineBreakpoint created at arrayMethods.kt:5
|
||||||
|
Run Java
|
||||||
|
Connected to the target VM
|
||||||
|
arrayMethods.kt:5
|
||||||
|
Compile bytecode for args.toString().length > 0
|
||||||
|
Compile bytecode for args.hashCode() and 0
|
||||||
|
Compile bytecode for args.clone()
|
||||||
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
Generated
+5
@@ -51,6 +51,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/anonymousObjects.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/anonymousObjects.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("arrayMethods.kt")
|
||||||
|
public void testArrayMethods() throws Exception {
|
||||||
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/arrayMethods.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("arrays.kt")
|
@TestMetadata("arrays.kt")
|
||||||
public void testArrays() throws Exception {
|
public void testArrays() throws Exception {
|
||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/arrays.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/arrays.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user