Handle annotated unused argument removal with missing parameter annotations

Code generated by certain versions of javac can have a mismatch between the
number of parameter annotations and the number of parameters. This is known
to happen for non-static inner classes, where the synthetic argument to
<init> for the outer instance is not counted.

The normal procedure is to keep the structure with this mismatch through to
the output. However, when removing arguments the rewriting now takes this
into account, and will explicitly add missing parameter annotation
information.

Change-Id: I6ae62a5040f18454ccb23cdc4f719a5208311561
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 0687442..d34a683 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -111,7 +111,7 @@
 
   public static final DexEncodedMethod[] EMPTY_ARRAY = {};
   public static final DexEncodedMethod SENTINEL =
-      new DexEncodedMethod(null, null, null, null, null);
+      new DexEncodedMethod(null, null, null, ParameterAnnotationsList.empty(), null);
 
   public final DexMethod method;
   public final MethodAccessFlags accessFlags;
@@ -190,6 +190,7 @@
     this.parameterAnnotationsList = parameterAnnotationsList;
     this.code = code;
     assert code == null || !shouldNotHaveCode();
+    assert parameterAnnotationsList != null;
   }
 
   public DexEncodedMethod(
@@ -1541,13 +1542,9 @@
           || from.parameterAnnotationsList.size() == method.proto.parameters.size()) {
         parameterAnnotations = from.parameterAnnotationsList;
       } else {
-        assert false
-            : "Parameter annotations does not match proto of method `"
-                + method.toSourceString()
-                + "` (was: "
-                + parameterAnnotations
-                + ")";
-        parameterAnnotations = ParameterAnnotationsList.empty();
+        // If the there are missing parameter annotations populate these when creating the builder.
+        parameterAnnotations =
+            from.parameterAnnotationsList.withParameterCount(method.proto.parameters.size());
       }
     }
 
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 b6e7513..ac5c8a6 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -748,16 +748,16 @@
           code = new JarCode(method, parent.origin, parent.context, parent.application);
         }
       }
-      ParameterAnnotationsList annotationsList;
+      ParameterAnnotationsList parameterAnnotationsList;
       if (parameterAnnotationsLists == null) {
-        annotationsList = ParameterAnnotationsList.empty();
+        parameterAnnotationsList = ParameterAnnotationsList.empty();
       } else {
         DexAnnotationSet[] sets = new DexAnnotationSet[parameterAnnotationsLists.size()];
         for (int i = 0; i < parameterAnnotationsLists.size(); i++) {
           sets[i] =
               createAnnotationSet(parameterAnnotationsLists.get(i), parent.application.options);
         }
-        annotationsList = new ParameterAnnotationsList(sets);
+        parameterAnnotationsList = new ParameterAnnotationsList(sets);
       }
       InternalOptions internalOptions = parent.application.options;
       if (parameterNames != null && internalOptions.canUseParameterNameAnnotations()) {
@@ -776,7 +776,7 @@
               method,
               flags,
               createAnnotationSet(annotations, parent.application.options),
-              annotationsList,
+              parameterAnnotationsList,
               code,
               parent.version);
       Wrapper<DexMethod> signature = MethodSignatureEquivalence.get().wrap(method);
diff --git a/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
index b46bbbf..53bb117 100644
--- a/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
+++ b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
@@ -23,6 +23,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApp;
@@ -158,7 +159,8 @@
         null,
         null);
     MethodAccessFlags flags = MethodAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC, false);
-    DexEncodedMethod method = new DexEncodedMethod(null, flags, null, null, code);
+    DexEncodedMethod method =
+        new DexEncodedMethod(null, flags, null, ParameterAnnotationsList.empty(), code);
     return new JumboStringRewriter(method, string, factory).rewrite();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/callgraph/CycleEliminationTest.java b/src/test/java/com/android/tools/r8/ir/callgraph/CycleEliminationTest.java
index 5e15f69..f3ed041 100644
--- a/src/test/java/com/android/tools/r8/ir/callgraph/CycleEliminationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/callgraph/CycleEliminationTest.java
@@ -16,6 +16,7 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.ParameterAnnotationsList;
 import com.android.tools.r8.ir.conversion.CallGraph.Node;
 import com.android.tools.r8.ir.conversion.CallGraphBuilder.CycleEliminator;
 import com.android.tools.r8.utils.InternalOptions;
@@ -203,7 +204,8 @@
             dexItemFactory.objectType,
             dexItemFactory.createProto(dexItemFactory.voidType),
             methodName);
