Only merge classes if the subclass has at least same visibility

Change-Id: Ie2632feae38e94ac6203a5f20f35fa7985a78214
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 08722c3..b11e33d 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -207,9 +207,13 @@
     return true;
   }
 
-  private boolean mergeMayLeadToIllegalAccesses(DexClass clazz, DexClass singleSubclass) {
-    if (clazz.type.isSamePackage(singleSubclass.type)) {
-      return false;
+  private boolean mergeMayLeadToIllegalAccesses(DexClass source, DexClass target) {
+    if (source.type.isSamePackage(target.type)) {
+      int accessLevel =
+          source.accessFlags.isPrivate() ? 0 : (source.accessFlags.isPublic() ? 2 : 1);
+      int otherAccessLevel =
+          target.accessFlags.isPrivate() ? 0 : (target.accessFlags.isPublic() ? 2 : 1);
+      return accessLevel > otherAccessLevel;
     }
     // TODO(christofferqa): To merge [clazz] into a class from another package we need to ensure:
     // (A) All accesses to [clazz] and its members from inside the current package of [clazz] will
diff --git a/src/test/examples/classmerging/SimpleInterface.java b/src/test/examples/classmerging/SimpleInterface.java
deleted file mode 100644
index e8ebcab..0000000
--- a/src/test/examples/classmerging/SimpleInterface.java
+++ /dev/null
@@ -1,9 +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 classmerging;
-
-public interface SimpleInterface {
-  void foo();
-}
diff --git a/src/test/examples/classmerging/SimpleInterfaceAccessTest.java b/src/test/examples/classmerging/SimpleInterfaceAccessTest.java
index 04b5386..ce7bf14 100644
--- a/src/test/examples/classmerging/SimpleInterfaceAccessTest.java
+++ b/src/test/examples/classmerging/SimpleInterfaceAccessTest.java
@@ -8,9 +8,35 @@
 
 public class SimpleInterfaceAccessTest {
   public static void main(String[] args) {
-    // It is not possible to merge the interface SimpleInterface into SimpleInterfaceImpl, since
-    // this would lead to an illegal class access here.
-    SimpleInterface obj = SimpleInterfaceImplRetriever.getSimpleInterfaceImpl();
-    obj.foo();
+    // Without access modifications, it is not possible to merge the interface SimpleInterface into
+    // SimpleInterfaceImpl, since this would lead to an illegal class access here.
+    SimpleInterface x = SimpleInterfaceImplRetriever.getSimpleInterfaceImpl();
+    x.foo();
+
+    // Without access modifications, it is not possible to merge the interface OtherSimpleInterface
+    // into OtherSimpleInterfaceImpl, since this could lead to an illegal class access if another
+    // package references OtherSimpleInterface.
+    OtherSimpleInterface y = new OtherSimpleInterfaceImpl();
+    y.bar();
+  }
+
+  // Should only be merged into OtherSimpleInterfaceImpl if access modifications are allowed.
+  public interface SimpleInterface {
+
+    void foo();
+  }
+
+  // Should only be merged into OtherSimpleInterfaceImpl if access modifications are allowed.
+  public interface OtherSimpleInterface {
+
+    void bar();
+  }
+
+  private static class OtherSimpleInterfaceImpl implements OtherSimpleInterface {
+
+    @Override
+    public void bar() {
+      System.out.println("In bar on OtherSimpleInterfaceImpl");
+    }
   }
 }
diff --git a/src/test/examples/classmerging/pkg/SimpleInterfaceImplRetriever.java b/src/test/examples/classmerging/pkg/SimpleInterfaceImplRetriever.java
index 5cfa11e..22391e9 100644
--- a/src/test/examples/classmerging/pkg/SimpleInterfaceImplRetriever.java
+++ b/src/test/examples/classmerging/pkg/SimpleInterfaceImplRetriever.java
@@ -4,7 +4,7 @@
 
 package classmerging.pkg;
 
-import classmerging.SimpleInterface;
+import classmerging.SimpleInterfaceAccessTest.SimpleInterface;
 
 public class SimpleInterfaceImplRetriever {
 
diff --git a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
index 2e983bd..f141d36 100644
--- a/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/ClassMergingTest.java
@@ -36,7 +36,6 @@
 import java.util.concurrent.ExecutionException;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
-import org.junit.Ignore;
 import org.junit.Test;
 
 // TODO(christofferqa): Add tests to check that statically typed invocations on method handles
@@ -270,8 +269,10 @@
     String main = "classmerging.SimpleInterfaceAccessTest";
     Path[] programFiles =
         new Path[] {
-          CF_DIR.resolve("SimpleInterface.class"),
           CF_DIR.resolve("SimpleInterfaceAccessTest.class"),
+          CF_DIR.resolve("SimpleInterfaceAccessTest$SimpleInterface.class"),
+          CF_DIR.resolve("SimpleInterfaceAccessTest$OtherSimpleInterface.class"),
+          CF_DIR.resolve("SimpleInterfaceAccessTest$OtherSimpleInterfaceImpl.class"),
           CF_DIR.resolve("pkg/SimpleInterfaceImplRetriever.class"),
           CF_DIR.resolve("pkg/SimpleInterfaceImplRetriever$SimpleInterfaceImpl.class")
         };
@@ -279,14 +280,15 @@
     // is in a different package and is not public.
     ImmutableSet<String> preservedClassNames =
         ImmutableSet.of(
-            "classmerging.SimpleInterface",
             "classmerging.SimpleInterfaceAccessTest",
+            "classmerging.SimpleInterfaceAccessTest$SimpleInterface",
+            "classmerging.SimpleInterfaceAccessTest$OtherSimpleInterface",
+            "classmerging.SimpleInterfaceAccessTest$OtherSimpleInterfaceImpl",
             "classmerging.pkg.SimpleInterfaceImplRetriever",
             "classmerging.pkg.SimpleInterfaceImplRetriever$SimpleInterfaceImpl");
     runTest(main, programFiles, preservedClassNames::contains);
   }
 
-  @Ignore("b/73958515")
   @Test
   public void testNoIllegalClassAccessWithAccessModifications() throws Exception {
     // If access modifications are allowed then SimpleInterface should be merged into
@@ -294,14 +296,20 @@
     String main = "classmerging.SimpleInterfaceAccessTest";
     Path[] programFiles =
         new Path[] {
-          CF_DIR.resolve("SimpleInterface.class"),
           CF_DIR.resolve("SimpleInterfaceAccessTest.class"),
+          CF_DIR.resolve("SimpleInterfaceAccessTest$SimpleInterface.class"),
+          CF_DIR.resolve("SimpleInterfaceAccessTest$OtherSimpleInterface.class"),
+          CF_DIR.resolve("SimpleInterfaceAccessTest$OtherSimpleInterfaceImpl.class"),
           CF_DIR.resolve("pkg/SimpleInterfaceImplRetriever.class"),
           CF_DIR.resolve("pkg/SimpleInterfaceImplRetriever$SimpleInterfaceImpl.class")
         };
     ImmutableSet<String> preservedClassNames =
         ImmutableSet.of(
             "classmerging.SimpleInterfaceAccessTest",
+            // TODO(christofferqa): Should be able to merge SimpleInterface into SimpleInterfaceImpl
+            // when access modifications are allowed.
+            "classmerging.SimpleInterfaceAccessTest$SimpleInterface",
+            "classmerging.SimpleInterfaceAccessTest$OtherSimpleInterfaceImpl",
             "classmerging.pkg.SimpleInterfaceImplRetriever",
             "classmerging.pkg.SimpleInterfaceImplRetriever$SimpleInterfaceImpl");
     // Allow access modifications (and prevent SimpleInterfaceImplRetriever from being removed as