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,