blob: 8520694b444eb93fa765bfb0ed478f70146eaeef [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 KotlinInlineFunctionInlineDebugTest 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(
"class A",
"class B",
"class C",
"inline fun foo(a: A, b: B, c: C) {",
" println() // Breakpoint",
"}",
"",
"fun main() {",
" val a = A()",
" val b = B()",
" val c = C()",
" foo(a, b, c)",
"}");
@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 testInlineFunctionParametersOrder() throws Throwable {
runDebugTest(
testForRuntime(parameters)
.addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
.debugConfig(parameters.getRuntime()),
DEBUGGEE_CLASS,
breakpoint(DEBUGGEE_CLASS, "main", "()V"),
run(),
checkLine(SOURCE_FILE, 9),
stepOver(),
checkLine(SOURCE_FILE, 10),
stepOver(),
checkLine(SOURCE_FILE, 11),
stepOver(),
checkLine(SOURCE_FILE, 12),
stepInto(),
// Line 15 in the SMAP corresponds to line 5 inside inlined foo().
checkLine(SOURCE_FILE, 15),
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> inlinedParametersByCodeIndex =
s.getVisibleVariables().stream()
.filter(v -> v.getName().endsWith("$iv"))
.sorted(Comparator.comparingLong(Variable::getCodeIndex))
.map(Variable::getName)
.collect(Collectors.toList());
assertEquals(ImmutableList.of("a$iv", "b$iv", "c$iv"), inlinedParametersByCodeIndex);
}),
run());
}
}