Add Nestmates attrs JarClassReader and CfWriter

- Write tests checking nestmate attrs are R/W correctly
- Add Classes for attributes NestHost and NestMembers
- Improve JarClassReader to read nestmates attrs
- Change DexClass creation to add the 2 attributes
- Change CfWriter to write nestmate attrs

Bug: 130527926
Change-Id: I59bbe1ee499c624c021cb5d60277c0a07970e477
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 3bcdfbd..1760ca4 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -702,6 +702,8 @@
               superclass,
               typeListAt(interfacesOffsets[i]),
               source,
+              null,
+              Collections.emptyList(),
               attrs.getEnclosingMethodAttribute(),
               attrs.getInnerClasses(),
               attrs.getAnnotations(),
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 92ae40e..6443795 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassKind.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassKind.java
@@ -25,6 +25,8 @@
         DexType superType,
         DexTypeList interfaces,
         DexString sourceFile,
+        NestHostClassAttribute nestHost,
+        List<NestMemberClassAttribute> nestMembers,
         EnclosingMethodAttribute enclosingMember,
         List<InnerClassAttribute> innerClasses,
         DexAnnotationSet annotations,
@@ -51,6 +53,8 @@
       DexType superType,
       DexTypeList interfaces,
       DexString sourceFile,
+      NestHostClassAttribute nestHost,
+      List<NestMemberClassAttribute> nestMembers,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       DexAnnotationSet annotations,
@@ -67,6 +71,8 @@
         superType,
         interfaces,
         sourceFile,
+        nestHost,
+        nestMembers,
         enclosingMember,
         innerClasses,
         annotations,
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 a7c20c0..f98f9b8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -62,6 +62,9 @@
   /** InnerClasses table. If this class is an inner class, it will have an entry here. */
   private final List<InnerClassAttribute> innerClasses;
 
+  private final NestHostClassAttribute nestHost;
+  private final List<NestMemberClassAttribute> nestMembers;
+
   public DexAnnotationSet annotations;
 
   public DexClass(
@@ -74,6 +77,8 @@
       DexEncodedField[] instanceFields,
       DexEncodedMethod[] directMethods,
       DexEncodedMethod[] virtualMethods,
+      NestHostClassAttribute nestHost,
+      List<NestMemberClassAttribute> nestMembers,
       EnclosingMethodAttribute enclosingMethod,
       List<InnerClassAttribute> innerClasses,
       DexAnnotationSet annotations,
@@ -90,6 +95,9 @@
     setInstanceFields(instanceFields);
     setDirectMethods(directMethods);
     setVirtualMethods(virtualMethods);
+    this.nestHost = nestHost;
+    this.nestMembers = nestMembers;
+    assert nestMembers != null;
     this.enclosingMethod = enclosingMethod;
     this.innerClasses = innerClasses;
     this.annotations = annotations;
@@ -802,6 +810,19 @@
         && getEnclosingMethod() != null;
   }
 
+  public boolean isInANest() {
+    assert nestMembers != null;
+    return !(nestMembers.isEmpty()) || (nestHost != null);
+  }
+
+  public NestHostClassAttribute getNestHostClassAttribute() {
+    return nestHost;
+  }
+
+  public List<NestMemberClassAttribute> getNestMembersClassAttributes() {
+    return nestMembers;
+  }
+
   /** Returns kotlin class info if the class is synthesized by kotlin compiler. */
   public abstract KotlinInfo 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 1cc1a80..ba47985 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
@@ -23,6 +23,8 @@
       DexType superType,
       DexTypeList interfaces,
       DexString sourceFile,
+      NestHostClassAttribute nestHost,
+      List<NestMemberClassAttribute> nestMembers,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       DexAnnotationSet annotations,
@@ -41,6 +43,8 @@
         instanceFields,
         directMethods,
         virtualMethods,
+        nestHost,
+        nestMembers,
         enclosingMember,
         innerClasses,
         annotations,
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 c47ac2c..8c622ae 100644
--- a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
@@ -24,6 +24,8 @@
       DexType superType,
       DexTypeList interfaces,
       DexString sourceFile,
+      NestHostClassAttribute nestHost,
+      List<NestMemberClassAttribute> nestMembers,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       DexAnnotationSet annotations,
@@ -42,6 +44,8 @@
         instanceFields,
         directMethods,
         virtualMethods,
+        nestHost,
+        nestMembers,
         enclosingMember,
         innerClasses,
         annotations,
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 aa2c411..625e28f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -38,6 +38,8 @@
       DexType superType,
       DexTypeList interfaces,
       DexString sourceFile,
+      NestHostClassAttribute nestHost,
+      List<NestMemberClassAttribute> nestMembers,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       DexAnnotationSet classAnnotations,
@@ -54,6 +56,8 @@
         superType,
         interfaces,
         sourceFile,
+        nestHost,
+        nestMembers,
         enclosingMember,
         innerClasses,
         classAnnotations,
@@ -73,6 +77,8 @@
       DexType superType,
       DexTypeList interfaces,
       DexString sourceFile,
