View Javadoc
1   package mockit.asm.types;
2   
3   import static mockit.asm.jvmConstants.Opcodes.ACONST_NULL;
4   import static mockit.asm.jvmConstants.Opcodes.ALOAD;
5   
6   import edu.umd.cs.findbugs.annotations.NonNull;
7   
8   import org.checkerframework.checker.index.qual.NonNegative;
9   
10  public abstract class ReferenceType extends JavaType {
11      /**
12       * The internal name of this Java reference type.
13       */
14      @NonNull
15      final char[] typeDescChars;
16  
17      /**
18       * The offset of the internal name of this Java type in {@link #typeDescChars}.
19       */
20      @NonNegative
21      final int off;
22  
23      ReferenceType(@NonNull char[] typeDesc) {
24          super(typeDesc.length);
25          typeDescChars = typeDesc;
26          off = 0;
27      }
28  
29      ReferenceType(@NonNull char[] typeDesc, @NonNegative int off, @NonNegative int len) {
30          super(len);
31          typeDescChars = typeDesc;
32          this.off = off;
33      }
34  
35      /**
36       * Returns the Java type corresponding to the given type descriptor.
37       *
38       * @param typeDesc
39       *            a type descriptor.
40       */
41      @NonNull
42      public static ReferenceType createFromTypeDescriptor(@NonNull String typeDesc) {
43          return getReferenceType(typeDesc.toCharArray(), 0);
44      }
45  
46      /**
47       * Returns the Java type corresponding to the given type descriptor. For method descriptors, <code>buf</code> is
48       * supposed to contain nothing more than the descriptor itself.
49       *
50       * @param buf
51       *            a buffer containing a type descriptor.
52       * @param off
53       *            the offset of this descriptor in the previous buffer.
54       */
55      @NonNull
56      static ReferenceType getReferenceType(@NonNull char[] buf, @NonNegative int off) {
57          switch (buf[off]) {
58              case '[':
59                  return ArrayType.create(buf, off);
60              case 'L':
61                  return ObjectType.create(buf, off);
62              case '(':
63                  return new MethodType(buf, off, buf.length - off);
64              default:
65                  throw new IllegalArgumentException("Invalid type descriptor: " + new String(buf));
66          }
67      }
68  
69      /**
70       * Returns the object or array type corresponding to the given internal name.
71       */
72      @NonNull
73      public static ReferenceType createFromInternalName(@NonNull String internalName) {
74          char[] buf = internalName.toCharArray();
75          return buf[0] == '[' ? new ArrayType(buf) : new ObjectType(buf);
76      }
77  
78      static int findTypeNameLength(@NonNull char[] buf, @NonNegative int off, @NonNegative int len) {
79          len++;
80  
81          while (buf[off + len] != ';') {
82              len++;
83          }
84  
85          return len;
86      }
87  
88      static void getDescriptor(@NonNull StringBuilder buf, @NonNull Class<?> aClass) {
89          buf.append('L');
90  
91          String name = aClass.getName();
92          int len = name.length();
93  
94          for (int i = 0; i < len; i++) {
95              char c = name.charAt(i);
96              buf.append(c == '.' ? '/' : c);
97          }
98  
99          buf.append(';');
100     }
101 
102     @Override
103     void getDescriptor(@NonNull StringBuilder typeDesc) {
104         typeDesc.append(typeDescChars, off, len);
105     }
106 
107     /**
108      * Returns the internal name of the class corresponding to this object or array type. The internal name of a class
109      * is its fully qualified name (as returned by Class.getName(), where '.' are replaced by '/'. For an array type, it
110      * starts with "[" and ends with the type descriptor of the array element type.
111      *
112      * @return the internal name of the class corresponding to this object or array type.
113      */
114     @NonNull
115     public final String getInternalName() {
116         return new String(typeDescChars, off, len);
117     }
118 
119     @Override
120     public int getSize() {
121         return 1;
122     }
123 
124     @Override
125     public int getOpcode(int opcode) {
126         return opcode + 4;
127     }
128 
129     @Override
130     public final int getLoadOpcode() {
131         return ALOAD;
132     }
133 
134     @Override
135     public final int getConstOpcode() {
136         return ACONST_NULL;
137     }
138 
139     @Override
140     public final boolean equals(Object o) {
141         if (this == o) {
142             return true;
143         }
144 
145         if (!(o instanceof ReferenceType)) {
146             return false;
147         }
148 
149         ReferenceType t = (ReferenceType) o;
150 
151         if (getClass() != t.getClass() || len != t.len) {
152             return false;
153         }
154 
155         for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
156             if (typeDescChars[i] != t.typeDescChars[j]) {
157                 return false;
158             }
159         }
160 
161         return true;
162     }
163 
164     @Override
165     public final int hashCode() {
166         int hc = 13;
167 
168         for (int i = off, end = i + len; i < end; i++) {
169             // noinspection CharUsedInArithmeticContext
170             hc = 17 * (hc + typeDescChars[i]);
171         }
172 
173         return hc;
174     }
175 }