-    return new Node(new DexEncodedMethod(signature, null, null, null, null));
+    return new Node(
+        new DexEncodedMethod(signature, null, null, ParameterAnnotationsList.empty(), null));
   }
 
   private Node createForceInlinedNode(String methodName) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsWithMissingAnnotationsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsWithMissingAnnotationsTest.java
new file mode 100644
index 0000000..ef269dc
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedAnnotatedArgumentsWithMissingAnnotationsTest.java
@@ -0,0 +1,562 @@
+// 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.ir.optimize.unusedarguments;
+
+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.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class UnusedAnnotatedArgumentsWithMissingAnnotationsTest extends TestBase
+    implements Opcodes {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withAllRuntimes().build();
+  }
+
+  public UnusedAnnotatedArgumentsWithMissingAnnotationsTest(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  private void checkClass(ClassSubject clazz, String expectedAnnotationClass) {
+    assertThat(clazz, isPresent());
+    MethodSubject init = clazz.init("Test", "java.lang.String");
+    assertThat(init, isPresent());
+    assertEquals(2, init.getMethod().parameterAnnotationsList.size());
+    assertTrue(init.getMethod().parameterAnnotationsList.get(0).isEmpty());
+    assertEquals(1, init.getMethod().parameterAnnotationsList.get(1).annotations.length);
+    assertEquals(
+        "L" + expectedAnnotationClass + ";",
+        init.getMethod()
+            .parameterAnnotationsList
+            .get(1)
+            .annotations[0]
+            .annotation
+            .type
+            .descriptor
+            .toString());
+  }
+
+  @Test
+  public void test() throws Exception {
+    String expectedOutput =
+        StringUtils.lines("In Inner1() used", "In Inner2() used", "In Inner3() used", "In main()");
+    testForR8(parameters.getBackend())
+        .addProgramClassFileData(
+            dumpTest(),
+            dumpInner1(),
+            dumpInner2(),
+            dumpInner3(),
+            dumpAnnotation1(),
+            dumpAnnotation2(),
+            dumpAnnotation3())
+        .addKeepMainRule("Test")
+        .addKeepRules("-keep @interface Annotation?")
+        .addKeepAttributes("RuntimeVisibleParameterAnnotations")
+        .enableProguardTestOptions()
+        .addKeepRules("-neverclassinline class *")
+        .setMinApi(parameters.getRuntime())
+        .compile()
+        .inspect(inspector -> {
+          checkClass(inspector.clazz("Test$Inner1"), "Annotation1");
+          checkClass(inspector.clazz("Test$Inner2"), "Annotation2");
+          checkClass(inspector.clazz("Test$Inner2"), "Annotation2");
+        })
+        .run(parameters.getRuntime(), "Test")
+        .assertSuccessWithOutput(expectedOutput);
+  }
+
+  /*
+   The dump is from Java 8 javac, and the dump is used to ensure that the input has parameter
+   annotations, where the number of annotations are less than the actual number of arguments.
+   Newer version of javac might change to include the synthetic argument in the in the list of
+   parameter annotations, so just using a java class could end up making the test no longer test
+   this case.
+
+   Dump of the following:
+
+   File Test.java:
+
+     public class Test {
+       public class Inner1 {
+         Inner1(@Annotation1 String used, @Annotation2 String unused) {
+             System.out.println("In Inner1() " + used);
+         }
+
+       }
+
+       public class Inner2 {
+         Inner2(@Annotation1 String unused, @Annotation2 String used) {
+             System.out.println("In Inner2() " + used);
+         }
+
+       }
+
+       public class Inner3 {
+         Inner3(
+             @Annotation1 String unused1, @Annotation2 String used, @Annotation3 String unused2) {
+             System.out.println("In Inner3() " + used);
+         }
+
+       }
+
+       public Test() {
+         new Inner1("used", null);
+         new Inner2(null, "used");
+         new Inner3(null, "used", null);
+       }
+
+       public static void main(String[] args) {
+         new Test();
+         System.out.println("In main()");
+       }
+     }
+
+   File Annotation1.java:
+
+     import java.lang.annotation.ElementType;
+     import java.lang.annotation.Retention;
+     import java.lang.annotation.RetentionPolicy;
+     import java.lang.annotation.Target;
+
+     @Retention(RetentionPolicy.RUNTIME)
+     @Target(ElementType.PARAMETER)
+     public @interface Annotation1 {}
+
+   File Annotation2.java:
+
+     import java.lang.annotation.ElementType;
+     import java.lang.annotation.Retention;
+     import java.lang.annotation.RetentionPolicy;
+     import java.lang.annotation.Target;
+
+     @Retention(RetentionPolicy.RUNTIME)
+     @Target(ElementType.PARAMETER)
+     public @interface Annotation2 {}
+
+   File Annotation3.java:
+
+     import java.lang.annotation.ElementType;
+     import java.lang.annotation.Retention;
+     import java.lang.annotation.RetentionPolicy;
+     import java.lang.annotation.Target;
+
+     @Retention(RetentionPolicy.RUNTIME)
+     @Target(ElementType.PARAMETER)
+     public @interface Annotation3 {}
+  */
+
+  static byte[] dumpTest() {
+    ClassWriter classWriter = new ClassWriter(0);
+    MethodVisitor methodVisitor;
+
+    classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, "Test", null, "java/lang/Object", null);
+
+    classWriter.visitSource("Test.java", null);
+
+    classWriter.visitInnerClass("Test$Inner3", "Test", "Inner3", ACC_PUBLIC);
+
+    classWriter.visitInnerClass("Test$Inner2", "Test", "Inner2", ACC_PUBLIC);
+
+    classWriter.visitInnerClass("Test$Inner1", "Test", "Inner1", ACC_PUBLIC);
+
+    {
+      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.visitTypeInsn(NEW, "Test$Inner1");
+      methodVisitor.visitInsn(DUP);
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitLdcInsn("used");
+      methodVisitor.visitInsn(ACONST_NULL);
+      methodVisitor.visitMethodInsn(
+          INVOKESPECIAL,
+          "Test$Inner1",
+          "<init>",
+          "(LTest;Ljava/lang/String;Ljava/lang/String;)V",
+          false);
+      methodVisitor.visitInsn(POP);
+      methodVisitor.visitTypeInsn(NEW, "Test$Inner2");
+      methodVisitor.visitInsn(DUP);
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitInsn(ACONST_NULL);
+      methodVisitor.visitLdcInsn("used");
+      methodVisitor.visitMethodInsn(
+          INVOKESPECIAL,
+          "Test$Inner2",
+          "<init>",
+          "(LTest;Ljava/lang/String;Ljava/lang/String;)V",
+          false);
+      methodVisitor.visitInsn(POP);
+      methodVisitor.visitTypeInsn(NEW, "Test$Inner3");
+      methodVisitor.visitInsn(DUP);
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitInsn(ACONST_NULL);
+      methodVisitor.visitLdcInsn("used");
+      methodVisitor.visitInsn(ACONST_NULL);
+      methodVisitor.visitMethodInsn(
+          INVOKESPECIAL,
+          "Test$Inner3",
+          "<init>",
+          "(LTest;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+          false);
+      methodVisitor.visitInsn(POP);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(6, 1);
+      methodVisitor.visitEnd();
+    }
+    {
+      methodVisitor =
+          classWriter.visitMethod(
+              ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+      methodVisitor.visitCode();
+      methodVisitor.visitTypeInsn(NEW, "Test");
+      methodVisitor.visitInsn(DUP);
+      methodVisitor.visitMethodInsn(INVOKESPECIAL, "Test", "<init>", "()V", false);
+      methodVisitor.visitInsn(POP);
+      methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+      methodVisitor.visitLdcInsn("In main()");
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(2, 1);
+      methodVisitor.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+
+  static byte[] dumpInner1() {
+    ClassWriter classWriter = new ClassWriter(0);
+    FieldVisitor fieldVisitor;
+    MethodVisitor methodVisitor;
+    AnnotationVisitor annotationVisitor0;
+
+    classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, "Test$Inner1", null, "java/lang/Object", null);
+
+    classWriter.visitSource("Test.java", null);
+
+    classWriter.visitInnerClass("Test$Inner1", "Test", "Inner1", ACC_PUBLIC);
+
+    {
+      fieldVisitor =
+          classWriter.visitField(ACC_FINAL | ACC_SYNTHETIC, "this$0", "LTest;", null, null);
+      fieldVisitor.visitEnd();
+    }
+    {
+      methodVisitor =
+          classWriter.visitMethod(
+              0, "<init>", "(LTest;Ljava/lang/String;Ljava/lang/String;)V", null, null);
+      methodVisitor.visitAnnotableParameterCount(2, true);
+      {
+        annotationVisitor0 = methodVisitor.visitParameterAnnotation(0, "LAnnotation1;", true);
+        annotationVisitor0.visitEnd();
+      }
+      {
+        annotationVisitor0 = methodVisitor.visitParameterAnnotation(1, "LAnnotation2;", true);
+        annotationVisitor0.visitEnd();
+      }
+      methodVisitor.visitCode();
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitVarInsn(ALOAD, 1);
+      methodVisitor.visitFieldInsn(PUTFIELD, "Test$Inner1", "this$0", "LTest;");
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+      methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+      methodVisitor.visitTypeInsn(NEW, "java/lang/StringBuilder");
+      methodVisitor.visitInsn(DUP);
+      methodVisitor.visitMethodInsn(
+          INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
+      methodVisitor.visitLdcInsn("In Inner1() ");
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL,
+          "java/lang/StringBuilder",
+          "append",
+          "(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+          false);
+      methodVisitor.visitVarInsn(ALOAD, 2);
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL,
+          "java/lang/StringBuilder",
+          "append",
+          "(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+          false);
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(3, 4);
+      methodVisitor.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+
+  static byte[] dumpInner2() {
+    ClassWriter classWriter = new ClassWriter(0);
+    FieldVisitor fieldVisitor;
+    MethodVisitor methodVisitor;
+    AnnotationVisitor annotationVisitor0;
+
+    classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, "Test$Inner2", null, "java/lang/Object", null);
+
+    classWriter.visitSource("Test.java", null);
+
+    classWriter.visitInnerClass("Test$Inner2", "Test", "Inner2", ACC_PUBLIC);
+
+    {
+      fieldVisitor =
+          classWriter.visitField(ACC_FINAL | ACC_SYNTHETIC, "this$0", "LTest;", null, null);
+      fieldVisitor.visitEnd();
+    }
+    {
+      methodVisitor =
+          classWriter.visitMethod(
+              0, "<init>", "(LTest;Ljava/lang/String;Ljava/lang/String;)V", null, null);
+      methodVisitor.visitAnnotableParameterCount(2, true);
+      {
+        annotationVisitor0 = methodVisitor.visitParameterAnnotation(0, "LAnnotation1;", true);
+        annotationVisitor0.visitEnd();
+      }
+      {
+        annotationVisitor0 = methodVisitor.visitParameterAnnotation(1, "LAnnotation2;", true);
+        annotationVisitor0.visitEnd();
+      }
+      methodVisitor.visitCode();
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitVarInsn(ALOAD, 1);
+      methodVisitor.visitFieldInsn(PUTFIELD, "Test$Inner2", "this$0", "LTest;");
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+      methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+      methodVisitor.visitTypeInsn(NEW, "java/lang/StringBuilder");
+      methodVisitor.visitInsn(DUP);
+      methodVisitor.visitMethodInsn(
+          INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
+      methodVisitor.visitLdcInsn("In Inner2() ");
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL,
+          "java/lang/StringBuilder",
+          "append",
+          "(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+          false);
+      methodVisitor.visitVarInsn(ALOAD, 3);
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL,
+          "java/lang/StringBuilder",
+          "append",
+          "(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+          false);
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(3, 4);
+      methodVisitor.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+
+  static byte[] dumpInner3() {
+    ClassWriter classWriter = new ClassWriter(0);
+    FieldVisitor fieldVisitor;
+    MethodVisitor methodVisitor;
+    AnnotationVisitor annotationVisitor0;
+
+    classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, "Test$Inner3", null, "java/lang/Object", null);
+
+    classWriter.visitSource("Test.java", null);
+
+    classWriter.visitInnerClass("Test$Inner3", "Test", "Inner3", ACC_PUBLIC);
+
+    {
+      fieldVisitor =
+          classWriter.visitField(ACC_FINAL | ACC_SYNTHETIC, "this$0", "LTest;", null, null);
+      fieldVisitor.visitEnd();
+    }
+    {
+      methodVisitor =
+          classWriter.visitMethod(
+              0,
+              "<init>",
+              "(LTest;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+              null,
+              null);
+      methodVisitor.visitAnnotableParameterCount(3, true);
+      {
+        annotationVisitor0 = methodVisitor.visitParameterAnnotation(0, "LAnnotation1;", true);
+        annotationVisitor0.visitEnd();
+      }
+      {
+        annotationVisitor0 = methodVisitor.visitParameterAnnotation(1, "LAnnotation2;", true);
+        annotationVisitor0.visitEnd();
+      }
+      {
+        annotationVisitor0 = methodVisitor.visitParameterAnnotation(2, "LAnnotation3;", true);
+        annotationVisitor0.visitEnd();
+      }
+      methodVisitor.visitCode();
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitVarInsn(ALOAD, 1);
+      methodVisitor.visitFieldInsn(PUTFIELD, "Test$Inner3", "this$0", "LTest;");
+      methodVisitor.visitVarInsn(ALOAD, 0);
+      methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+      methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+      methodVisitor.visitTypeInsn(NEW, "java/lang/StringBuilder");
+      methodVisitor.visitInsn(DUP);
+      methodVisitor.visitMethodInsn(
+          INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V", false);
+      methodVisitor.visitLdcInsn("In Inner3() ");
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL,
+          "java/lang/StringBuilder",
+          "append",
+          "(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+          false);
+      methodVisitor.visitVarInsn(ALOAD, 3);
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL,
+          "java/lang/StringBuilder",
+          "append",
+          "(Ljava/lang/String;)Ljava/lang/StringBuilder;",
+          false);
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
+      methodVisitor.visitMethodInsn(
+          INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
+      methodVisitor.visitInsn(RETURN);
+      methodVisitor.visitMaxs(3, 5);
+      methodVisitor.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+
+  static byte[] dumpAnnotation1() {
+    ClassWriter classWriter = new ClassWriter(0);
+    AnnotationVisitor annotationVisitor0;
+
+    classWriter.visit(
+        V1_8,
+        ACC_PUBLIC | ACC_ANNOTATION | ACC_ABSTRACT | ACC_INTERFACE,
+        "Annotation1",
+        null,
+        "java/lang/Object",
+        new String[] {"java/lang/annotation/Annotation"});
+
+    classWriter.visitSource("Annotation1.java", null);
+
+    {
+      annotationVisitor0 = classWriter.visitAnnotation("Ljava/lang/annotation/Retention;", true);
+      annotationVisitor0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
+      annotationVisitor0.visitEnd();
+    }
+    {
+      annotationVisitor0 = classWriter.visitAnnotation("Ljava/lang/annotation/Target;", true);
+      {
+        AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("value");
+        annotationVisitor1.visitEnum(null, "Ljava/lang/annotation/ElementType;", "PARAMETER");
+        annotationVisitor1.visitEnd();
+      }
+      annotationVisitor0.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+
+  static byte[] dumpAnnotation2() {
+    ClassWriter classWriter = new ClassWriter(0);
+    AnnotationVisitor annotationVisitor0;
+
+    classWriter.visit(
+        V1_8,
+        ACC_PUBLIC | ACC_ANNOTATION | ACC_ABSTRACT | ACC_INTERFACE,
+        "Annotation2",
+        null,
+        "java/lang/Object",
+        new String[] {"java/lang/annotation/Annotation"});
+
+    classWriter.visitSource("Annotation2.java", null);
+
+    {
+      annotationVisitor0 = classWriter.visitAnnotation("Ljava/lang/annotation/Retention;", true);
+      annotationVisitor0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
+      annotationVisitor0.visitEnd();
+    }
+    {
+      annotationVisitor0 = classWriter.visitAnnotation("Ljava/lang/annotation/Target;", true);
+      {
+        AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("value");
+        annotationVisitor1.visitEnum(null, "Ljava/lang/annotation/ElementType;", "PARAMETER");
+        annotationVisitor1.visitEnd();
+      }
+      annotationVisitor0.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+
+  static byte[] dumpAnnotation3() {
+    ClassWriter classWriter = new ClassWriter(0);
+    AnnotationVisitor annotationVisitor0;
+
+    classWriter.visit(
+        V1_8,
+        ACC_PUBLIC | ACC_ANNOTATION | ACC_ABSTRACT | ACC_INTERFACE,
+        "Annotation3",
+        null,
+        "java/lang/Object",
+        new String[] {"java/lang/annotation/Annotation"});
+
+    classWriter.visitSource("Annotation3.java", null);
+
+    {
+      annotationVisitor0 = classWriter.visitAnnotation("Ljava/lang/annotation/Retention;", true);
+      annotationVisitor0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME");
+      annotationVisitor0.visitEnd();
+    }
+    {
+      annotationVisitor0 = classWriter.visitAnnotation("Ljava/lang/annotation/Target;", true);
+      {
+        AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("value");
+        annotationVisitor1.visitEnum(null, "Ljava/lang/annotation/ElementType;", "PARAMETER");
+        annotationVisitor1.visitEnd();
+      }
+      annotationVisitor0.visitEnd();
+    }
+    classWriter.visitEnd();
+
+    return classWriter.toByteArray();
+  }
+}