|  | // Copyright (c) 2020, 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; | 
|  |  | 
|  | import static com.android.tools.r8.Collectors.toSingle; | 
|  | import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineFrame; | 
|  | import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineStack; | 
|  | import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent; | 
|  | import static com.android.tools.r8.utils.codeinspector.Matchers.isTopOfStackTrace; | 
|  | import static junit.framework.TestCase.assertEquals; | 
|  | import static junit.framework.TestCase.assertNotNull; | 
|  | import static junit.framework.TestCase.assertNull; | 
|  | import static org.hamcrest.CoreMatchers.containsString; | 
|  | import static org.hamcrest.CoreMatchers.not; | 
|  | import static org.hamcrest.MatcherAssert.assertThat; | 
|  |  | 
|  | import com.android.tools.r8.CompilationFailedException; | 
|  | import com.android.tools.r8.TestBase; | 
|  | import com.android.tools.r8.TestParameters; | 
|  | import com.android.tools.r8.TestParametersCollection; | 
|  | import com.android.tools.r8.ToolHelper.DexVm.Version; | 
|  | import com.android.tools.r8.references.Reference; | 
|  | import com.android.tools.r8.retrace.RetraceMethodResult; | 
|  | 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; | 
|  | import com.android.tools.r8.utils.codeinspector.FoundMethodSubject; | 
|  | import com.android.tools.r8.utils.codeinspector.InstructionSubject; | 
|  | import com.android.tools.r8.utils.codeinspector.Matchers.LinePosition; | 
|  | import com.android.tools.r8.utils.codeinspector.MethodSubject; | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import java.io.IOException; | 
|  | import java.util.concurrent.ExecutionException; | 
|  | import org.junit.Test; | 
|  | import org.junit.runner.RunWith; | 
|  | import org.junit.runners.Parameterized; | 
|  | import org.junit.runners.Parameterized.Parameters; | 
|  |  | 
|  | @RunWith(Parameterized.class) | 
|  | public class DexPcWithDebugInfoForOverloadedMethodsTestRunner extends TestBase { | 
|  |  | 
|  | private static final String FILENAME_INLINE = "InlineFunction.kt"; | 
|  | private static final Class<?> MAIN = DexPcWithDebugInfoForOverloadedMethodsTest.class; | 
|  | private static final int MINIFIED_LINE_POSITION = 6; | 
|  | private static final String EXPECTED = "java.lang.RuntimeException: overloaded(String)42"; | 
|  | private final TestParameters parameters; | 
|  |  | 
|  | @Parameters(name = "{0}") | 
|  | public static TestParametersCollection data() { | 
|  | return getTestParameters() | 
|  | .withDexRuntimesStartingFromIncluding(Version.V8_1_0) | 
|  | .withApiLevelsStartingAtIncluding(AndroidApiLevel.O) | 
|  | .build(); | 
|  | } | 
|  |  | 
|  | public DexPcWithDebugInfoForOverloadedMethodsTestRunner(TestParameters parameters) { | 
|  | this.parameters = parameters; | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testEmittedDebugInfoForOverloads() | 
|  | throws ExecutionException, CompilationFailedException, IOException, NoSuchMethodException { | 
|  | testForR8(parameters.getBackend()) | 
|  | .addProgramClasses(MAIN) | 
|  | .addKeepMainRule(MAIN) | 
|  | .addKeepMethodRules(MAIN, "void overloaded(...)") | 
|  | .addKeepAttributeLineNumberTable() | 
|  | .addKeepAttributes(ProguardKeepAttributes.SOURCE_FILE) | 
|  | .setMinApi(parameters.getApiLevel()) | 
|  | .addOptionsModification( | 
|  | internalOptions -> { | 
|  | // TODO(b/37830524): Remove when activated. | 
|  | internalOptions.enablePcDebugInfoOutput = true; | 
|  | }) | 
|  | .run(parameters.getRuntime(), MAIN) | 
|  | .assertFailureWithErrorThatMatches(containsString(EXPECTED)) | 
|  | .inspectOriginalStackTrace( | 
|  | (stackTrace, inspector) -> { | 
|  | assertEquals(MAIN.getTypeName(), stackTrace.get(0).className); | 
|  | assertEquals("overloaded", stackTrace.get(0).methodName); | 
|  | assertThat(stackTrace.get(0).fileName, not("Unknown Source")); | 
|  | inspect(inspector); | 
|  | }) | 
|  | .inspectStackTrace( | 
|  | (stackTrace, codeInspector) -> { | 
|  | MethodSubject throwingSubject = | 
|  | codeInspector.clazz(MAIN).method("void", "overloaded", "java.lang.String"); | 
|  | assertThat(throwingSubject, isPresent()); | 
|  | LinePosition inlineStack = | 
|  | LinePosition.stack( | 
|  | LinePosition.create( | 
|  | Reference.methodFromMethod( | 
|  | MAIN.getDeclaredMethod("inlinee", String.class)), | 
|  | MINIFIED_LINE_POSITION, | 
|  | 11, | 
|  | FILENAME_INLINE), | 
|  | LinePosition.create( | 
|  | Reference.methodFromMethod( | 
|  | MAIN.getDeclaredMethod("overloaded", String.class)), | 
|  | MINIFIED_LINE_POSITION, | 
|  | 20, | 
|  | FILENAME_INLINE)); | 
|  | RetraceMethodResult retraceResult = | 
|  | throwingSubject | 
|  | .streamInstructions() | 
|  | .filter(InstructionSubject::isThrow) | 
|  | .collect(toSingle()) | 
|  | .retraceLinePosition(codeInspector.retrace()); | 
|  | assertThat(retraceResult, isInlineFrame()); | 
|  | assertThat(retraceResult, isInlineStack(inlineStack)); | 
|  | assertThat( | 
|  | retraceResult, | 
|  | isTopOfStackTrace( | 
|  | stackTrace, | 
|  | ImmutableList.of(MINIFIED_LINE_POSITION, MINIFIED_LINE_POSITION))); | 
|  | }); | 
|  | } | 
|  |  | 
|  | private void inspect(CodeInspector inspector) { | 
|  | ClassSubject clazz = inspector.clazz(MAIN); | 
|  | assertThat(clazz, isPresent()); | 
|  | assertEquals(3, clazz.allMethods().size()); | 
|  | for (FoundMethodSubject method : clazz.allMethods()) { | 
|  | if (method.getOriginalName().equals("main")) { | 
|  | assertNull(method.getMethod().getCode().asDexCode().getDebugInfo()); | 
|  | } else { | 
|  | assertEquals("overloaded", method.getOriginalName()); | 
|  | assertNotNull(method.getMethod().getCode().asDexCode().getDebugInfo()); | 
|  | } | 
|  | } | 
|  | } | 
|  | } |