Debugger: Support parameters of inlined lambda in evaluate expression
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.psi
|
package org.jetbrains.kotlin.psi
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.impl.PsiManagerEx
|
import com.intellij.psi.impl.PsiManagerEx
|
||||||
import com.intellij.psi.impl.source.tree.FileElement
|
import com.intellij.psi.impl.source.tree.FileElement
|
||||||
@@ -24,14 +25,9 @@ import com.intellij.psi.search.GlobalSearchScope
|
|||||||
import com.intellij.psi.tree.IElementType
|
import com.intellij.psi.tree.IElementType
|
||||||
import com.intellij.testFramework.LightVirtualFile
|
import com.intellij.testFramework.LightVirtualFile
|
||||||
import org.jetbrains.kotlin.idea.JetFileType
|
import org.jetbrains.kotlin.idea.JetFileType
|
||||||
import java.util.HashSet
|
|
||||||
import com.intellij.openapi.util.Key
|
|
||||||
import com.intellij.psi.impl.PsiModificationTrackerImpl
|
|
||||||
import com.intellij.psi.util.PsiModificationTracker
|
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||||
import java.util.LinkedHashSet
|
import java.util.LinkedHashSet
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
public abstract class JetCodeFragment(
|
public abstract class JetCodeFragment(
|
||||||
private val _project: Project,
|
private val _project: Project,
|
||||||
@@ -44,6 +40,9 @@ public abstract class JetCodeFragment(
|
|||||||
|
|
||||||
private var viewProvider = super<JetFile>.getViewProvider() as SingleRootFileViewProvider
|
private var viewProvider = super<JetFile>.getViewProvider() as SingleRootFileViewProvider
|
||||||
private var myImports = LinkedHashSet<String>()
|
private var myImports = LinkedHashSet<String>()
|
||||||
|
private val additionalContextForLambda: PsiElement? by lazy {
|
||||||
|
this.getCopyableUserData(ADDITIONAL_CONTEXT_FOR_LAMBDA)?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
getViewProvider().forceCachedPsi(this)
|
getViewProvider().forceCachedPsi(this)
|
||||||
@@ -70,7 +69,7 @@ public abstract class JetCodeFragment(
|
|||||||
|
|
||||||
override fun isValid() = true
|
override fun isValid() = true
|
||||||
|
|
||||||
override fun getContext() = context
|
override fun getContext() = additionalContextForLambda ?: context
|
||||||
|
|
||||||
override fun getResolveScope() = context?.getResolveScope() ?: super<JetFile>.getResolveScope()
|
override fun getResolveScope() = context?.getResolveScope() ?: super<JetFile>.getResolveScope()
|
||||||
|
|
||||||
@@ -146,5 +145,6 @@ public abstract class JetCodeFragment(
|
|||||||
companion object {
|
companion object {
|
||||||
public val IMPORT_SEPARATOR: String = ","
|
public val IMPORT_SEPARATOR: String = ","
|
||||||
public val RUNTIME_TYPE_EVALUATOR: Key<Function1<JetExpression, JetType?>> = Key.create("RUNTIME_TYPE_EVALUATOR")
|
public val RUNTIME_TYPE_EVALUATOR: Key<Function1<JetExpression, JetType?>> = Key.create("RUNTIME_TYPE_EVALUATOR")
|
||||||
|
public val ADDITIONAL_CONTEXT_FOR_LAMBDA: Key<Function0<JetElement?>> = Key.create("ADDITIONAL_CONTEXT_FOR_LAMBDA")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+112
-18
@@ -20,6 +20,10 @@ import com.intellij.debugger.DebuggerManagerEx
|
|||||||
import com.intellij.debugger.engine.evaluation.CodeFragmentFactory
|
import com.intellij.debugger.engine.evaluation.CodeFragmentFactory
|
||||||
import com.intellij.debugger.engine.evaluation.CodeFragmentKind
|
import com.intellij.debugger.engine.evaluation.CodeFragmentKind
|
||||||
import com.intellij.debugger.engine.evaluation.TextWithImports
|
import com.intellij.debugger.engine.evaluation.TextWithImports
|
||||||
|
import com.intellij.debugger.engine.events.DebuggerCommandImpl
|
||||||
|
import com.intellij.debugger.jdi.LocalVariableProxyImpl
|
||||||
|
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.progress.ProgressManager
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
@@ -32,20 +36,34 @@ import com.intellij.xdebugger.XDebuggerManager
|
|||||||
import com.intellij.xdebugger.impl.XDebugSessionImpl
|
import com.intellij.xdebugger.impl.XDebugSessionImpl
|
||||||
import com.intellij.xdebugger.impl.ui.tree.ValueMarkup
|
import com.intellij.xdebugger.impl.ui.tree.ValueMarkup
|
||||||
import com.sun.jdi.ArrayReference
|
import com.sun.jdi.ArrayReference
|
||||||
import com.sun.jdi.ObjectReference
|
|
||||||
import com.sun.jdi.PrimitiveValue
|
import com.sun.jdi.PrimitiveValue
|
||||||
import com.sun.jdi.Value
|
import com.sun.jdi.Value
|
||||||
|
import org.jetbrains.annotations.TestOnly
|
||||||
|
import org.jetbrains.eval4j.jdi.asValue
|
||||||
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
import org.jetbrains.kotlin.asJava.KotlinLightClass
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.idea.JetFileType
|
import org.jetbrains.kotlin.idea.JetFileType
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||||
import org.jetbrains.kotlin.idea.core.refactoring.j2kText
|
import org.jetbrains.kotlin.idea.core.refactoring.j2kText
|
||||||
|
import org.jetbrains.kotlin.idea.core.refactoring.quoteIfNeeded
|
||||||
import org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider
|
import org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider
|
||||||
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||||
import java.util.HashMap
|
import java.util.*
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
import kotlin.reflect.jvm.java
|
import kotlin.reflect.jvm.java
|
||||||
|
|
||||||
@@ -106,6 +124,65 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (contextElement != null) {
|
||||||
|
val lambdas = getInlinedLambdasInside(contextElement)
|
||||||
|
if (lambdas.isNotEmpty()) {
|
||||||
|
codeFragment.putCopyableUserData(JetCodeFragment.ADDITIONAL_CONTEXT_FOR_LAMBDA, lamdba@ {
|
||||||
|
val debuggerContext = DebuggerManagerEx.getInstanceEx(project).context
|
||||||
|
|
||||||
|
val semaphore = Semaphore()
|
||||||
|
semaphore.down()
|
||||||
|
|
||||||
|
var visibleVariables: List<Pair<LocalVariableProxyImpl, Value>>? = null
|
||||||
|
|
||||||
|
val worker = object : DebuggerCommandImpl() {
|
||||||
|
override fun action() {
|
||||||
|
try {
|
||||||
|
val frameProxy = if (ApplicationManager.getApplication().isUnitTestMode)
|
||||||
|
context?.getCopyableUserData(DEBUG_FRAME_FOR_TESTS)
|
||||||
|
else
|
||||||
|
debuggerContext.frameProxy
|
||||||
|
|
||||||
|
visibleVariables = frameProxy?.let { f -> f.visibleVariables().map { it to f.getValue(it) } } ?: emptyList()
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
semaphore.up()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debuggerContext.debugProcess?.managerThread?.invoke(worker)
|
||||||
|
|
||||||
|
for (i in 0..50) {
|
||||||
|
if (semaphore.waitFor(20)) break
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isLocalVariableForParameterPresent(p: ValueParameterDescriptor): Boolean {
|
||||||
|
return visibleVariables?.firstOrNull {
|
||||||
|
if (it.first.name() != p.name.asString()) return@firstOrNull false
|
||||||
|
|
||||||
|
val parameterClassDescriptor = p.type.constructor.declarationDescriptor as? ClassDescriptor ?: return@firstOrNull true
|
||||||
|
val actualClassDescriptor = it.second.asValue().asmType.getClassDescriptor(debuggerContext.project) ?: return@firstOrNull true
|
||||||
|
return@firstOrNull runReadAction { DescriptorUtils.isSubclass(actualClassDescriptor, parameterClassDescriptor) }
|
||||||
|
} != null
|
||||||
|
}
|
||||||
|
|
||||||
|
for (lambda in lambdas) {
|
||||||
|
val function = lambda.analyze(BodyResolveMode.PARTIAL).get(BindingContext.FUNCTION, lambda)
|
||||||
|
if (function != null && function.valueParameters.all { isLocalVariableForParameterPresent(it) }) {
|
||||||
|
val fragmentForVisibleVariables = createCodeFragmentForVisibleVariables(lambda.project, visibleVariables!!)
|
||||||
|
return@lamdba createWrappingContext(
|
||||||
|
fragmentForVisibleVariables.first,
|
||||||
|
fragmentForVisibleVariables.second,
|
||||||
|
lambda.bodyExpression,
|
||||||
|
lambda.project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return@lamdba null
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return codeFragment
|
return codeFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,6 +208,7 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
companion object {
|
companion object {
|
||||||
public val LABEL_VARIABLE_VALUE_KEY: Key<Value> = Key.create<Value>("_label_variable_value_key_")
|
public val LABEL_VARIABLE_VALUE_KEY: Key<Value> = Key.create<Value>("_label_variable_value_key_")
|
||||||
public val DEBUG_LABEL_SUFFIX: String = "_DebugLabel"
|
public val DEBUG_LABEL_SUFFIX: String = "_DebugLabel"
|
||||||
|
@TestOnly val DEBUG_FRAME_FOR_TESTS: Key<StackFrameProxyImpl> = Key.create("DEBUG_FRAME_FOR_TESTS")
|
||||||
|
|
||||||
fun getContextElement(elementAt: PsiElement?): JetElement? {
|
fun getContextElement(elementAt: PsiElement?): JetElement? {
|
||||||
if (elementAt == null) return null
|
if (elementAt == null) return null
|
||||||
@@ -161,6 +239,16 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
|
|
||||||
private fun JetElement?.check(): Boolean = this != null && this.check { KotlinEditorTextProvider.isAcceptedAsCodeFragmentContext(it) } != null
|
private fun JetElement?.check(): Boolean = this != null && this.check { KotlinEditorTextProvider.isAcceptedAsCodeFragmentContext(it) } != null
|
||||||
|
|
||||||
|
private fun getInlinedLambdasInside(contextElement: JetElement): List<JetFunction> {
|
||||||
|
val start = contextElement.startOffset
|
||||||
|
val end = contextElement.endOffset
|
||||||
|
|
||||||
|
val bindingContext = contextElement.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
return CodeInsightUtils.findElementsOfClassInRange(contextElement.getContainingJetFile(), start, end, javaClass<JetFunctionLiteral>(), javaClass<JetNamedFunction>())
|
||||||
|
.filterIsInstance<JetFunction>()
|
||||||
|
.filter { JetPsiUtil.getParentCallIfPresent(it as JetExpression) != null && InlineUtil.isInlinedArgument(it, bindingContext, false) }
|
||||||
|
}
|
||||||
|
|
||||||
//internal for tests
|
//internal for tests
|
||||||
fun createCodeFragmentForLabeledObjects(project: Project, markupMap: Map<*, ValueMarkup>): Pair<String, Map<String, Value>> {
|
fun createCodeFragmentForLabeledObjects(project: Project, markupMap: Map<*, ValueMarkup>): Pair<String, Map<String, Value>> {
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
@@ -172,7 +260,7 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
val objectRef = value as? Value ?: continue
|
val objectRef = value as? Value ?: continue
|
||||||
|
|
||||||
val labelNameWithSuffix = "$labelName$DEBUG_LABEL_SUFFIX"
|
val labelNameWithSuffix = "$labelName$DEBUG_LABEL_SUFFIX"
|
||||||
sb.append("${createKotlinProperty(project, labelNameWithSuffix, objectRef.type().name(), TypeKind.getTypeKind(objectRef))}\n")
|
sb.append("${createKotlinProperty(project, labelNameWithSuffix, objectRef.type().name(), objectRef)}\n")
|
||||||
|
|
||||||
labeledObjects.put(labelNameWithSuffix, objectRef)
|
labeledObjects.put(labelNameWithSuffix, objectRef)
|
||||||
}
|
}
|
||||||
@@ -180,28 +268,34 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
|
|||||||
return sb.toString() to labeledObjects
|
return sb.toString() to labeledObjects
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum class TypeKind {
|
private fun createCodeFragmentForVisibleVariables(project: Project, visibleVariables: List<Pair<LocalVariableProxyImpl, Value>>): Pair<String, Map<String, Value>> {
|
||||||
PRIMITIVE,
|
val sb = StringBuilder()
|
||||||
ARRAY,
|
val labeledObjects = HashMap<String, Value>()
|
||||||
OBJECT;
|
for ((variable, value) in visibleVariables) {
|
||||||
|
val variableName = variable.name()
|
||||||
|
if (!Name.isValidIdentifier(variableName)) continue
|
||||||
|
|
||||||
companion object {
|
val kotlinProperty = createKotlinProperty(project, variableName, variable.typeName(), value) ?: continue
|
||||||
fun getTypeKind(value: Value): TypeKind {
|
sb.append("$kotlinProperty\n")
|
||||||
return when(value) {
|
|
||||||
is ArrayReference -> ARRAY
|
labeledObjects.put(variableName, value)
|
||||||
is PrimitiveValue -> PRIMITIVE
|
|
||||||
else -> OBJECT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
sb.append("val _debug_context_val = 1")
|
||||||
|
return sb.toString() to labeledObjects
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createKotlinProperty(project: Project, variableName: String, variableTypeName: String, typeKind: TypeKind): String? {
|
private fun createKotlinProperty(project: Project, variableName: String, variableTypeName: String, value: Value): String? {
|
||||||
fun String.addArraySuffix() = if (typeKind == TypeKind.ARRAY) this + "[]" else this
|
val actualClassDescriptor = value.asValue().asmType.getClassDescriptor(project)
|
||||||
|
if (actualClassDescriptor != null && actualClassDescriptor.defaultType.arguments.isEmpty()) {
|
||||||
|
val renderedType = IdeDescriptorRenderers.SOURCE_CODE.renderType(actualClassDescriptor.defaultType.makeNullable())
|
||||||
|
return "val ${variableName.quoteIfNeeded()}: $renderedType = null"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.addArraySuffix() = if (value is ArrayReference) this + "[]" else this
|
||||||
|
|
||||||
val className = variableTypeName.replace("$", ".").substringBefore("[]")
|
val className = variableTypeName.replace("$", ".").substringBefore("[]")
|
||||||
val classType = PsiType.getTypeByName(className, project, GlobalSearchScope.allScope(project))
|
val classType = PsiType.getTypeByName(className, project, GlobalSearchScope.allScope(project))
|
||||||
val type = (if (typeKind != TypeKind.PRIMITIVE && classType.resolve() == null)
|
val type = (if (value !is PrimitiveValue && classType.resolve() == null)
|
||||||
CommonClassNames.JAVA_LANG_OBJECT
|
CommonClassNames.JAVA_LANG_OBJECT
|
||||||
else
|
else
|
||||||
className).addArraySuffix()
|
className).addArraySuffix()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ LineBreakpoint created at inlineFunctionalExpression.kt:9
|
|||||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
inlineFunctionalExpression.kt:9
|
inlineFunctionalExpression.kt:9
|
||||||
inlineFunctionalExpression.kt:9
|
inlineFunctionalExpression.kt:9
|
||||||
|
Compile bytecode for it
|
||||||
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
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ LineBreakpoint created at inlineLambda.kt:9
|
|||||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
inlineLambda.kt:9
|
inlineLambda.kt:9
|
||||||
inlineLambda.kt:9
|
inlineLambda.kt:9
|
||||||
|
Compile bytecode for it
|
||||||
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
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
LineBreakpoint created at parametersOfInlineFun.kt:8
|
||||||
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! parametersOfInlineFun.ParametersOfInlineFunPackage
|
||||||
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
parametersOfInlineFun.kt:8
|
||||||
|
parametersOfInlineFun.kt:8
|
||||||
|
Compile bytecode for primitive
|
||||||
|
Compile bytecode for it
|
||||||
|
Compile bytecode for array
|
||||||
|
Compile bytecode for str
|
||||||
|
Compile bytecode for list
|
||||||
|
Compile bytecode for `$receiver`.prop
|
||||||
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
LineBreakpoint created at parametersOfInlineFunSeveralOnLine.kt:8
|
||||||
|
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! parametersOfInlineFunSeveralOnLine.ParametersOfInlineFunSeveralOnLinePackage
|
||||||
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
parametersOfInlineFunSeveralOnLine.kt:8
|
||||||
|
parametersOfInlineFunSeveralOnLine.kt:8
|
||||||
|
parametersOfInlineFunSeveralOnLine.kt:8
|
||||||
|
parametersOfInlineFunSeveralOnLine.kt:8
|
||||||
|
Compile bytecode for it
|
||||||
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
Vendored
+2
-2
@@ -3,8 +3,8 @@ package inlineFunctionalExpression
|
|||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val a = array(1)
|
val a = array(1)
|
||||||
// EXPRESSION: it
|
// EXPRESSION: it
|
||||||
// RESULT: Unresolved reference: it
|
// RESULT: 1: I
|
||||||
// STEP_INTO: 1
|
// RESUME: 1
|
||||||
//Breakpoint!
|
//Breakpoint!
|
||||||
a.map(fun (it): Int { return it * 1 })
|
a.map(fun (it): Int { return it * 1 })
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -3,8 +3,8 @@ package inlineLambda
|
|||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val a = array(1)
|
val a = array(1)
|
||||||
// EXPRESSION: it
|
// EXPRESSION: it
|
||||||
// RESULT: Unresolved reference: it
|
// RESULT: 1: I
|
||||||
// STEP_INTO: 1
|
// RESUME: 1
|
||||||
//Breakpoint!
|
//Breakpoint!
|
||||||
a.map { it * 1 }
|
a.map { it * 1 }
|
||||||
}
|
}
|
||||||
|
|||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
// Check that evaluate expression works inside inline function
|
||||||
|
package parametersOfInlineFun
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val a = A(1)
|
||||||
|
// RESUME: 1
|
||||||
|
//Breakpoint!
|
||||||
|
a.foo { 1 + 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun A.foo(f: (i: Int) -> Unit) {
|
||||||
|
val primitive = 1
|
||||||
|
val array = arrayOf(1)
|
||||||
|
val str = "str"
|
||||||
|
val list = listOf("str")
|
||||||
|
f(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
class A(val prop: Int)
|
||||||
|
|
||||||
|
// EXPRESSION: primitive
|
||||||
|
// RESULT: 1: I
|
||||||
|
|
||||||
|
// EXPRESSION: it
|
||||||
|
// RESULT: 1: I
|
||||||
|
|
||||||
|
// EXPRESSION: array
|
||||||
|
// RESULT: instance of java.lang.Integer[1] (id=ID): [Ljava/lang/Integer;
|
||||||
|
|
||||||
|
// EXPRESSION: str
|
||||||
|
// RESULT: "str": Ljava/lang/String;
|
||||||
|
|
||||||
|
// EXPRESSION: list
|
||||||
|
// RESULT: instance of java.util.Collections$SingletonList(id=ID): Ljava/util/Collections$SingletonList;
|
||||||
|
|
||||||
|
// EXPRESSION: `$receiver`.prop
|
||||||
|
// RESULT: 1: I
|
||||||
Vendored
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// Check that evaluate expression works inside inline function
|
||||||
|
package parametersOfInlineFunSeveralOnLine
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val a = A()
|
||||||
|
// RESUME: 3
|
||||||
|
//Breakpoint!
|
||||||
|
a.foo { 1 + 1 }.bar { 1 + 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun A.foo(f: (i: Int) -> Unit): A {
|
||||||
|
f(1)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun A.bar(f: (s: String) -> Unit): A {
|
||||||
|
f("str")
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
class A()
|
||||||
|
|
||||||
|
// EXPRESSION: it
|
||||||
|
// RESULT: "str": Ljava/lang/String;
|
||||||
+2
@@ -311,6 +311,8 @@ public abstract class AbstractKotlinEvaluateExpressionTest : KotlinDebuggerTestB
|
|||||||
val sourcePosition = ContextUtil.getSourcePosition(this)
|
val sourcePosition = ContextUtil.getSourcePosition(this)
|
||||||
val contextElement = createContextElement(this)
|
val contextElement = createContextElement(this)
|
||||||
|
|
||||||
|
contextElement.putCopyableUserData(KotlinCodeFragmentFactory.DEBUG_FRAME_FOR_TESTS, evaluationContext?.frameProxy)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
val evaluator =
|
val evaluator =
|
||||||
|
|||||||
+12
@@ -211,6 +211,18 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
doSingleBreakpointTest(fileName);
|
doSingleBreakpointTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("parametersOfInlineFun.kt")
|
||||||
|
public void testParametersOfInlineFun() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/parametersOfInlineFun.kt");
|
||||||
|
doSingleBreakpointTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("parametersOfInlineFunSeveralOnLine.kt")
|
||||||
|
public void testParametersOfInlineFunSeveralOnLine() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/parametersOfInlineFunSeveralOnLine.kt");
|
||||||
|
doSingleBreakpointTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("privateMember.kt")
|
@TestMetadata("privateMember.kt")
|
||||||
public void testPrivateMember() throws Exception {
|
public void testPrivateMember() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateMember.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/privateMember.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user