Version 1.5.54

Cherry pick: Publicize inner class attribute access flags
CL: https://r8-review.googlesource.com/c/r8/+/40099

Bug: 136236245, 136079178
Change-Id: I6001fa706b2822a161171d6905088bda78c479f0
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 2c62373..8038d4e 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.5.53";
+  public static final String LABEL = "1.5.54";
 
   private Version() {
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 928cb27..3429bb3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -20,6 +20,7 @@
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Consumer;
@@ -828,6 +829,18 @@
     return null;
   }
 
+  public void replaceInnerClassAttributeForThisClass(InnerClassAttribute newInnerClassAttribute) {
+    ListIterator<InnerClassAttribute> iterator = getInnerClasses().listIterator();
+    while (iterator.hasNext()) {
+      InnerClassAttribute innerClassAttribute = iterator.next();
+      if (type == innerClassAttribute.getInner()) {
+        iterator.set(newInnerClassAttribute);
+        return;
+      }
+    }
+    throw new Unreachable();
+  }
+
   public boolean isLocalClass() {
     InnerClassAttribute innerClass = getInnerClassAttributeForThisClass();
     // The corresponding enclosing-method attribute might be not available, e.g., CF version 50.
diff --git a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
index e6584a8..a1006fe 100644
--- a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
@@ -3,12 +3,17 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.optimize;
 
+import static com.android.tools.r8.dex.Constants.ACC_PRIVATE;
+import static com.android.tools.r8.dex.Constants.ACC_PROTECTED;
+import static com.android.tools.r8.dex.Constants.ACC_PUBLIC;
+
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.ir.optimize.MethodPoolCollection;
 import com.android.tools.r8.optimize.PublicizerLense.PublicizedLenseBuilder;
@@ -70,7 +75,11 @@
     DexClass clazz = application.definitionFor(type);
     if (clazz != null && clazz.isProgramClass()) {
       clazz.accessFlags.promoteToPublic();
+
+      // Publicize fields.
       clazz.forEachField(field -> field.accessFlags.promoteToPublic());
+
+      // Publicize methods.
       Set<DexEncodedMethod> privateInstanceEncodedMethods = new LinkedHashSet<>();
       clazz.forEachMethod(encodedMethod -> {
         if (publicizeMethod(clazz, encodedMethod)) {
@@ -80,6 +89,15 @@
       if (!privateInstanceEncodedMethods.isEmpty()) {
         clazz.virtualizeMethods(privateInstanceEncodedMethods);
       }
+
+      // Publicize inner class attribute.
+      InnerClassAttribute attr = clazz.getInnerClassAttributeForThisClass();
+      if (attr != null) {
+        int accessFlags = ((attr.getAccess() | ACC_PUBLIC) & ~ACC_PRIVATE) & ~ACC_PROTECTED;
+        clazz.replaceInnerClassAttributeForThisClass(
+            new InnerClassAttribute(
+                accessFlags, attr.getInner(), attr.getOuter(), attr.getInnerName()));
+      }
     }
 
     appView.appInfo().forAllExtendsSubtypes(type, this::publicizeType);
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/InnerClassAttributePublicizerTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/InnerClassAttributePublicizerTest.java
new file mode 100644
index 0000000..e3647b1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/InnerClassAttributePublicizerTest.java
@@ -0,0 +1,88 @@
+// 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.accessrelaxation;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.ClassAccessFlags;
+import com.android.tools.r8.graph.InnerClassAttribute;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class InnerClassAttributePublicizerTest extends TestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().build();
+  }
+
+  public InnerClassAttributePublicizerTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(parameters.getBackend())
+        .addInnerClasses(InnerClassAttributePublicizerTest.class)
+        .addKeepMainRule(TestClass.class)
+        .addKeepRules("-allowaccessmodification")
+        .addKeepAttributes("EnclosingMethod", "InnerClasses")
+        .setMinApi(parameters.getRuntime())
+        .compile()
+        .inspect(this::inspect)
+        .run(parameters.getRuntime(), TestClass.class)
+        .assertSuccessWithOutputLines("Hello world!");
+  }
+
+  private void inspect(CodeInspector inspector) {
+    ClassSubject classSubject = inspector.clazz(Outer.Inner.class);
+    assertThat(classSubject, isPresent());
+
+    InnerClassAttribute innerClassAttribute =
+        classSubject.getDexClass().getInnerClassAttributeForThisClass();
+    assertNotNull(innerClassAttribute);
+
+    ClassAccessFlags accessFlags =
+        ClassAccessFlags.fromSharedAccessFlags(innerClassAttribute.getAccess());
+    assertTrue(accessFlags.isPublic());
+    assertFalse(accessFlags.isPrivate());
+    assertFalse(accessFlags.isProtected());
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      new Outer();
+      new Outer.Inner();
+    }
+  }
+
+  static class Outer {
+
+    static {
+      System.out.print("Hello");
+    }
+
+    static class Inner {
+
+      static {
+        System.out.println(" world!");
+      }
+    }
+  }
+}