Don't strip debug info when it could loose source file information.
This CL fixes the issue of stripping single line entries which can
cause the same lack of source file.
Bug: 206902024
Change-Id: Ide9c7bcbf2ca6fe88ab9fd8b07f962dde246d064
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index b67a8c2..5c84cd4 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1869,8 +1869,17 @@
return !isDesugaring() || hasMinApi(AndroidApiLevel.N);
}
+ // Debug entries may be dropped only if the source file content allows being omitted from
+ // stack traces, or if the VM will report the source file even with a null valued debug info.
+ public boolean allowDiscardingResidualDebugInfo() {
+ // TODO(b/146565491): We can drop debug info once fixed at a known min-api.
+ return sourceFileProvider != null && sourceFileProvider.allowDiscardingSourceFile();
+ }
+
public boolean canUseDexPcAsDebugInformation() {
- return lineNumberOptimization == LineNumberOptimization.ON && hasMinApi(AndroidApiLevel.O);
+ return lineNumberOptimization == LineNumberOptimization.ON
+ && hasMinApi(AndroidApiLevel.O)
+ && allowDiscardingResidualDebugInfo();
}
public boolean isInterfaceMethodDesugaringEnabled() {
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index 8505e9f..71da5cc 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -389,10 +389,6 @@
}
}
- boolean canStripDebugInfo =
- appView.options().sourceFileProvider != null
- && appView.options().sourceFileProvider.allowDiscardingSourceFile();
-
if (isSyntheticClass) {
onDemandClassNamingBuilder
.get()
@@ -444,9 +440,7 @@
List<MappedPosition> mappedPositions;
Code code = method.getCode();
boolean canUseDexPc =
- canStripDebugInfo
- && appView.options().canUseDexPcAsDebugInformation()
- && methods.size() == 1;
+ appView.options().canUseDexPcAsDebugInformation() && methods.size() == 1;
if (code != null) {
if (code.isDexCode() && doesContainPositions(code.asDexCode())) {
if (canUseDexPc) {
@@ -485,6 +479,9 @@
&& methodMappingInfo.isEmpty()
&& obfuscatedNameDexString == originalMethod.name
&& originalMethod.holder == originalType) {
+ assert appView.options().lineNumberOptimization == LineNumberOptimization.OFF
+ || !doesContainPositions(method)
+ || appView.isCfByteCodePassThrough(method);
continue;
}
@@ -615,10 +612,10 @@
}
i = j;
}
- if (canStripDebugInfo
- && method.getCode().isDexCode()
+ if (method.getCode().isDexCode()
&& method.getCode().asDexCode().getDebugInfo()
== DexDebugInfoForSingleLineMethod.getInstance()) {
+ assert appView.options().allowDiscardingResidualDebugInfo();
method.getCode().asDexCode().setDebugInfo(null);
}
} // for each method of the group
@@ -946,6 +943,7 @@
&& !hasOverloads
&& !appView.options().debug
&& appView.options().lineNumberOptimization != LineNumberOptimization.OFF
+ && appView.options().allowDiscardingResidualDebugInfo()
&& (mappedPositions.isEmpty() || !mappedPositions.get(0).isOutlineCaller())) {
dexCode.setDebugInfo(DexDebugInfoForSingleLineMethod.getInstance());
return mappedPositions;
diff --git a/src/test/java/com/android/tools/r8/debuginfo/CanonicalizeWithInline.java b/src/test/java/com/android/tools/r8/debuginfo/CanonicalizeWithInline.java
index 48b9fc8..a8eb9cc 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/CanonicalizeWithInline.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/CanonicalizeWithInline.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.debuginfo;
+import static org.junit.Assert.assertNull;
+
import com.android.tools.r8.AssumeMayHaveSideEffects;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.OutputMode;
@@ -13,6 +15,8 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.DexParser;
import com.android.tools.r8.dex.DexSection;
+import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.io.IOException;
import java.nio.file.Path;
@@ -31,10 +35,8 @@
return getTestParameters().withNoneRuntime().build();
}
- private final TestParameters parameters;
-
public CanonicalizeWithInline(TestParameters parameters) {
- this.parameters = parameters;
+ parameters.assertNoneRuntime();
}
private int getNumberOfDebugInfos(Path file) throws IOException {
@@ -58,10 +60,17 @@
.addProgramClasses(clazzA, clazzB)
.addKeepRules(
"-keepattributes SourceFile,LineNumberTable",
- "-keep class ** {\n" + "public void call(int);\n" + "}")
+ "-keep class ** { public void call(int); }")
.enableInliningAnnotations()
.enableSideEffectAnnotations()
.compile();
+ result.inspect(
+ inspector -> {
+ DexEncodedMethod method =
+ inspector.clazz(ClassA.class).uniqueMethodWithName("call").getMethod();
+ DexDebugInfo debugInfo = method.getCode().asDexCode().getDebugInfo();
+ assertNull(debugInfo);
+ });
Path classesPath = temp.getRoot().toPath();
result.app.write(classesPath, OutputMode.DexIndexed);
int numberOfDebugInfos =
diff --git a/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java
index 37d2b6e..b3c1c08 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/DexPcWithDebugInfoForOverloadedMethodsTestRunner.java
@@ -23,7 +23,6 @@
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.retrace.RetraceFrameResult;
-import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -68,7 +67,6 @@
.addKeepMainRule(MAIN)
.addKeepMethodRules(MAIN, "void overloaded(...)")
.addKeepAttributeLineNumberTable()
- .addKeepAttributes(ProguardKeepAttributes.SOURCE_FILE)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertFailureWithErrorThatMatches(containsString(EXPECTED))
diff --git a/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java
index 30505ab..a5e76eb 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/EnsureNoDebugInfoEmittedForPcOnlyTestRunner.java
@@ -7,8 +7,8 @@
import static com.android.tools.r8.naming.retrace.StackTrace.isSameExceptForFileNameAndLineNumber;
import static com.android.tools.r8.utils.InternalOptions.LineNumberOptimization.ON;
import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertNull;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
@@ -21,7 +21,6 @@
import com.android.tools.r8.graph.DexDebugEntryBuilder;
import com.android.tools.r8.naming.retrace.StackTrace;
import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -38,7 +37,6 @@
private static final String FILENAME_MAIN = "EnsureNoDebugInfoEmittedForPcOnlyTest.java";
private static final Class<?> MAIN = EnsureNoDebugInfoEmittedForPcOnlyTest.class;
- private static final int INLINED_DEX_PC = 32;
private final TestParameters parameters;
@@ -51,8 +49,9 @@
this.parameters = parameters;
}
- private boolean apiLevelSupportsPcOutput() {
- return parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.O);
+ private boolean apiLevelSupportsPcAndSourceFileOutput() {
+ // TODO(b/146565491): Update with API level once fixed.
+ return false;
}
@Test
@@ -77,7 +76,7 @@
.internalEnableMappingOutput()
// TODO(b/191038746): Enable LineNumberOptimization for release builds for DEX PC Output.
.applyIf(
- apiLevelSupportsPcOutput(),
+ apiLevelSupportsPcAndSourceFileOutput(),
builder ->
builder.addOptionsModification(
options -> {
@@ -98,7 +97,7 @@
.run(parameters.getRuntime(), MAIN)
.inspectFailure(
inspector -> {
- if (apiLevelSupportsPcOutput()) {
+ if (apiLevelSupportsPcAndSourceFileOutput()) {
checkNoDebugInfo(inspector, 5);
} else {
checkHasLineNumberInfo(inspector);
@@ -122,7 +121,7 @@
@Test
public void testNoEmittedDebugInfoR8() throws Exception {
- assumeTrue(apiLevelSupportsPcOutput());
+ assumeTrue(apiLevelSupportsPcAndSourceFileOutput());
testForR8(parameters.getBackend())
.addProgramClasses(MAIN)
.addKeepMainRule(MAIN)
diff --git a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java
index 652f401..b881f55 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/SingleLineInfoRemoveTest.java
@@ -9,14 +9,18 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import java.util.List;
+import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -27,14 +31,17 @@
public class SingleLineInfoRemoveTest extends TestBase {
private final TestParameters parameters;
+ private final boolean customSourceFile;
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ @Parameters(name = "{0}, custom-source-file:{1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
}
- public SingleLineInfoRemoveTest(TestParameters parameters) {
+ public SingleLineInfoRemoveTest(TestParameters parameters, boolean customSourceFile) {
this.parameters = parameters;
+ this.customSourceFile = customSourceFile;
}
public StackTrace expectedStackTrace;
@@ -58,9 +65,27 @@
.addKeepMainRule(Main.class)
.addKeepAttributeSourceFile()
.addKeepAttributeLineNumberTable()
+ .applyIf(
+ customSourceFile,
+ b -> b.getBuilder().setSourceFileProvider(env -> "MyCustomSourceFile"))
.enableInliningAnnotations()
.run(parameters.getRuntime(), Main.class)
.assertFailureWithErrorThatThrows(NullPointerException.class)
+ .inspectOriginalStackTrace(
+ stackTrace -> {
+ for (StackTraceLine line : stackTrace.getStackTraceLines()) {
+ if (customSourceFile) {
+ assertEquals("MyCustomSourceFile", line.fileName);
+ } else if (parameters.isCfRuntime()) {
+ assertEquals("SourceFile", line.fileName);
+ } else {
+ assertThat(
+ line.fileName,
+ CoreMatchers.anyOf(
+ CoreMatchers.is("SourceFile"), CoreMatchers.is("Unknown Source")));
+ }
+ }
+ })
.inspectStackTrace(
(stackTrace, inspector) -> {
assertThat(stackTrace, isSame(expectedStackTrace));
@@ -68,10 +93,14 @@
assertThat(mainSubject, isPresent());
assertThat(
mainSubject.uniqueMethodWithName("shouldRemoveLineNumber"),
- notIf(hasLineNumberTable(), parameters.isDexRuntime()));
+ notIf(hasLineNumberTable(), canSingleLineDebugInfoBeDiscarded()));
});
}
+ private boolean canSingleLineDebugInfoBeDiscarded() {
+ return parameters.isDexRuntime() && !customSourceFile;
+ }
+
public static class Main {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestRunner.java
new file mode 100644
index 0000000..637e1f0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestRunner.java
@@ -0,0 +1,90 @@
+// Copyright (c) 2021, 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.debuginfo.pc2pc;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DifferentParameterCountMultilineCodeTestRunner extends TestBase {
+
+ public static final Class<?> CLASS = DifferentParameterCountMultilineCodeTestSource.class;
+
+ private final TestParameters parameters;
+ private final boolean customSourceFile;
+
+ @Parameterized.Parameters(name = "{0}, custom-source-file:{1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values());
+ }
+
+ public DifferentParameterCountMultilineCodeTestRunner(
+ TestParameters parameters, boolean customSourceFile) {
+ this.parameters = parameters;
+ this.customSourceFile = customSourceFile;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(CLASS)
+ .addKeepMainRule(CLASS)
+ // Keep all the methods but allow renaming.
+ .noTreeShaking()
+ .addKeepAttributeLineNumberTable()
+ .addKeepAttributeSourceFile()
+ .addKeepRules("-renamesourcefileattribute " + (customSourceFile ? "X" : "SourceFile"))
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), CLASS)
+ .assertFailureWithErrorThatThrows(IllegalStateException.class)
+ .inspectOriginalStackTrace(
+ s -> {
+ for (StackTraceLine line : s.getStackTraceLines()) {
+ assertTrue("Expected line number in: " + line, line.hasLineNumber());
+ if (customSourceFile) {
+ assertEquals("X", line.fileName);
+ } else if (parameters
+ .getApiLevel()
+ .isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport())) {
+ assertEquals("Unknown Source", line.fileName);
+ } else {
+ assertEquals("SourceFile", line.fileName);
+ }
+ }
+ assertEquals("Expected 4 stack frames in:\n" + s, 4, s.getStackTraceLines().size());
+ })
+ .inspectStackTrace(
+ retracedStack ->
+ assertThat(
+ retracedStack,
+ StackTrace.isSame(
+ StackTrace.builder()
+ .add(makeLine("args0", 12))
+ .add(makeLine("args1", 17))
+ .add(makeLine("args2", 25))
+ .add(makeLine("main", 32))
+ .build())));
+ }
+
+ private StackTraceLine makeLine(String methodName, int lineNumber) {
+ return StackTraceLine.builder()
+ .setClassName(typeName(CLASS))
+ .setFileName(CLASS.getSimpleName() + ".java")
+ .setMethodName(methodName)
+ .setLineNumber(lineNumber)
+ .build();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestSource.java b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestSource.java
new file mode 100644
index 0000000..221becb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountMultilineCodeTestSource.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2021, 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.debuginfo.pc2pc;
+
+class DifferentParameterCountMultilineCodeTestSource {
+
+ public static void args0() {
+ if (System.nanoTime() < 0) {
+ System.out.println("Not hit...");
+ }
+ throw new IllegalStateException("DONE!");
+ }
+
+ public static void args1(String arg1) {
+ if (!arg1.equals("asdf")) {
+ args0();
+ } else {
+ throw new ArithmeticException("WAT");
+ }
+ }
+
+ public static void args2(String arg1, Object arg2) {
+ if (!arg1.equals(arg2)) {
+ args1(arg1);
+ } else {
+ throw new ArithmeticException("NO");
+ }
+ }
+
+ public static void main(String[] args) {
+ args2(System.nanoTime() < 0 ? args[0] : "foo", args.length > 0 ? args[0] : "bar");
+ throw new ArithmeticException("NO AGAIN");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestRunner.java
new file mode 100644
index 0000000..398ecb4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestRunner.java
@@ -0,0 +1,102 @@
+// Copyright (c) 2021, 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.debuginfo.pc2pc;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DifferentParameterCountSingleLineCodeTestRunner extends TestBase {
+
+ private static final Class<?> CLASS = DifferentParameterCountSingleLineCodeTestSource.class;
+
+ private final TestParameters parameters;
+ private final boolean customSourceFile;
+
+ @Parameterized.Parameters(name = "{0}, custom-source-file:{1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values());
+ }
+
+ public DifferentParameterCountSingleLineCodeTestRunner(
+ TestParameters parameters, boolean customSourceFile) {
+ this.parameters = parameters;
+ this.customSourceFile = customSourceFile;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(CLASS)
+ .addKeepMainRule(CLASS)
+ // Keep all the methods but allow renaming.
+ .noTreeShaking()
+ .addKeepAttributeLineNumberTable()
+ .addKeepAttributeSourceFile()
+ .addKeepRules("-renamesourcefileattribute " + (customSourceFile ? "X" : "SourceFile"))
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), CLASS)
+ .assertFailureWithErrorThatThrows(IllegalStateException.class)
+ .inspectOriginalStackTrace(
+ s -> {
+ for (StackTraceLine line : s.getStackTraceLines()) {
+ if (customSourceFile) {
+ // For a custom source file, all debug info must be present.
+ assertEquals("X", line.fileName);
+ assertTrue("Expected line number in: " + line, line.hasLineNumber());
+ } else if (vmHasPcSupport()) {
+ // Single line debug info is stripped. If running with PC support the PC is
+ // printed.
+ assertEquals("Unknown Source", line.fileName);
+ assertTrue("Expected PC in: " + line, line.hasLineNumber());
+ } else {
+ // Otherwise, just the bare source file is printed.
+ assertEquals("SourceFile", line.fileName);
+ assertFalse("Expected no line number in: " + line, line.hasLineNumber());
+ }
+ }
+ assertEquals("Expected 4 stack frames in:\n" + s, 4, s.getStackTraceLines().size());
+ })
+ .inspectStackTrace(
+ retracedStack ->
+ assertThat(
+ retracedStack,
+ StackTrace.isSame(
+ StackTrace.builder()
+ .add(makeLine("args0", 9))
+ .add(makeLine("args1", 13))
+ .add(makeLine("args2", 17))
+ .add(makeLine("main", 21))
+ .build())));
+ }
+
+ private boolean vmHasPcSupport() {
+ return parameters
+ .asDexRuntime()
+ .maxSupportedApiLevel()
+ .isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport());
+ }
+
+ private StackTraceLine makeLine(String methodName, int lineNumber) {
+ return StackTraceLine.builder()
+ .setClassName(typeName(CLASS))
+ .setFileName(CLASS.getSimpleName() + ".java")
+ .setMethodName(methodName)
+ .setLineNumber(lineNumber)
+ .build();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestSource.java b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestSource.java
new file mode 100644
index 0000000..4f1ea5d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/pc2pc/DifferentParameterCountSingleLineCodeTestSource.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2021, 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.debuginfo.pc2pc;
+
+class DifferentParameterCountSingleLineCodeTestSource {
+
+ public static RuntimeException args0() {
+ throw System.nanoTime() < 0 ? null : new IllegalStateException("DONE!");
+ }
+
+ public static RuntimeException args1(String arg1) {
+ return !arg1.equals("asdf") ? args0() : null;
+ }
+
+ public static RuntimeException args2(String arg1, Object arg2) {
+ return !arg1.equals(arg2) ? args1(arg1) : null;
+ }
+
+ public static void main(String[] args) {
+ throw args2(System.nanoTime() < 0 ? args[0] : "foo", args.length > 0 ? args[0] : "bar");
+ }
+}