Test for disallowing horizontal merging of classes in main dex list
Bug: 178460068
Change-Id: I7e057546ccd389ce364131453ad0de814c325796
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningTest.java
index 94392e6..8f88d08 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainDexInliningTest.java
@@ -80,7 +80,6 @@
.enableInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
.enableNoStaticClassMergingAnnotations()
- .noMinification()
.setMinApi(parameters.getApiLevel())
.compile();
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainHorizontalMergingTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainHorizontalMergingTest.java
new file mode 100644
index 0000000..867b1ec
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListFromGenerateMainHorizontalMergingTest.java
@@ -0,0 +1,155 @@
+// 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.maindexlist;
+
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.TypeReference;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.BeforeClass;
+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 MainDexListFromGenerateMainHorizontalMergingTest extends TestBase {
+
+ private static List<ClassReference> mainDexList;
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ .withDexRuntimes()
+ .withApiLevelsEndingAtExcluding(apiLevelWithNativeMultiDexSupport())
+ .build();
+ }
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ mainDexList =
+ testForMainDexListGenerator(getStaticTemp())
+ .addInnerClasses(MainDexListFromGenerateMainHorizontalMergingTest.class)
+ .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+ .addMainDexRules(
+ "-keep class " + Main.class.getTypeName() + " { public static void foo(); }")
+ .run()
+ .getMainDexList();
+ }
+
+ public MainDexListFromGenerateMainHorizontalMergingTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ assertEquals(3, mainDexList.size());
+ Set<String> mainDexReferences =
+ mainDexList.stream().map(TypeReference::getTypeName).collect(Collectors.toSet());
+ assertTrue(mainDexReferences.contains(A.class.getTypeName()));
+ assertTrue(mainDexReferences.contains(B.class.getTypeName()));
+ assertTrue(mainDexReferences.contains(Main.class.getTypeName()));
+
+ R8TestCompileResult compileResult =
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addInliningAnnotations()
+ .addKeepClassAndMembersRules(Main.class, Outside.class)
+ .addMainDexListClassReferences(mainDexList)
+ .collectMainDexClasses()
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .addHorizontallyMergedClassesInspector(
+ horizontallyMergedClassesInspector -> {
+ horizontallyMergedClassesInspector.assertMergedInto(B.class, A.class);
+ })
+ .compile();
+
+ CodeInspector inspector = compileResult.inspector();
+ ClassSubject mainClassSubject = inspector.clazz(Main.class);
+ assertThat(mainClassSubject, isPresent());
+
+ MethodSubject fooMethodSubject = mainClassSubject.uniqueMethodWithName("foo");
+ assertThat(fooMethodSubject, isPresent());
+
+ ClassSubject aClassSubject = inspector.clazz(A.class);
+ assertThat(aClassSubject, isPresent());
+
+ // TODO(b/178460068): Should be present, but was merged with A.
+ ClassSubject bClassSubject = inspector.clazz(B.class);
+ assertThat(bClassSubject, isAbsent());
+
+ MethodSubject fooASubject = aClassSubject.uniqueMethodWithName("foo");
+ assertThat(fooASubject, isPresent());
+
+ assertThat(fooMethodSubject, invokesMethod(fooASubject));
+
+ compileResult.inspectMainDexClasses(
+ mainDexClasses -> {
+ assertEquals(
+ ImmutableSet.of(mainClassSubject.getFinalName(), aClassSubject.getFinalName()),
+ mainDexClasses);
+ });
+
+ compileResult
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputThatMatches(containsString(Outside.class.getTypeName()));
+ }
+
+ static class Main {
+
+ // public static B b;
+
+ public static void main(String[] args) {
+ B.print();
+ }
+
+ public static void foo() {
+ A.foo();
+ }
+ }
+
+ public static class Outside {}
+
+ public static class A {
+
+ @NeverInline
+ public static void foo() {
+ System.out.println("A::foo");
+ }
+ }
+
+ @NeverClassInline
+ public static class B {
+
+ @NeverInline
+ public static void print() {
+ System.out.println(Outside.class);
+ }
+ }
+}