• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // ASM: a very small and fast Java bytecode manipulation framework
2 // Copyright (c) 2000-2011 INRIA, France Telecom
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions
7 // are met:
8 // 1. Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 // 2. Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in the
12 //    documentation and/or other materials provided with the distribution.
13 // 3. Neither the name of the copyright holders nor the names of its
14 //    contributors may be used to endorse or promote products derived from
15 //    this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27 // THE POSSIBILITY OF SUCH DAMAGE.
28 package org.objectweb.asm.util;
29 
30 import java.io.IOException;
31 import java.io.PrintWriter;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 import org.objectweb.asm.Attribute;
38 import org.objectweb.asm.ConstantDynamic;
39 import org.objectweb.asm.Handle;
40 import org.objectweb.asm.Label;
41 import org.objectweb.asm.Opcodes;
42 import org.objectweb.asm.Type;
43 import org.objectweb.asm.TypePath;
44 
45 /**
46  * A {@link Printer} that prints the ASM code to generate the classes it visits.
47  *
48  * @author Eric Bruneton
49  */
50 // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
51 public class ASMifier extends Printer {
52 
53   /** The help message shown when command line arguments are incorrect. */
54   private static final String USAGE =
55       "Prints the ASM code to generate the given class.\n"
56           + "Usage: ASMifier [-nodebug] <fully qualified class name or class file name>";
57 
58   /** A pseudo access flag used to distinguish class access flags. */
59   private static final int ACCESS_CLASS = 0x40000;
60 
61   /** A pseudo access flag used to distinguish field access flags. */
62   private static final int ACCESS_FIELD = 0x80000;
63 
64   /** A pseudo access flag used to distinguish inner class flags. */
65   private static final int ACCESS_INNER = 0x100000;
66 
67   /** A pseudo access flag used to distinguish module requires / exports flags. */
68   private static final int ACCESS_MODULE = 0x200000;
69 
70   private static final String ANNOTATION_VISITOR = "annotationVisitor";
71   private static final String ANNOTATION_VISITOR0 = "annotationVisitor0 = ";
72   private static final String COMMA = "\", \"";
73   private static final String END_ARRAY = " });\n";
74   private static final String END_PARAMETERS = ");\n\n";
75   private static final String NEW_OBJECT_ARRAY = ", new Object[] {";
76   private static final String VISIT_END = ".visitEnd();\n";
77 
78   private static final List<String> FRAME_TYPES =
79       Collections.unmodifiableList(
80           Arrays.asList(
81               "Opcodes.TOP",
82               "Opcodes.INTEGER",
83               "Opcodes.FLOAT",
84               "Opcodes.DOUBLE",
85               "Opcodes.LONG",
86               "Opcodes.NULL",
87               "Opcodes.UNINITIALIZED_THIS"));
88 
89   private static final Map<Integer, String> CLASS_VERSIONS;
90 
91   static {
92     HashMap<Integer, String> classVersions = new HashMap<>();
classVersions.put(Opcodes.V1_1, "V1_1")93     classVersions.put(Opcodes.V1_1, "V1_1");
classVersions.put(Opcodes.V1_2, "V1_2")94     classVersions.put(Opcodes.V1_2, "V1_2");
classVersions.put(Opcodes.V1_3, "V1_3")95     classVersions.put(Opcodes.V1_3, "V1_3");
classVersions.put(Opcodes.V1_4, "V1_4")96     classVersions.put(Opcodes.V1_4, "V1_4");
classVersions.put(Opcodes.V1_5, "V1_5")97     classVersions.put(Opcodes.V1_5, "V1_5");
classVersions.put(Opcodes.V1_6, "V1_6")98     classVersions.put(Opcodes.V1_6, "V1_6");
classVersions.put(Opcodes.V1_7, "V1_7")99     classVersions.put(Opcodes.V1_7, "V1_7");
classVersions.put(Opcodes.V1_8, "V1_8")100     classVersions.put(Opcodes.V1_8, "V1_8");
classVersions.put(Opcodes.V9, "V9")101     classVersions.put(Opcodes.V9, "V9");
classVersions.put(Opcodes.V10, "V10")102     classVersions.put(Opcodes.V10, "V10");
classVersions.put(Opcodes.V11, "V11")103     classVersions.put(Opcodes.V11, "V11");
classVersions.put(Opcodes.V12, "V12")104     classVersions.put(Opcodes.V12, "V12");
classVersions.put(Opcodes.V13, "V13")105     classVersions.put(Opcodes.V13, "V13");
classVersions.put(Opcodes.V14, "V14")106     classVersions.put(Opcodes.V14, "V14");
classVersions.put(Opcodes.V15, "V15")107     classVersions.put(Opcodes.V15, "V15");
classVersions.put(Opcodes.V16, "V16")108     classVersions.put(Opcodes.V16, "V16");
classVersions.put(Opcodes.V17, "V17")109     classVersions.put(Opcodes.V17, "V17");
classVersions.put(Opcodes.V18, "V18")110     classVersions.put(Opcodes.V18, "V18");
classVersions.put(Opcodes.V19, "V19")111     classVersions.put(Opcodes.V19, "V19");
classVersions.put(Opcodes.V20, "V20")112     classVersions.put(Opcodes.V20, "V20");
classVersions.put(Opcodes.V21, "V21")113     classVersions.put(Opcodes.V21, "V21");
114     CLASS_VERSIONS = Collections.unmodifiableMap(classVersions);
115   }
116 
117   /** The name of the visitor variable in the produced code. */
118   protected final String name;
119 
120   /** The identifier of the annotation visitor variable in the produced code. */
121   protected final int id;
122 
123   /** The name of the Label variables in the produced code. */
124   protected Map<Label, String> labelNames;
125 
126   /**
127    * Constructs a new {@link ASMifier}. <i>Subclasses must not use this constructor</i>. Instead,
128    * they must use the {@link #ASMifier(int, String, int)} version.
129    *
130    * @throws IllegalStateException If a subclass calls this constructor.
131    */
ASMifier()132   public ASMifier() {
133     this(/* latest api = */ Opcodes.ASM9, "classWriter", 0);
134     if (getClass() != ASMifier.class) {
135       throw new IllegalStateException();
136     }
137   }
138 
139   /**
140    * Constructs a new {@link ASMifier}.
141    *
142    * @param api the ASM API version implemented by this class. Must be one of the {@code
143    *     ASM}<i>x</i> values in {@link Opcodes}.
144    * @param visitorVariableName the name of the visitor variable in the produced code.
145    * @param annotationVisitorId identifier of the annotation visitor variable in the produced code.
146    */
ASMifier( final int api, final String visitorVariableName, final int annotationVisitorId)147   protected ASMifier(
148       final int api, final String visitorVariableName, final int annotationVisitorId) {
149     super(api);
150     this.name = visitorVariableName;
151     this.id = annotationVisitorId;
152   }
153 
154   /**
155    * Prints the ASM source code to generate the given class to the standard output.
156    *
157    * <p>Usage: ASMifier [-nodebug] &lt;binary class name or class file name&gt;
158    *
159    * @param args the command line arguments.
160    * @throws IOException if the class cannot be found, or if an IOException occurs.
161    */
main(final String[] args)162   public static void main(final String[] args) throws IOException {
163     main(args, new PrintWriter(System.out, true), new PrintWriter(System.err, true));
164   }
165 
166   /**
167    * Prints the ASM source code to generate the given class to the given output.
168    *
169    * <p>Usage: ASMifier [-nodebug] &lt;binary class name or class file name&gt;
170    *
171    * @param args the command line arguments.
172    * @param output where to print the result.
173    * @param logger where to log errors.
174    * @throws IOException if the class cannot be found, or if an IOException occurs.
175    */
main(final String[] args, final PrintWriter output, final PrintWriter logger)176   static void main(final String[] args, final PrintWriter output, final PrintWriter logger)
177       throws IOException {
178     main(args, USAGE, new ASMifier(), output, logger);
179   }
180 
181   // -----------------------------------------------------------------------------------------------
182   // Classes
183   // -----------------------------------------------------------------------------------------------
184 
185   @Override
visit( final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces)186   public void visit(
187       final int version,
188       final int access,
189       final String name,
190       final String signature,
191       final String superName,
192       final String[] interfaces) {
193     String simpleName;
194     if (name == null) {
195       simpleName = "module-info";
196     } else {
197       int lastSlashIndex = name.lastIndexOf('/');
198       if (lastSlashIndex == -1) {
199         simpleName = name;
200       } else {
201         text.add("package asm." + name.substring(0, lastSlashIndex).replace('/', '.') + ";\n");
202         simpleName = name.substring(lastSlashIndex + 1).replaceAll("[-\\(\\)]", "_");
203       }
204     }
205     text.add("import org.objectweb.asm.AnnotationVisitor;\n");
206     text.add("import org.objectweb.asm.Attribute;\n");
207     text.add("import org.objectweb.asm.ClassReader;\n");
208     text.add("import org.objectweb.asm.ClassWriter;\n");
209     text.add("import org.objectweb.asm.ConstantDynamic;\n");
210     text.add("import org.objectweb.asm.FieldVisitor;\n");
211     text.add("import org.objectweb.asm.Handle;\n");
212     text.add("import org.objectweb.asm.Label;\n");
213     text.add("import org.objectweb.asm.MethodVisitor;\n");
214     text.add("import org.objectweb.asm.Opcodes;\n");
215     text.add("import org.objectweb.asm.RecordComponentVisitor;\n");
216     text.add("import org.objectweb.asm.Type;\n");
217     text.add("import org.objectweb.asm.TypePath;\n");
218     text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
219     text.add("public static byte[] dump () throws Exception {\n\n");
220     text.add("ClassWriter classWriter = new ClassWriter(0);\n");
221     text.add("FieldVisitor fieldVisitor;\n");
222     text.add("RecordComponentVisitor recordComponentVisitor;\n");
223     text.add("MethodVisitor methodVisitor;\n");
224     text.add("AnnotationVisitor annotationVisitor0;\n\n");
225 
226     stringBuilder.setLength(0);
227     stringBuilder.append("classWriter.visit(");
228     String versionString = CLASS_VERSIONS.get(version);
229     if (versionString != null) {
230       stringBuilder.append(versionString);
231     } else {
232       stringBuilder.append(version);
233     }
234     stringBuilder.append(", ");
235     appendAccessFlags(access | ACCESS_CLASS);
236     stringBuilder.append(", ");
237     appendConstant(name);
238     stringBuilder.append(", ");
239     appendConstant(signature);
240     stringBuilder.append(", ");
241     appendConstant(superName);
242     stringBuilder.append(", ");
243     if (interfaces != null && interfaces.length > 0) {
244       stringBuilder.append("new String[] {");
245       for (int i = 0; i < interfaces.length; ++i) {
246         stringBuilder.append(i == 0 ? " " : ", ");
247         appendConstant(interfaces[i]);
248       }
249       stringBuilder.append(" }");
250     } else {
251       stringBuilder.append("null");
252     }
253     stringBuilder.append(END_PARAMETERS);
254     text.add(stringBuilder.toString());
255   }
256 
257   @Override
visitSource(final String file, final String debug)258   public void visitSource(final String file, final String debug) {
259     stringBuilder.setLength(0);
260     stringBuilder.append("classWriter.visitSource(");
261     appendConstant(file);
262     stringBuilder.append(", ");
263     appendConstant(debug);
264     stringBuilder.append(END_PARAMETERS);
265     text.add(stringBuilder.toString());
266   }
267 
268   @Override
visitModule(final String name, final int flags, final String version)269   public Printer visitModule(final String name, final int flags, final String version) {
270     stringBuilder.setLength(0);
271     stringBuilder.append("{\n");
272     stringBuilder.append("ModuleVisitor moduleVisitor = classWriter.visitModule(");
273     appendConstant(name);
274     stringBuilder.append(", ");
275     appendAccessFlags(flags | ACCESS_MODULE);
276     stringBuilder.append(", ");
277     appendConstant(version);
278     stringBuilder.append(END_PARAMETERS);
279     text.add(stringBuilder.toString());
280     ASMifier asmifier = createASMifier("moduleVisitor", 0);
281     text.add(asmifier.getText());
282     text.add("}\n");
283     return asmifier;
284   }
285 
286   @Override
visitNestHost(final String nestHost)287   public void visitNestHost(final String nestHost) {
288     stringBuilder.setLength(0);
289     stringBuilder.append("classWriter.visitNestHost(");
290     appendConstant(nestHost);
291     stringBuilder.append(END_PARAMETERS);
292     text.add(stringBuilder.toString());
293   }
294 
295   @Override
visitOuterClass(final String owner, final String name, final String descriptor)296   public void visitOuterClass(final String owner, final String name, final String descriptor) {
297     stringBuilder.setLength(0);
298     stringBuilder.append("classWriter.visitOuterClass(");
299     appendConstant(owner);
300     stringBuilder.append(", ");
301     appendConstant(name);
302     stringBuilder.append(", ");
303     appendConstant(descriptor);
304     stringBuilder.append(END_PARAMETERS);
305     text.add(stringBuilder.toString());
306   }
307 
308   @Override
visitClassAnnotation(final String descriptor, final boolean visible)309   public ASMifier visitClassAnnotation(final String descriptor, final boolean visible) {
310     return visitAnnotation(descriptor, visible);
311   }
312 
313   @Override
visitClassTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)314   public ASMifier visitClassTypeAnnotation(
315       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
316     return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
317   }
318 
319   @Override
visitClassAttribute(final Attribute attribute)320   public void visitClassAttribute(final Attribute attribute) {
321     visitAttribute(attribute);
322   }
323 
324   @Override
visitNestMember(final String nestMember)325   public void visitNestMember(final String nestMember) {
326     stringBuilder.setLength(0);
327     stringBuilder.append("classWriter.visitNestMember(");
328     appendConstant(nestMember);
329     stringBuilder.append(END_PARAMETERS);
330     text.add(stringBuilder.toString());
331   }
332 
333   @Override
visitPermittedSubclass(final String permittedSubclass)334   public void visitPermittedSubclass(final String permittedSubclass) {
335     stringBuilder.setLength(0);
336     stringBuilder.append("classWriter.visitPermittedSubclass(");
337     appendConstant(permittedSubclass);
338     stringBuilder.append(END_PARAMETERS);
339     text.add(stringBuilder.toString());
340   }
341 
342   @Override
visitInnerClass( final String name, final String outerName, final String innerName, final int access)343   public void visitInnerClass(
344       final String name, final String outerName, final String innerName, final int access) {
345     stringBuilder.setLength(0);
346     stringBuilder.append("classWriter.visitInnerClass(");
347     appendConstant(name);
348     stringBuilder.append(", ");
349     appendConstant(outerName);
350     stringBuilder.append(", ");
351     appendConstant(innerName);
352     stringBuilder.append(", ");
353     appendAccessFlags(access | ACCESS_INNER);
354     stringBuilder.append(END_PARAMETERS);
355     text.add(stringBuilder.toString());
356   }
357 
358   @Override
visitRecordComponent( final String name, final String descriptor, final String signature)359   public ASMifier visitRecordComponent(
360       final String name, final String descriptor, final String signature) {
361     stringBuilder.setLength(0);
362     stringBuilder.append("{\n");
363     stringBuilder.append("recordComponentVisitor = classWriter.visitRecordComponent(");
364     appendConstant(name);
365     stringBuilder.append(", ");
366     appendConstant(descriptor);
367     stringBuilder.append(", ");
368     appendConstant(signature);
369     stringBuilder.append(");\n");
370     text.add(stringBuilder.toString());
371     ASMifier asmifier = createASMifier("recordComponentVisitor", 0);
372     text.add(asmifier.getText());
373     text.add("}\n");
374     return asmifier;
375   }
376 
377   @Override
visitField( final int access, final String name, final String descriptor, final String signature, final Object value)378   public ASMifier visitField(
379       final int access,
380       final String name,
381       final String descriptor,
382       final String signature,
383       final Object value) {
384     stringBuilder.setLength(0);
385     stringBuilder.append("{\n");
386     stringBuilder.append("fieldVisitor = classWriter.visitField(");
387     appendAccessFlags(access | ACCESS_FIELD);
388     stringBuilder.append(", ");
389     appendConstant(name);
390     stringBuilder.append(", ");
391     appendConstant(descriptor);
392     stringBuilder.append(", ");
393     appendConstant(signature);
394     stringBuilder.append(", ");
395     appendConstant(value);
396     stringBuilder.append(");\n");
397     text.add(stringBuilder.toString());
398     ASMifier asmifier = createASMifier("fieldVisitor", 0);
399     text.add(asmifier.getText());
400     text.add("}\n");
401     return asmifier;
402   }
403 
404   @Override
visitMethod( final int access, final String name, final String descriptor, final String signature, final String[] exceptions)405   public ASMifier visitMethod(
406       final int access,
407       final String name,
408       final String descriptor,
409       final String signature,
410       final String[] exceptions) {
411     stringBuilder.setLength(0);
412     stringBuilder.append("{\n");
413     stringBuilder.append("methodVisitor = classWriter.visitMethod(");
414     appendAccessFlags(access);
415     stringBuilder.append(", ");
416     appendConstant(name);
417     stringBuilder.append(", ");
418     appendConstant(descriptor);
419     stringBuilder.append(", ");
420     appendConstant(signature);
421     stringBuilder.append(", ");
422     if (exceptions != null && exceptions.length > 0) {
423       stringBuilder.append("new String[] {");
424       for (int i = 0; i < exceptions.length; ++i) {
425         stringBuilder.append(i == 0 ? " " : ", ");
426         appendConstant(exceptions[i]);
427       }
428       stringBuilder.append(" }");
429     } else {
430       stringBuilder.append("null");
431     }
432     stringBuilder.append(");\n");
433     text.add(stringBuilder.toString());
434     ASMifier asmifier = createASMifier("methodVisitor", 0);
435     text.add(asmifier.getText());
436     text.add("}\n");
437     return asmifier;
438   }
439 
440   @Override
visitClassEnd()441   public void visitClassEnd() {
442     text.add("classWriter.visitEnd();\n\n");
443     text.add("return classWriter.toByteArray();\n");
444     text.add("}\n");
445     text.add("}\n");
446   }
447 
448   // -----------------------------------------------------------------------------------------------
449   // Modules
450   // -----------------------------------------------------------------------------------------------
451 
452   @Override
visitMainClass(final String mainClass)453   public void visitMainClass(final String mainClass) {
454     stringBuilder.setLength(0);
455     stringBuilder.append("moduleVisitor.visitMainClass(");
456     appendConstant(mainClass);
457     stringBuilder.append(");\n");
458     text.add(stringBuilder.toString());
459   }
460 
461   @Override
visitPackage(final String packaze)462   public void visitPackage(final String packaze) {
463     stringBuilder.setLength(0);
464     stringBuilder.append("moduleVisitor.visitPackage(");
465     appendConstant(packaze);
466     stringBuilder.append(");\n");
467     text.add(stringBuilder.toString());
468   }
469 
470   @Override
visitRequire(final String module, final int access, final String version)471   public void visitRequire(final String module, final int access, final String version) {
472     stringBuilder.setLength(0);
473     stringBuilder.append("moduleVisitor.visitRequire(");
474     appendConstant(module);
475     stringBuilder.append(", ");
476     appendAccessFlags(access | ACCESS_MODULE);
477     stringBuilder.append(", ");
478     appendConstant(version);
479     stringBuilder.append(");\n");
480     text.add(stringBuilder.toString());
481   }
482 
483   @Override
visitExport(final String packaze, final int access, final String... modules)484   public void visitExport(final String packaze, final int access, final String... modules) {
485     visitExportOrOpen("moduleVisitor.visitExport(", packaze, access, modules);
486   }
487 
488   @Override
visitOpen(final String packaze, final int access, final String... modules)489   public void visitOpen(final String packaze, final int access, final String... modules) {
490     visitExportOrOpen("moduleVisitor.visitOpen(", packaze, access, modules);
491   }
492 
visitExportOrOpen( final String visitMethod, final String packaze, final int access, final String... modules)493   private void visitExportOrOpen(
494       final String visitMethod, final String packaze, final int access, final String... modules) {
495     stringBuilder.setLength(0);
496     stringBuilder.append(visitMethod);
497     appendConstant(packaze);
498     stringBuilder.append(", ");
499     appendAccessFlags(access | ACCESS_MODULE);
500     if (modules != null && modules.length > 0) {
501       stringBuilder.append(", new String[] {");
502       for (int i = 0; i < modules.length; ++i) {
503         stringBuilder.append(i == 0 ? " " : ", ");
504         appendConstant(modules[i]);
505       }
506       stringBuilder.append(" }");
507     }
508     stringBuilder.append(");\n");
509     text.add(stringBuilder.toString());
510   }
511 
512   @Override
visitUse(final String service)513   public void visitUse(final String service) {
514     stringBuilder.setLength(0);
515     stringBuilder.append("moduleVisitor.visitUse(");
516     appendConstant(service);
517     stringBuilder.append(");\n");
518     text.add(stringBuilder.toString());
519   }
520 
521   @Override
visitProvide(final String service, final String... providers)522   public void visitProvide(final String service, final String... providers) {
523     stringBuilder.setLength(0);
524     stringBuilder.append("moduleVisitor.visitProvide(");
525     appendConstant(service);
526     stringBuilder.append(",  new String[] {");
527     for (int i = 0; i < providers.length; ++i) {
528       stringBuilder.append(i == 0 ? " " : ", ");
529       appendConstant(providers[i]);
530     }
531     stringBuilder.append(END_ARRAY);
532     text.add(stringBuilder.toString());
533   }
534 
535   @Override
visitModuleEnd()536   public void visitModuleEnd() {
537     text.add("moduleVisitor.visitEnd();\n");
538   }
539 
540   // -----------------------------------------------------------------------------------------------
541   // Annotations
542   // -----------------------------------------------------------------------------------------------
543 
544   // DontCheck(OverloadMethodsDeclarationOrder): overloads are semantically different.
545   @Override
visit(final String name, final Object value)546   public void visit(final String name, final Object value) {
547     stringBuilder.setLength(0);
548     stringBuilder.append(ANNOTATION_VISITOR).append(id).append(".visit(");
549     appendConstant(name);
550     stringBuilder.append(", ");
551     appendConstant(value);
552     stringBuilder.append(");\n");
553     text.add(stringBuilder.toString());
554   }
555 
556   @Override
visitEnum(final String name, final String descriptor, final String value)557   public void visitEnum(final String name, final String descriptor, final String value) {
558     stringBuilder.setLength(0);
559     stringBuilder.append(ANNOTATION_VISITOR).append(id).append(".visitEnum(");
560     appendConstant(name);
561     stringBuilder.append(", ");
562     appendConstant(descriptor);
563     stringBuilder.append(", ");
564     appendConstant(value);
565     stringBuilder.append(");\n");
566     text.add(stringBuilder.toString());
567   }
568 
569   @Override
visitAnnotation(final String name, final String descriptor)570   public ASMifier visitAnnotation(final String name, final String descriptor) {
571     stringBuilder.setLength(0);
572     stringBuilder
573         .append("{\n")
574         .append("AnnotationVisitor annotationVisitor")
575         .append(id + 1)
576         .append(" = annotationVisitor");
577     stringBuilder.append(id).append(".visitAnnotation(");
578     appendConstant(name);
579     stringBuilder.append(", ");
580     appendConstant(descriptor);
581     stringBuilder.append(");\n");
582     text.add(stringBuilder.toString());
583     ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, id + 1);
584     text.add(asmifier.getText());
585     text.add("}\n");
586     return asmifier;
587   }
588 
589   @Override
visitArray(final String name)590   public ASMifier visitArray(final String name) {
591     stringBuilder.setLength(0);
592     stringBuilder.append("{\n");
593     stringBuilder
594         .append("AnnotationVisitor annotationVisitor")
595         .append(id + 1)
596         .append(" = annotationVisitor");
597     stringBuilder.append(id).append(".visitArray(");
598     appendConstant(name);
599     stringBuilder.append(");\n");
600     text.add(stringBuilder.toString());
601     ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, id + 1);
602     text.add(asmifier.getText());
603     text.add("}\n");
604     return asmifier;
605   }
606 
607   @Override
visitAnnotationEnd()608   public void visitAnnotationEnd() {
609     stringBuilder.setLength(0);
610     stringBuilder.append(ANNOTATION_VISITOR).append(id).append(VISIT_END);
611     text.add(stringBuilder.toString());
612   }
613 
614   // -----------------------------------------------------------------------------------------------
615   // Record components
616   // -----------------------------------------------------------------------------------------------
617 
618   @Override
visitRecordComponentAnnotation(final String descriptor, final boolean visible)619   public ASMifier visitRecordComponentAnnotation(final String descriptor, final boolean visible) {
620     return visitAnnotation(descriptor, visible);
621   }
622 
623   @Override
visitRecordComponentTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)624   public ASMifier visitRecordComponentTypeAnnotation(
625       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
626     return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
627   }
628 
629   @Override
visitRecordComponentAttribute(final Attribute attribute)630   public void visitRecordComponentAttribute(final Attribute attribute) {
631     visitAttribute(attribute);
632   }
633 
634   @Override
visitRecordComponentEnd()635   public void visitRecordComponentEnd() {
636     visitMemberEnd();
637   }
638 
639   // -----------------------------------------------------------------------------------------------
640   // Fields
641   // -----------------------------------------------------------------------------------------------
642 
643   @Override
visitFieldAnnotation(final String descriptor, final boolean visible)644   public ASMifier visitFieldAnnotation(final String descriptor, final boolean visible) {
645     return visitAnnotation(descriptor, visible);
646   }
647 
648   @Override
visitFieldTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)649   public ASMifier visitFieldTypeAnnotation(
650       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
651     return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
652   }
653 
654   @Override
visitFieldAttribute(final Attribute attribute)655   public void visitFieldAttribute(final Attribute attribute) {
656     visitAttribute(attribute);
657   }
658 
659   @Override
visitFieldEnd()660   public void visitFieldEnd() {
661     visitMemberEnd();
662   }
663 
664   // -----------------------------------------------------------------------------------------------
665   // Methods
666   // -----------------------------------------------------------------------------------------------
667 
668   @Override
visitParameter(final String parameterName, final int access)669   public void visitParameter(final String parameterName, final int access) {
670     stringBuilder.setLength(0);
671     stringBuilder.append(name).append(".visitParameter(");
672     appendString(stringBuilder, parameterName);
673     stringBuilder.append(", ");
674     appendAccessFlags(access);
675     text.add(stringBuilder.append(");\n").toString());
676   }
677 
678   @Override
visitAnnotationDefault()679   public ASMifier visitAnnotationDefault() {
680     stringBuilder.setLength(0);
681     stringBuilder
682         .append("{\n")
683         .append(ANNOTATION_VISITOR0)
684         .append(name)
685         .append(".visitAnnotationDefault();\n");
686     text.add(stringBuilder.toString());
687     ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
688     text.add(asmifier.getText());
689     text.add("}\n");
690     return asmifier;
691   }
692 
693   @Override
visitMethodAnnotation(final String descriptor, final boolean visible)694   public ASMifier visitMethodAnnotation(final String descriptor, final boolean visible) {
695     return visitAnnotation(descriptor, visible);
696   }
697 
698   @Override
visitMethodTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)699   public ASMifier visitMethodTypeAnnotation(
700       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
701     return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
702   }
703 
704   @Override
visitAnnotableParameterCount(final int parameterCount, final boolean visible)705   public ASMifier visitAnnotableParameterCount(final int parameterCount, final boolean visible) {
706     stringBuilder.setLength(0);
707     stringBuilder
708         .append(name)
709         .append(".visitAnnotableParameterCount(")
710         .append(parameterCount)
711         .append(", ")
712         .append(visible)
713         .append(");\n");
714     text.add(stringBuilder.toString());
715     return this;
716   }
717 
718   @Override
visitParameterAnnotation( final int parameter, final String descriptor, final boolean visible)719   public ASMifier visitParameterAnnotation(
720       final int parameter, final String descriptor, final boolean visible) {
721     stringBuilder.setLength(0);
722     stringBuilder
723         .append("{\n")
724         .append(ANNOTATION_VISITOR0)
725         .append(name)
726         .append(".visitParameterAnnotation(")
727         .append(parameter)
728         .append(", ");
729     appendConstant(descriptor);
730     stringBuilder.append(", ").append(visible).append(");\n");
731     text.add(stringBuilder.toString());
732     ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
733     text.add(asmifier.getText());
734     text.add("}\n");
735     return asmifier;
736   }
737 
738   @Override
visitMethodAttribute(final Attribute attribute)739   public void visitMethodAttribute(final Attribute attribute) {
740     visitAttribute(attribute);
741   }
742 
743   @Override
visitCode()744   public void visitCode() {
745     text.add(name + ".visitCode();\n");
746   }
747 
748   @Override
visitFrame( final int type, final int numLocal, final Object[] local, final int numStack, final Object[] stack)749   public void visitFrame(
750       final int type,
751       final int numLocal,
752       final Object[] local,
753       final int numStack,
754       final Object[] stack) {
755     stringBuilder.setLength(0);
756     switch (type) {
757       case Opcodes.F_NEW:
758       case Opcodes.F_FULL:
759         declareFrameTypes(numLocal, local);
760         declareFrameTypes(numStack, stack);
761         if (type == Opcodes.F_NEW) {
762           stringBuilder.append(name).append(".visitFrame(Opcodes.F_NEW, ");
763         } else {
764           stringBuilder.append(name).append(".visitFrame(Opcodes.F_FULL, ");
765         }
766         stringBuilder.append(numLocal).append(NEW_OBJECT_ARRAY);
767         appendFrameTypes(numLocal, local);
768         stringBuilder.append("}, ").append(numStack).append(NEW_OBJECT_ARRAY);
769         appendFrameTypes(numStack, stack);
770         stringBuilder.append('}');
771         break;
772       case Opcodes.F_APPEND:
773         declareFrameTypes(numLocal, local);
774         stringBuilder
775             .append(name)
776             .append(".visitFrame(Opcodes.F_APPEND,")
777             .append(numLocal)
778             .append(NEW_OBJECT_ARRAY);
779         appendFrameTypes(numLocal, local);
780         stringBuilder.append("}, 0, null");
781         break;
782       case Opcodes.F_CHOP:
783         stringBuilder
784             .append(name)
785             .append(".visitFrame(Opcodes.F_CHOP,")
786             .append(numLocal)
787             .append(", null, 0, null");
788         break;
789       case Opcodes.F_SAME:
790         stringBuilder.append(name).append(".visitFrame(Opcodes.F_SAME, 0, null, 0, null");
791         break;
792       case Opcodes.F_SAME1:
793         declareFrameTypes(1, stack);
794         stringBuilder
795             .append(name)
796             .append(".visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {");
797         appendFrameTypes(1, stack);
798         stringBuilder.append('}');
799         break;
800       default:
801         throw new IllegalArgumentException();
802     }
803     stringBuilder.append(");\n");
804     text.add(stringBuilder.toString());
805   }
806 
807   @Override
visitInsn(final int opcode)808   public void visitInsn(final int opcode) {
809     stringBuilder.setLength(0);
810     stringBuilder.append(name).append(".visitInsn(").append(OPCODES[opcode]).append(");\n");
811     text.add(stringBuilder.toString());
812   }
813 
814   @Override
visitIntInsn(final int opcode, final int operand)815   public void visitIntInsn(final int opcode, final int operand) {
816     stringBuilder.setLength(0);
817     stringBuilder
818         .append(name)
819         .append(".visitIntInsn(")
820         .append(OPCODES[opcode])
821         .append(", ")
822         .append(opcode == Opcodes.NEWARRAY ? TYPES[operand] : Integer.toString(operand))
823         .append(");\n");
824     text.add(stringBuilder.toString());
825   }
826 
827   @Override
visitVarInsn(final int opcode, final int varIndex)828   public void visitVarInsn(final int opcode, final int varIndex) {
829     stringBuilder.setLength(0);
830     stringBuilder
831         .append(name)
832         .append(".visitVarInsn(")
833         .append(OPCODES[opcode])
834         .append(", ")
835         .append(varIndex)
836         .append(");\n");
837     text.add(stringBuilder.toString());
838   }
839 
840   @Override
visitTypeInsn(final int opcode, final String type)841   public void visitTypeInsn(final int opcode, final String type) {
842     stringBuilder.setLength(0);
843     stringBuilder.append(name).append(".visitTypeInsn(").append(OPCODES[opcode]).append(", ");
844     appendConstant(type);
845     stringBuilder.append(");\n");
846     text.add(stringBuilder.toString());
847   }
848 
849   @Override
visitFieldInsn( final int opcode, final String owner, final String name, final String descriptor)850   public void visitFieldInsn(
851       final int opcode, final String owner, final String name, final String descriptor) {
852     stringBuilder.setLength(0);
853     stringBuilder.append(this.name).append(".visitFieldInsn(").append(OPCODES[opcode]).append(", ");
854     appendConstant(owner);
855     stringBuilder.append(", ");
856     appendConstant(name);
857     stringBuilder.append(", ");
858     appendConstant(descriptor);
859     stringBuilder.append(");\n");
860     text.add(stringBuilder.toString());
861   }
862 
863   @Override
visitMethodInsn( final int opcode, final String owner, final String name, final String descriptor, final boolean isInterface)864   public void visitMethodInsn(
865       final int opcode,
866       final String owner,
867       final String name,
868       final String descriptor,
869       final boolean isInterface) {
870     stringBuilder.setLength(0);
871     stringBuilder
872         .append(this.name)
873         .append(".visitMethodInsn(")
874         .append(OPCODES[opcode])
875         .append(", ");
876     appendConstant(owner);
877     stringBuilder.append(", ");
878     appendConstant(name);
879     stringBuilder.append(", ");
880     appendConstant(descriptor);
881     stringBuilder.append(", ");
882     stringBuilder.append(isInterface ? "true" : "false");
883     stringBuilder.append(");\n");
884     text.add(stringBuilder.toString());
885   }
886 
887   @Override
visitInvokeDynamicInsn( final String name, final String descriptor, final Handle bootstrapMethodHandle, final Object... bootstrapMethodArguments)888   public void visitInvokeDynamicInsn(
889       final String name,
890       final String descriptor,
891       final Handle bootstrapMethodHandle,
892       final Object... bootstrapMethodArguments) {
893     stringBuilder.setLength(0);
894     stringBuilder.append(this.name).append(".visitInvokeDynamicInsn(");
895     appendConstant(name);
896     stringBuilder.append(", ");
897     appendConstant(descriptor);
898     stringBuilder.append(", ");
899     appendConstant(bootstrapMethodHandle);
900     stringBuilder.append(", new Object[]{");
901     for (int i = 0; i < bootstrapMethodArguments.length; ++i) {
902       appendConstant(bootstrapMethodArguments[i]);
903       if (i != bootstrapMethodArguments.length - 1) {
904         stringBuilder.append(", ");
905       }
906     }
907     stringBuilder.append("});\n");
908     text.add(stringBuilder.toString());
909   }
910 
911   @Override
visitJumpInsn(final int opcode, final Label label)912   public void visitJumpInsn(final int opcode, final Label label) {
913     stringBuilder.setLength(0);
914     declareLabel(label);
915     stringBuilder.append(name).append(".visitJumpInsn(").append(OPCODES[opcode]).append(", ");
916     appendLabel(label);
917     stringBuilder.append(");\n");
918     text.add(stringBuilder.toString());
919   }
920 
921   @Override
visitLabel(final Label label)922   public void visitLabel(final Label label) {
923     stringBuilder.setLength(0);
924     declareLabel(label);
925     stringBuilder.append(name).append(".visitLabel(");
926     appendLabel(label);
927     stringBuilder.append(");\n");
928     text.add(stringBuilder.toString());
929   }
930 
931   @Override
visitLdcInsn(final Object value)932   public void visitLdcInsn(final Object value) {
933     stringBuilder.setLength(0);
934     stringBuilder.append(name).append(".visitLdcInsn(");
935     appendConstant(value);
936     stringBuilder.append(");\n");
937     text.add(stringBuilder.toString());
938   }
939 
940   @Override
visitIincInsn(final int varIndex, final int increment)941   public void visitIincInsn(final int varIndex, final int increment) {
942     stringBuilder.setLength(0);
943     stringBuilder
944         .append(name)
945         .append(".visitIincInsn(")
946         .append(varIndex)
947         .append(", ")
948         .append(increment)
949         .append(");\n");
950     text.add(stringBuilder.toString());
951   }
952 
953   @Override
visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label... labels)954   public void visitTableSwitchInsn(
955       final int min, final int max, final Label dflt, final Label... labels) {
956     stringBuilder.setLength(0);
957     for (Label label : labels) {
958       declareLabel(label);
959     }
960     declareLabel(dflt);
961 
962     stringBuilder
963         .append(name)
964         .append(".visitTableSwitchInsn(")
965         .append(min)
966         .append(", ")
967         .append(max)
968         .append(", ");
969     appendLabel(dflt);
970     stringBuilder.append(", new Label[] {");
971     for (int i = 0; i < labels.length; ++i) {
972       stringBuilder.append(i == 0 ? " " : ", ");
973       appendLabel(labels[i]);
974     }
975     stringBuilder.append(END_ARRAY);
976     text.add(stringBuilder.toString());
977   }
978 
979   @Override
visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels)980   public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
981     stringBuilder.setLength(0);
982     for (Label label : labels) {
983       declareLabel(label);
984     }
985     declareLabel(dflt);
986 
987     stringBuilder.append(name).append(".visitLookupSwitchInsn(");
988     appendLabel(dflt);
989     stringBuilder.append(", new int[] {");
990     for (int i = 0; i < keys.length; ++i) {
991       stringBuilder.append(i == 0 ? " " : ", ").append(keys[i]);
992     }
993     stringBuilder.append(" }, new Label[] {");
994     for (int i = 0; i < labels.length; ++i) {
995       stringBuilder.append(i == 0 ? " " : ", ");
996       appendLabel(labels[i]);
997     }
998     stringBuilder.append(END_ARRAY);
999     text.add(stringBuilder.toString());
1000   }
1001 
1002   @Override
visitMultiANewArrayInsn(final String descriptor, final int numDimensions)1003   public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
1004     stringBuilder.setLength(0);
1005     stringBuilder.append(name).append(".visitMultiANewArrayInsn(");
1006     appendConstant(descriptor);
1007     stringBuilder.append(", ").append(numDimensions).append(");\n");
1008     text.add(stringBuilder.toString());
1009   }
1010 
1011   @Override
visitInsnAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1012   public ASMifier visitInsnAnnotation(
1013       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1014     return visitTypeAnnotation("visitInsnAnnotation", typeRef, typePath, descriptor, visible);
1015   }
1016 
1017   @Override
visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type)1018   public void visitTryCatchBlock(
1019       final Label start, final Label end, final Label handler, final String type) {
1020     stringBuilder.setLength(0);
1021     declareLabel(start);
1022     declareLabel(end);
1023     declareLabel(handler);
1024     stringBuilder.append(name).append(".visitTryCatchBlock(");
1025     appendLabel(start);
1026     stringBuilder.append(", ");
1027     appendLabel(end);
1028     stringBuilder.append(", ");
1029     appendLabel(handler);
1030     stringBuilder.append(", ");
1031     appendConstant(type);
1032     stringBuilder.append(");\n");
1033     text.add(stringBuilder.toString());
1034   }
1035 
1036   @Override
visitTryCatchAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1037   public ASMifier visitTryCatchAnnotation(
1038       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1039     return visitTypeAnnotation("visitTryCatchAnnotation", typeRef, typePath, descriptor, visible);
1040   }
1041 
1042   @Override
visitLocalVariable( final String name, final String descriptor, final String signature, final Label start, final Label end, final int index)1043   public void visitLocalVariable(
1044       final String name,
1045       final String descriptor,
1046       final String signature,
1047       final Label start,
1048       final Label end,
1049       final int index) {
1050     stringBuilder.setLength(0);
1051     stringBuilder.append(this.name).append(".visitLocalVariable(");
1052     appendConstant(name);
1053     stringBuilder.append(", ");
1054     appendConstant(descriptor);
1055     stringBuilder.append(", ");
1056     appendConstant(signature);
1057     stringBuilder.append(", ");
1058     appendLabel(start);
1059     stringBuilder.append(", ");
1060     appendLabel(end);
1061     stringBuilder.append(", ").append(index).append(");\n");
1062     text.add(stringBuilder.toString());
1063   }
1064 
1065   @Override
visitLocalVariableAnnotation( final int typeRef, final TypePath typePath, final Label[] start, final Label[] end, final int[] index, final String descriptor, final boolean visible)1066   public Printer visitLocalVariableAnnotation(
1067       final int typeRef,
1068       final TypePath typePath,
1069       final Label[] start,
1070       final Label[] end,
1071       final int[] index,
1072       final String descriptor,
1073       final boolean visible) {
1074     stringBuilder.setLength(0);
1075     stringBuilder
1076         .append("{\n")
1077         .append(ANNOTATION_VISITOR0)
1078         .append(name)
1079         .append(".visitLocalVariableAnnotation(")
1080         .append(typeRef);
1081     if (typePath == null) {
1082       stringBuilder.append(", null, ");
1083     } else {
1084       stringBuilder.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
1085     }
1086     stringBuilder.append("new Label[] {");
1087     for (int i = 0; i < start.length; ++i) {
1088       stringBuilder.append(i == 0 ? " " : ", ");
1089       appendLabel(start[i]);
1090     }
1091     stringBuilder.append(" }, new Label[] {");
1092     for (int i = 0; i < end.length; ++i) {
1093       stringBuilder.append(i == 0 ? " " : ", ");
1094       appendLabel(end[i]);
1095     }
1096     stringBuilder.append(" }, new int[] {");
1097     for (int i = 0; i < index.length; ++i) {
1098       stringBuilder.append(i == 0 ? " " : ", ").append(index[i]);
1099     }
1100     stringBuilder.append(" }, ");
1101     appendConstant(descriptor);
1102     stringBuilder.append(", ").append(visible).append(");\n");
1103     text.add(stringBuilder.toString());
1104     ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
1105     text.add(asmifier.getText());
1106     text.add("}\n");
1107     return asmifier;
1108   }
1109 
1110   @Override
visitLineNumber(final int line, final Label start)1111   public void visitLineNumber(final int line, final Label start) {
1112     stringBuilder.setLength(0);
1113     stringBuilder.append(name).append(".visitLineNumber(").append(line).append(", ");
1114     appendLabel(start);
1115     stringBuilder.append(");\n");
1116     text.add(stringBuilder.toString());
1117   }
1118 
1119   @Override
visitMaxs(final int maxStack, final int maxLocals)1120   public void visitMaxs(final int maxStack, final int maxLocals) {
1121     stringBuilder.setLength(0);
1122     stringBuilder
1123         .append(name)
1124         .append(".visitMaxs(")
1125         .append(maxStack)
1126         .append(", ")
1127         .append(maxLocals)
1128         .append(");\n");
1129     text.add(stringBuilder.toString());
1130   }
1131 
1132   @Override
visitMethodEnd()1133   public void visitMethodEnd() {
1134     visitMemberEnd();
1135   }
1136 
1137   // -----------------------------------------------------------------------------------------------
1138   // Common methods
1139   // -----------------------------------------------------------------------------------------------
1140 
1141   /**
1142    * Visits a class, field or method annotation.
1143    *
1144    * @param descriptor the class descriptor of the annotation class.
1145    * @param visible {@literal true} if the annotation is visible at runtime.
1146    * @return a new {@link ASMifier} to visit the annotation values.
1147    */
1148   // DontCheck(OverloadMethodsDeclarationOrder): overloads are semantically different.
visitAnnotation(final String descriptor, final boolean visible)1149   public ASMifier visitAnnotation(final String descriptor, final boolean visible) {
1150     stringBuilder.setLength(0);
1151     stringBuilder
1152         .append("{\n")
1153         .append(ANNOTATION_VISITOR0)
1154         .append(name)
1155         .append(".visitAnnotation(");
1156     appendConstant(descriptor);
1157     stringBuilder.append(", ").append(visible).append(");\n");
1158     text.add(stringBuilder.toString());
1159     ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
1160     text.add(asmifier.getText());
1161     text.add("}\n");
1162     return asmifier;
1163   }
1164 
1165   /**
1166    * Visits a class, field or method type annotation.
1167    *
1168    * @param typeRef a reference to the annotated type. The sort of this type reference must be
1169    *     {@link org.objectweb.asm.TypeReference#FIELD}. See {@link org.objectweb.asm.TypeReference}.
1170    * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
1171    *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
1172    *     'typeRef' as a whole.
1173    * @param descriptor the class descriptor of the annotation class.
1174    * @param visible {@literal true} if the annotation is visible at runtime.
1175    * @return a new {@link ASMifier} to visit the annotation values.
1176    */
visitTypeAnnotation( final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1177   public ASMifier visitTypeAnnotation(
1178       final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
1179     return visitTypeAnnotation("visitTypeAnnotation", typeRef, typePath, descriptor, visible);
1180   }
1181 
1182   /**
1183    * Visits a class, field, method, instruction or try catch block type annotation.
1184    *
1185    * @param method the name of the visit method for this type of annotation.
1186    * @param typeRef a reference to the annotated type. The sort of this type reference must be
1187    *     {@link org.objectweb.asm.TypeReference#FIELD}. See {@link org.objectweb.asm.TypeReference}.
1188    * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
1189    *     static inner type within 'typeRef'. May be {@literal null} if the annotation targets
1190    *     'typeRef' as a whole.
1191    * @param descriptor the class descriptor of the annotation class.
1192    * @param visible {@literal true} if the annotation is visible at runtime.
1193    * @return a new {@link ASMifier} to visit the annotation values.
1194    */
visitTypeAnnotation( final String method, final int typeRef, final TypePath typePath, final String descriptor, final boolean visible)1195   public ASMifier visitTypeAnnotation(
1196       final String method,
1197       final int typeRef,
1198       final TypePath typePath,
1199       final String descriptor,
1200       final boolean visible) {
1201     stringBuilder.setLength(0);
1202     stringBuilder
1203         .append("{\n")
1204         .append(ANNOTATION_VISITOR0)
1205         .append(name)
1206         .append('.')
1207         .append(method)
1208         .append('(')
1209         .append(typeRef);
1210     if (typePath == null) {
1211       stringBuilder.append(", null, ");
1212     } else {
1213       stringBuilder.append(", TypePath.fromString(\"").append(typePath).append("\"), ");
1214     }
1215     appendConstant(descriptor);
1216     stringBuilder.append(", ").append(visible).append(");\n");
1217     text.add(stringBuilder.toString());
1218     ASMifier asmifier = createASMifier(ANNOTATION_VISITOR, 0);
1219     text.add(asmifier.getText());
1220     text.add("}\n");
1221     return asmifier;
1222   }
1223 
1224   /**
1225    * Visit a class, field or method attribute.
1226    *
1227    * @param attribute an attribute.
1228    */
visitAttribute(final Attribute attribute)1229   public void visitAttribute(final Attribute attribute) {
1230     stringBuilder.setLength(0);
1231     stringBuilder.append("// ATTRIBUTE ").append(attribute.type).append('\n');
1232     if (attribute instanceof ASMifierSupport) {
1233       if (labelNames == null) {
1234         labelNames = new HashMap<>();
1235       }
1236       stringBuilder.append("{\n");
1237       ((ASMifierSupport) attribute).asmify(stringBuilder, "attribute", labelNames);
1238       stringBuilder.append(name).append(".visitAttribute(attribute);\n");
1239       stringBuilder.append("}\n");
1240     }
1241     text.add(stringBuilder.toString());
1242   }
1243 
1244   /** Visits the end of a field, record component or method. */
visitMemberEnd()1245   private void visitMemberEnd() {
1246     stringBuilder.setLength(0);
1247     stringBuilder.append(name).append(VISIT_END);
1248     text.add(stringBuilder.toString());
1249   }
1250 
1251   // -----------------------------------------------------------------------------------------------
1252   // Utility methods
1253   // -----------------------------------------------------------------------------------------------
1254 
1255   /**
1256    * Constructs a new {@link ASMifier}.
1257    *
1258    * @param visitorVariableName the name of the visitor variable in the produced code.
1259    * @param annotationVisitorId identifier of the annotation visitor variable in the produced code.
1260    * @return a new {@link ASMifier}.
1261    */
1262   // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
createASMifier( final String visitorVariableName, final int annotationVisitorId)1263   protected ASMifier createASMifier(
1264       final String visitorVariableName, final int annotationVisitorId) {
1265     return new ASMifier(api, visitorVariableName, annotationVisitorId);
1266   }
1267 
1268   /**
1269    * Appends a string representation of the given access flags to {@link #stringBuilder}.
1270    *
1271    * @param accessFlags some access flags.
1272    */
appendAccessFlags(final int accessFlags)1273   private void appendAccessFlags(final int accessFlags) {
1274     boolean isEmpty = true;
1275     if ((accessFlags & Opcodes.ACC_PUBLIC) != 0) {
1276       stringBuilder.append("ACC_PUBLIC");
1277       isEmpty = false;
1278     }
1279     if ((accessFlags & Opcodes.ACC_PRIVATE) != 0) {
1280       stringBuilder.append("ACC_PRIVATE");
1281       isEmpty = false;
1282     }
1283     if ((accessFlags & Opcodes.ACC_PROTECTED) != 0) {
1284       stringBuilder.append("ACC_PROTECTED");
1285       isEmpty = false;
1286     }
1287     if ((accessFlags & Opcodes.ACC_FINAL) != 0) {
1288       if (!isEmpty) {
1289         stringBuilder.append(" | ");
1290       }
1291       stringBuilder.append("ACC_FINAL");
1292       isEmpty = false;
1293     }
1294     if ((accessFlags & Opcodes.ACC_STATIC) != 0) {
1295       if (!isEmpty) {
1296         stringBuilder.append(" | ");
1297       }
1298       stringBuilder.append("ACC_STATIC");
1299       isEmpty = false;
1300     }
1301     if ((accessFlags & (Opcodes.ACC_SYNCHRONIZED | Opcodes.ACC_SUPER | Opcodes.ACC_TRANSITIVE))
1302         != 0) {
1303       if (!isEmpty) {
1304         stringBuilder.append(" | ");
1305       }
1306       if ((accessFlags & ACCESS_CLASS) == 0) {
1307         if ((accessFlags & ACCESS_MODULE) == 0) {
1308           stringBuilder.append("ACC_SYNCHRONIZED");
1309         } else {
1310           stringBuilder.append("ACC_TRANSITIVE");
1311         }
1312       } else {
1313         stringBuilder.append("ACC_SUPER");
1314       }
1315       isEmpty = false;
1316     }
1317     if ((accessFlags & (Opcodes.ACC_VOLATILE | Opcodes.ACC_BRIDGE | Opcodes.ACC_STATIC_PHASE))
1318         != 0) {
1319       if (!isEmpty) {
1320         stringBuilder.append(" | ");
1321       }
1322       if ((accessFlags & ACCESS_FIELD) == 0) {
1323         if ((accessFlags & ACCESS_MODULE) == 0) {
1324           stringBuilder.append("ACC_BRIDGE");
1325         } else {
1326           stringBuilder.append("ACC_STATIC_PHASE");
1327         }
1328       } else {
1329         stringBuilder.append("ACC_VOLATILE");
1330       }
1331       isEmpty = false;
1332     }
1333     if ((accessFlags & Opcodes.ACC_VARARGS) != 0
1334         && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD)) == 0) {
1335       if (!isEmpty) {
1336         stringBuilder.append(" | ");
1337       }
1338       stringBuilder.append("ACC_VARARGS");
1339       isEmpty = false;
1340     }
1341     if ((accessFlags & Opcodes.ACC_TRANSIENT) != 0 && (accessFlags & ACCESS_FIELD) != 0) {
1342       if (!isEmpty) {
1343         stringBuilder.append(" | ");
1344       }
1345       stringBuilder.append("ACC_TRANSIENT");
1346       isEmpty = false;
1347     }
1348     if ((accessFlags & Opcodes.ACC_NATIVE) != 0
1349         && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD)) == 0) {
1350       if (!isEmpty) {
1351         stringBuilder.append(" | ");
1352       }
1353       stringBuilder.append("ACC_NATIVE");
1354       isEmpty = false;
1355     }
1356     if ((accessFlags & Opcodes.ACC_ENUM) != 0
1357         && (accessFlags & (ACCESS_CLASS | ACCESS_FIELD | ACCESS_INNER)) != 0) {
1358       if (!isEmpty) {
1359         stringBuilder.append(" | ");
1360       }
1361       stringBuilder.append("ACC_ENUM");
1362       isEmpty = false;
1363     }
1364     if ((accessFlags & Opcodes.ACC_ANNOTATION) != 0
1365         && (accessFlags & (ACCESS_CLASS | ACCESS_INNER)) != 0) {
1366       if (!isEmpty) {
1367         stringBuilder.append(" | ");
1368       }
1369       stringBuilder.append("ACC_ANNOTATION");
1370       isEmpty = false;
1371     }
1372     if ((accessFlags & Opcodes.ACC_ABSTRACT) != 0) {
1373       if (!isEmpty) {
1374         stringBuilder.append(" | ");
1375       }
1376       stringBuilder.append("ACC_ABSTRACT");
1377       isEmpty = false;
1378     }
1379     if ((accessFlags & Opcodes.ACC_INTERFACE) != 0) {
1380       if (!isEmpty) {
1381         stringBuilder.append(" | ");
1382       }
1383       stringBuilder.append("ACC_INTERFACE");
1384       isEmpty = false;
1385     }
1386     if ((accessFlags & Opcodes.ACC_STRICT) != 0) {
1387       if (!isEmpty) {
1388         stringBuilder.append(" | ");
1389       }
1390       stringBuilder.append("ACC_STRICT");
1391       isEmpty = false;
1392     }
1393     if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0) {
1394       if (!isEmpty) {
1395         stringBuilder.append(" | ");
1396       }
1397       stringBuilder.append("ACC_SYNTHETIC");
1398       isEmpty = false;
1399     }
1400     if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
1401       if (!isEmpty) {
1402         stringBuilder.append(" | ");
1403       }
1404       stringBuilder.append("ACC_DEPRECATED");
1405       isEmpty = false;
1406     }
1407     if ((accessFlags & Opcodes.ACC_RECORD) != 0) {
1408       if (!isEmpty) {
1409         stringBuilder.append(" | ");
1410       }
1411       stringBuilder.append("ACC_RECORD");
1412       isEmpty = false;
1413     }
1414     if ((accessFlags & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) {
1415       if (!isEmpty) {
1416         stringBuilder.append(" | ");
1417       }
1418       if ((accessFlags & ACCESS_CLASS) == 0) {
1419         stringBuilder.append("ACC_MANDATED");
1420       } else {
1421         stringBuilder.append("ACC_MODULE");
1422       }
1423       isEmpty = false;
1424     }
1425     if (isEmpty) {
1426       stringBuilder.append('0');
1427     }
1428   }
1429 
1430   /**
1431    * Appends a string representation of the given constant to {@link #stringBuilder}.
1432    *
1433    * @param value a {@link String}, {@link Type}, {@link Handle}, {@link Byte}, {@link Short},
1434    *     {@link Character}, {@link Integer}, {@link Float}, {@link Long} or {@link Double} object,
1435    *     or an array of primitive values. May be {@literal null}.
1436    */
appendConstant(final Object value)1437   protected void appendConstant(final Object value) {
1438     if (value == null) {
1439       stringBuilder.append("null");
1440     } else if (value instanceof String) {
1441       appendString(stringBuilder, (String) value);
1442     } else if (value instanceof Type) {
1443       stringBuilder.append("Type.getType(\"");
1444       stringBuilder.append(((Type) value).getDescriptor());
1445       stringBuilder.append("\")");
1446     } else if (value instanceof Handle) {
1447       stringBuilder.append("new Handle(");
1448       Handle handle = (Handle) value;
1449       stringBuilder.append("Opcodes.").append(HANDLE_TAG[handle.getTag()]).append(", \"");
1450       stringBuilder.append(handle.getOwner()).append(COMMA);
1451       stringBuilder.append(handle.getName()).append(COMMA);
1452       stringBuilder.append(handle.getDesc()).append("\", ");
1453       stringBuilder.append(handle.isInterface()).append(')');
1454     } else if (value instanceof ConstantDynamic) {
1455       stringBuilder.append("new ConstantDynamic(\"");
1456       ConstantDynamic constantDynamic = (ConstantDynamic) value;
1457       stringBuilder.append(constantDynamic.getName()).append(COMMA);
1458       stringBuilder.append(constantDynamic.getDescriptor()).append("\", ");
1459       appendConstant(constantDynamic.getBootstrapMethod());
1460       stringBuilder.append(NEW_OBJECT_ARRAY);
1461       int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
1462       for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
1463         appendConstant(constantDynamic.getBootstrapMethodArgument(i));
1464         if (i != bootstrapMethodArgumentCount - 1) {
1465           stringBuilder.append(", ");
1466         }
1467       }
1468       stringBuilder.append("})");
1469     } else if (value instanceof Byte) {
1470       stringBuilder.append("new Byte((byte)").append(value).append(')');
1471     } else if (value instanceof Boolean) {
1472       stringBuilder.append(((Boolean) value).booleanValue() ? "Boolean.TRUE" : "Boolean.FALSE");
1473     } else if (value instanceof Short) {
1474       stringBuilder.append("new Short((short)").append(value).append(')');
1475     } else if (value instanceof Character) {
1476       stringBuilder
1477           .append("new Character((char)")
1478           .append((int) ((Character) value).charValue())
1479           .append(')');
1480     } else if (value instanceof Integer) {
1481       stringBuilder.append("new Integer(").append(value).append(')');
1482     } else if (value instanceof Float) {
1483       stringBuilder.append("new Float(\"").append(value).append("\")");
1484     } else if (value instanceof Long) {
1485       stringBuilder.append("new Long(").append(value).append("L)");
1486     } else if (value instanceof Double) {
1487       stringBuilder.append("new Double(\"").append(value).append("\")");
1488     } else if (value instanceof byte[]) {
1489       byte[] byteArray = (byte[]) value;
1490       stringBuilder.append("new byte[] {");
1491       for (int i = 0; i < byteArray.length; i++) {
1492         stringBuilder.append(i == 0 ? "" : ",").append(byteArray[i]);
1493       }
1494       stringBuilder.append('}');
1495     } else if (value instanceof boolean[]) {
1496       boolean[] booleanArray = (boolean[]) value;
1497       stringBuilder.append("new boolean[] {");
1498       for (int i = 0; i < booleanArray.length; i++) {
1499         stringBuilder.append(i == 0 ? "" : ",").append(booleanArray[i]);
1500       }
1501       stringBuilder.append('}');
1502     } else if (value instanceof short[]) {
1503       short[] shortArray = (short[]) value;
1504       stringBuilder.append("new short[] {");
1505       for (int i = 0; i < shortArray.length; i++) {
1506         stringBuilder.append(i == 0 ? "" : ",").append("(short)").append(shortArray[i]);
1507       }
1508       stringBuilder.append('}');
1509     } else if (value instanceof char[]) {
1510       char[] charArray = (char[]) value;
1511       stringBuilder.append("new char[] {");
1512       for (int i = 0; i < charArray.length; i++) {
1513         stringBuilder.append(i == 0 ? "" : ",").append("(char)").append((int) charArray[i]);
1514       }
1515       stringBuilder.append('}');
1516     } else if (value instanceof int[]) {
1517       int[] intArray = (int[]) value;
1518       stringBuilder.append("new int[] {");
1519       for (int i = 0; i < intArray.length; i++) {
1520         stringBuilder.append(i == 0 ? "" : ",").append(intArray[i]);
1521       }
1522       stringBuilder.append('}');
1523     } else if (value instanceof long[]) {
1524       long[] longArray = (long[]) value;
1525       stringBuilder.append("new long[] {");
1526       for (int i = 0; i < longArray.length; i++) {
1527         stringBuilder.append(i == 0 ? "" : ",").append(longArray[i]).append('L');
1528       }
1529       stringBuilder.append('}');
1530     } else if (value instanceof float[]) {
1531       float[] floatArray = (float[]) value;
1532       stringBuilder.append("new float[] {");
1533       for (int i = 0; i < floatArray.length; i++) {
1534         stringBuilder.append(i == 0 ? "" : ",").append(floatArray[i]).append('f');
1535       }
1536       stringBuilder.append('}');
1537     } else if (value instanceof double[]) {
1538       double[] doubleArray = (double[]) value;
1539       stringBuilder.append("new double[] {");
1540       for (int i = 0; i < doubleArray.length; i++) {
1541         stringBuilder.append(i == 0 ? "" : ",").append(doubleArray[i]).append('d');
1542       }
1543       stringBuilder.append('}');
1544     }
1545   }
1546 
1547   /**
1548    * Calls {@link #declareLabel} for each label in the given stack map frame types.
1549    *
1550    * @param numTypes the number of stack map frame types in 'frameTypes'.
1551    * @param frameTypes an array of stack map frame types, in the format described in {@link
1552    *     org.objectweb.asm.MethodVisitor#visitFrame}.
1553    */
declareFrameTypes(final int numTypes, final Object[] frameTypes)1554   private void declareFrameTypes(final int numTypes, final Object[] frameTypes) {
1555     for (int i = 0; i < numTypes; ++i) {
1556       if (frameTypes[i] instanceof Label) {
1557         declareLabel((Label) frameTypes[i]);
1558       }
1559     }
1560   }
1561 
1562   /**
1563    * Appends the given stack map frame types to {@link #stringBuilder}.
1564    *
1565    * @param numTypes the number of stack map frame types in 'frameTypes'.
1566    * @param frameTypes an array of stack map frame types, in the format described in {@link
1567    *     org.objectweb.asm.MethodVisitor#visitFrame}.
1568    */
appendFrameTypes(final int numTypes, final Object[] frameTypes)1569   private void appendFrameTypes(final int numTypes, final Object[] frameTypes) {
1570     for (int i = 0; i < numTypes; ++i) {
1571       if (i > 0) {
1572         stringBuilder.append(", ");
1573       }
1574       if (frameTypes[i] instanceof String) {
1575         appendConstant(frameTypes[i]);
1576       } else if (frameTypes[i] instanceof Integer) {
1577         stringBuilder.append(FRAME_TYPES.get(((Integer) frameTypes[i]).intValue()));
1578       } else {
1579         appendLabel((Label) frameTypes[i]);
1580       }
1581     }
1582   }
1583 
1584   /**
1585    * Appends a declaration of the given label to {@link #stringBuilder}. This declaration is of the
1586    * form "Label labelXXX = new Label();". Does nothing if the given label has already been
1587    * declared.
1588    *
1589    * @param label a label.
1590    */
declareLabel(final Label label)1591   protected void declareLabel(final Label label) {
1592     if (labelNames == null) {
1593       labelNames = new HashMap<>();
1594     }
1595     String labelName = labelNames.get(label);
1596     if (labelName == null) {
1597       labelName = "label" + labelNames.size();
1598       labelNames.put(label, labelName);
1599       stringBuilder.append("Label ").append(labelName).append(" = new Label();\n");
1600     }
1601   }
1602 
1603   /**
1604    * Appends the name of the given label to {@link #stringBuilder}. The given label <i>must</i>
1605    * already have a name. One way to ensure this is to always call {@link #declareLabel} before
1606    * calling this method.
1607    *
1608    * @param label a label.
1609    */
appendLabel(final Label label)1610   protected void appendLabel(final Label label) {
1611     stringBuilder.append(labelNames.get(label));
1612   }
1613 }
1614