1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.bcel.generic;
20
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.List;
24 import java.util.Objects;
25
26 import org.apache.bcel.Const;
27 import org.apache.bcel.classfile.ClassFormatException;
28 import org.apache.bcel.classfile.InvalidMethodSignatureException;
29 import org.apache.bcel.classfile.Utility;
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.commons.lang3.Strings;
32
33
34
35
36
37 public abstract class Type {
38
39
40
41
42 public static final BasicType VOID = new BasicType(Const.T_VOID);
43
44 public static final BasicType BOOLEAN = new BasicType(Const.T_BOOLEAN);
45 public static final BasicType INT = new BasicType(Const.T_INT);
46 public static final BasicType SHORT = new BasicType(Const.T_SHORT);
47 public static final BasicType BYTE = new BasicType(Const.T_BYTE);
48 public static final BasicType LONG = new BasicType(Const.T_LONG);
49 public static final BasicType DOUBLE = new BasicType(Const.T_DOUBLE);
50 public static final BasicType FLOAT = new BasicType(Const.T_FLOAT);
51 public static final BasicType CHAR = new BasicType(Const.T_CHAR);
52 public static final ObjectType OBJECT = new ObjectType("java.lang.Object");
53 public static final ObjectType CLASS = new ObjectType("java.lang.Class");
54 public static final ObjectType STRING = new ObjectType("java.lang.String");
55 public static final ObjectType STRINGBUFFER = new ObjectType("java.lang.StringBuffer");
56 public static final ObjectType THROWABLE = new ObjectType("java.lang.Throwable");
57
58
59
60
61 public static final Type[] NO_ARGS = {};
62 public static final ReferenceType NULL = new ReferenceType() {
63 };
64
65 public static final Type UNKNOWN = new Type(Const.T_UNKNOWN, "<unknown object>") {
66 };
67
68 private static final ThreadLocal<Integer> CONSUMED_CHARS = ThreadLocal.withInitial(() -> Integer.valueOf(0));
69
70
71 static int consumed(final int coded) {
72 return coded >> 2;
73 }
74
75 static int encode(final int size, final int consumed) {
76 return consumed << 2 | size;
77 }
78
79
80
81
82
83
84
85 public static Type[] getArgumentTypes(final String signature) {
86 final List<Type> vec = new ArrayList<>();
87 int index;
88 try {
89
90 index = signature.indexOf('(') + 1;
91 if (index <= 0) {
92 throw new InvalidMethodSignatureException(signature);
93 }
94 while (signature.charAt(index) != ')') {
95 vec.add(getType(signature.substring(index)));
96
97 index += unwrap(CONSUMED_CHARS);
98 }
99 } catch (final StringIndexOutOfBoundsException e) {
100 throw new InvalidMethodSignatureException(signature, e);
101 }
102 final Type[] types = new Type[vec.size()];
103 vec.toArray(types);
104 return types;
105 }
106
107 static int getArgumentTypesSize(final String signature) {
108 int res = 0;
109 int index;
110 try {
111
112 index = signature.indexOf('(') + 1;
113 if (index <= 0) {
114 throw new InvalidMethodSignatureException(signature);
115 }
116 while (signature.charAt(index) != ')') {
117 final int coded = getTypeSize(signature.substring(index));
118 res += size(coded);
119 index += consumed(coded);
120 }
121 } catch (final StringIndexOutOfBoundsException e) {
122 throw new InvalidMethodSignatureException(signature, e);
123 }
124 return res;
125 }
126
127
128
129
130
131
132
133
134 public static String getMethodSignature(final Type returnType, final Type[] argTypes) {
135 final StringBuilder buf = new StringBuilder("(");
136 if (argTypes != null) {
137 for (final Type argType : argTypes) {
138 buf.append(argType.getSignature());
139 }
140 }
141 buf.append(')');
142 buf.append(returnType.getSignature());
143 return buf.toString();
144 }
145
146
147
148
149
150
151
152 public static Type getReturnType(final String signature) {
153 try {
154
155 final int index = signature.lastIndexOf(')') + 1;
156 return getType(signature.substring(index));
157 } catch (final StringIndexOutOfBoundsException e) {
158 throw new InvalidMethodSignatureException(signature, e);
159 }
160 }
161
162 static int getReturnTypeSize(final String signature) {
163 final int index = signature.lastIndexOf(')') + 1;
164 return size(getTypeSize(signature.substring(index)));
165 }
166
167 public static String getSignature(final java.lang.reflect.Method meth) {
168 final StringBuilder sb = new StringBuilder("(");
169 final Class<?>[] params = meth.getParameterTypes();
170 for (final Class<?> param : params) {
171 sb.append(getType(param).getSignature());
172 }
173 sb.append(")");
174 sb.append(getType(meth.getReturnType()).getSignature());
175 return sb.toString();
176 }
177
178
179
180
181
182
183
184 public static Type getType(final Class<?> cls) {
185 Objects.requireNonNull(cls, "cls");
186
187
188
189 if (cls.isArray()) {
190 return getType(cls.getName());
191 }
192 if (!cls.isPrimitive()) {
193 return ObjectType.getInstance(cls.getName());
194 }
195 if (cls == Integer.TYPE) {
196 return INT;
197 }
198 if (cls == Void.TYPE) {
199 return VOID;
200 }
201 if (cls == Double.TYPE) {
202 return DOUBLE;
203 }
204 if (cls == Float.TYPE) {
205 return FLOAT;
206 }
207 if (cls == Boolean.TYPE) {
208 return BOOLEAN;
209 }
210 if (cls == Byte.TYPE) {
211 return BYTE;
212 }
213 if (cls == Short.TYPE) {
214 return SHORT;
215 }
216 if (cls == Long.TYPE) {
217 return LONG;
218 }
219 if (cls == Character.TYPE) {
220 return CHAR;
221 }
222 throw new IllegalStateException("Unknown primitive type " + cls);
223 }
224
225
226
227
228
229
230
231 public static Type getType(final String signature) throws StringIndexOutOfBoundsException {
232 final byte type = Utility.typeOfSignature(signature);
233 if (type <= Const.T_VOID) {
234
235 wrap(CONSUMED_CHARS, 1);
236 return BasicType.getType(type);
237 }
238 if (type != Const.T_ARRAY) {
239
240 final String parsedSignature = Utility.typeSignatureToString(signature, false);
241 wrap(CONSUMED_CHARS, parsedSignature.length() + 2);
242 return ObjectType.getInstance(Utility.pathToPackage(parsedSignature));
243 }
244 int dim = 0;
245 do {
246 dim++;
247 } while (signature.charAt(dim) == '[');
248
249 final Type t = getType(signature.substring(dim));
250
251
252 final int temp = unwrap(CONSUMED_CHARS) + dim;
253 wrap(CONSUMED_CHARS, temp);
254 return new ArrayType(t, dim);
255 }
256
257
258
259
260
261
262
263 public static Type[] getTypes(final Class<?>[] classes) {
264 final Type[] ret = new Type[classes.length];
265 Arrays.setAll(ret, i -> getType(classes[i]));
266 return ret;
267 }
268
269 static int getTypeSize(final String signature) throws StringIndexOutOfBoundsException {
270 final byte type = Utility.typeOfSignature(signature);
271 if (type <= Const.T_VOID) {
272 return encode(BasicType.getType(type).getSize(), 1);
273 }
274 if (type == Const.T_ARRAY) {
275 int dim = 0;
276 do {
277 dim++;
278 } while (signature.charAt(dim) == '[');
279
280 final int consumed = consumed(getTypeSize(signature.substring(dim)));
281 return encode(1, dim + consumed);
282 }
283 final int index = signature.indexOf(';');
284 if (index < 0) {
285 throw new ClassFormatException("Invalid signature: " + signature);
286 }
287 return encode(1, index + 1);
288 }
289
290 static String internalTypeNameToSignature(final String internalTypeName) {
291 if (StringUtils.isEmpty(internalTypeName) || Strings.CS.equalsAny(internalTypeName, Const.SHORT_TYPE_NAMES)) {
292 return internalTypeName;
293 }
294 switch (internalTypeName.charAt(0)) {
295 case '[':
296 return internalTypeName;
297 case 'L':
298 case 'T':
299 if (internalTypeName.charAt(internalTypeName.length() - 1) == ';') {
300 return internalTypeName;
301 }
302 return 'L' + internalTypeName + ';';
303 default:
304 return 'L' + internalTypeName + ';';
305 }
306 }
307
308 static int size(final int coded) {
309 return coded & 3;
310 }
311
312 private static int unwrap(final ThreadLocal<Integer> tl) {
313 return tl.get().intValue();
314 }
315
316 private static void wrap(final ThreadLocal<Integer> tl, final int value) {
317 tl.set(Integer.valueOf(value));
318 }
319
320
321
322
323 @Deprecated
324 protected byte type;
325
326
327
328
329 @Deprecated
330 protected String signature;
331
332 protected Type(final byte type, final String signature) {
333 this.type = type;
334 this.signature = signature;
335 }
336
337
338
339
340 @Override
341 public boolean equals(final Object o) {
342 if (o instanceof Type) {
343 final Type t = (Type) o;
344 return type == t.type && signature.equals(t.signature);
345 }
346 return false;
347 }
348
349
350
351
352
353
354 public String getClassName() {
355 return toString();
356 }
357
358
359
360
361
362
363 public String getSignature() {
364 return signature;
365 }
366
367
368
369
370
371
372 public int getSize() {
373 switch (type) {
374 case Const.T_DOUBLE:
375 case Const.T_LONG:
376 return 2;
377 case Const.T_VOID:
378 return 0;
379 default:
380 return 1;
381 }
382 }
383
384
385
386
387
388
389 public byte getType() {
390 return type;
391 }
392
393
394
395
396
397
398 @Override
399 public int hashCode() {
400 return type ^ signature.hashCode();
401 }
402
403
404
405
406
407
408
409
410 public Type normalizeForStackOrLocal() {
411 if (this == BOOLEAN || this == BYTE || this == SHORT || this == CHAR) {
412 return INT;
413 }
414 return this;
415 }
416
417
418
419
420 @Override
421 public String toString() {
422 return equals(NULL) || type >= Const.T_UNKNOWN ? signature : Utility.signatureToString(signature, false);
423 }
424 }