Debugger: do not change package name for debug function

This commit is contained in:
Natalia Ukhorskaya
2015-11-19 18:52:27 +03:00
parent 002aaaa908
commit 062b27995c
8 changed files with 30 additions and 28 deletions
@@ -16,22 +16,22 @@
package org.jetbrains.kotlin.idea.debugger.evaluate package org.jetbrains.kotlin.idea.debugger.evaluate
import com.intellij.openapi.project.Project
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.kotlin.psi.KtCodeFragment
import com.intellij.debugger.SourcePosition import com.intellij.debugger.SourcePosition
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
import java.util.ArrayList
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.util.containers.MultiMap import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.apache.log4j.Logger import org.apache.log4j.Logger
import org.jetbrains.eval4j.Value import org.jetbrains.eval4j.Value
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
class KotlinEvaluateExpressionCache(val project: Project) { class KotlinEvaluateExpressionCache(val project: Project) {
@@ -89,7 +89,6 @@ class KotlinEvaluateExpressionCache(val project: Project) {
val bytecodes: ByteArray, val bytecodes: ByteArray,
val additionalClasses: List<Pair<String, ByteArray>>, val additionalClasses: List<Pair<String, ByteArray>>,
val sourcePosition: SourcePosition, val sourcePosition: SourcePosition,
val funName: String,
val parameters: ParametersDescriptor val parameters: ParametersDescriptor
) )
@@ -81,7 +81,8 @@ import java.util.*
internal val RECEIVER_NAME = "\$receiver" internal val RECEIVER_NAME = "\$receiver"
internal val THIS_NAME = "this" internal val THIS_NAME = "this"
val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluator") internal val LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluator")
internal val GENERATED_FUNCTION_NAME = "generated_for_debugger_kotlin_rulezzzz"
private val DEBUG_MODE = false private val DEBUG_MODE = false
@@ -197,9 +198,6 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
} }
} }
val funName = runReadAction { extractedFunction.name }
?: throw IllegalStateException("Extracted function should have a name: ${extractedFunction.text}")
val additionalFiles = if (outputFiles.size < 2) emptyList() val additionalFiles = if (outputFiles.size < 2) emptyList()
else outputFiles.subList(1, outputFiles.size).map { getClassName(it.relativePath) to it.asByteArray() } else outputFiles.subList(1, outputFiles.size).map { getClassName(it.relativePath) to it.asByteArray() }
@@ -207,7 +205,6 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
outputFiles.first().asByteArray(), outputFiles.first().asByteArray(),
additionalFiles, additionalFiles,
sourcePosition, sourcePosition,
funName,
parametersDescriptor) parametersDescriptor)
} }
@@ -225,7 +222,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
var resultValue: InterpreterResult? = null var resultValue: InterpreterResult? = null
ClassReader(compiledData.bytecodes).accept(object : ClassVisitor(ASM5) { ClassReader(compiledData.bytecodes).accept(object : ClassVisitor(ASM5) {
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? { override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
if (name == compiledData.funName) { if (name == GENERATED_FUNCTION_NAME) {
val argumentTypes = Type.getArgumentTypes(desc) val argumentTypes = Type.getArgumentTypes(desc)
val args = context.getArgumentsForEval4j(compiledData.parameters, argumentTypes) val args = context.getArgumentsForEval4j(compiledData.parameters, argumentTypes)
@@ -255,7 +252,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
} }
}, 0) }, 0)
return resultValue ?: throw IllegalStateException("resultValue is null: cannot find method ${compiledData.funName}") return resultValue ?: throw IllegalStateException("resultValue is null: cannot find method " + GENERATED_FUNCTION_NAME)
} }
private fun boxOrUnboxArgumentIfNeeded(eval: JDIEval, argumentValue: Value, parameterType: Type): Value { private fun boxOrUnboxArgumentIfNeeded(eval: JDIEval, argumentValue: Value, parameterType: Type): Value {
@@ -469,7 +466,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
} }
private val template = """ private val template = """
package packageForDebugger !PACKAGE!
!IMPORT_LIST! !IMPORT_LIST!
@@ -481,17 +478,17 @@ private fun createFileForDebugger(codeFragment: KtCodeFragment,
): KtFile { ): KtFile {
val containingContextFile = codeFragment.getContextContainingFile() val containingContextFile = codeFragment.getContextContainingFile()
val importsFromContextFile = containingContextFile?.importList?.let { it.text + "\n" } ?: "" val importsFromContextFile = containingContextFile?.importList?.let { it.text + "\n" } ?: ""
val packageFromContextFile = containingContextFile?.packageName?.let {
if (it.isNotBlank()) "import $it.*\n" else null
} ?: ""
var fileText = template.replace( var fileText = template.replace(
"!IMPORT_LIST!", "!IMPORT_LIST!",
packageFromContextFile importsFromContextFile + codeFragment.importsToString().split(KtCodeFragment.IMPORT_SEPARATOR).joinToString("\n")
+ importsFromContextFile
+ codeFragment.importsToString().split(KtCodeFragment.IMPORT_SEPARATOR).joinToString("\n")
) )
val packageFromContextFile = containingContextFile?.packageName?.let {
if (it.isNotBlank()) "package $it" else ""
} ?: ""
fileText = fileText.replace("!PACKAGE!", packageFromContextFile)
val extractedFunctionText = extractedFunction.text val extractedFunctionText = extractedFunction.text
assert(extractedFunctionText != null) { "Text of extracted function shouldn't be null" } assert(extractedFunctionText != null) { "Text of extracted function shouldn't be null" }
fileText = fileText.replace("!FUNCTION!", extractedFunction.text!!) fileText = fileText.replace("!FUNCTION!", extractedFunction.text!!)
@@ -100,7 +100,7 @@ fun getFunctionForExtractedFragment(
val generatorOptions = ExtractionGeneratorOptions(inTempFile = true, val generatorOptions = ExtractionGeneratorOptions(inTempFile = true,
flexibleTypesAllowed = true, flexibleTypesAllowed = true,
allowDummyName = true, dummyName = GENERATED_FUNCTION_NAME,
allowExpressionBody = false) allowExpressionBody = false)
return ExtractionGeneratorConfiguration(validationResult.descriptor, generatorOptions).generateDeclaration() return ExtractionGeneratorConfiguration(validationResult.descriptor, generatorOptions).generateDeclaration()
} }
@@ -414,7 +414,7 @@ data class ExtractionGeneratorOptions(
val inTempFile: Boolean = false, val inTempFile: Boolean = false,
val target: ExtractionTarget = ExtractionTarget.FUNCTION, val target: ExtractionTarget = ExtractionTarget.FUNCTION,
val flexibleTypesAllowed: Boolean = false, val flexibleTypesAllowed: Boolean = false,
val allowDummyName: Boolean = false, val dummyName: String? = null,
val allowExpressionBody: Boolean = true, val allowExpressionBody: Boolean = true,
val delayInitialOccurrenceReplacement: Boolean = false val delayInitialOccurrenceReplacement: Boolean = false
) { ) {
@@ -93,7 +93,7 @@ fun ExtractionGeneratorConfiguration.getDeclarationText(
builder.receiver(if (isFunctionType) "($receiverTypeAsString)" else receiverTypeAsString) builder.receiver(if (isFunctionType) "($receiverTypeAsString)" else receiverTypeAsString)
} }
builder.name(if (descriptor.name == "" && generatorOptions.allowDummyName) "myFun" else descriptor.name) builder.name(generatorOptions.dummyName ?: descriptor.name)
descriptor.parameters.forEach { parameter -> descriptor.parameters.forEach { parameter ->
builder.param(parameter.name, builder.param(parameter.name,
+1
View File
@@ -3,6 +3,7 @@ LineBreakpoint created at .kt.kt:5
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
.kt.kt:5 .kt.kt:5
Compile bytecode for 1 + 1 Compile bytecode for 1 + 1
Compile bytecode for Test(1).a
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -5,5 +5,10 @@ fun main(args: Array<String>) {
args.size() args.size()
} }
class Test(val a: Int)
// EXPRESSION: 1 + 1 // EXPRESSION: 1 + 1
// RESULT: 2: I // RESULT: 2: I
// EXPRESSION: Test(1).a
// RESULT: 1: I
@@ -16,4 +16,4 @@ interface T {
// RESULT: 1: I // RESULT: 1: I
// EXPRESSION: object: T {} // EXPRESSION: object: T {}
// RESULT: instance of packageForDebugger.DebugFileKt$myFun$1(id=ID): LpackageForDebugger/DebugFileKt$myFun$1; // RESULT: instance of ceObject.DebugFileKt$generated_for_debugger_kotlin_rulezzzz$1(id=ID): LceObject/DebugFileKt$generated_for_debugger_kotlin_rulezzzz$1;