+      NestHostClassAttribute nestHost,
+      List<NestMemberClassAttribute> nestMembers,
       EnclosingMethodAttribute enclosingMember,
       List<InnerClassAttribute> innerClasses,
       DexAnnotationSet classAnnotations,
@@ -92,6 +98,8 @@
         instanceFields,
         directMethods,
         virtualMethods,
+        nestHost,
+        nestMembers,
         enclosingMember,
         innerClasses,
         classAnnotations,
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 4aa5b7c..b87d13c 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -3,11 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
 import static org.objectweb.asm.ClassReader.SKIP_CODE;
 import static org.objectweb.asm.ClassReader.SKIP_DEBUG;
 import static org.objectweb.asm.ClassReader.SKIP_FRAMES;
 import static org.objectweb.asm.Opcodes.ACC_DEPRECATED;
-import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
 
 import com.android.tools.r8.ProgramResource.Kind;
 import com.android.tools.r8.dex.Constants;
@@ -181,6 +181,8 @@
     private DexType superType;
     private DexTypeList interfaces;
     private DexString sourceFile;
+    private NestHostClassAttribute nestHost = null;
+    private final List<NestMemberClassAttribute> nestMembers = new ArrayList<>();
     private EnclosingMethodAttribute enclosingMember = null;
     private final List<InnerClassAttribute> innerClasses = new ArrayList<>();
     private List<DexAnnotation> annotations = null;
@@ -228,6 +230,22 @@
               : new EnclosingMethodAttribute(application.getMethod(ownerType, name, desc));
     }
 
