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