Version 2.1.57
Cherry-pick: Close stream of input source when dumping
CL: https://r8-review.googlesource.com/52560
Cherry-pick: Move synchronization of class initializer from DexClass to MethodColl
CL: https://r8-review.googlesource.com/52544
Cherry-pick: Add reproduction of removed fields in kotlin.Metadata
CL: https://r8-review.googlesource.com/52666
Cherry-pick: Only emit kotlin metadata values for non-pruned
annotation members
CL: https://r8-review.googlesource.com/52667
Bug: 160901582
Bug: 159194018
Bug: 161230424
Bug: 162900580
Bug: 152476580
Change-Id: I3e506acaba9333ed6bd31d7229f5982bab215696
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 4037c85..f1e1b89 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 = "2.1.56";
+ public static final String LABEL = "2.1.57";
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 be8c6f1..1c9b40c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -532,8 +532,10 @@
return false;
}
- public synchronized DexEncodedMethod getClassInitializer() {
- return methodCollection.getClassInitializer();
+ public DexEncodedMethod getClassInitializer() {
+ DexEncodedMethod classInitializer = methodCollection.getClassInitializer();
+ assert classInitializer != DexEncodedMethod.SENTINEL;
+ return classInitializer;
}
public Origin getOrigin() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index cf25051..adb1dcc 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -119,7 +119,11 @@
public static final DexEncodedMethod[] EMPTY_ARRAY = {};
public static final DexEncodedMethod SENTINEL =
new DexEncodedMethod(
- null, null, DexAnnotationSet.empty(), ParameterAnnotationsList.empty(), null);
+ null,
+ MethodAccessFlags.fromDexAccessFlags(0),
+ DexAnnotationSet.empty(),
+ ParameterAnnotationsList.empty(),
+ null);
public static final Int2ReferenceMap<DebugLocalInfo> NO_PARAMETER_INFO =
new Int2ReferenceArrayMap<>(0);
@@ -246,6 +250,7 @@
this.code = code;
this.classFileVersion = classFileVersion;
this.d8R8Synthesized = d8R8Synthesized;
+ assert accessFlags != null;
assert code == null || !shouldNotHaveCode();
assert parameterAnnotationsList != null;
}
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollection.java b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
index c93d366..b1a8f8e 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -178,7 +178,7 @@
cachedClassInitializer = DexEncodedMethod.SENTINEL;
}
- public DexEncodedMethod getClassInitializer() {
+ public synchronized DexEncodedMethod getClassInitializer() {
if (cachedClassInitializer == DexEncodedMethod.SENTINEL) {
cachedClassInitializer = null;
for (DexEncodedMethod directMethod : directMethods()) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
index 2171a00..281950c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassMetadataReader.java
@@ -188,8 +188,8 @@
return v.asDexValueString().getValue().toString();
}
- private static class MetadataError extends RuntimeException {
- MetadataError(String cause) {
+ public static class MetadataError extends RuntimeException {
+ private MetadataError(String cause) {
super(cause);
}
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index d709ea4..5e11d43 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -9,8 +9,10 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationElement;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedAnnotation;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DexValue.DexValueArray;
import com.android.tools.r8.graph.DexValue.DexValueInt;
@@ -25,6 +27,36 @@
public class KotlinMetadataRewriter {
+ private static final class WriteMetadataFieldInfo {
+ final boolean writeKind;
+ final boolean writeMetadataVersion;
+ final boolean writeByteCodeVersion;
+ final boolean writeData1;
+ final boolean writeData2;
+ final boolean writeExtraString;
+ final boolean writePackageName;
+ final boolean writeExtraInt;
+
+ public WriteMetadataFieldInfo(
+ boolean writeKind,
+ boolean writeMetadataVersion,
+ boolean writeByteCodeVersion,
+ boolean writeData1,
+ boolean writeData2,
+ boolean writeExtraString,
+ boolean writePackageName,
+ boolean writeExtraInt) {
+ this.writeKind = writeKind;
+ this.writeMetadataVersion = writeMetadataVersion;
+ this.writeByteCodeVersion = writeByteCodeVersion;
+ this.writeData1 = writeData1;
+ this.writeData2 = writeData2;
+ this.writeExtraString = writeExtraString;
+ this.writePackageName = writePackageName;
+ this.writeExtraInt = writeExtraInt;
+ }
+ }
+
private final AppView<?> appView;
private final NamingLens lens;
private final DexItemFactory factory;
@@ -42,6 +74,18 @@
}
public void run(ExecutorService executorService) throws ExecutionException {
+ final DexClass kotlinMetadata =
+ appView.definitionFor(appView.dexItemFactory().kotlinMetadataType);
+ final WriteMetadataFieldInfo writeMetadataFieldInfo =
+ new WriteMetadataFieldInfo(
+ kotlinMetadataFieldExists(kotlinMetadata, appView, kotlin.metadata.kind),
+ kotlinMetadataFieldExists(kotlinMetadata, appView, kotlin.metadata.metadataVersion),
+ kotlinMetadataFieldExists(kotlinMetadata, appView, kotlin.metadata.bytecodeVersion),
+ kotlinMetadataFieldExists(kotlinMetadata, appView, kotlin.metadata.data1),
+ kotlinMetadataFieldExists(kotlinMetadata, appView, kotlin.metadata.data2),
+ kotlinMetadataFieldExists(kotlinMetadata, appView, kotlin.metadata.extraString),
+ kotlinMetadataFieldExists(kotlinMetadata, appView, kotlin.metadata.packageName),
+ kotlinMetadataFieldExists(kotlinMetadata, appView, kotlin.metadata.extraInt));
ThreadUtils.processItems(
appView.appInfo().classes(),
clazz -> {
@@ -66,7 +110,8 @@
try {
KotlinClassHeader kotlinClassHeader = kotlinInfo.rewrite(clazz, appView, lens);
DexAnnotation newMeta =
- createKotlinMetadataAnnotation(kotlinClassHeader, kotlinInfo.getPackageName());
+ createKotlinMetadataAnnotation(
+ kotlinClassHeader, kotlinInfo.getPackageName(), writeMetadataFieldInfo);
clazz.setAnnotations(
clazz.annotations().rewrite(anno -> anno == oldMeta ? newMeta : anno));
} catch (Throwable t) {
@@ -79,33 +124,54 @@
executorService);
}
+ private boolean kotlinMetadataFieldExists(
+ DexClass kotlinMetadata, AppView<?> appView, DexString fieldName) {
+ if (!appView.appInfo().hasLiveness()) {
+ return true;
+ }
+ if (kotlinMetadata == null || kotlinMetadata.isNotProgramClass()) {
+ return true;
+ }
+ return kotlinMetadata.methods(method -> method.method.name == fieldName).iterator().hasNext();
+ }
+
private DexAnnotation createKotlinMetadataAnnotation(
- KotlinClassHeader header, String packageName) {
+ KotlinClassHeader header, String packageName, WriteMetadataFieldInfo writeMetadataFieldInfo) {
List<DexAnnotationElement> elements = new ArrayList<>();
- elements.add(
- new DexAnnotationElement(
- kotlin.metadata.metadataVersion, createIntArray(header.getMetadataVersion())));
- elements.add(
- new DexAnnotationElement(
- kotlin.metadata.bytecodeVersion, createIntArray(header.getBytecodeVersion())));
- elements.add(
- new DexAnnotationElement(kotlin.metadata.kind, DexValueInt.create(header.getKind())));
- elements.add(
- new DexAnnotationElement(kotlin.metadata.data1, createStringArray(header.getData1())));
- elements.add(
- new DexAnnotationElement(kotlin.metadata.data2, createStringArray(header.getData2())));
- if (packageName != null && !packageName.isEmpty()) {
+ if (writeMetadataFieldInfo.writeMetadataVersion) {
+ elements.add(
+ new DexAnnotationElement(
+ kotlin.metadata.metadataVersion, createIntArray(header.getMetadataVersion())));
+ }
+ if (writeMetadataFieldInfo.writeByteCodeVersion) {
+ elements.add(
+ new DexAnnotationElement(
+ kotlin.metadata.bytecodeVersion, createIntArray(header.getBytecodeVersion())));
+ }
+ if (writeMetadataFieldInfo.writeKind) {
+ elements.add(
+ new DexAnnotationElement(kotlin.metadata.kind, DexValueInt.create(header.getKind())));
+ }
+ if (writeMetadataFieldInfo.writeData1) {
+ elements.add(
+ new DexAnnotationElement(kotlin.metadata.data1, createStringArray(header.getData1())));
+ }
+ if (writeMetadataFieldInfo.writeData2) {
+ elements.add(
+ new DexAnnotationElement(kotlin.metadata.data2, createStringArray(header.getData2())));
+ }
+ if (writeMetadataFieldInfo.writePackageName && packageName != null && !packageName.isEmpty()) {
elements.add(
new DexAnnotationElement(
kotlin.metadata.packageName, new DexValueString(factory.createString(packageName))));
}
- if (!header.getExtraString().isEmpty()) {
+ if (writeMetadataFieldInfo.writeExtraString && !header.getExtraString().isEmpty()) {
elements.add(
new DexAnnotationElement(
kotlin.metadata.extraString,
new DexValueString(factory.createString(header.getExtraString()))));
}
- if (header.getExtraInt() != 0) {
+ if (writeMetadataFieldInfo.writeExtraInt && header.getExtraInt() != 0) {
elements.add(
new DexAnnotationElement(
kotlin.metadata.extraInt, DexValueInt.create(header.getExtraInt())));
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index 8599b02..faebc96 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -640,7 +640,7 @@
ZipOutputStream dexArchiveOutputStream,
ProgramResource programResource)
throws ResourceException, IOException {
- byte[] bytes = ByteStreams.toByteArray(programResource.getByteStream());
+ byte[] bytes = StreamUtils.StreamToByteArrayClose(programResource.getByteStream());
if (programResource.getKind() == Kind.CF) {
Set<String> classDescriptors = programResource.getClassDescriptors();
String classDescriptor =
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 2d56233..0465bc5 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
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CallGraph.Node;
@@ -50,7 +51,11 @@
new ProgramMethod(
clazz,
new DexEncodedMethod(
- signature, null, DexAnnotationSet.empty(), ParameterAnnotationsList.empty(), null));
+ signature,
+ MethodAccessFlags.fromDexAccessFlags(0),
+ DexAnnotationSet.empty(),
+ ParameterAnnotationsList.empty(),
+ null));
return new Node(method);
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
new file mode 100644
index 0000000..77134d8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2020, 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.kotlin.metadata;
+
+import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.kotlin.metadata.metadata_pruned_fields.Main;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/** This is a reproduction of b/161230424. */
+@RunWith(Parameterized.class)
+public class MetadataPrunedFieldsTest extends KotlinMetadataTestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0} target: {1}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), KotlinTargetVersion.values());
+ }
+
+ public MetadataPrunedFieldsTest(TestParameters parameters, KotlinTargetVersion targetVersion) {
+ super(targetVersion);
+ this.parameters = parameters;
+ }
+
+ private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+
+ @BeforeClass
+ public static void createLibJar() throws Exception {
+ String baseLibFolder = PKG_PREFIX + "/metadata_pruned_fields";
+ for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
+ Path baseLibJar =
+ kotlinc(KOTLINC, targetVersion)
+ .addSourceFiles(getKotlinFileInTest(baseLibFolder, "Methods"))
+ .compile();
+ libJars.put(targetVersion, baseLibJar);
+ }
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(libJars.get(targetVersion))
+ .addProgramClassFileData(Main.dump())
+ .addKeepRules("-keep class " + PKG + ".metadata_pruned_fields.MethodsKt { *; }")
+ .addKeepRules("-keep class kotlin.Metadata { *** pn(); }")
+ .addKeepMainRule(Main.class)
+ .allowDiagnosticWarningMessages()
+ .setMinApi(parameters.getApiLevel())
+ .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+ .compile()
+ .inspect(
+ codeInspector -> {
+ final ClassSubject clazz = codeInspector.clazz("kotlin.Metadata");
+ assertThat(clazz, isPresent());
+ assertThat(clazz.uniqueMethodWithName("pn"), isPresent());
+ assertThat(clazz.uniqueMethodWithName("d1"), not(isPresent()));
+ assertThat(clazz.uniqueMethodWithName("d2"), not(isPresent()));
+ assertThat(clazz.uniqueMethodWithName("bv"), not(isPresent()));
+ })
+ .assertAllWarningMessagesMatch(equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("", "Hello World!");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
index f474cf1..fd70455 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
@@ -101,7 +101,7 @@
.addProgramFiles(inputJarMap.get(targetVersion))
.addKeepRules(OBFUSCATE_RENAMED, KEEP_KEPT)
.addKeepRules("-keep class **.Anno")
- .addKeepRules("-keep class kotlin.Metadata")
+ .addKeepKotlinMetadata()
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
.allowDiagnosticWarningMessages()
.compile()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
index 295f26a..3986b38 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
@@ -4,17 +4,15 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
+import com.android.tools.r8.kotlin.KotlinClassMetadataReader.MetadataError;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import java.util.Collection;
@@ -51,55 +49,19 @@
}
@Test
- public void testR8KeepPartial() throws Exception {
- // This test is a bit weird, since it shows that we can remove params from the kotlin.Metadata
- // class, but still be able to fully read the kotlin.Metadata.
- testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
- .setMinApi(parameters.getApiLevel())
- .addKeepRules("-keep class kotlin.Metadata { *** d1(); }")
- .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
- .compile()
- .inspect(
- inspector -> {
- inspect(inspector);
- ClassSubject kotlinMetadataClass = inspector.clazz("kotlin.Metadata");
- assertThat(kotlinMetadataClass, isPresent());
- assertEquals(1, kotlinMetadataClass.allMethods().size());
- assertNotNull(kotlinMetadataClass.getKmClass().getName());
- });
- }
-
- @Test
- public void testR8KeepPartialCooking() throws Exception {
- // This test is a bit weird, since it shows that we can remove params from the kotlin.Metadata
- // class, but still be able to fully read the kotlin.Metadata externally.
- testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
- .setMinApi(parameters.getApiLevel())
- .addKeepRules("-keep class kotlin.Metadata { *** d1(); }")
- .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
- .compile()
- .inspect(
- inspector -> {
- inspect(inspector);
- ClassSubject kotlinMetadataClass = inspector.clazz("kotlin.Metadata");
- assertThat(kotlinMetadataClass, isPresent());
- assertEquals(1, kotlinMetadataClass.allMethods().size());
- assertNotNull(kotlinMetadataClass.getKmClass().getName());
- });
- }
-
- @Test
public void testR8KeepIf() throws Exception {
testForR8(parameters.getBackend())
.addProgramFiles(ToolHelper.getKotlinStdlibJar())
.setMinApi(parameters.getApiLevel())
.addKeepRules("-keep class kotlin.io.** { *; }")
- .addKeepRules("-if class * { *** $VALUES; }", "-keep class kotlin.Metadata { *; }")
+ .addKeepRules("-if class *", "-keep class kotlin.Metadata { *; }")
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
.compile()
- .inspect(this::inspect);
+ .inspect(
+ codeInspector -> {
+ // TODO(b/162900580): This should be kept or the test refined.
+ assertThrows(MetadataError.class, () -> inspect(codeInspector));
+ });
}
private void inspect(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Main.java b/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Main.java
new file mode 100644
index 0000000..10ebf6b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Main.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2020, 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.kotlin.metadata.metadata_pruned_fields;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+public class Main implements Opcodes {
+
+ // The dump is generated from the code below, which cannot compile because of a missing
+ // reference to MethodsKt.
+ //
+ // public static void main(String[] args) {
+ // final kotlin.Metadata annotation = MethodsKt.class.getAnnotation(kotlin.Metadata.class);
+ // System.out.println(annotation.pn());
+ // MethodsKt.staticMethod();
+ // }
+
+ public static byte[] dump() {
+
+ ClassWriter classWriter = new ClassWriter(0);
+ MethodVisitor methodVisitor;
+
+ classWriter.visit(
+ V1_8,
+ ACC_PUBLIC | ACC_SUPER,
+ "com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Main",
+ null,
+ "java/lang/Object",
+ new String[] {});
+
+ {
+ methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(1, 1);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitLdcInsn(
+ Type.getType("Lcom/android/tools/r8/kotlin/metadata/metadata_pruned_fields/MethodsKt;"));
+ methodVisitor.visitLdcInsn(Type.getType("Lkotlin/Metadata;"));
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL,
+ "java/lang/Class",
+ "getAnnotation",
+ "(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;",
+ false);
+ methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/Metadata");
+ methodVisitor.visitVarInsn(ASTORE, 1);
+ methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ methodVisitor.visitVarInsn(ALOAD, 1);
+ methodVisitor.visitMethodInsn(
+ INVOKEINTERFACE, "kotlin/Metadata", "pn", "()Ljava/lang/String;", true);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/MethodsKt",
+ "staticMethod",
+ "()V",
+ false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 2);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+
+ return classWriter.toByteArray();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Methods.kt b/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Methods.kt
new file mode 100644
index 0000000..5f67164
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/metadata_pruned_fields/Methods.kt
@@ -0,0 +1,9 @@
+// Copyright (c) 2020, 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.kotlin.metadata.metadata_pruned_fields
+
+fun staticMethod() {
+ println("Hello World!")
+}
\ No newline at end of file