blob: a3ac54dfc14478a2823503ffcce92ce322270173 [file]
// Copyright (c) 2026, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.debug;
import static com.android.tools.r8.KotlinCompilerTool.KotlinTargetVersion.JAVA_8;
import static com.android.tools.r8.KotlinTestBase.getCompileMemoizer;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.KotlinCompileMemoizer;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.internal.FileUtils;
import com.android.tools.r8.utils.internal.StringUtils;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.harmony.jpda.tests.framework.jdwp.Frame.Variable;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
// See b/574583375 for context.
@RunWith(Parameterized.class)
public class KotlinInlineLambdaDebugTest extends KotlinDebugTestBase {
private static final String SOURCE_FILE = "Main.kt";
private static final String DEBUGGEE_CLASS = "MainKt";
private static final String KOTLIN_SOURCE =
StringUtils.lines(
"private inline fun inlineLambda(",
" x: String,",
" y: String,",
" z: String,",
" block: (String, String, String) -> Unit",
") {",
" block(x, y, z)",
"}",
"",
"fun main() {",
" inlineLambda(\"a\", \"b\", \"c\") { p1, p2, p3 ->",
" println() // Breakpoint",
" }",
"}");
@Parameter(0)
public TestParameters parameters;
@Parameter(1)
public KotlinTestParameters kotlinParameters;
@Parameters(name = "{0}, {1}")
public static List<Object[]> data() {
return buildParameters(
getTestParameters()
.withDexRuntimes()
.withCfRuntimes()
.withApiLevel(AndroidApiLevel.B)
.build(),
getKotlinTestParameters()
.withAllCompilers()
.withAllLambdaGenerations()
.withTargetVersion(JAVA_8)
.build());
}
private static KotlinCompileMemoizer compiledJars;
@BeforeClass
public static void setup() throws Exception {
Path sourceFile = getStaticTemp().newFolder().toPath().resolve(SOURCE_FILE);
FileUtils.writeTextFile(sourceFile, KOTLIN_SOURCE);
compiledJars = getCompileMemoizer(sourceFile);
}
@Test
public void testInlineLambdaParametersOrder() throws Throwable {
runDebugTest(
testForRuntime(parameters)
.addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
.debugConfig(parameters.getRuntime()),
DEBUGGEE_CLASS,
breakpoint(DEBUGGEE_CLASS, "main", "()V"),
run(),
checkLine(SOURCE_FILE, 11),
stepInto(),
// Line 16 in the SMAP corresponds to line 7 inside inlined inlineLambda().
checkLine(SOURCE_FILE, 16),
stepInto(),
checkLine(SOURCE_FILE, 12),
inspect(
s -> {
// The Kotlin debugger in IntelliJ / Android Studio sorts visible variables in an
// inline frame by their starting code index (LocalVariable.compareTo).
List<String> lambdaParametersByCodeIndex =
s.getVisibleVariables().stream()
.filter(v -> v.getName().startsWith("p"))
.sorted(Comparator.comparingLong(Variable::getCodeIndex))
.map(Variable::getName)
.collect(Collectors.toList());
assertEquals(ImmutableList.of("p1", "p2", "p3"), lambdaParametersByCodeIndex);
}),
run());
}
}