blob: 6f5aadeae147a9b90b2eb8ac2675192fb5d5e951 [file] [log] [blame]
// 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.naming;
import static com.android.tools.r8.utils.codeinspector.Matchers.containsLinePositions;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.naming.retrace.StackTrace;
import com.android.tools.r8.naming.testclasses.ClassToBeMinified;
import com.android.tools.r8.naming.testclasses.Main;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.Matchers.LinePosition;
import java.io.IOException;
import java.util.List;
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 RenameSourceFileRetraceTest extends TestBase {
private static final String FILENAME_RENAME = "FOO";
private static final String FILENAME_MAIN = "Main.java";
private static final String FILENAME_CLASS_TO_BE_MINIFIED = "ClassToBeMinified.java";
private final TestParameters parameters;
private final boolean isCompat;
private final boolean keepSourceFile;
@Parameters(name = "{0}, is compat: {1}, keep source file attribute: {2}")
public static List<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
BooleanUtils.values(),
BooleanUtils.values());
}
public RenameSourceFileRetraceTest(
TestParameters parameters, Boolean isCompat, Boolean keepSourceFile) {
this.parameters = parameters;
this.isCompat = isCompat;
this.keepSourceFile = keepSourceFile;
}
@Test
public void testR8()
throws ExecutionException, CompilationFailedException, IOException, NoSuchMethodException {
R8TestBuilder<? extends R8TestBuilder<?>> r8TestBuilder =
isCompat ? testForR8Compat(parameters.getBackend()) : testForR8(parameters.getBackend());
if (keepSourceFile) {
r8TestBuilder.addKeepAttributes(ProguardKeepAttributes.SOURCE_FILE);
}
String minifiedFileName =
(keepSourceFile && isCompat) ? FILENAME_CLASS_TO_BE_MINIFIED : getDefaultExpectedName();
String mainFileName = keepSourceFile ? FILENAME_MAIN : getDefaultExpectedName();
r8TestBuilder
.addProgramClasses(ClassToBeMinified.class, Main.class)
.addKeepAttributes(ProguardKeepAttributes.LINE_NUMBER_TABLE)
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
.enableInliningAnnotations()
.run(parameters.getRuntime(), Main.class)
.assertFailureWithErrorThatMatches(containsString("ClassToBeMinified.foo()"))
.inspectFailure(inspector -> inspectOutput(inspector, minifiedFileName, mainFileName))
.inspectStackTrace(stackTrace -> inspectStackTrace(stackTrace, FILENAME_MAIN));
}
@Test
public void testRenameSourceFileR8()
throws ExecutionException, CompilationFailedException, IOException, NoSuchMethodException {
R8TestBuilder<? extends R8TestBuilder<?>> r8TestBuilder =
isCompat ? testForR8Compat(parameters.getBackend()) : testForR8(parameters.getBackend());
if (keepSourceFile) {
r8TestBuilder.addKeepAttributes(ProguardKeepAttributes.SOURCE_FILE);
}
String expectedName = getDefaultExpectedName(FILENAME_RENAME);
r8TestBuilder
.addProgramClasses(ClassToBeMinified.class, Main.class)
.addKeepAttributes(ProguardKeepAttributes.LINE_NUMBER_TABLE)
.addKeepRules("-renamesourcefileattribute " + FILENAME_RENAME)
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
.enableInliningAnnotations()
.run(parameters.getRuntime(), Main.class)
.assertFailureWithErrorThatMatches(containsString("ClassToBeMinified.foo()"))
.inspectFailure(inspector -> inspectOutput(inspector, expectedName, expectedName))
.inspectStackTrace(stackTrace -> inspectStackTrace(stackTrace, expectedName));
}
private String getDefaultExpectedName() {
return getDefaultExpectedName(parameters.getBackend() == Backend.CF ? "SourceFile" : "");
}
private String getDefaultExpectedName(String name) {
if (!isCompat && !keepSourceFile) {
return null;
} else {
return name;
}
}
private void inspectOutput(
CodeInspector inspector, String classToBeMinifiedFilename, String mainClassFilename) {
inspectSourceFileForClass(inspector, Main.class, mainClassFilename);
inspectSourceFileForClass(inspector, ClassToBeMinified.class, classToBeMinifiedFilename);
}
private void inspectSourceFileForClass(CodeInspector inspector, Class<?> clazz, String expected) {
ClassSubject classToBeMinifiedSubject = inspector.clazz(clazz);
assertThat(classToBeMinifiedSubject, isPresent());
DexClass dexClass = classToBeMinifiedSubject.getDexProgramClass();
String actualString = dexClass.sourceFile == null ? null : dexClass.sourceFile.toString();
assertEquals(expected, actualString);
}
private void inspectStackTrace(StackTrace stackTrace, String mainFileName)
throws NoSuchMethodException {
if (!keepSourceFile) {
return;
}
assertEquals(2, stackTrace.getStackTraceLines().size());
MethodReference classToBeMinifiedFoo =
Reference.methodFromMethod(ClassToBeMinified.class.getDeclaredMethod("foo"));
MethodReference mainMain =
Reference.methodFromMethod(Main.class.getDeclaredMethod("main", String[].class));
LinePosition expectedStack =
LinePosition.stack(
LinePosition.create(classToBeMinifiedFoo, 1, 13, FILENAME_CLASS_TO_BE_MINIFIED),
LinePosition.create(mainMain, 1, 10, mainFileName));
assertThat(stackTrace, containsLinePositions(expectedStack));
}
}