Version 1.4.71
Don't use qualified entries in apply-mapping.
Fix and regressions tests added directly to 1.4, to be picked to master.
Bug: 121042934
Change-Id: I610b13ad5ac46c70a5a9624db80fd9ccc1c1f79c
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 30d9b3b..2f7ec60 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.4.70";
+ public static final String LABEL = "1.4.71";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNaming.java b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
index 094dcaf..c76b422 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNaming.java
@@ -106,6 +106,8 @@
abstract void write(Writer builder) throws IOException;
+ boolean isQualified() { return name.contains("."); }
+
@Override
public String toString() {
try {
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
index d95f299..a447e37 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapApplier.java
@@ -191,7 +191,7 @@
// e.g., private methods with same names, could be mapped to a wrong renamed name.
classNaming.forAllFieldNaming(memberNaming -> {
FieldSignature signature = (FieldSignature) memberNaming.getOriginalSignature();
- if (!appliedMemberSignature.contains(signature)) {
+ if (!signature.isQualified() && !appliedMemberSignature.contains(signature)) {
DexField pretendedOriginalField = signature.toDexField(appInfo.dexItemFactory, from);
if (appInfo.definitionFor(pretendedOriginalField) == null) {
applyFieldMapping(pretendedOriginalField, memberNaming);
@@ -200,7 +200,7 @@
});
classNaming.forAllMethodNaming(memberNaming -> {
MethodSignature signature = (MethodSignature) memberNaming.getOriginalSignature();
- if (!appliedMemberSignature.contains(signature)) {
+ if (!signature.isQualified() && !appliedMemberSignature.contains(signature)) {
DexMethod pretendedOriginalMethod = signature.toDexMethod(appInfo.dexItemFactory, from);
if (appInfo.definitionFor(pretendedOriginalMethod) == null) {
applyMethodMapping(pretendedOriginalMethod, memberNaming);
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index e8555d7..7f06ea2 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -12,11 +12,14 @@
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
+import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -45,6 +48,7 @@
private boolean enableUnusedArgumentAnnotations = false;
private CollectingGraphConsumer graphConsumer = null;
private List<String> keepRules = new ArrayList<>();
+ private List<String> applyMappingMaps = new ArrayList<>();
@Override
R8TestBuilder self() {
@@ -70,6 +74,21 @@
builder.setDisableMinification(!enableMinification);
builder.setProguardMapConsumer((string, ignore) -> proguardMapBuilder.append(string));
+ if (!applyMappingMaps.isEmpty()) {
+ try {
+ Path mappingsDir = getState().getNewTempFolder();
+ for (int i = 0; i < applyMappingMaps.size(); i++) {
+ String mapContent = applyMappingMaps.get(i);
+ Path mapPath = mappingsDir.resolve("mapping" + i + ".map");
+ FileUtils.writeTextFile(mapPath, mapContent);
+ builder.addProguardConfiguration(
+ Collections.singletonList("-applymapping " + mapPath.toString()), Origin.unknown());
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
class Box {
private List<ProguardConfigurationRule> syntheticProguardRules;
private ProguardConfiguration proguardConfiguration;
@@ -208,6 +227,11 @@
return self();
}
+ public R8TestBuilder addApplyMapping(String proguardMap) {
+ applyMappingMaps.add(proguardMap);
+ return self();
+ }
+
private void addInternalKeepRules(String... rules) {
// We don't add these to the keep-rule set for other test provided rules.
builder.addProguardConfiguration(Arrays.asList(rules), Origin.unknown());
diff --git a/src/test/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
index ecb0a92..95ec572 100644
--- a/src/test/java/com/android/tools/r8/R8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
@@ -94,4 +94,8 @@
public R8TestRunResult createRunResult(ProcessResult result) {
return new R8TestRunResult(app, result, proguardMap, this::graphInspector);
}
+
+ public String getProguardMap() {
+ return proguardMap;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/TestBaseBuilder.java b/src/test/java/com/android/tools/r8/TestBaseBuilder.java
index 5fcd1b5..1304357 100644
--- a/src/test/java/com/android/tools/r8/TestBaseBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBaseBuilder.java
@@ -4,9 +4,14 @@
package com.android.tools.r8;
+import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.collect.ImmutableMap;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
public abstract class TestBaseBuilder<
C extends BaseCommand,
@@ -43,6 +48,35 @@
return self();
}
+ @Override
+ public T addLibraryClasses(Collection<Class<?>> classes) {
+ builder.addLibraryResourceProvider(
+ new ClassFileResourceProvider() {
+ final Map<String, ProgramResource> resources;
+
+ {
+ ImmutableMap.Builder<String, ProgramResource> builder = ImmutableMap.builder();
+ classes.forEach(
+ c ->
+ builder.put(
+ DescriptorUtils.javaTypeToDescriptor(c.getTypeName()),
+ ProgramResource.fromFile(Kind.CF, ToolHelper.getClassFileForTestClass(c))));
+ resources = builder.build();
+ }
+
+ @Override
+ public Set<String> getClassDescriptors() {
+ return resources.keySet();
+ }
+
+ @Override
+ public ProgramResource getProgramResource(String descriptor) {
+ return resources.get(descriptor);
+ }
+ });
+ return self();
+ }
+
public T addMainDexListFiles(Collection<Path> files) {
builder.addMainDexListFiles(files);
return self();
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index cee2519..30159d3 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -4,6 +4,7 @@
package com.android.tools.r8;
import com.android.tools.r8.debug.DebugTestConfig;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.utils.ListUtils;
import java.io.IOException;
import java.nio.file.Path;
@@ -85,7 +86,7 @@
}
public T addLibraryClasses(Collection<Class<?>> classes) {
- return addLibraryFiles(getFilesForClasses(classes));
+ throw new Unimplemented("Unsupported addLibraryClasses");
}
public T addLibraryFiles(Path... files) {
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index a17ab09..cbf8e81 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -82,6 +82,13 @@
return self();
}
+ public T addKeepClassAndDefaultConstructor(Class<?>... classes) {
+ for (Class<?> clazz : classes) {
+ addKeepRules("-keep class " + clazz.getTypeName() + " { <init>(); }");
+ }
+ return self();
+ }
+
public T addKeepPackageRules(Package pkg) {
return addKeepRules("-keep class " + pkg.getName() + ".*");
}
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
new file mode 100644
index 0000000..bae227f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingFieldTest.java
@@ -0,0 +1,116 @@
+// Copyright (c) 2019, 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.applymapping;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import java.util.Collections;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ApplyMappingAfterHorizontalMergingFieldTest extends TestBase {
+
+ // Will merge with B.
+ public static class LibraryA {
+
+ public static boolean bar;
+ }
+
+ // Will merge with A.
+ public static class LibraryB {
+
+ public static boolean foo;
+ }
+
+ // Ensure kept entry hitting the merged classes.
+ public static class LibraryMain {
+
+ public static void main(String[] args) {
+ LibraryA.bar = System.nanoTime() > 0;
+ LibraryB.foo = args.length < 123;
+ System.out.println(LibraryA.bar && LibraryB.foo);
+ }
+ }
+
+ // Program class simply calling library main.
+ public static class ProgramClass {
+
+ public static void main(String[] args) {
+ LibraryMain.main(args);
+ }
+ }
+
+ // Test runner code follows.
+
+ private static final Class<?>[] LIBRARY_CLASSES = {
+ NeverInline.class,
+ LibraryA.class,
+ LibraryB.class,
+ LibraryMain.class
+ };
+
+ private static final Class<?>[] PROGRAM_CLASSES = {
+ ProgramClass.class
+ };
+
+ private Backend backend;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Backend[] data() {
+ return Backend.values();
+ }
+
+ public ApplyMappingAfterHorizontalMergingFieldTest(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void runOnJvm() throws Throwable {
+ Assume.assumeTrue(backend == Backend.CF);
+ testForJvm()
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addProgramClasses(PROGRAM_CLASSES)
+ .run(ProgramClass.class)
+ .assertSuccessWithOutput(StringUtils.lines("true"));
+ }
+
+ @Test
+ public void b121042934() throws Exception {
+ R8TestCompileResult libraryResult = testForR8(backend)
+ .enableInliningAnnotations()
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addKeepMainRule(LibraryMain.class)
+ .compile();
+
+ CodeInspector inspector = libraryResult.inspector();
+ assertThat(inspector.clazz(LibraryMain.class), isPresent());
+ // Classes A and B have been merged, check only one remains.
+ assertTrue(inspector.clazz(LibraryA.class).isPresent()
+ != inspector.clazz(LibraryB.class).isPresent());
+
+ Path libraryOut = temp.newFolder().toPath().resolve("out.jar");
+ libraryResult.writeToZip(libraryOut);
+ testForR8(backend)
+ .noTreeShaking()
+ .noMinification()
+ .addProgramClasses(PROGRAM_CLASSES)
+ .addApplyMapping(libraryResult.getProguardMap())
+ .addLibraryClasses(LIBRARY_CLASSES)
+ .compile()
+ .addRunClasspath(Collections.singletonList(libraryOut))
+ .run(ProgramClass.class)
+ .assertSuccessWithOutput(StringUtils.lines("true"));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingMethodTest.java
new file mode 100644
index 0000000..88cb16a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterHorizontalMergingMethodTest.java
@@ -0,0 +1,120 @@
+// Copyright (c) 2019, 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.applymapping;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import java.util.Collections;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ApplyMappingAfterHorizontalMergingMethodTest extends TestBase {
+
+ // Will merge with B.
+ public static class LibraryA {
+
+ @NeverInline
+ public static String bar() {
+ return "LibraryA::foo";
+ }
+ }
+
+ // Will merge with A.
+ public static class LibraryB {
+
+ @NeverInline
+ public static String foo() {
+ return LibraryA.bar();
+ }
+ }
+
+ // Ensure kept entry hitting the merged classes.
+ public static class LibraryMain {
+
+ public static void main(String[] args) {
+ System.out.println(LibraryB.foo());
+ }
+ }
+
+ // Program class simply calling library main.
+ public static class ProgramClass {
+
+ public static void main(String[] args) {
+ LibraryMain.main(args);
+ }
+ }
+
+ // Test runner code follows.
+
+ private static final Class<?>[] LIBRARY_CLASSES = {
+ NeverInline.class,
+ LibraryA.class,
+ LibraryB.class,
+ LibraryMain.class
+ };
+
+ private static final Class<?>[] PROGRAM_CLASSES = {
+ ProgramClass.class
+ };
+
+ private Backend backend;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Backend[] data() {
+ return Backend.values();
+ }
+
+ public ApplyMappingAfterHorizontalMergingMethodTest(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void runOnJvm() throws Throwable {
+ Assume.assumeTrue(backend == Backend.CF);
+ testForJvm()
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addProgramClasses(PROGRAM_CLASSES)
+ .run(ProgramClass.class)
+ .assertSuccessWithOutput(StringUtils.lines("LibraryA::foo"));
+ }
+
+ @Test
+ public void b121042934() throws Exception {
+ R8TestCompileResult libraryResult = testForR8(backend)
+ .enableInliningAnnotations()
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addKeepMainRule(LibraryMain.class)
+ .compile();
+
+ CodeInspector inspector = libraryResult.inspector();
+ assertThat(inspector.clazz(LibraryMain.class), isPresent());
+ // Classes A and B have been merged, check only one remains.
+ assertTrue(inspector.clazz(LibraryA.class).isPresent()
+ != inspector.clazz(LibraryB.class).isPresent());
+
+ Path libraryOut = temp.newFolder().toPath().resolve("out.jar");
+ libraryResult.writeToZip(libraryOut);
+ testForR8(backend)
+ .noTreeShaking()
+ .noMinification()
+ .addProgramClasses(PROGRAM_CLASSES)
+ .addApplyMapping(libraryResult.getProguardMap())
+ .addLibraryClasses(LIBRARY_CLASSES)
+ .compile()
+ .addRunClasspath(Collections.singletonList(libraryOut))
+ .run(ProgramClass.class)
+ .assertSuccessWithOutput(StringUtils.lines("LibraryA::foo"));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingFieldTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingFieldTest.java
new file mode 100644
index 0000000..2a35205
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingFieldTest.java
@@ -0,0 +1,107 @@
+// Copyright (c) 2018, 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.applymapping;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import java.util.Collections;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ApplyMappingAfterVerticalMergingFieldTest extends TestBase {
+
+ // Base class will be vertical class merged into subclass
+ public static class LibraryBase {
+
+ public boolean foo = System.nanoTime() > 0;
+ }
+
+ // Subclass targeted via vertical class merging. The main method ensures a reference to foo.
+ public static class LibrarySubclass extends LibraryBase {
+
+ public static void main(String[] args) {
+ System.out.println(new LibrarySubclass().foo);
+ }
+ }
+
+ // Program class that uses LibrarySubclass but the library does not explicitly keep foo and
+ // should thus fail at runtime.
+ public static class ProgramClass extends LibrarySubclass {
+
+ public static void main(String[] args) {
+ System.out.println(new ProgramClass().foo);
+ }
+ }
+
+ // Test runner code follows.
+
+ private static final Class<?>[] LIBRARY_CLASSES = {
+ NeverMerge.class, LibraryBase.class, LibrarySubclass.class
+ };
+
+ private static final Class<?>[] PROGRAM_CLASSES = {
+ ProgramClass.class
+ };
+
+ private Backend backend;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Backend[] data() {
+ return Backend.values();
+ }
+
+ public ApplyMappingAfterVerticalMergingFieldTest(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void runOnJvm() throws Throwable {
+ Assume.assumeTrue(backend == Backend.CF);
+ testForJvm()
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addProgramClasses(PROGRAM_CLASSES)
+ .run(ProgramClass.class)
+ .assertSuccessWithOutput(StringUtils.lines("true"));
+ }
+
+ @Test
+ public void b121042934() throws Exception {
+ R8TestCompileResult libraryResult = testForR8(backend)
+ .enableInliningAnnotations()
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addKeepMainRule(LibrarySubclass.class)
+ .addKeepClassAndDefaultConstructor(LibrarySubclass.class)
+ .compile();
+
+ CodeInspector inspector = libraryResult.inspector();
+ assertThat(inspector.clazz(LibraryBase.class), not(isPresent()));
+ assertThat(inspector.clazz(LibrarySubclass.class), isPresent());
+
+ Path libraryOut = temp.newFolder().toPath().resolve("out.jar");
+ libraryResult.writeToZip(libraryOut);
+ testForR8(backend)
+ .noTreeShaking()
+ .noMinification()
+ .addProgramClasses(PROGRAM_CLASSES)
+ .addApplyMapping(libraryResult.getProguardMap())
+ .addLibraryClasses(LIBRARY_CLASSES)
+ .compile()
+ .addRunClasspath(Collections.singletonList(libraryOut))
+ .run(ProgramClass.class)
+ .assertFailureWithErrorThatMatches(containsString("NoSuchFieldError"));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
new file mode 100644
index 0000000..9d2000e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
@@ -0,0 +1,110 @@
+// Copyright (c) 2018, 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.applymapping;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import java.util.Collections;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ApplyMappingAfterVerticalMergingMethodTest extends TestBase {
+
+ // Base class will be vertical class merged into subclass
+ public static class LibraryBase {
+
+ @NeverInline
+ public String foo() {
+ return "LibraryBase::foo";
+ }
+ }
+
+ // Subclass targeted via vertical class merging. The main method ensures a reference to foo.
+ public static class LibrarySubclass extends LibraryBase {
+
+ public static void main(String[] args) {
+ System.out.println(new LibrarySubclass().foo());
+ }
+ }
+
+ // Program class that uses LibrarySubclass but the library does not explicitly keep foo and
+ // should thus fail at runtime.
+ public static class ProgramClass extends LibrarySubclass {
+
+ public static void main(String[] args) {
+ System.out.println(new ProgramClass().foo());
+ }
+ }
+
+ // Test runner code follows.
+
+ private static final Class<?>[] LIBRARY_CLASSES = {
+ NeverMerge.class, LibraryBase.class, LibrarySubclass.class
+ };
+
+ private static final Class<?>[] PROGRAM_CLASSES = {
+ ProgramClass.class
+ };
+
+ private Backend backend;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Backend[] data() {
+ return Backend.values();
+ }
+
+ public ApplyMappingAfterVerticalMergingMethodTest(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void runOnJvm() throws Throwable {
+ Assume.assumeTrue(backend == Backend.CF);
+ testForJvm()
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addProgramClasses(PROGRAM_CLASSES)
+ .run(ProgramClass.class)
+ .assertSuccessWithOutput(StringUtils.lines("LibraryBase::foo"));
+ }
+
+ @Test
+ public void b121042934() throws Exception {
+ R8TestCompileResult libraryResult = testForR8(backend)
+ .enableInliningAnnotations()
+ .addProgramClasses(LIBRARY_CLASSES)
+ .addKeepMainRule(LibrarySubclass.class)
+ .addKeepClassAndDefaultConstructor(LibrarySubclass.class)
+ .compile();
+
+ CodeInspector inspector = libraryResult.inspector();
+ assertThat(inspector.clazz(LibraryBase.class), not(isPresent()));
+ assertThat(inspector.clazz(LibrarySubclass.class), isPresent());
+
+ Path libraryOut = temp.newFolder().toPath().resolve("out.jar");
+ libraryResult.writeToZip(libraryOut);
+ testForR8(backend)
+ .noTreeShaking()
+ .noMinification()
+ .addProgramClasses(PROGRAM_CLASSES)
+ .addApplyMapping(libraryResult.getProguardMap())
+ .addLibraryClasses(LIBRARY_CLASSES)
+ .compile()
+ .addRunClasspath(Collections.singletonList(libraryOut))
+ .run(ProgramClass.class)
+ .assertFailureWithErrorThatMatches(containsString("NoSuchMethodError"));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingTest.java
deleted file mode 100644
index 8856f47..0000000
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2018, 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.applymapping;
-
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isRenamed;
-import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import com.android.tools.r8.NeverMerge;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.FieldSubject;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import java.lang.ref.WeakReference;
-import java.nio.file.Path;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-class Resources {
-}
-
-@NeverMerge
-class ResourceWrapper extends Resources {
- // Will be merged down, and represented as:
- // ...applymapping.Resources ...applymapping.ResourceWrapper.mResources -> a
- private Resources mResources;
-
- ResourceWrapper(Resources resource) {
- this.mResources = resource;
- }
-
- // Will be merged down, and represented as:
- // java.lang.String ...applymapping.ResourceWrapper.foo() -> a
- String foo() {
- return mResources.toString();
- }
-
- @Override
- public String toString() {
- return mResources.toString();
- }
-}
-
-class TintResources extends ResourceWrapper {
- private WeakReference<Resources> ref;
-
- TintResources(Resources resource) {
- super(resource);
- ref = new WeakReference<>(resource);
- }
-
- public static void main(String[] args) {
- TintResources t = new TintResources(new Resources());
- System.out.println(t.foo());
- }
-}
-
-@RunWith(Parameterized.class)
-public class ApplyMappingAfterVerticalMergingTest extends TestBase {
- private final static Class<?>[] CLASSES = {
- NeverMerge.class, Resources.class, ResourceWrapper.class, TintResources.class
- };
- private final static Class<?> MAIN = TintResources.class;
-
- private Backend backend;
-
- @Parameterized.Parameters(name = "Backend: {0}")
- public static Backend[] data() {
- return Backend.values();
- }
-
- public ApplyMappingAfterVerticalMergingTest(Backend backend) {
- this.backend = backend;
- }
-
- @Ignore("b/12042934")
- @Test
- public void b121042934() throws Exception {
- Path mapPath = temp.newFile("test-mapping.txt").toPath();
- CodeInspector inspector1 = testForR8(backend)
- .addProgramClasses(CLASSES)
- .addKeepMainRule(MAIN)
- .addKeepRules("-printmapping " + mapPath.toAbsolutePath())
- .compile()
- .inspector();
- CodeInspector inspector2 = testForR8(backend)
- .addProgramClasses(CLASSES)
- .addKeepMainRule(MAIN)
- .addKeepRules("-applymapping " + mapPath.toAbsolutePath())
- .compile()
- .inspector();
-
- ClassSubject classSubject1 = inspector1.clazz(MAIN);
- assertThat(classSubject1, isPresent());
- assertThat(classSubject1, isRenamed());
- ClassSubject classSubject2 = inspector2.clazz(
- DescriptorUtils.getClassNameFromDescriptor(classSubject1.getFinalDescriptor()));
- assertThat(classSubject2, isPresent());
- assertThat(classSubject2, not(isRenamed()));
- assertEquals(classSubject1.getFinalDescriptor(), classSubject2.getFinalDescriptor());
-
- FieldSubject field1 = classSubject1.uniqueFieldWithName("mResources");
- assertThat(field1, isPresent());
- assertThat(field1, isRenamed());
- FieldSubject field2 = classSubject2.uniqueFieldWithName("mResources");
- assertThat(field2, isPresent());
- assertThat(field2, not(isRenamed()));
- assertEquals(field1.getFinalSignature().toString(), field2.getFinalSignature().toString());
-
- MethodSubject method1 = classSubject1.uniqueMethodWithName("foo");
- assertThat(method1, isPresent());
- assertThat(method1, isRenamed());
- MethodSubject method2 = classSubject2.uniqueMethodWithName("foo");
- assertThat(method2, isPresent());
- assertThat(method2, not(isRenamed()));
- assertEquals(method1.getFinalSignature().toString(), method2.getFinalSignature().toString());
- }
-
-}