View Javadoc
1   package mockit.asm;
2   
3   import edu.umd.cs.findbugs.annotations.NonNull;
4   import edu.umd.cs.findbugs.annotations.Nullable;
5   
6   import mockit.asm.annotations.AnnotationReader;
7   import mockit.asm.annotations.AnnotationVisitor;
8   import mockit.asm.jvmConstants.Access;
9   import mockit.asm.util.BytecodeReader;
10  
11  import org.checkerframework.checker.index.qual.NonNegative;
12  
13  /**
14   * A bytecode reader for reading common elements (signature, annotations) of a class, field, or method.
15   */
16  public abstract class AnnotatedReader extends BytecodeReader {
17      @NonNull
18      private final AnnotationReader annotationReader = new AnnotationReader(this);
19      @NonNegative
20      private int annotationsCodeIndex;
21  
22      /**
23       * The access flags of the class, field, or method currently being parsed.
24       */
25      protected int access;
26  
27      /**
28       * The generic type signature of the class/field/method, if it has one.
29       */
30      @Nullable
31      protected String signature;
32  
33      protected AnnotatedReader(@NonNull byte[] code) {
34          super(code);
35      }
36  
37      protected AnnotatedReader(@NonNull AnnotatedReader another) {
38          super(another);
39      }
40  
41      protected final void readAttributes() {
42          signature = null;
43          annotationsCodeIndex = 0;
44  
45          for (int attributeCount = readUnsignedShort(); attributeCount > 0; attributeCount--) {
46              String attributeName = readNonnullUTF8();
47              int codeOffsetToNextAttribute = readInt();
48  
49              if ("Signature".equals(attributeName)) {
50                  signature = readNonnullUTF8();
51                  continue;
52              }
53  
54              Boolean outcome = readAttribute(attributeName);
55  
56              if (outcome == Boolean.TRUE) {
57                  continue;
58              }
59  
60              if (outcome == null) {
61                  // noinspection SwitchStatementWithoutDefaultBranch
62                  switch (attributeName) {
63                      case "RuntimeVisibleAnnotations":
64                          annotationsCodeIndex = codeIndex;
65                          break;
66                      case "Deprecated":
67                          access = Access.asDeprecated(access);
68                          break;
69                      case "Synthetic":
70                          access = Access.asSynthetic(access);
71                  }
72              }
73  
74              codeIndex += codeOffsetToNextAttribute;
75          }
76      }
77  
78      /**
79       * Attempts to read the next attribute, provided it's one recognizable by the implementing subclass.
80       *
81       * @param attributeName
82       *            the attribute name
83       *
84       * @return {@code true} if {@link #codeIndex} is already pointing to the next attribute in the classfile,
85       *         {@code false} or {@code null} otherwise; in the case of {@code null}, the current attribute was not yet
86       *         identified, but is one of the more general ones ("RuntimeVisibleAnnotations", "Deprecated", or
87       *         "Synthetic")
88       */
89      @Nullable
90      protected abstract Boolean readAttribute(@NonNull String attributeName);
91  
92      protected final void readAnnotations(@NonNull BaseWriter visitor) {
93          if (annotationsCodeIndex > 0) {
94              int previousCodeIndex = codeIndex;
95              codeIndex = annotationsCodeIndex;
96  
97              for (int annotationCount = readUnsignedShort(); annotationCount > 0; annotationCount--) {
98                  String annotationTypeDesc = readNonnullUTF8();
99                  AnnotationVisitor av = visitor.visitAnnotation(annotationTypeDesc);
100                 readAnnotationValues(av);
101             }
102 
103             codeIndex = previousCodeIndex;
104         }
105     }
106 
107     protected final void readAnnotationValues(@Nullable AnnotationVisitor av) {
108         codeIndex = annotationReader.readNamedAnnotationValues(codeIndex, av);
109     }
110 }