1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.bcel.internal.generic;
23
24
25import com.sun.org.apache.bcel.internal.Constants;
26import com.sun.org.apache.bcel.internal.classfile.*;
27import java.util.ArrayList;
28
29/**
30 * Abstract super class for all possible java types, namely basic types
31 * such as int, object types like String and array types, e.g. int[]
32 *
33 * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
34 */
35public abstract class Type implements java.io.Serializable {
36  protected byte   type;
37  protected String signature; // signature for the type
38
39  /** Predefined constants
40   */
41  public static final BasicType     VOID         = new BasicType(Constants.T_VOID);
42  public static final BasicType     BOOLEAN      = new BasicType(Constants.T_BOOLEAN);
43  public static final BasicType     INT          = new BasicType(Constants.T_INT);
44  public static final BasicType     SHORT        = new BasicType(Constants.T_SHORT);
45  public static final BasicType     BYTE         = new BasicType(Constants.T_BYTE);
46  public static final BasicType     LONG         = new BasicType(Constants.T_LONG);
47  public static final BasicType     DOUBLE       = new BasicType(Constants.T_DOUBLE);
48  public static final BasicType     FLOAT        = new BasicType(Constants.T_FLOAT);
49  public static final BasicType     CHAR         = new BasicType(Constants.T_CHAR);
50  public static final ObjectType    OBJECT       = new ObjectType("java.lang.Object");
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  public static final Type[]        NO_ARGS      = new Type[0];
55  public static final ReferenceType NULL         = new ReferenceType(){};
56  public static final Type          UNKNOWN      = new Type(Constants.T_UNKNOWN,
57                                                            "<unknown object>"){};
58
59  protected Type(byte t, String s) {
60    type      = t;
61    signature = s;
62  }
63
64  /**
65   * @return signature for given type.
66   */
67  public String getSignature() { return signature; }
68
69  /**
70   * @return type as defined in Constants
71   */
72  public byte getType() { return type; }
73
74  /**
75   * @return stack size of this type (2 for long and double, 0 for void, 1 otherwise)
76   */
77  public int getSize() {
78    switch(type) {
79    case Constants.T_DOUBLE:
80    case Constants.T_LONG: return 2;
81    case Constants.T_VOID: return 0;
82    default:     return 1;
83    }
84  }
85
86  /**
87   * @return Type string, e.g. `int[]'
88   */
89  public String toString() {
90    return ((this.equals(Type.NULL) || (type >= Constants.T_UNKNOWN)))? signature :
91      Utility.signatureToString(signature, false);
92  }
93
94  /**
95   * Convert type to Java method signature, e.g. int[] f(java.lang.String x)
96   * becomes (Ljava/lang/String;)[I
97   *
98   * @param return_type what the method returns
99   * @param arg_types what are the argument types
100   * @return method signature for given type(s).
101   */
102  public static String getMethodSignature(Type return_type, Type[] arg_types) {
103    StringBuffer buf = new StringBuffer("(");
104    int length = (arg_types == null)? 0 : arg_types.length;
105
106    for(int i=0; i < length; i++)
107      buf.append(arg_types[i].getSignature());
108
109    buf.append(')');
110    buf.append(return_type.getSignature());
111
112    return buf.toString();
113  }
114
115  private static int consumed_chars=0; // Remember position in string, see getArgumentTypes
116
117  /**
118   * Convert signature to a Type object.
119   * @param signature signature string such as Ljava/lang/String;
120   * @return type object
121   */
122  public static final Type getType(String signature)
123    throws StringIndexOutOfBoundsException
124  {
125    byte type = Utility.typeOfSignature(signature);
126
127    if(type <= Constants.T_VOID) {
128      consumed_chars = 1;
129      return BasicType.getType(type);
130    } else if(type == Constants.T_ARRAY) {
131      int dim=0;
132      do { // Count dimensions
133        dim++;
134      } while(signature.charAt(dim) == '[');
135
136      // Recurse, but just once, if the signature is ok
137      Type t = getType(signature.substring(dim));
138
139      consumed_chars += dim; // update counter
140
141      return new ArrayType(t, dim);
142    } else { // type == T_REFERENCE
143      int index = signature.indexOf(';'); // Look for closing `;'
144
145      if(index < 0)
146        throw new ClassFormatException("Invalid signature: " + signature);
147
148      consumed_chars = index + 1; // "Lblabla;" `L' and `;' are removed
149
150      return new ObjectType(signature.substring(1, index).replace('/', '.'));
151    }
152  }
153
154  /**
155   * Convert return value of a method (signature) to a Type object.
156   *
157   * @param signature signature string such as (Ljava/lang/String;)V
158   * @return return type
159   */
160  public static Type getReturnType(String signature) {
161    try {
162      // Read return type after `)'
163      int index = signature.lastIndexOf(')') + 1;
164      return getType(signature.substring(index));
165    } catch(StringIndexOutOfBoundsException e) { // Should never occur
166      throw new ClassFormatException("Invalid method signature: " + signature);
167    }
168  }
169
170  /**
171   * Convert arguments of a method (signature) to an array of Type objects.
172   * @param signature signature string such as (Ljava/lang/String;)V
173   * @return array of argument types
174   */
175  public static Type[] getArgumentTypes(String signature) {
176    ArrayList vec = new ArrayList();
177    int       index;
178    Type[]     types;
179
180    try { // Read all declarations between for `(' and `)'
181      if(signature.charAt(0) != '(')
182        throw new ClassFormatException("Invalid method signature: " + signature);
183
184      index = 1; // current string position
185
186      while(signature.charAt(index) != ')') {
187        vec.add(getType(signature.substring(index)));
188        index += consumed_chars; // update position
189      }
190    } catch(StringIndexOutOfBoundsException e) { // Should never occur
191      throw new ClassFormatException("Invalid method signature: " + signature);
192    }
193
194    types = new Type[vec.size()];
195    vec.toArray(types);
196    return types;
197  }
198
199  /** Convert runtime java.lang.Class to BCEL Type object.
200   * @param cl Java class
201   * @return corresponding Type object
202   */
203  public static Type getType(java.lang.Class cl) {
204    if(cl == null) {
205      throw new IllegalArgumentException("Class must not be null");
206    }
207
208    /* That's an amzingly easy case, because getName() returns
209     * the signature. That's what we would have liked anyway.
210     */
211    if(cl.isArray()) {
212      return getType(cl.getName());
213    } else if(cl.isPrimitive()) {
214      if(cl == Integer.TYPE) {
215        return INT;
216      } else if(cl == Void.TYPE) {
217        return VOID;
218      } else if(cl == Double.TYPE) {
219        return DOUBLE;
220      } else if(cl == Float.TYPE) {
221        return FLOAT;
222      } else if(cl == Boolean.TYPE) {
223        return BOOLEAN;
224      } else if(cl == Byte.TYPE) {
225        return BYTE;
226      } else if(cl == Short.TYPE) {
227        return SHORT;
228      } else if(cl == Byte.TYPE) {
229        return BYTE;
230      } else if(cl == Long.TYPE) {
231        return LONG;
232      } else if(cl == Character.TYPE) {
233        return CHAR;
234      } else {
235        throw new IllegalStateException("Ooops, what primitive type is " + cl);
236      }
237    } else { // "Real" class
238      return new ObjectType(cl.getName());
239    }
240  }
241
242  public static String getSignature(java.lang.reflect.Method meth) {
243    StringBuffer sb = new StringBuffer("(");
244    Class[] params = meth.getParameterTypes(); // avoid clone
245
246    for(int j = 0; j < params.length; j++) {
247      sb.append(getType(params[j]).getSignature());
248    }
249
250    sb.append(")");
251    sb.append(getType(meth.getReturnType()).getSignature());
252    return sb.toString();
253  }
254}
255