Add permitted subclass attributes to internal structure

Bug: 227160052
Change-Id: I5b5af1c493492e8ac3b732813594aa54185d0643
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index 9dc5143..af340d4 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -205,6 +205,7 @@
             null,
             null,
             Collections.emptyList(),
+            Collections.emptyList(),
             null,
             Collections.emptyList(),
             ClassSignature.noSignature(),
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index 10132f3..604565b 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -65,6 +65,7 @@
 import com.android.tools.r8.graph.NestMemberClassAttribute;
 import com.android.tools.r8.graph.OffsetToObjectMapping;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.PermittedSubclassAttribute;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.origin.PathOrigin;
@@ -859,6 +860,7 @@
               source,
               attrs.nestHostAttribute,
               attrs.nestMembersAttribute,
+              attrs.permittedSubclasses,
               attrs.getEnclosingMethodAttribute(),
               attrs.getInnerClasses(),
               attrs.classSignature,
@@ -1427,6 +1429,7 @@
     private ClassSignature classSignature = ClassSignature.noSignature();
     private NestHostClassAttribute nestHostAttribute;
     private List<NestMemberClassAttribute> nestMembersAttribute = Collections.emptyList();
+    private List<PermittedSubclassAttribute> permittedSubclasses = Collections.emptyList();
 
     public DexAnnotationSet getAnnotations() {
       if (lazyAnnotations != null) {
diff --git a/src/main/java/com/android/tools/r8/graph/ClassKind.java b/src/main/java/com/android/tools/r8/graph/ClassKind.java
index 60f78ea..e878e0d 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassKind.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassKind.java
@@ -26,6 +26,7 @@
               sourceFile,
               nestHost,
               nestMembers,
+              permittedSubclasses,
               enclosingMember,
               innerClasses,
               classSignature,
@@ -47,6 +48,7 @@
                   sourceFile,
                   nestHost,
                   nestMembers,
+                  permittedSubclasses,
                   enclosingMember,
                   innerClasses,
                   classSignature,
@@ -69,6 +71,7 @@
               sourceFile,
               nestHost,
               nestMembers,
+              permittedSubclasses,
               enclosingMember,
               innerClasses,
               classSignature,
@@ -90,6 +93,7 @@
                   sourceFile,
                   nestHost,
                   nestMembers,
+                  permittedSubclasses,
                   enclosingMember,
                   innerClasses,
                   classSignature,
@@ -110,6 +114,7 @@
               sourceFile,
               nestHost,
               nestMembers,
+              permittedSubclasses,
               enclosingMember,
               innerClasses,
               classSignature,
@@ -131,6 +136,7 @@
                   sourceFile,
                   nestHost,
                   nestMembers,
+                  permittedSubclasses,
                   enclosingMember,
                   innerClasses,
                   classSignature,
@@ -152,6 +158,7 @@
         DexString sourceFile,
         NestHostClassAttribute nestHost,
         List<NestMemberClassAttribute> nestMembers,
+        List<PermittedSubclassAttribute> permittedSubclasses,
         EnclosingMethodAttribute enclosingMember,
         List<InnerClassAttribute> innerClasses,
         ClassSignature classSignature,
@@ -183,6 +190,7 @@
       DexString sourceFile,
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
+      List<PermittedSubclassAttribute> permittedSubclasses,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -204,6 +212,7 @@
         sourceFile,
         nestHost,
         nestMembers,
+        permittedSubclasses,
         enclosingMember,
         innerClasses,
         classSignature,
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 6f5e604..a77f418 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -80,6 +80,8 @@
 
   private List<NestMemberClassAttribute> nestMembers;
 
+  private List<PermittedSubclassAttribute> permittedSubclasses;
+
   /** Generic signature information if the attribute is present in the input */
   protected ClassSignature classSignature;
 
@@ -94,6 +96,7 @@
       MethodCollectionFactory methodCollectionFactory,
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
+      List<PermittedSubclassAttribute> permittedSubclasses,
       EnclosingMethodAttribute enclosingMethod,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -114,6 +117,8 @@
     this.nestHost = nestHost;
     this.nestMembers = nestMembers;
     assert nestMembers != null;
+    this.permittedSubclasses = permittedSubclasses;
+    assert permittedSubclasses != null;
     this.enclosingMethod = enclosingMethod;
     this.innerClasses = innerClasses;
     assert classSignature != null;
@@ -1180,7 +1185,7 @@
   }
 
   public boolean hasNestMemberAttributes() {
-    return nestMembers != null && !nestMembers.isEmpty();
+    return !nestMembers.isEmpty();
   }
 
   public List<NestMemberClassAttribute> getNestMembersClassAttributes() {
@@ -1195,6 +1200,14 @@
     nestMembers.removeIf(predicate);
   }
 
+  public boolean hasPermittedSubclassAttributes() {
+    return !permittedSubclasses.isEmpty();
+  }
+
+  public List<PermittedSubclassAttribute> getPermittedSubclassAttributes() {
+    return permittedSubclasses;
+  }
+
   /** Returns kotlin class info if the class is synthesized by kotlin compiler. */
   public abstract KotlinClassLevelInfo getKotlinInfo();
 
diff --git a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
index 5130c57..43c2532 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
@@ -35,6 +35,7 @@
       DexString sourceFile,
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
+      List<PermittedSubclassAttribute> permittedSubclasses,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -54,6 +55,7 @@
         methodCollectionFactory,
         nestHost,
         nestMembers,
+        permittedSubclasses,
         enclosingMember,
         innerClasses,
         classSignature,
diff --git a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
index e5cd61c..24091e4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
@@ -33,6 +33,7 @@
       DexString sourceFile,
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
+      List<PermittedSubclassAttribute> permittedSubclasses,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -52,6 +53,7 @@
         methodCollectionFactory,
         nestHost,
         nestMembers,
+        permittedSubclasses,
         enclosingMember,
         innerClasses,
         classSignature,
@@ -171,6 +173,7 @@
     private DexString sourceFile = null;
     private NestHostClassAttribute nestHost = null;
     private List<NestMemberClassAttribute> nestMembers = Collections.emptyList();
+    private List<PermittedSubclassAttribute> permittedSubclasses = Collections.emptyList();
     private EnclosingMethodAttribute enclosingMember = null;
     private List<InnerClassAttribute> innerClasses = Collections.emptyList();
     private ClassSignature classSignature = ClassSignature.noSignature();
@@ -213,6 +216,7 @@
           sourceFile,
           nestHost,
           nestMembers,
+          permittedSubclasses,
           enclosingMember,
           innerClasses,
           classSignature,
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 46bebdc..b49abbe 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -69,6 +69,7 @@
       DexString sourceFile,
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
+      List<PermittedSubclassAttribute> permittedSubclasses,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -90,6 +91,7 @@
         methodCollectionFactory,
         nestHost,
         nestMembers,
+        permittedSubclasses,
         enclosingMember,
         innerClasses,
         classSignature,
@@ -113,6 +115,7 @@
       DexString sourceFile,
       NestHostClassAttribute nestHost,
       List<NestMemberClassAttribute> nestMembers,
+      List<PermittedSubclassAttribute> permittedSubclasses,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       ClassSignature classSignature,
@@ -132,6 +135,7 @@
         sourceFile,
         nestHost,
         nestMembers,
+        permittedSubclasses,
         enclosingMember,
         innerClasses,
         classSignature,
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index d88983a..ac2c8aa 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -226,6 +226,7 @@
     private DexString sourceFile;
     private NestHostClassAttribute nestHost = null;
     private final List<NestMemberClassAttribute> nestMembers = new ArrayList<>();
+    private final List<PermittedSubclassAttribute> permittedSubclasses = new ArrayList<>();
     private final Set<DexField> recordComponents = Sets.newIdentityHashSet();
     private EnclosingMethodAttribute enclosingMember = null;
     private final List<InnerClassAttribute> innerClasses = new ArrayList<>();
@@ -348,11 +349,12 @@
 
     @Override
     public void visitPermittedSubclass(String permittedSubclass) {
+      assert permittedSubclass != null;
+      DexType permittedSubclassType = application.getTypeFromName(permittedSubclass);
+      permittedSubclasses.add(new PermittedSubclassAttribute(permittedSubclassType));
       if (classKind == ClassKind.PROGRAM) {
         throw new CompilationError("Sealed classes are not supported as program classes", origin);
       }
-      // For library and classpath just ignore the permitted subclasses, as the compiler is not
-      // validating the code with respect to sealed classes.
     }
 
     @Override
@@ -476,6 +478,7 @@
               sourceFile,
               nestHost,
               nestMembers,
+              permittedSubclasses,
               enclosingMember,
               innerClasses,
               classSignature,
diff --git a/src/main/java/com/android/tools/r8/graph/PermittedSubclassAttribute.java b/src/main/java/com/android/tools/r8/graph/PermittedSubclassAttribute.java
new file mode 100644
index 0000000..0c4dd43
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/PermittedSubclassAttribute.java
@@ -0,0 +1,49 @@
+// Copyright (c) 2022, 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.graph;
+
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralMapping;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
+import java.util.Collections;
+import java.util.List;
+import org.objectweb.asm.ClassWriter;
+
+public class PermittedSubclassAttribute implements StructuralItem<PermittedSubclassAttribute> {
+
+  private final DexType permittedSubclass;
+
+  private static void specify(StructuralSpecification<PermittedSubclassAttribute, ?> spec) {
+    spec.withItem(a -> a.permittedSubclass);
+  }
+
+  public PermittedSubclassAttribute(DexType nestMember) {
+    this.permittedSubclass = nestMember;
+  }
+
+  public static List<PermittedSubclassAttribute> emptyList() {
+    return Collections.emptyList();
+  }
+
+  public DexType getPermittedSubclass() {
+    return permittedSubclass;
+  }
+
+  public void write(ClassWriter writer, NamingLens lens) {
+    assert permittedSubclass != null;
+    writer.visitPermittedSubclass(lens.lookupInternalName(permittedSubclass));
+  }
+
+  @Override
+  public PermittedSubclassAttribute self() {
+    return this;
+  }
+
+  @Override
+  public StructuralMapping<PermittedSubclassAttribute> getStructuralMapping() {
+    return PermittedSubclassAttribute::specify;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java b/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java
index 0828ff2..1c99b6c 100644
--- a/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java
+++ b/src/main/java/com/android/tools/r8/graph/TreeFixerBase.java
@@ -107,6 +107,7 @@
             clazz.getSourceFile(),
             fixupNestHost(clazz.getNestHostClassAttribute()),
             fixupNestMemberAttributes(clazz.getNestMembersClassAttributes()),
+            fixupPermittedSubclassAttribute(clazz.getPermittedSubclassAttributes()),
             fixupEnclosingMethodAttribute(clazz.getEnclosingMethodAttribute()),
             fixupInnerClassAttributes(clazz.getInnerClasses()),
             clazz.getClassSignature(),
@@ -271,6 +272,23 @@
     return changed ? newNestMemberAttributes : nestMemberAttributes;
   }
 
+  protected List<PermittedSubclassAttribute> fixupPermittedSubclassAttribute(
+      List<PermittedSubclassAttribute> permittedSubclassAttributes) {
+    if (permittedSubclassAttributes.isEmpty()) {
+      return permittedSubclassAttributes;
+    }
+    boolean changed = false;
+    List<PermittedSubclassAttribute> newPermittedSubclassAttributes =
+        new ArrayList<>(permittedSubclassAttributes.size());
+    for (PermittedSubclassAttribute permittedSubclassAttribute : permittedSubclassAttributes) {
+      DexType permittedSubclassType = permittedSubclassAttribute.getPermittedSubclass();
+      DexType newPermittedSubclassType = fixupType(permittedSubclassType);
+      newPermittedSubclassAttributes.add(new PermittedSubclassAttribute(newPermittedSubclassType));
+      changed |= newPermittedSubclassType != permittedSubclassType;
+    }
+    return changed ? newPermittedSubclassAttributes : permittedSubclassAttributes;
+  }
+
   /** Fixup a proto descriptor. */
   public DexProto fixupProto(DexProto proto) {
     DexProto result = protoFixupCache.get(proto);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
index 695af34..c764377 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
@@ -78,6 +78,7 @@
             emulatedInterface.getSourceFile(),
             null,
             Collections.emptyList(),
+            Collections.emptyList(),
             null, // Note that we clear the enclosing and inner class attributes.
             Collections.emptyList(),
             emulatedInterface.getClassSignature(),
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
index 598dc4f..e9951c3 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.graph.NestHostClassAttribute;
 import com.android.tools.r8.graph.NestMemberClassAttribute;
+import com.android.tools.r8.graph.PermittedSubclassAttribute;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import java.util.ArrayList;
@@ -171,6 +172,7 @@
             abstractFlag | finalFlag | itfFlag | Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
     NestHostClassAttribute nestHost = null;
     List<NestMemberClassAttribute> nestMembers = Collections.emptyList();
+    List<PermittedSubclassAttribute> permittedSubclasses = Collections.emptyList();
     EnclosingMethodAttribute enclosingMembers = null;
     List<InnerClassAttribute> innerClasses = Collections.emptyList();
     for (SyntheticMethodBuilder builder : methods) {
@@ -198,6 +200,7 @@
                 sourceFile,
                 nestHost,
                 nestMembers,
+                permittedSubclasses,
                 enclosingMembers,
                 innerClasses,
                 signature,
diff --git a/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java b/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
index 493df28..9d13687 100644
--- a/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/conversion/CallGraphTestBase.java
@@ -34,6 +34,7 @@
           null,
           null,
           Collections.emptyList(),
+          Collections.emptyList(),
           null,
           Collections.emptyList(),
           ClassSignature.noSignature(),
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index ed70ece..5d54843 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -834,6 +834,7 @@
               null,
               null,
               Collections.emptyList(),
+              Collections.emptyList(),
               null,
               Collections.emptyList(),
               ClassSignature.noSignature(),