Evaluate expression: find local variable using callText from extract function instead of function parameter names

This commit is contained in:
Natalia Ukhorskaya
2015-03-10 14:23:28 +03:00
parent cdf081ddc3
commit 3eb2182ef0
5 changed files with 55 additions and 17 deletions
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluateExpressionCache.CompiledDataDescriptor import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluateExpressionCache.CompiledDataDescriptor
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluateExpressionCache.ParametersDescriptor import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinEvaluateExpressionCache.ParametersDescriptor
import org.jetbrains.kotlin.idea.debugger.evaluate.compilingEvaluator.loadClasses import org.jetbrains.kotlin.idea.debugger.evaluate.compilingEvaluator.loadClasses
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.ExtractionResult
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.attachment.attachmentByPsiFile import org.jetbrains.kotlin.idea.util.attachment.attachmentByPsiFile
import org.jetbrains.kotlin.idea.util.attachment.mergeAttachments import org.jetbrains.kotlin.idea.util.attachment.mergeAttachments
@@ -152,10 +153,11 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
private fun extractAndCompile(codeFragment: JetCodeFragment, sourcePosition: SourcePosition, context: EvaluationContextImpl): CompiledDataDescriptor { private fun extractAndCompile(codeFragment: JetCodeFragment, sourcePosition: SourcePosition, context: EvaluationContextImpl): CompiledDataDescriptor {
codeFragment.checkForErrors() codeFragment.checkForErrors()
val extractedFunction = getFunctionForExtractedFragment(codeFragment, sourcePosition.getFile(), sourcePosition.getLine()) val extractionResult = getFunctionForExtractedFragment(codeFragment, sourcePosition.getFile(), sourcePosition.getLine())
if (extractedFunction == null) { if (extractionResult == null) {
throw IllegalStateException("Code fragment cannot be extracted to function") throw IllegalStateException("Code fragment cannot be extracted to function")
} }
val extractedFunction = extractionResult.declaration as JetNamedFunction
val classFileFactory = createClassFileFactory(codeFragment, extractedFunction, context) val classFileFactory = createClassFileFactory(codeFragment, extractedFunction, context)
@@ -177,7 +179,7 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
additionalFiles, additionalFiles,
sourcePosition, sourcePosition,
funName, funName,
extractedFunction.getParametersForDebugger()) extractionResult.getParametersForDebugger())
} }
private fun getClassName(fileName: String): String { private fun getClassName(fileName: String): String {
@@ -239,21 +241,22 @@ class KotlinEvaluator(val codeFragment: JetCodeFragment,
return jdiValue.asJdiValue(vm, jdiValue.asmType) return jdiValue.asJdiValue(vm, jdiValue.asmType)
} }
private fun JetNamedFunction.getParametersForDebugger(): ParametersDescriptor { private fun ExtractionResult.getParametersForDebugger(): ParametersDescriptor {
return runReadAction { return runReadAction {
val parameters = ParametersDescriptor() val parameters = ParametersDescriptor()
val bindingContext = analyzeFullyAndGetResult().bindingContext val receiver = config.descriptor.receiverParameter
val descriptor = bindingContext[BindingContext.FUNCTION, this] if (receiver != null) {
if (descriptor != null) { parameters.add(THIS_NAME, receiver.getParameterType(true))
val receiver = descriptor.getExtensionReceiverParameter() }
if (receiver != null) {
parameters.add(THIS_NAME, receiver.getType())
}
descriptor.getValueParameters().forEach { for (param in config.descriptor.parameters) {
param -> val paramName = if (param.argumentText.contains("@")) {
parameters.add(param.getName().asString(), param.getType()) param.argumentText.substringBefore("@")
} }
else {
param.argumentText
}
parameters.add(paramName, param.getParameterType(true))
} }
parameters parameters
} }
@@ -38,7 +38,7 @@ fun getFunctionForExtractedFragment(
codeFragment: JetCodeFragment, codeFragment: JetCodeFragment,
breakpointFile: PsiFile, breakpointFile: PsiFile,
breakpointLine: Int breakpointLine: Int
): JetNamedFunction? { ): ExtractionResult? {
fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult): String { fun getErrorMessageForExtractFunctionResult(analysisResult: AnalysisResult): String {
if (KotlinInternalMode.enabled) { if (KotlinInternalMode.enabled) {
@@ -66,7 +66,7 @@ fun getFunctionForExtractedFragment(
}.joinToString(", ") }.joinToString(", ")
} }
fun generateFunction(): JetNamedFunction? { fun generateFunction(): ExtractionResult? {
val originalFile = breakpointFile as JetFile val originalFile = breakpointFile as JetFile
val tmpFile = originalFile.createTempCopy { it } val tmpFile = originalFile.createTempCopy { it }
@@ -105,7 +105,7 @@ fun getFunctionForExtractedFragment(
validationResult.descriptor, validationResult.descriptor,
ExtractionGeneratorOptions(inTempFile = true, flexibleTypesAllowed = true) ExtractionGeneratorOptions(inTempFile = true, flexibleTypesAllowed = true)
) )
return config.generateDeclaration().declaration as JetNamedFunction return config.generateDeclaration()
} }
return runReadAction { generateFunction() } return runReadAction { generateFunction() }
@@ -0,0 +1,8 @@
LineBreakpoint created at innerClass.kt:13
!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! innerClass.InnerClassPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
innerClass.kt:13
Compile bytecode for baseFun(innerProp)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,21 @@
package innerClass
fun main(args: Array<String>) {
MyClass().MyInnerClass().innerFun()
}
class MyClass {
inner class MyInnerClass {
val innerProp = 1
fun innerFun() {
//Breakpoint!
baseFun(innerProp)
}
}
fun baseFun(i: Int) = i
}
// EXPRESSION: baseFun(innerProp)
// RESULT: 1: I
@@ -151,6 +151,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
doSingleBreakpointTest(fileName); doSingleBreakpointTest(fileName);
} }
@TestMetadata("innerClass.kt")
public void testInnerClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/innerClass.kt");
doSingleBreakpointTest(fileName);
}
@TestMetadata("insertInBlock.kt") @TestMetadata("insertInBlock.kt")
public void testInsertInBlock() throws Exception { public void testInsertInBlock() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/insertInBlock.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/insertInBlock.kt");