Do not issue exceptions for non-captured local variables
This partly fixes KT-28192.
This commit is contained in:
Generated
+1
@@ -9,6 +9,7 @@
|
|||||||
<w>parceler</w>
|
<w>parceler</w>
|
||||||
<w>repl</w>
|
<w>repl</w>
|
||||||
<w>uast</w>
|
<w>uast</w>
|
||||||
|
<w>unbox</w>
|
||||||
<w>unboxed</w>
|
<w>unboxed</w>
|
||||||
<w>unmute</w>
|
<w>unmute</w>
|
||||||
</words>
|
</words>
|
||||||
|
|||||||
+2
-1
@@ -223,7 +223,8 @@ class KotlinDebuggerCaches(project: Project) {
|
|||||||
data class CompiledDataDescriptor(
|
data class CompiledDataDescriptor(
|
||||||
val classes: List<ClassToLoad>,
|
val classes: List<ClassToLoad>,
|
||||||
val sourcePosition: SourcePosition,
|
val sourcePosition: SourcePosition,
|
||||||
val parameters: List<Parameter>
|
val parameters: List<Parameter>,
|
||||||
|
val variablesCrossingInlineBounds: Set<String>
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Parameter(val callText: String, val type: KotlinType, val value: Value? = null, val error: EvaluateException? = null)
|
data class Parameter(val callText: String, val type: KotlinType, val value: Value? = null, val error: EvaluateException? = null)
|
||||||
|
|||||||
+26
-12
@@ -224,13 +224,15 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun extractAndCompile(codeFragment: KtCodeFragment, sourcePosition: SourcePosition, context: EvaluationContextImpl): CompiledDataDescriptor {
|
private fun extractAndCompile(codeFragment: KtCodeFragment, sourcePosition: SourcePosition, context: EvaluationContextImpl): CompiledDataDescriptor {
|
||||||
val (bindingContext) = codeFragment.checkForErrors()
|
var bindingContext = codeFragment.checkForErrors().bindingContext
|
||||||
|
|
||||||
if (codeFragment.wrapToStringIfNeeded(bindingContext)) {
|
if (codeFragment.wrapToStringIfNeeded(bindingContext)) {
|
||||||
// Repeat analysis with toString() added
|
// Repeat analysis with toString() added
|
||||||
codeFragment.checkForErrors()
|
bindingContext = codeFragment.checkForErrors().bindingContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val variablesCrossingInlineBounds = ScopeCheckerForEvaluator.checkScopes(bindingContext, codeFragment)
|
||||||
|
|
||||||
val extractionResult = getFunctionForExtractedFragment(codeFragment, sourcePosition.file, sourcePosition.line)
|
val extractionResult = getFunctionForExtractedFragment(codeFragment, sourcePosition.file, sourcePosition.line)
|
||||||
?: throw IllegalStateException("Code fragment cannot be extracted to function: ${codeFragment.text}")
|
?: throw IllegalStateException("Code fragment cannot be extracted to function: ${codeFragment.text}")
|
||||||
val (parametersDescriptor, extractedFunction) = try {
|
val (parametersDescriptor, extractedFunction) = try {
|
||||||
@@ -259,9 +261,11 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
|
|||||||
val additionalFiles = outputFiles.map { ClassToLoad(getClassName(it.relativePath), it.relativePath, it.asByteArray()) }
|
val additionalFiles = outputFiles.map { ClassToLoad(getClassName(it.relativePath), it.relativePath, it.asByteArray()) }
|
||||||
|
|
||||||
return CompiledDataDescriptor(
|
return CompiledDataDescriptor(
|
||||||
additionalFiles,
|
additionalFiles,
|
||||||
sourcePosition,
|
sourcePosition,
|
||||||
parametersDescriptor)
|
parametersDescriptor,
|
||||||
|
variablesCrossingInlineBounds
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtCodeFragment.wrapToStringIfNeeded(bindingContext: BindingContext): Boolean {
|
private fun KtCodeFragment.wrapToStringIfNeeded(bindingContext: BindingContext): Boolean {
|
||||||
@@ -326,7 +330,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
|
|||||||
// Prepare the main class
|
// Prepare the main class
|
||||||
|
|
||||||
val argumentTypes = Type.getArgumentTypes(methodToInvoke.desc)
|
val argumentTypes = Type.getArgumentTypes(methodToInvoke.desc)
|
||||||
val args = context.getArgumentsForEvaluation(compiledData.parameters, argumentTypes)
|
val args = context.getArgumentsForEvaluation(compiledData.parameters, argumentTypes, compiledData)
|
||||||
.zip(argumentTypes)
|
.zip(argumentTypes)
|
||||||
.map { (value, type) ->
|
.map { (value, type) ->
|
||||||
// Make argument type classes prepared for sure
|
// Make argument type classes prepared for sure
|
||||||
@@ -359,7 +363,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
|
|||||||
// Maybe just take the single method from the class, as it is done in 'evaluateWithCompilation'
|
// Maybe just take the single method from the class, as it is done in 'evaluateWithCompilation'
|
||||||
if (name == GENERATED_FUNCTION_NAME || name.startsWith(GENERATED_FUNCTION_NAME + "-")) {
|
if (name == GENERATED_FUNCTION_NAME || name.startsWith(GENERATED_FUNCTION_NAME + "-")) {
|
||||||
val argumentTypes = Type.getArgumentTypes(desc)
|
val argumentTypes = Type.getArgumentTypes(desc)
|
||||||
val args = context.getArgumentsForEvaluation(compiledData.parameters, argumentTypes)
|
val args = context.getArgumentsForEvaluation(compiledData.parameters, argumentTypes, compiledData)
|
||||||
|
|
||||||
return object : MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions) {
|
return object : MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions) {
|
||||||
override fun visitEnd() {
|
override fun visitEnd() {
|
||||||
@@ -507,18 +511,28 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
|
|||||||
|
|
||||||
private fun EvaluationContextImpl.getArgumentsForEvaluation(
|
private fun EvaluationContextImpl.getArgumentsForEvaluation(
|
||||||
parameters: List<Parameter>,
|
parameters: List<Parameter>,
|
||||||
parameterTypes: Array<Type>
|
parameterTypes: Array<Type>,
|
||||||
|
compiledData: CompiledDataDescriptor
|
||||||
): List<Value> {
|
): List<Value> {
|
||||||
val variableFinder = VariableFinder.instance(this) ?: error("No stack frame available")
|
val variableFinder = VariableFinder.instance(this) ?: error("No stack frame available")
|
||||||
return parameters.zip(parameterTypes).map { (parameter, type) ->
|
return parameters.zip(parameterTypes).map { (parameter, type) ->
|
||||||
parameter.error?.let { throw it }
|
parameter.error?.let { throw it }
|
||||||
|
parameter.value?.let { return@map it }
|
||||||
|
|
||||||
val result = parameter.value ?: variableFinder.get(parameter.callText, type).asValue()
|
val name = parameter.callText
|
||||||
|
val result = variableFinder.find(name, type)
|
||||||
|
|
||||||
if (LOG.isDebugEnabled) {
|
if (result == null) {
|
||||||
LOG.debug("Parameter for eval4j: name = ${parameter.callText}, type = $type, value = $result")
|
if (name in compiledData.variablesCrossingInlineBounds) {
|
||||||
|
throw EvaluateExceptionUtil.createEvaluateException("'$name' is not captured")
|
||||||
|
} else {
|
||||||
|
throw VariableFinder.variableNotFound(this, buildString {
|
||||||
|
append("Cannot find local variable: name = '").append(name).append("', type = ").append(type.className)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return@map result.value.asValue()
|
||||||
}
|
}
|
||||||
result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.debugger.evaluate
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.toSourceElement
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
|
|
||||||
|
object ScopeCheckerForEvaluator {
|
||||||
|
fun checkScopes(bindingContext: BindingContext, codeFragment: KtCodeFragment): Set<String> {
|
||||||
|
val result = hashSetOf<String>()
|
||||||
|
|
||||||
|
codeFragment.accept(object : KtTreeVisitor<Unit>() {
|
||||||
|
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, data: Unit?): Void? {
|
||||||
|
val target = bindingContext[BindingContext.REFERENCE_TARGET, expression]
|
||||||
|
if (target is DeclarationDescriptorWithVisibility && target.visibility == Visibilities.LOCAL) {
|
||||||
|
val declarationPsiElement = target.toSourceElement.getPsi()
|
||||||
|
if (declarationPsiElement != null) {
|
||||||
|
runReadAction {
|
||||||
|
if (doesCrossInlineBounds(bindingContext, expression, declarationPsiElement)) {
|
||||||
|
result.add(expression.getReferencedName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}, Unit)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doesCrossInlineBounds(bindingContext: BindingContext, reference: KtSimpleNameExpression, declaration: PsiElement): Boolean {
|
||||||
|
val declarationParent = declaration.parent ?: return false
|
||||||
|
var currentParent: PsiElement? = reference.parent?.takeIf { it.isInside(declarationParent) } ?: return false
|
||||||
|
|
||||||
|
while (currentParent != null && currentParent != declarationParent) {
|
||||||
|
if (currentParent is KtFunctionLiteral) {
|
||||||
|
val functionDescriptor = bindingContext[BindingContext.FUNCTION, currentParent]
|
||||||
|
if (functionDescriptor != null && !functionDescriptor.isInline) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentParent = when (currentParent) {
|
||||||
|
is KtCodeFragment -> currentParent.context
|
||||||
|
else -> currentParent.parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private tailrec fun PsiElement.isInside(parent: PsiElement): Boolean {
|
||||||
|
if (parent.isAncestor(this)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
val context = (this.containingFile as? KtCodeFragment)?.context ?: return false
|
||||||
|
return context.isInside(parent)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import com.sun.jdi.*
|
|||||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil.getCapturedFieldName
|
import org.jetbrains.kotlin.codegen.AsmUtil.getCapturedFieldName
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil.getLabeledThisName
|
import org.jetbrains.kotlin.codegen.AsmUtil.getLabeledThisName
|
||||||
|
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_VARIABLE_NAME
|
||||||
import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX
|
import org.jetbrains.kotlin.codegen.inline.INLINE_FUN_VAR_SUFFIX
|
||||||
import org.jetbrains.kotlin.codegen.inline.INLINE_TRANSFORMATION_SUFFIX
|
import org.jetbrains.kotlin.codegen.inline.INLINE_TRANSFORMATION_SUFFIX
|
||||||
import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX
|
import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX
|
||||||
@@ -50,7 +51,40 @@ class VariableFinder private constructor(private val context: EvaluationContextI
|
|||||||
return NamedEntity("<nameForUnwrapOnly>", value.type()) { value }.unwrap().value()
|
return NamedEntity("<nameForUnwrapOnly>", value.type()) { value }.unwrap().value()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val inlinedThisRegex = getLocalVariableNameRegexInlineAware(AsmUtil.THIS + "_")
|
fun variableNotFound(context: EvaluationContextImpl, message: String): Exception {
|
||||||
|
val frameProxy = context.frameProxy
|
||||||
|
val location = frameProxy?.location()
|
||||||
|
val scope = context.debugProcess.searchScope
|
||||||
|
|
||||||
|
val locationText = location?.run { "Location: ${sourceName()}:${lineNumber()}" } ?: "No location available"
|
||||||
|
|
||||||
|
val sourceName = location?.sourceName()
|
||||||
|
val declaringTypeName = location?.declaringType()?.name()?.replace('.', '/')?.let { JvmClassName.byInternalName(it) }
|
||||||
|
|
||||||
|
val sourceFile = if (sourceName != null && declaringTypeName != null) {
|
||||||
|
DebuggerUtils.findSourceFileForClassIncludeLibrarySources(context.project, scope, declaringTypeName, sourceName, location)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
val sourceFileText = runReadAction { sourceFile?.text }
|
||||||
|
|
||||||
|
if (sourceName != null && sourceFileText != null) {
|
||||||
|
val attachments = mergeAttachments(
|
||||||
|
Attachment(sourceName, sourceFileText),
|
||||||
|
Attachment("location.txt", locationText)
|
||||||
|
)
|
||||||
|
|
||||||
|
LOG.error(message, attachments)
|
||||||
|
}
|
||||||
|
|
||||||
|
return EvaluateExceptionUtil.createEvaluateException(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// org.jetbrains.kotlin.codegen.inline.MethodInliner.prepareNode
|
||||||
|
private const val OUTER_THIS_FOR_INLINE = AsmUtil.THIS + '_'
|
||||||
|
|
||||||
|
val inlinedThisRegex = getLocalVariableNameRegexInlineAware(OUTER_THIS_FOR_INLINE)
|
||||||
|
|
||||||
private fun getCapturedVariableNameRegex(capturedName: String): Regex {
|
private fun getCapturedVariableNameRegex(capturedName: String): Regex {
|
||||||
val escapedName = Regex.escape(capturedName)
|
val escapedName = Regex.escape(capturedName)
|
||||||
@@ -168,17 +202,6 @@ class VariableFinder private constructor(private val context: EvaluationContextI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun get(name: String, type: AsmType?): Value? {
|
|
||||||
val result = find(name, type) ?: throw variableNotFound(buildString {
|
|
||||||
append("Cannot find local variable: name = '").append(name).append("'")
|
|
||||||
if (type != null) {
|
|
||||||
append(", type = " + type.className)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return result.value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun find(name: String, type: AsmType?): Result? {
|
fun find(name: String, type: AsmType?): Result? {
|
||||||
return when {
|
return when {
|
||||||
name.startsWith(AsmUtil.THIS + "@") -> {
|
name.startsWith(AsmUtil.THIS + "@") -> {
|
||||||
@@ -317,7 +340,7 @@ class VariableFinder private constructor(private val context: EvaluationContextI
|
|||||||
name.startsWith(AsmUtil.LABELED_THIS_PARAMETER)
|
name.startsWith(AsmUtil.LABELED_THIS_PARAMETER)
|
||||||
|| name == AsmUtil.RECEIVER_PARAMETER_NAME
|
|| name == AsmUtil.RECEIVER_PARAMETER_NAME
|
||||||
|| name == AsmUtil.getCapturedFieldName(AsmUtil.THIS)
|
|| name == AsmUtil.getCapturedFieldName(AsmUtil.THIS)
|
||||||
|| inlinedThisRegex.matches(name) // org.jetbrains.kotlin.codegen.inline.MethodInliner.prepareNode
|
|| inlinedThisRegex.matches(name)
|
||||||
|
|
||||||
if (kind is VariableKind.LabeledThis) {
|
if (kind is VariableKind.LabeledThis) {
|
||||||
variables.namedEntitySequence()
|
variables.namedEntitySequence()
|
||||||
@@ -366,35 +389,6 @@ class VariableFinder private constructor(private val context: EvaluationContextI
|
|||||||
|| name == AsmUtil.CAPTURED_RECEIVER_FIELD
|
|| name == AsmUtil.CAPTURED_RECEIVER_FIELD
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun variableNotFound(message: String): Exception {
|
|
||||||
val location = frameProxy.location()
|
|
||||||
val scope = context.debugProcess.searchScope
|
|
||||||
|
|
||||||
val locationText = location?.run { "Location: ${sourceName()}:${lineNumber()}" } ?: "No location available"
|
|
||||||
|
|
||||||
val sourceName = location?.sourceName()
|
|
||||||
val declaringTypeName = location?.declaringType()?.name()?.replace('.', '/')?.let { JvmClassName.byInternalName(it) }
|
|
||||||
|
|
||||||
val sourceFile = if (sourceName != null && declaringTypeName != null) {
|
|
||||||
DebuggerUtils.findSourceFileForClassIncludeLibrarySources(context.project, scope, declaringTypeName, sourceName, location)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
val sourceFileText = runReadAction { sourceFile?.text }
|
|
||||||
|
|
||||||
if (sourceName != null && sourceFileText != null) {
|
|
||||||
val attachments = mergeAttachments(
|
|
||||||
Attachment(sourceName, sourceFileText),
|
|
||||||
Attachment("location.txt", locationText)
|
|
||||||
)
|
|
||||||
|
|
||||||
LOG.error(message, attachments)
|
|
||||||
}
|
|
||||||
|
|
||||||
return EvaluateExceptionUtil.createEvaluateException(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun List<Field>.namedEntitySequence(owner: ObjectReference) = asSequence().map { NamedEntity.of(it, owner) }
|
private fun List<Field>.namedEntitySequence(owner: ObjectReference) = asSequence().map { NamedEntity.of(it, owner) }
|
||||||
private fun List<LocalVariableProxyImpl>.namedEntitySequence() = asSequence().map { NamedEntity.of(it, frameProxy) }
|
private fun List<LocalVariableProxyImpl>.namedEntitySequence() = asSequence().map { NamedEntity.of(it, frameProxy) }
|
||||||
}
|
}
|
||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
package nonCapturedVariables
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val a = 5
|
||||||
|
|
||||||
|
inlineBlock {
|
||||||
|
//Breakpoint!
|
||||||
|
val b = 6
|
||||||
|
|
||||||
|
inlineBlock {
|
||||||
|
//Breakpoint!
|
||||||
|
val c = 7
|
||||||
|
|
||||||
|
block {
|
||||||
|
//Breakpoint!
|
||||||
|
val d = 8
|
||||||
|
|
||||||
|
inlineBlock {
|
||||||
|
//Breakpoint!
|
||||||
|
val e = 9
|
||||||
|
|
||||||
|
block {
|
||||||
|
//Breakpoint!
|
||||||
|
val f = 10
|
||||||
|
|
||||||
|
block {
|
||||||
|
//Breakpoint!
|
||||||
|
val g = 11
|
||||||
|
|
||||||
|
//Breakpoint!
|
||||||
|
val g2 = 12
|
||||||
|
|
||||||
|
//Breakpoint!
|
||||||
|
val g3 = 13
|
||||||
|
|
||||||
|
//Breakpoint!
|
||||||
|
val g4 = 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun block(block: () -> Unit) {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun inlineBlock(block: () -> Unit) {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPRESSION: a
|
||||||
|
// RESULT: 5: I
|
||||||
|
|
||||||
|
// EXPRESSION: b
|
||||||
|
// RESULT: 6: I
|
||||||
|
|
||||||
|
// EXPRESSION: c
|
||||||
|
// RESULT: 'c' is not captured
|
||||||
|
|
||||||
|
// EXPRESSION: d
|
||||||
|
// RESULT: 8: I
|
||||||
|
|
||||||
|
// EXPRESSION: e
|
||||||
|
// RESULT: 'e' is not captured
|
||||||
|
|
||||||
|
// EXPRESSION: f
|
||||||
|
// RESULT: 'f' is not captured
|
||||||
|
|
||||||
|
// EXPRESSION: e
|
||||||
|
// RESULT: 'e' is not captured
|
||||||
|
|
||||||
|
// EXPRESSION: d
|
||||||
|
// RESULT: 'd' is not captured
|
||||||
|
|
||||||
|
// EXPRESSION: c
|
||||||
|
// RESULT: 'c' is not captured
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
LineBreakpoint created at nonCapturedVariables.kt:8
|
||||||
|
LineBreakpoint created at nonCapturedVariables.kt:12
|
||||||
|
LineBreakpoint created at nonCapturedVariables.kt:16
|
||||||
|
LineBreakpoint created at nonCapturedVariables.kt:20
|
||||||
|
LineBreakpoint created at nonCapturedVariables.kt:24
|
||||||
|
LineBreakpoint created at nonCapturedVariables.kt:28
|
||||||
|
LineBreakpoint created at nonCapturedVariables.kt:31
|
||||||
|
LineBreakpoint created at nonCapturedVariables.kt:34
|
||||||
|
LineBreakpoint created at nonCapturedVariables.kt:37
|
||||||
|
Run Java
|
||||||
|
Connected to the target VM
|
||||||
|
nonCapturedVariables.kt:8
|
||||||
|
Compile bytecode for a
|
||||||
|
nonCapturedVariables.kt:12
|
||||||
|
Compile bytecode for b
|
||||||
|
nonCapturedVariables.kt:16
|
||||||
|
Compile bytecode for c
|
||||||
|
nonCapturedVariables.kt:20
|
||||||
|
Compile bytecode for d
|
||||||
|
nonCapturedVariables.kt:24
|
||||||
|
Compile bytecode for e
|
||||||
|
nonCapturedVariables.kt:28
|
||||||
|
Compile bytecode for f
|
||||||
|
nonCapturedVariables.kt:31
|
||||||
|
Compile bytecode for e
|
||||||
|
nonCapturedVariables.kt:34
|
||||||
|
Compile bytecode for d
|
||||||
|
nonCapturedVariables.kt:37
|
||||||
|
Compile bytecode for c
|
||||||
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
+1
-1
@@ -15,4 +15,4 @@ fun foo(f: () -> Unit) {
|
|||||||
// PRINT_FRAME
|
// PRINT_FRAME
|
||||||
|
|
||||||
// EXPRESSION: val1
|
// EXPRESSION: val1
|
||||||
// RESULT: java.lang.AssertionError : Cannot find local variable: name = 'val1', type = int
|
// RESULT: 'val1' is not captured
|
||||||
+1
-1
@@ -20,7 +20,7 @@ fun foo(f: () -> Unit) {
|
|||||||
// PRINT_FRAME
|
// PRINT_FRAME
|
||||||
|
|
||||||
// EXPRESSION: val1
|
// EXPRESSION: val1
|
||||||
// RESULT: java.lang.AssertionError : Cannot find local variable: name = 'val1', type = int
|
// RESULT: 'val1' is not captured
|
||||||
frame = invoke:7, FrameLambdaNotUsedKt$main$1 {frameLambdaNotUsed}
|
frame = invoke:7, FrameLambdaNotUsedKt$main$1 {frameLambdaNotUsed}
|
||||||
this = this = {frameLambdaNotUsed.FrameLambdaNotUsedKt$main$1@uniqueID}Function0<kotlin.Unit>
|
this = this = {frameLambdaNotUsed.FrameLambdaNotUsedKt$main$1@uniqueID}Function0<kotlin.Unit>
|
||||||
field = arity: int = 0 (sp = Lambda.!EXT!)
|
field = arity: int = 0 (sp = Lambda.!EXT!)
|
||||||
|
|||||||
Generated
+5
@@ -996,6 +996,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/multipleBreakpointsAtLine.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/multipleBreakpointsAtLine.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonCapturedVariables.kt")
|
||||||
|
public void testNonCapturedVariables() throws Exception {
|
||||||
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/nonCapturedVariables.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("privateMembersPriority.kt")
|
@TestMetadata("privateMembersPriority.kt")
|
||||||
public void testPrivateMembersPriority() throws Exception {
|
public void testPrivateMembersPriority() throws Exception {
|
||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/privateMembersPriority.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/privateMembersPriority.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user