Support breakpoints for inline function with cross inline argument
This commit is contained in:
@@ -41,10 +41,12 @@ import com.sun.jdi.request.ClassPrepareRequest
|
|||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||||
|
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper
|
import org.jetbrains.kotlin.codegen.state.JetTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||||
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
|
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
|
||||||
import org.jetbrains.kotlin.fileClasses.getFileClassInternalName
|
import org.jetbrains.kotlin.fileClasses.getFileClassInternalName
|
||||||
@@ -63,9 +65,14 @@ import org.jetbrains.kotlin.idea.util.application.runReadAction
|
|||||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
import org.jetbrains.kotlin.utils.toReadOnlyList
|
import org.jetbrains.kotlin.utils.toReadOnlyList
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import com.intellij.debugger.engine.DebuggerUtils as JDebuggerUtils
|
import com.intellij.debugger.engine.DebuggerUtils as JDebuggerUtils
|
||||||
@@ -168,7 +175,7 @@ public class KotlinPositionManager(private val myDebugProcess: DebugProcess) : M
|
|||||||
|
|
||||||
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName
|
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName
|
||||||
for (literal in literalsOrFunctions) {
|
for (literal in literalsOrFunctions) {
|
||||||
if (isInlinedLambda(literal, typeMapper.bindingContext)) {
|
if (InlineUtil.isInlinedArgument(literal, typeMapper.bindingContext, true)) {
|
||||||
if (isInsideInlineArgument(literal, location, myDebugProcess as DebugProcessImpl)) {
|
if (isInsideInlineArgument(literal, location, myDebugProcess as DebugProcessImpl)) {
|
||||||
return literal
|
return literal
|
||||||
}
|
}
|
||||||
@@ -201,8 +208,9 @@ public class KotlinPositionManager(private val myDebugProcess: DebugProcess) : M
|
|||||||
try {
|
try {
|
||||||
if (location.declaringType().containsKotlinStrata()) {
|
if (location.declaringType().containsKotlinStrata()) {
|
||||||
//replace is required for windows
|
//replace is required for windows
|
||||||
referenceInternalName = location.sourcePath().replace('\\','/')
|
referenceInternalName = location.sourcePath().replace('\\', '/')
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
referenceInternalName = defaultInternalName(location)
|
referenceInternalName = defaultInternalName(location)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -353,14 +361,24 @@ public class KotlinPositionManager(private val myDebugProcess: DebugProcess) : M
|
|||||||
private fun getInternalClassNameForElement(notPositionedElement: PsiElement?, typeMapper: JetTypeMapper, file: KtFile, isInLibrary: Boolean): Collection<String> {
|
private fun getInternalClassNameForElement(notPositionedElement: PsiElement?, typeMapper: JetTypeMapper, file: KtFile, isInLibrary: Boolean): Collection<String> {
|
||||||
val element = getElementToCalculateClassName(notPositionedElement)
|
val element = getElementToCalculateClassName(notPositionedElement)
|
||||||
when {
|
when {
|
||||||
element is KtClassOrObject -> return getJvmInternalNameForImpl(typeMapper, element).toCollection()
|
element is KtClassOrObject -> return getJvmInternalNameForImpl(typeMapper, element).toSet()
|
||||||
element is KtFunctionLiteral -> {
|
element is KtFunctionLiteral -> {
|
||||||
if (isInlinedLambda(element, typeMapper.bindingContext)) {
|
val descriptor = InlineUtil.getInlineArgumentDescriptor(element, typeMapper.bindingContext)
|
||||||
return getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary)
|
if (descriptor != null) {
|
||||||
|
val classNamesForParent = getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary)
|
||||||
|
if (descriptor.isCrossinline) {
|
||||||
|
return findCrossInlineArguments(element, descriptor, typeMapper.bindingContext) + classNamesForParent
|
||||||
|
}
|
||||||
|
return classNamesForParent
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
val crossInlineParameterUsages = element.containsCrossInlineParameterUsages(typeMapper.bindingContext)
|
||||||
|
if (crossInlineParameterUsages.isNotEmpty()) {
|
||||||
|
return classNamesForCrossInlineParameters(crossInlineParameterUsages, typeMapper.bindingContext)
|
||||||
|
}
|
||||||
|
|
||||||
val asmType = CodegenBinding.asmTypeForAnonymousClass(typeMapper.bindingContext, element)
|
val asmType = CodegenBinding.asmTypeForAnonymousClass(typeMapper.bindingContext, element)
|
||||||
return asmType.internalName.toCollection()
|
return asmType.internalName.toSet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
element is KtAnonymousInitializer -> {
|
element is KtAnonymousInitializer -> {
|
||||||
@@ -375,7 +393,7 @@ public class KotlinPositionManager(private val myDebugProcess: DebugProcess) : M
|
|||||||
if (isInPropertyAccessor(notPositionedElement)) {
|
if (isInPropertyAccessor(notPositionedElement)) {
|
||||||
val classOrObject = PsiTreeUtil.getParentOfType(element, KtClassOrObject::class.java)
|
val classOrObject = PsiTreeUtil.getParentOfType(element, KtClassOrObject::class.java)
|
||||||
if (classOrObject != null) {
|
if (classOrObject != null) {
|
||||||
return getJvmInternalNameForImpl(typeMapper, classOrObject).toCollection()
|
return getJvmInternalNameForImpl(typeMapper, classOrObject).toSet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,14 +402,18 @@ public class KotlinPositionManager(private val myDebugProcess: DebugProcess) : M
|
|||||||
return getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary)
|
return getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary)
|
||||||
}
|
}
|
||||||
|
|
||||||
return getJvmInternalNameForPropertyOwner(typeMapper, descriptor).toCollection()
|
return getJvmInternalNameForPropertyOwner(typeMapper, descriptor).toSet()
|
||||||
}
|
}
|
||||||
element is KtNamedFunction -> {
|
element is KtNamedFunction -> {
|
||||||
if (isInlinedLambda(element, typeMapper.bindingContext)) {
|
if (isInlinedLambda(element, typeMapper.bindingContext)) {
|
||||||
return getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary)
|
return getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary)
|
||||||
}
|
}
|
||||||
|
|
||||||
val inlinedCalls = findInlinedCalls(element, typeMapper.bindingContext)
|
val crossInlineParameterUsages = element.containsCrossInlineParameterUsages(typeMapper.bindingContext)
|
||||||
|
if (crossInlineParameterUsages.isNotEmpty()) {
|
||||||
|
return classNamesForCrossInlineParameters(crossInlineParameterUsages, typeMapper.bindingContext)
|
||||||
|
}
|
||||||
|
|
||||||
val parent = getElementToCalculateClassName(element.parent)
|
val parent = getElementToCalculateClassName(element.parent)
|
||||||
val parentInternalName = if (parent is KtClassOrObject) {
|
val parentInternalName = if (parent is KtClassOrObject) {
|
||||||
getJvmInternalNameForImpl(typeMapper, parent)
|
getJvmInternalNameForImpl(typeMapper, parent)
|
||||||
@@ -404,11 +426,12 @@ public class KotlinPositionManager(private val myDebugProcess: DebugProcess) : M
|
|||||||
NoResolveFileClassesProvider.getFileClassInternalName(file)
|
NoResolveFileClassesProvider.getFileClassInternalName(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (inlinedCalls + parentInternalName.toCollection()).toSet()
|
val inlinedCalls = findInlinedCalls(element, typeMapper.bindingContext)
|
||||||
|
return inlinedCalls + parentInternalName.toSet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NoResolveFileClassesProvider.getFileClassInternalName(file).toCollection()
|
return NoResolveFileClassesProvider.getFileClassInternalName(file).toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val TYPES_TO_CALCULATE_CLASSNAME: Array<Class<out KtElement>> =
|
private val TYPES_TO_CALCULATE_CLASSNAME: Array<Class<out KtElement>> =
|
||||||
@@ -463,8 +486,7 @@ public class KotlinPositionManager(private val myDebugProcess: DebugProcess) : M
|
|||||||
|
|
||||||
private fun createKeyForTypeMapper(file: KtFile) = NoResolveFileClassesProvider.getFileClassInternalName(file)
|
private fun createKeyForTypeMapper(file: KtFile) = NoResolveFileClassesProvider.getFileClassInternalName(file)
|
||||||
|
|
||||||
|
private fun findInlinedCalls(function: KtNamedFunction, context: BindingContext): Set<String> {
|
||||||
private fun findInlinedCalls(function: KtNamedFunction, context: BindingContext): Collection<String> {
|
|
||||||
return runReadAction {
|
return runReadAction {
|
||||||
val result = hashSetOf<String>()
|
val result = hashSetOf<String>()
|
||||||
|
|
||||||
@@ -485,9 +507,87 @@ public class KotlinPositionManager(private val myDebugProcess: DebugProcess) : M
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun findCrossInlineArguments(argument: KtFunction, parameterDescriptor: ValueParameterDescriptor, context: BindingContext): Set<String> {
|
||||||
|
return runReadAction {
|
||||||
|
val source = parameterDescriptor.source.getPsi() as? KtParameter
|
||||||
|
val functionName = source?.ownerFunction?.name
|
||||||
|
if (functionName != null) {
|
||||||
|
return@runReadAction setOf(getCrossInlineArgumentClassName(argument, functionName, context))
|
||||||
|
}
|
||||||
|
return@runReadAction emptySet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCrossInlineArgumentClassName(argument: KtFunction, inlineFunctionName: String, context: BindingContext): String {
|
||||||
|
val anonymousClassNameForArgument = CodegenBinding.asmTypeForAnonymousClass(context, argument).internalName
|
||||||
|
val newName = anonymousClassNameForArgument.substringIndex() + InlineCodegenUtil.INLINE_TRANSFORMATION_SUFFIX + "$" + inlineFunctionName
|
||||||
|
return "$newName$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtFunction.containsCrossInlineParameterUsages(context: BindingContext): Collection<ValueParameterDescriptor> {
|
||||||
|
fun KtFunction.hasParameterCall(parameter: KtParameter): Boolean {
|
||||||
|
return ReferencesSearch.search(parameter).any {
|
||||||
|
this.textRange.contains(it.element.textRange)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val inlineFunction = this.parents.firstIsInstanceOrNull<KtNamedFunction>() ?: return emptySet()
|
||||||
|
|
||||||
|
val inlineFunctionDescriptor = context[BindingContext.FUNCTION, inlineFunction]
|
||||||
|
if (inlineFunctionDescriptor == null || !InlineUtil.isInline(inlineFunctionDescriptor)) return emptySet()
|
||||||
|
|
||||||
|
return inlineFunctionDescriptor.valueParameters
|
||||||
|
.filter { it.isCrossinline }
|
||||||
|
.mapNotNull {
|
||||||
|
val psiParameter = it.source.getPsi() as? KtParameter
|
||||||
|
if (psiParameter != null && this@containsCrossInlineParameterUsages.hasParameterCall(psiParameter))
|
||||||
|
it
|
||||||
|
else
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun classNamesForCrossInlineParameters(usedParameters: Collection<ValueParameterDescriptor>, context: BindingContext): Set<String> {
|
||||||
|
// We could calculate className only for one of parameters, because we add '*' to match all crossInlined parameter calls
|
||||||
|
val parameter = usedParameters.first()
|
||||||
|
val result = hashSetOf<String>()
|
||||||
|
val inlineFunction = parameter.containingDeclaration.source.getPsi() as? KtNamedFunction ?: return emptySet()
|
||||||
|
|
||||||
|
ReferencesSearch.search(inlineFunction).forEach {
|
||||||
|
if (!it.isImportUsage()) {
|
||||||
|
val call = (it.element as? KtExpression)?.let { KtPsiUtil.getParentCallIfPresent(it) }
|
||||||
|
if (call != null) {
|
||||||
|
val resolvedCall = call.getResolvedCall(context)
|
||||||
|
val argument = resolvedCall?.valueArguments?.get(parameter)
|
||||||
|
if (argument != null) {
|
||||||
|
val argumentExpression = getArgumentExpression(argument.arguments.first())
|
||||||
|
if (argumentExpression is KtFunction) {
|
||||||
|
result.add(getCrossInlineArgumentClassName(argumentExpression, inlineFunction.name!!, context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getArgumentExpression(it: ValueArgument) = (it.getArgumentExpression() as? KtLambdaExpression)?.functionLiteral ?: it.getArgumentExpression()
|
||||||
|
|
||||||
|
private fun String.substringIndex(): String {
|
||||||
|
if (lastIndexOf("$") < 0) return this
|
||||||
|
|
||||||
|
val suffix = substringAfterLast("$")
|
||||||
|
if (suffix.all { it.isDigit() }) {
|
||||||
|
return substringBeforeLast("$") + "$"
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
private fun ReferenceType.containsKotlinStrata() = availableStrata().contains("Kotlin")
|
private fun ReferenceType.containsKotlinStrata() = availableStrata().contains("Kotlin")
|
||||||
|
|
||||||
private fun String?.toCollection() = if (this == null) emptySet() else setOf(this)
|
private fun String?.toSet() = if (this == null) emptySet() else setOf(this)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
public fun createTypeMapper(file: KtFile): JetTypeMapper {
|
public fun createTypeMapper(file: KtFile): JetTypeMapper {
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
LineBreakpoint created at crossinlineLiteral.kt:12
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:17
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:22
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:27
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:32
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:35
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:40
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:48
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:56
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:64
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:70
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:79
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:87
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:97
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:104
|
||||||
|
LineBreakpoint created at crossinlineLiteral.kt:114
|
||||||
|
!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! crossinlineLiteral.CrossinlineLiteralKt
|
||||||
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
crossinlineLiteral.kt:64
|
||||||
|
crossinlineLiteral.kt:12
|
||||||
|
crossinlineLiteral.kt:70
|
||||||
|
crossinlineLiteral.kt:17
|
||||||
|
crossinlineLiteral.kt:79
|
||||||
|
crossinlineLiteral.kt:22
|
||||||
|
crossinlineLiteral.kt:87
|
||||||
|
crossinlineLiteral.kt:27
|
||||||
|
crossinlineLiteral.kt:97
|
||||||
|
crossinlineLiteral.kt:32
|
||||||
|
crossinlineLiteral.kt:104
|
||||||
|
crossinlineLiteral.kt:35
|
||||||
|
crossinlineLiteral.kt:114
|
||||||
|
crossinlineLiteral.kt:40
|
||||||
|
crossinlineLiteral.kt:87
|
||||||
|
crossinlineLiteral.kt:48
|
||||||
|
crossinlineLiteral.kt:87
|
||||||
|
crossinlineLiteral.kt:56
|
||||||
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package crossinlineLiteral
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
callFromTopLevel()
|
||||||
|
A().callFromClass()
|
||||||
|
A.callFromCompanion()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun callFromTopLevel() {
|
||||||
|
simpleCall {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
lambdaCall {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
inlinedLambdaCall {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
objectCall {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
multipleCrossInline({
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
}, {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
})
|
||||||
|
|
||||||
|
lambdaInInlinedLambdaCall {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class A {
|
||||||
|
fun callFromClass() {
|
||||||
|
objectCall {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun callFromCompanion() {
|
||||||
|
objectCall {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun simpleCall(crossinline f: (Int) -> Unit) {
|
||||||
|
//Breakpoint!
|
||||||
|
f(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun lambdaCall(crossinline f: (Int) -> Unit) {
|
||||||
|
val a = {
|
||||||
|
//Breakpoint!
|
||||||
|
f(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
a.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun inlinedLambdaCall(crossinline f: (Int) -> Unit) {
|
||||||
|
run {
|
||||||
|
//Breakpoint!
|
||||||
|
f(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun objectCall(crossinline f: (Int) -> Unit) {
|
||||||
|
val a = object {
|
||||||
|
fun objFun() {
|
||||||
|
//Breakpoint!
|
||||||
|
f(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.objFun()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun multipleCrossInline(crossinline f1: (Int) -> Unit, crossinline f2: (Int) -> Unit) {
|
||||||
|
val a1 = {
|
||||||
|
//Breakpoint!
|
||||||
|
f1(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
a1.invoke()
|
||||||
|
|
||||||
|
val a2 = {
|
||||||
|
//Breakpoint!
|
||||||
|
f2(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
a2.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun lambdaInInlinedLambdaCall(crossinline f: (Int) -> Unit) {
|
||||||
|
run {
|
||||||
|
{
|
||||||
|
//Breakpoint!
|
||||||
|
f(1)
|
||||||
|
}()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RESUME: 17
|
||||||
@@ -523,6 +523,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/stepping/custom"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/stepping/custom"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("crossinlineLiteral.kt")
|
||||||
|
public void testCrossinlineLiteral() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/crossinlineLiteral.kt");
|
||||||
|
doCustomTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("funLiteral.kt")
|
@TestMetadata("funLiteral.kt")
|
||||||
public void testFunLiteral() throws Exception {
|
public void testFunLiteral() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/funLiteral.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/funLiteral.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user