Merge "Add failing test for default interface desugaring and apply mapping."
diff --git a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
index 3bd33f7..0225784 100644
--- a/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ExternalR8TestBuilder.java
@@ -131,6 +131,11 @@
}
@Override
+ public ExternalR8TestBuilder addApplyMapping(String proguardMap) {
+ throw new Unimplemented("No support for adding mapfile content yet");
+ }
+
+ @Override
public ExternalR8TestBuilder addDataEntryResources(DataEntryResource... resources) {
throw new Unimplemented("No support for adding data entry resources");
}
diff --git a/src/test/java/com/android/tools/r8/JvmTestBuilder.java b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
index 06ddf44..f7af253 100644
--- a/src/test/java/com/android/tools/r8/JvmTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/JvmTestBuilder.java
@@ -124,6 +124,11 @@
}
@Override
+ public JvmTestBuilder addLibraryClasses(Collection<Class<?>> classes) {
+ throw new Unimplemented("No support for changing the Java runtime library.");
+ }
+
+ @Override
public JvmTestBuilder addProgramClasses(Collection<Class<?>> classes) {
addProgramResources(ListUtils.map(classes, ClassFileResource::new));
return self();
diff --git a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
index 51dbd51..ac3b582 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -181,6 +181,11 @@
}
@Override
+ public ProguardTestBuilder addApplyMapping(String proguardMap) {
+ throw new Unimplemented("No support for adding mapfile content yet");
+ }
+
+ @Override
public ProguardTestBuilder addDataEntryResources(DataEntryResource... resources) {
throw new Unimplemented("No support for adding data entry resources");
}
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 4d0d9ae..01b6cee 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;
@@ -47,6 +50,7 @@
private CollectingGraphConsumer graphConsumer = null;
private List<String> keepRules = new ArrayList<>();
private List<Path> mainDexRulesFiles = new ArrayList<>();
+ private List<String> applyMappingMaps = new ArrayList<>();
@Override
R8TestBuilder self() {
@@ -74,6 +78,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;
@@ -240,6 +259,12 @@
return self();
}
+ @Override
+ 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/TestBaseBuilder.java b/src/test/java/com/android/tools/r8/TestBaseBuilder.java
index fda7025..7e21839f 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,
@@ -51,6 +56,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 e6a5bbe..858e1bb 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -90,9 +90,7 @@
return addLibraryClasses(Arrays.asList(classes));
}
- public T addLibraryClasses(Collection<Class<?>> classes) {
- return addLibraryFiles(getFilesForClasses(classes));
- }
+ public abstract T addLibraryClasses(Collection<Class<?>> classes);
public T addLibraryFiles(Path... files) {
return addLibraryFiles(Arrays.asList(files));
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index d74fab5..6883d1d 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -5,6 +5,7 @@
import static com.android.tools.r8.TestBase.Backend.DEX;
+import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer;
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.ProcessResult;
@@ -13,12 +14,15 @@
import com.android.tools.r8.debug.DexDebugTestConfig;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
@@ -58,11 +62,43 @@
}
}
- public CR addRunClasspath(List<Path> classpath) {
+ public CR addRunClasspathFiles(Path... classpath) {
+ return addRunClasspathFiles(Arrays.asList(classpath));
+ }
+
+ public CR addRunClasspathFiles(List<Path> classpath) {
additionalRunClassPath.addAll(classpath);
return self();
}
+ public CR addRunClasspathClasses(Class<?>... classpath) {
+ return addRunClasspathClasses(Arrays.asList(classpath));
+ }
+
+ public CR addRunClasspathClasses(List<Class<?>> classpath) {
+ try {
+ Path path = state.getNewTempFolder().resolve("runtime-classes.jar");
+ ArchiveConsumer consumer = new ArchiveConsumer(path);
+ for (Class clazz : classpath) {
+ consumer.accept(
+ ByteDataView.of(ToolHelper.getClassAsBytes(clazz)),
+ DescriptorUtils.javaTypeToDescriptor(clazz.getTypeName()),
+ null);
+ }
+ consumer.finished(null);
+ additionalRunClassPath.addAll(Collections.singletonList(path));
+ return self();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Path writeToZip() throws IOException {
+ Path file = state.getNewTempFolder().resolve("out.zip");
+ writeToZip(file);
+ return file;
+ }
+
public CR writeToZip(Path file) throws IOException {
app.writeToZip(file, getBackend() == DEX ? OutputMode.DexIndexed : OutputMode.ClassFile);
return self();
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index a17ab09..7f428f9 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -107,6 +107,8 @@
return self();
}
+ public abstract T addApplyMapping(String proguardMap);
+
private static String getMethodLine(MethodReference method) {
// Should we encode modifiers in method references?
StringBuilder builder = new StringBuilder();
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
new file mode 100644
index 0000000..6c3af2b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
@@ -0,0 +1,98 @@
+// 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.desugar;
+
+import static org.hamcrest.CoreMatchers.containsString;
+
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Assume;
+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 DefaultInterfaceMethodTest extends TestBase {
+
+ public static final String OUTPUT = "Called LibraryInterface::foo";
+ public static final String EXPECTED = StringUtils.lines(OUTPUT);
+
+ public interface LibraryInterface {
+ default void foo() {
+ System.out.println(OUTPUT);
+ }
+ }
+
+ public static class ProgramClass implements LibraryInterface {
+
+ public static void main(String[] args) {
+ new ProgramClass().foo();
+ }
+ }
+
+ @Parameters(name = "{0}")
+ public static Backend[] data() {
+ return Backend.values();
+ }
+
+ private final Backend backend;
+
+ public DefaultInterfaceMethodTest(Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void testJvm() throws Throwable {
+ Assume.assumeTrue(backend == Backend.CF);
+ testForJvm()
+ .addProgramClasses(LibraryInterface.class, ProgramClass.class)
+ .run(ProgramClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void testFullProgram() throws Throwable {
+ testForR8(backend)
+ .addProgramClasses(LibraryInterface.class, ProgramClass.class)
+ .addKeepMainRule(ProgramClass.class)
+ .run(ProgramClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void testLibraryLinkedWithProgram() throws Throwable {
+ R8TestCompileResult libraryResult =
+ testForR8(backend)
+ .addProgramClasses(LibraryInterface.class)
+ .addKeepRules("-keep class " + LibraryInterface.class.getTypeName() + " { *; }")
+ .compile();
+
+ R8TestRunResult result =
+ testForR8(backend)
+ .noTreeShaking()
+ .noMinification()
+ .addProgramClasses(ProgramClass.class)
+ .addLibraryClasses(LibraryInterface.class)
+ .addApplyMapping(libraryResult.getProguardMap())
+ .compile()
+ .addRunClasspathFiles(libraryResult.writeToZip())
+ .run(ProgramClass.class);
+
+ if (backend == Backend.DEX && willDesugarDefaultInterfaceMethods()) {
+ // TODO(b/127779880): The use of the default lambda will fail in case of desugaring.
+ result.assertFailureWithErrorThatMatches(containsString("AbstractMethodError"));
+ } else {
+ result.assertSuccessWithOutput(EXPECTED);
+ }
+ }
+
+ private static boolean willDesugarDefaultInterfaceMethods() {
+ return ToolHelper.getMinApiLevelForDexVm().getLevel() < AndroidApiLevel.N.getLevel();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java b/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
index dd11dc1..ffe6c21 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumevalues/SynthesizedRulesFromApiLevelTest.java
@@ -177,7 +177,7 @@
syntheticProguardRules ->
checkSynthesizedRuleExpectation(syntheticProguardRules, synthesizedRule))
.inspect(inspector)
- .addRunClasspath(ImmutableList.of(buildMockAndroidRuntimeLibrary(runtimeApiLevel)))
+ .addRunClasspathFiles(ImmutableList.of(buildMockAndroidRuntimeLibrary(runtimeApiLevel)))
.run(mainClassName)
.assertSuccessWithOutput(expectedOutput);
} else {
@@ -188,7 +188,7 @@
.addKeepRules(additionalKeepRules)
.compile()
.inspectProguardConfiguration(this::noSynthesizedRules)
- .addRunClasspath(
+ .addRunClasspathFiles(
ImmutableList.of(mockAndroidRuntimeLibrary(AndroidApiLevel.D.getLevel())))
.run(mainClassName)
.assertSuccessWithOutput(expectedResultForCompat(AndroidApiLevel.D));