+    @Override
+    public void visitNestHost(String nestHost) {
+      assert this.nestHost == null && nestMembers.isEmpty();
+      DexType nestHostType = application.getTypeFromName(nestHost);
+      // TODO anonymous classes b/130716158
+      this.nestHost = new NestHostClassAttribute(nestHostType);
+    }
+
+    @Override
+    public void visitNestMember(String nestMember) {
+      assert nestHost == null;
+      DexType nestMemberType = application.getTypeFromName(nestMember);
+      // TODO anonymous classes b/130716158
+      nestMembers.add(new NestMemberClassAttribute(nestMemberType));
+    }
+
     private String illegalClassFilePrefix(ClassAccessFlags accessFlags, String name) {
       return "Illegal class file: "
           + (accessFlags.isInterface() ? "Interface" : "Class")
@@ -349,6 +367,8 @@
               superType,
               interfaces,
               sourceFile,
+              nestHost,
+              nestMembers,
               enclosingMember,
               innerClasses,
               createAnnotationSet(annotations, application.options),
diff --git a/src/main/java/com/android/tools/r8/graph/NestHostClassAttribute.java b/src/main/java/com/android/tools/r8/graph/NestHostClassAttribute.java
new file mode 100644
index 0000000..96fb82b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/NestHostClassAttribute.java
@@ -0,0 +1,26 @@
+// 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.graph;
+
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.ClassWriter;
+
+public class NestHostClassAttribute {
+
+  private final DexType nestHost;
+
+  public NestHostClassAttribute(DexType nestHost) {
+    this.nestHost = nestHost;
+  }
+
+  public DexType getNestHost() {
+    return nestHost;
+  }
+
+  public void write(ClassWriter writer, NamingLens lens) {
+    assert nestHost != null;
+    writer.visitNestHost(lens.lookupInternalName(nestHost));
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/NestMemberClassAttribute.java b/src/main/java/com/android/tools/r8/graph/NestMemberClassAttribute.java
new file mode 100644
index 0000000..f88a39f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/NestMemberClassAttribute.java
@@ -0,0 +1,26 @@
+// 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.graph;
+
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.ClassWriter;
+
+public class NestMemberClassAttribute {
+
+  private final DexType nestMember;
+
+  public NestMemberClassAttribute(DexType nestMember) {
+    this.nestMember = nestMember;
+  }
+
+  public DexType getNestMember() {
+    return nestMember;
+  }
+
+  public void write(ClassWriter writer, NamingLens lens) {
+    assert nestMember != null;
+    writer.visitNestMember(lens.lookupInternalName(nestMember));
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index db93b99..d11d2da 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -190,6 +190,8 @@
             iface.sourceFile,
             null,
             Collections.emptyList(),
+            null,
+            Collections.emptyList(),
             DexAnnotationSet.empty(),
             DexEncodedField.EMPTY_ARRAY,
             DexEncodedField.EMPTY_ARRAY,
@@ -265,6 +267,8 @@
             iface.sourceFile,
             null,
             Collections.emptyList(),
+            null,
+            Collections.emptyList(),
             DexAnnotationSet.empty(),
             DexEncodedField.EMPTY_ARRAY,
             DexEncodedField.EMPTY_ARRAY,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
index 1c345a2..646f24e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
@@ -135,10 +135,12 @@
               null,
               null,
               Collections.emptyList(),
+              null,
+              Collections.emptyList(),
               DexAnnotationSet.empty(),
               DexEncodedField.EMPTY_ARRAY,
               DexEncodedField.EMPTY_ARRAY,
-              new DexEncodedMethod[]{dexEncodedMethod},
+              new DexEncodedMethod[] {dexEncodedMethod},
               DexEncodedMethod.EMPTY_ARRAY,
               factory.getSkipNameValidationForTesting(),
               referencingClasses);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 7d2191c..b5a5f0c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -162,6 +162,8 @@
             rewriter.factory.createString("lambda"),
             null,
             Collections.emptyList(),
+            null,
+            Collections.emptyList(),
             DexAnnotationSet.empty(),
             synthesizeStaticFields(),
             synthesizeInstanceFields(),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
index 566caf1..89721b1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
@@ -144,6 +144,8 @@
             null,
             null,
             Collections.emptyList(),
+            null,
+            Collections.emptyList(),
             DexAnnotationSet.empty(),
             DexEncodedField.EMPTY_ARRAY,
             DexEncodedField.EMPTY_ARRAY,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index be5525e..91e6b25 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -1293,6 +1293,8 @@
             sourceFile,
             null,
             Collections.emptyList(),
+            null,
+            Collections.emptyList(),
             // TODO: Build dex annotations structure.
             DexAnnotationSet.empty(),
             DexEncodedField.EMPTY_ARRAY, // Static fields.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
index 10dc013..4f5f110 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
@@ -15,6 +15,7 @@
 import com.android.tools.r8.graph.EnclosingMethodAttribute;
 import com.android.tools.r8.graph.InnerClassAttribute;
 import com.android.tools.r8.origin.SynthesizedOrigin;
+import java.util.Collections;
 import java.util.List;
 
 // Encapsulates lambda group class building logic and separates
@@ -42,6 +43,8 @@
         superClassType,
         buildInterfaces(),
         factory.createString(origin),
+        null,
+        Collections.emptyList(),
         buildEnclosingMethodAttribute(),
         buildInnerClasses(),
         buildAnnotations(),
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index dabfd6c..d1fe96b 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -37,6 +37,7 @@
 import com.android.tools.r8.graph.DexValue.UnknownDexValue;
 import com.android.tools.r8.graph.GraphLense;
 import com.android.tools.r8.graph.InnerClassAttribute;
+import com.android.tools.r8.graph.NestMemberClassAttribute;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.naming.ProguardMapSupplier;
@@ -162,6 +163,14 @@
       clazz.getEnclosingMethod().write(writer, namingLens);
     }
 
+    if (clazz.getNestHostClassAttribute() != null) {
+      clazz.getNestHostClassAttribute().write(writer, namingLens);
+    }
+
+    for (NestMemberClassAttribute entry : clazz.getNestMembersClassAttributes()) {
+      entry.write(writer, namingLens);
+    }
+
     for (InnerClassAttribute entry : clazz.getInnerClasses()) {
       entry.write(writer, namingLens, options);
     }
diff --git a/src/test/java/com/android/tools/r8/desugar/NestAccessControl/NestAttributesTest.java b/src/test/java/com/android/tools/r8/desugar/NestAccessControl/NestAttributesTest.java
new file mode 100644
index 0000000..e5b20bc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/NestAccessControl/NestAttributesTest.java
@@ -0,0 +1,65 @@
+// 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.desugar.NestAccessControl;
+
+import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.graph.DexClass;
+import java.nio.file.Paths;
+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 NestAttributesTest extends TestBase {
+
+  static final String EXAMPLE_DIR = ToolHelper.EXAMPLES_JAVA11_BUILD_DIR;
+
+  private final TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withCfRuntimesStartingFromIncluding(CfVm.JDK11).build();
+  }
+
+  public NestAttributesTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  @Test
+  public void testNestMatesAttributes() throws Exception {
+    testForR8(parameters.getBackend())
+        .addProgramFiles(Paths.get(EXAMPLE_DIR, "nestHostExample" + JAR_EXTENSION))
+        .addKeepAllClassesRule()
+        .compile()
+        .inspect(
+            inspector -> {
+              assertEquals(6, inspector.allClasses().size());
+              inspector.forAllClasses(
+                  classSubject -> {
+                    DexClass dexClass = classSubject.getDexClass();
+                    assertTrue(dexClass.isInANest());
+                    if (dexClass.type.getName().equals("NestHostExample")) {
+                      assertNull(dexClass.getNestHostClassAttribute());
+                      assertEquals(5, dexClass.getNestMembersClassAttributes().size());
+                    } else {
+                      assertTrue(dexClass.getNestMembersClassAttributes().isEmpty());
+                      assertEquals(
+                          "NestHostExample",
+                          dexClass.getNestHostClassAttribute().getNestHost().getName());
+                    }
+                  });
+            });
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
index 298ffe1..a6ace5b 100644
--- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -101,6 +101,8 @@
         null,
         null,
         Collections.emptyList(),
+        null,
+        Collections.emptyList(),
         DexAnnotationSet.empty(),
         DexEncodedField.EMPTY_ARRAY,
         DexEncodedField.EMPTY_ARRAY,
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 2b00c20..7b3f379 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -787,6 +787,8 @@
               null,
               null,
               Collections.emptyList(),
+              null,
+              Collections.emptyList(),
               DexAnnotationSet.empty(),
               DexEncodedField.EMPTY_ARRAY,
               DexEncodedField.EMPTY_ARRAY,