View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   *
17   */
18  package org.apache.bcel.generic;
19  
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import org.apache.bcel.Const;
24  import org.apache.bcel.classfile.ClassFormatException;
25  import org.apache.bcel.classfile.Utility;
26  
27  /**
28   * Abstract super class for all possible java types, namely basic types
29   * such as int, object types like String and array types, e.g. int[]
30   *
31   */
32  public abstract class Type {
33  
34      /**
35       * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
36       */
37      @Deprecated
38      protected byte type; // TODO should be final (and private)
39  
40      /**
41       * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
42       */
43      @Deprecated
44      protected String signature; // signature for the type TODO should be private
45      /** Predefined constants
46       */
47      public static final BasicTypeType.html#BasicType">BasicType VOID = new BasicType(Const.T_VOID);
48      public static final BasicTypee.html#BasicType">BasicType BOOLEAN = new BasicType(Const.T_BOOLEAN);
49      public static final BasicTypecType.html#BasicType">BasicType INT = new BasicType(Const.T_INT);
50      public static final BasicTypeype.html#BasicType">BasicType SHORT = new BasicType(Const.T_SHORT);
51      public static final BasicTypeType.html#BasicType">BasicType BYTE = new BasicType(Const.T_BYTE);
52      public static final BasicTypeType.html#BasicType">BasicType LONG = new BasicType(Const.T_LONG);
53      public static final BasicTypepe.html#BasicType">BasicType DOUBLE = new BasicType(Const.T_DOUBLE);
54      public static final BasicTypeype.html#BasicType">BasicType FLOAT = new BasicType(Const.T_FLOAT);
55      public static final BasicTypeType.html#BasicType">BasicType CHAR = new BasicType(Const.T_CHAR);
56      public static final ObjectTypepe.html#ObjectType">ObjectType OBJECT = new ObjectType("java.lang.Object");
57      public static final ObjectTypeype.html#ObjectType">ObjectType CLASS = new ObjectType("java.lang.Class");
58      public static final ObjectTypepe.html#ObjectType">ObjectType STRING = new ObjectType("java.lang.String");
59      public static final ObjectTypel#ObjectType">ObjectType STRINGBUFFER = new ObjectType("java.lang.StringBuffer");
60      public static final ObjectTypehtml#ObjectType">ObjectType THROWABLE = new ObjectType("java.lang.Throwable");
61      public static final Typehtml#Type">Type[] NO_ARGS = new Type[0]; // EMPTY, so immutable
62      public static final ReferenceTypeType.html#ReferenceType">ReferenceType NULL = new ReferenceType() {
63      };
64      public static final Typee.html#Type">Type UNKNOWN = new Type(Const.T_UNKNOWN, "<unknown object>") {
65      };
66  
67  
68      protected Type(final byte t, final String s) {
69          type = t;
70          signature = s;
71      }
72  
73  
74      /**
75       * @return hashcode of Type
76       */
77      @Override
78      public int hashCode() {
79          return type ^ signature.hashCode();
80      }
81  
82  
83      /**
84       * @return whether the Types are equal
85       */
86      @Override
87      public boolean equals(final Object o) {
88            if (o instanceof Type) {
89                final Type href="../../../../org/apache/bcel/generic/Type.html#Type">Type t = (Type)o;
90                return (type == t.type) && signature.equals(t.signature);
91            }
92            return false;
93      }
94  
95  
96      /**
97       * @return signature for given type.
98       */
99      public String getSignature() {
100         return signature;
101     }
102 
103 
104     /**
105      * @return type as defined in Constants
106      */
107     public byte getType() {
108         return type;
109     }
110 
111     /**
112      * boolean, short and char variable are considered as int in the stack or local variable area.
113      * Returns {@link Type#INT} for {@link Type#BOOLEAN}, {@link Type#SHORT} or {@link Type#CHAR}, otherwise
114      * returns the given type.
115      * @since 6.0
116      */
117     public Type normalizeForStackOrLocal() {
118         if (this == Type.BOOLEAN || this == Type.BYTE || this == Type.SHORT || this == Type.CHAR) {
119             return Type.INT;
120         }
121         return this;
122     }
123 
124     /**
125      * @return stack size of this type (2 for long and double, 0 for void, 1 otherwise)
126      */
127     public int getSize() {
128         switch (type) {
129             case Const.T_DOUBLE:
130             case Const.T_LONG:
131                 return 2;
132             case Const.T_VOID:
133                 return 0;
134             default:
135                 return 1;
136         }
137     }
138 
139 
140     /**
141      * @return Type string, e.g. `int[]'
142      */
143     @Override
144     public String toString() {
145         return ((this.equals(Type.NULL) || (type >= Const.T_UNKNOWN))) ? signature : Utility
146                 .signatureToString(signature, false);
147     }
148 
149 
150     /**
151      * Convert type to Java method signature, e.g. int[] f(java.lang.String x)
152      * becomes (Ljava/lang/String;)[I
153      *
154      * @param return_type what the method returns
155      * @param arg_types what are the argument types
156      * @return method signature for given type(s).
157      */
158     public static String getMethodSignature( final Type Typeeyword">return_type, final Type[] arg_types ) {
159         final StringBuilder buf = new StringBuilder("(");
160         if (arg_types != null) {
161             for (final Type arg_type : arg_types) {
162                 buf.append(arg_type.getSignature());
163             }
164         }
165         buf.append(')');
166         buf.append(return_type.getSignature());
167         return buf.toString();
168     }
169 
170     private static final ThreadLocal<Integer> consumed_chars = new ThreadLocal<Integer>() {
171 
172         @Override
173         protected Integer initialValue() {
174             return Integer.valueOf(0);
175         }
176     };//int consumed_chars=0; // Remember position in string, see getArgumentTypes
177 
178 
179     private static int unwrap( final ThreadLocal<Integer> tl ) {
180         return tl.get().intValue();
181     }
182 
183 
184     private static void wrap( final ThreadLocal<Integer> tl, final int value ) {
185         tl.set(Integer.valueOf(value));
186     }
187 
188 
189     /**
190      * Convert signature to a Type object.
191      * @param signature signature string such as Ljava/lang/String;
192      * @return type object
193      */
194     // @since 6.0 no longer final
195     public static Type getType( final String signature ) throws StringIndexOutOfBoundsException {
196         final byte type = Utility.typeOfSignature(signature);
197         if (type <= Const.T_VOID) {
198             //corrected concurrent private static field acess
199             wrap(consumed_chars, 1);
200             return BasicType.getType(type);
201         } else if (type == Const.T_ARRAY) {
202             int dim = 0;
203             do { // Count dimensions
204                 dim++;
205             } while (signature.charAt(dim) == '[');
206             // Recurse, but just once, if the signature is ok
207             final Type t = getType(signature.substring(dim));
208             //corrected concurrent private static field acess
209             //  consumed_chars += dim; // update counter - is replaced by
210             final int _temp = unwrap(consumed_chars) + dim;
211             wrap(consumed_chars, _temp);
212             return new ArrayType(t, dim);
213         } else { // type == T_REFERENCE
214             // Utility.typeSignatureToString understands how to parse generic types.
215             final String parsedSignature = Utility.typeSignatureToString(signature, false);
216             wrap(consumed_chars, parsedSignature.length() + 2); // "Lblabla;" `L' and `;' are removed
217             return ObjectType.getInstance(parsedSignature.replace('/', '.'));
218         }
219     }
220 
221 
222     /**
223      * Convert return value of a method (signature) to a Type object.
224      *
225      * @param signature signature string such as (Ljava/lang/String;)V
226      * @return return type
227      */
228     public static Type getReturnType( final String signature ) {
229         try {
230             // Read return type after `)'
231             final int index = signature.lastIndexOf(')') + 1;
232             return getType(signature.substring(index));
233         } catch (final StringIndexOutOfBoundsException e) { // Should never occur
234             throw new ClassFormatException("Invalid method signature: " + signature, e);
235         }
236     }
237 
238 
239     /**
240      * Convert arguments of a method (signature) to an array of Type objects.
241      * @param signature signature string such as (Ljava/lang/String;)V
242      * @return array of argument types
243      */
244     public static Type[] getArgumentTypes( final String signature ) {
245         final List<Type> vec = new ArrayList<>();
246         int index;
247         Type[] types;
248         try {
249             // Skip any type arguments to read argument declarations between `(' and `)'
250             index = signature.indexOf('(') + 1;
251             if (index <= 0) {
252                 throw new ClassFormatException("Invalid method signature: " + signature);
253             }
254             while (signature.charAt(index) != ')') {
255                 vec.add(getType(signature.substring(index)));
256                 //corrected concurrent private static field acess
257                 index += unwrap(consumed_chars); // update position
258             }
259         } catch (final StringIndexOutOfBoundsException e) { // Should never occur
260             throw new ClassFormatException("Invalid method signature: " + signature, e);
261         }
262         types = new Type[vec.size()];
263         vec.toArray(types);
264         return types;
265     }
266 
267 
268     /** Convert runtime java.lang.Class to BCEL Type object.
269      * @param cl Java class
270      * @return corresponding Type object
271      */
272     public static Type getType( final java.lang.Class<?> cl ) {
273         if (cl == null) {
274             throw new IllegalArgumentException("Class must not be null");
275         }
276         /* That's an amzingly easy case, because getName() returns
277          * the signature. That's what we would have liked anyway.
278          */
279         if (cl.isArray()) {
280             return getType(cl.getName());
281         } else if (cl.isPrimitive()) {
282             if (cl == Integer.TYPE) {
283                 return INT;
284             } else if (cl == Void.TYPE) {
285                 return VOID;
286             } else if (cl == Double.TYPE) {
287                 return DOUBLE;
288             } else if (cl == Float.TYPE) {
289                 return FLOAT;
290             } else if (cl == Boolean.TYPE) {
291                 return BOOLEAN;
292             } else if (cl == Byte.TYPE) {
293                 return BYTE;
294             } else if (cl == Short.TYPE) {
295                 return SHORT;
296             } else if (cl == Byte.TYPE) {
297                 return BYTE;
298             } else if (cl == Long.TYPE) {
299                 return LONG;
300             } else if (cl == Character.TYPE) {
301                 return CHAR;
302             } else {
303                 throw new IllegalStateException("Unknown primitive type " + cl);
304             }
305         } else { // "Real" class
306             return ObjectType.getInstance(cl.getName());
307         }
308     }
309 
310 
311     /**
312      * Convert runtime java.lang.Class[] to BCEL Type objects.
313      * @param classes an array of runtime class objects
314      * @return array of corresponding Type objects
315      */
316     public static Type[] getTypes( final java.lang.Class<?>[] classes ) {
317         final Typeype.html#Type">Type[] ret = new Type[classes.length];
318         for (int i = 0; i < ret.length; i++) {
319             ret[i] = getType(classes[i]);
320         }
321         return ret;
322     }
323 
324 
325     public static String getSignature( final java.lang.reflect.Method meth ) {
326         final StringBuilder sb = new StringBuilder("(");
327         final Class<?>[] params = meth.getParameterTypes(); // avoid clone
328         for (final Class<?> param : params) {
329             sb.append(getType(param).getSignature());
330         }
331         sb.append(")");
332         sb.append(getType(meth.getReturnType()).getSignature());
333         return sb.toString();
334     }
335 
336     static int size(final int coded) {
337         return coded & 3;
338     }
339 
340     static int consumed(final int coded) {
341         return coded >> 2;
342     }
343 
344     static int encode(final int size, final int consumed) {
345         return consumed << 2 | size;
346     }
347 
348     static int getArgumentTypesSize( final String signature ) {
349         int res = 0;
350         int index;
351         try {
352             // Skip any type arguments to read argument declarations between `(' and `)'
353             index = signature.indexOf('(') + 1;
354             if (index <= 0) {
355                 throw new ClassFormatException("Invalid method signature: " + signature);
356             }
357             while (signature.charAt(index) != ')') {
358                 final int coded = getTypeSize(signature.substring(index));
359                 res += size(coded);
360                 index += consumed(coded);
361             }
362         } catch (final StringIndexOutOfBoundsException e) { // Should never occur
363             throw new ClassFormatException("Invalid method signature: " + signature, e);
364         }
365         return res;
366     }
367 
368     static int getTypeSize( final String signature ) throws StringIndexOutOfBoundsException {
369         final byte type = Utility.typeOfSignature(signature);
370         if (type <= Const.T_VOID) {
371             return encode(BasicType.getType(type).getSize(), 1);
372         } else if (type == Const.T_ARRAY) {
373             int dim = 0;
374             do { // Count dimensions
375                 dim++;
376             } while (signature.charAt(dim) == '[');
377             // Recurse, but just once, if the signature is ok
378             final int consumed = consumed(getTypeSize(signature.substring(dim)));
379             return encode(1, dim + consumed);
380         } else { // type == T_REFERENCE
381             final int index = signature.indexOf(';'); // Look for closing `;'
382             if (index < 0) {
383                 throw new ClassFormatException("Invalid signature: " + signature);
384             }
385             return encode(1, index + 1);
386         }
387     }
388 
389 
390     static int getReturnTypeSize(final String signature) {
391         final int index = signature.lastIndexOf(')') + 1;
392         return Type.size(getTypeSize(signature.substring(index)));
393     }
394 
395 
396     /*
397      * Currently only used by the ArrayType constructor.
398      * The signature has a complicated dependency on other parameter
399      * so it's tricky to do it in a call to the super ctor.
400      */
401     void setSignature(final String signature) {
402         this.signature = signature;
403     }
404 }