diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt index 28e71228858..de2099a94e2 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionCache.kt @@ -25,20 +25,11 @@ import com.intellij.debugger.SourcePosition import com.intellij.debugger.engine.evaluation.EvaluationContextImpl import java.util.ArrayList import com.intellij.openapi.components.ServiceManager -import org.jetbrains.org.objectweb.asm.Type import com.intellij.util.containers.MultiMap import org.jetbrains.jet.lang.types.JetType -import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap -import com.intellij.psi.search.GlobalSearchScope -import com.intellij.psi.JavaPsiFacade import org.jetbrains.jet.lang.resolve.DescriptorUtils import org.jetbrains.jet.lang.descriptors.ClassDescriptor -import org.jetbrains.jet.plugin.caches.resolve.JavaResolveExtension -import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaClassImpl -import org.jetbrains.jet.lang.resolve.java.JvmClassName -import org.jetbrains.jet.codegen.AsmUtil import org.apache.log4j.Logger -import org.jetbrains.jet.plugin.refactoring.runReadAction class KotlinEvaluateExpressionCache(val project: Project) { @@ -86,29 +77,12 @@ class KotlinEvaluateExpressionCache(val project: Project) { val value = context.findLocalVariable(name, asmType = null, checkType = false, failIfNotFound = false) if (value == null) return@all false - val thisDescriptor = value.asmType.getClassDescriptor() + val thisDescriptor = value.asmType.getClassDescriptor(project) val superClassDescriptor = jetType.getConstructor().getDeclarationDescriptor() as? ClassDescriptor return@all thisDescriptor != null && superClassDescriptor != null && DescriptorUtils.isSubclass(thisDescriptor, superClassDescriptor) } } - private fun Type.getClassDescriptor(): ClassDescriptor? { - if (AsmUtil.isPrimitive(this)) return null - - val jvmName = JvmClassName.byInternalName(getInternalName()).getFqNameForClassNameWithoutDollars() - - val platformClasses = JavaToKotlinClassMap.getInstance().mapPlatformClass(jvmName) - if (platformClasses.notEmpty) return platformClasses.first() - - return runReadAction { - val classes = JavaPsiFacade.getInstance(project).findClasses(jvmName.asString(), GlobalSearchScope.allScope(project)) - if (classes.isEmpty()) null else { - val clazz = classes.first() - JavaResolveExtension.getResolver(project, clazz).resolveClass(JavaClassImpl(clazz)) - } - } - } - data class CompiledDataDescriptor(val bytecodes: ByteArray, val sourcePosition: SourcePosition, val funName: String, val parameters: ParametersDescriptor) class ParametersDescriptor : Iterable> { diff --git a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt index 0fc97fbb8ee..2c038df74ce 100644 --- a/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt +++ b/idea/src/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluationBuilder.kt @@ -61,6 +61,15 @@ import org.jetbrains.jet.codegen.AsmUtil import com.sun.jdi.InvalidStackFrameException import org.jetbrains.jet.plugin.refactoring.runReadAction import org.jetbrains.jet.lang.psi.analysisContext +import org.jetbrains.jet.lang.descriptors.ClassDescriptor +import org.jetbrains.jet.lang.resolve.java.JvmClassName +import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.jet.plugin.caches.resolve.JavaResolveExtension +import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaClassImpl +import com.intellij.openapi.project.Project +import org.jetbrains.jet.lang.resolve.DescriptorUtils private val RECEIVER_NAME = "\$receiver" private val THIS_NAME = "this" @@ -295,8 +304,20 @@ private fun SuspendContext.getInvokePolicy(): Int { } fun EvaluationContextImpl.findLocalVariable(name: String, asmType: Type?, checkType: Boolean, failIfNotFound: Boolean): Value? { + val project = getDebugProcess().getProject() val frame = getFrameProxy()?.getStackFrame() if (frame == null) return null + + fun isValueOfCorrectType(value: Value, asmType: Type?, shouldCheckType: Boolean): Boolean { + if (!shouldCheckType || asmType == null || value.asmType == asmType) return true + if (project == null) return false + + val thisDesc = value.asmType.getClassDescriptor(project) + val expDesc = asmType.getClassDescriptor(project) + return thisDesc != null && expDesc != null && DescriptorUtils.isSubclass(thisDesc, expDesc) + } + + try { when (name) { THIS_NAME -> { @@ -365,6 +386,23 @@ fun EvaluationContextImpl.findLocalVariable(name: String, asmType: Type?, checkT } } +fun Type.getClassDescriptor(project: Project): ClassDescriptor? { + if (AsmUtil.isPrimitive(this)) return null + + val jvmName = JvmClassName.byInternalName(getInternalName()).getFqNameForClassNameWithoutDollars() + + val platformClasses = JavaToKotlinClassMap.getInstance().mapPlatformClass(jvmName) + if (platformClasses.notEmpty) return platformClasses.first() + + return runReadAction { + val classes = JavaPsiFacade.getInstance(project).findClasses(jvmName.asString(), GlobalSearchScope.allScope(project)) + if (classes.isEmpty()) null else { + val clazz = classes.first() + JavaResolveExtension.getResolver(project, clazz).resolveClass(JavaClassImpl(clazz)) + } + } +} + private fun getCapturedFieldName(name: String) = when (name) { RECEIVER_NAME -> AsmUtil.CAPTURED_RECEIVER_FIELD THIS_NAME -> AsmUtil.CAPTURED_THIS_FIELD @@ -373,4 +411,3 @@ private fun getCapturedFieldName(name: String) = when (name) { else -> "$$name" } -private fun isValueOfCorrectType(value: Value, asmType: Type?, shouldCheckType: Boolean) = !shouldCheckType || asmType == null || value.asmType == asmType \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/outs/funFromSuperClass.out b/idea/testData/debugger/tinyApp/outs/funFromSuperClass.out new file mode 100644 index 00000000000..ff3b5bb0af8 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/funFromSuperClass.out @@ -0,0 +1,8 @@ +LineBreakpoint created at funFromSuperClass.kt:12 +!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! funFromSuperClass.FunFromSuperClassPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +funFromSuperClass.kt:11 +Compile bytecode for foo() +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/funFromSuperClass.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/funFromSuperClass.kt new file mode 100644 index 00000000000..8d98e286388 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/funFromSuperClass.kt @@ -0,0 +1,20 @@ +package funFromSuperClass + +fun main(args: Array) { + Derived().test() +} + +open class Base { + fun foo() = 1 + + fun test() { + //Breakpoint! + val a = 1 + } +} + +class Derived: Base() + + +// EXPRESSION: foo() +// RESULT: 1: I \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index 321f2fae64e..b9d3735e23f 100644 --- a/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -120,6 +120,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat doSingleBreakpointTest(fileName); } + @TestMetadata("funFromSuperClass.kt") + public void testFunFromSuperClass() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/funFromSuperClass.kt"); + doSingleBreakpointTest(fileName); + } + @TestMetadata("imports.kt") public void testImports() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/imports.kt");