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