blob: e936ca9b891cba046ac7ab3bc43444222db7d80d [file] [log] [blame]
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sun.org.apache.bcel.internal.generic;
import com.sun.org.apache.bcel.internal.Constants;
import com.sun.org.apache.bcel.internal.classfile.*;
import java.util.ArrayList;
/**
* Abstract super class for all possible java types, namely basic types
* such as int, object types like String and array types, e.g. int[]
*
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*/
public abstract class Type implements java.io.Serializable {
protected byte type;
protected String signature; // signature for the type
/** Predefined constants
*/
public static final BasicType VOID = new BasicType(Constants.T_VOID);
public static final BasicType BOOLEAN = new BasicType(Constants.T_BOOLEAN);
public static final BasicType INT = new BasicType(Constants.T_INT);
public static final BasicType SHORT = new BasicType(Constants.T_SHORT);
public static final BasicType BYTE = new BasicType(Constants.T_BYTE);
public static final BasicType LONG = new BasicType(Constants.T_LONG);
public static final BasicType DOUBLE = new BasicType(Constants.T_DOUBLE);
public static final BasicType FLOAT = new BasicType(Constants.T_FLOAT);
public static final BasicType CHAR = new BasicType(Constants.T_CHAR);
public static final ObjectType OBJECT = new ObjectType("java.lang.Object");
public static final ObjectType STRING = new ObjectType("java.lang.String");
public static final ObjectType STRINGBUFFER = new ObjectType("java.lang.StringBuffer");
public static final ObjectType THROWABLE = new ObjectType("java.lang.Throwable");
public static final Type[] NO_ARGS = new Type[0];
public static final ReferenceType NULL = new ReferenceType(){};
public static final Type UNKNOWN = new Type(Constants.T_UNKNOWN,
"<unknown object>"){};
protected Type(byte t, String s) {
type = t;
signature = s;
}
/**
* @return signature for given type.
*/
public String getSignature() { return signature; }
/**
* @return type as defined in Constants
*/
public byte getType() { return type; }
/**
* @return stack size of this type (2 for long and double, 0 for void, 1 otherwise)
*/
public int getSize() {
switch(type) {
case Constants.T_DOUBLE:
case Constants.T_LONG: return 2;
case Constants.T_VOID: return 0;
default: return 1;
}
}
/**
* @return Type string, e.g. `int[]'
*/
public String toString() {
return ((this.equals(Type.NULL) || (type >= Constants.T_UNKNOWN)))? signature :
Utility.signatureToString(signature, false);
}
/**
* Convert type to Java method signature, e.g. int[] f(java.lang.String x)
* becomes (Ljava/lang/String;)[I
*
* @param return_type what the method returns
* @param arg_types what are the argument types
* @return method signature for given type(s).
*/
public static String getMethodSignature(Type return_type, Type[] arg_types) {
StringBuffer buf = new StringBuffer("(");
int length = (arg_types == null)? 0 : arg_types.length;
for(int i=0; i < length; i++)
buf.append(arg_types[i].getSignature());
buf.append(')');
buf.append(return_type.getSignature());
return buf.toString();
}
private static int consumed_chars=0; // Remember position in string, see getArgumentTypes
/**
* Convert signature to a Type object.
* @param signature signature string such as Ljava/lang/String;
* @return type object
*/
public static final Type getType(String signature)
throws StringIndexOutOfBoundsException
{
byte type = Utility.typeOfSignature(signature);
if(type <= Constants.T_VOID) {
consumed_chars = 1;
return BasicType.getType(type);
} else if(type == Constants.T_ARRAY) {
int dim=0;
do { // Count dimensions
dim++;
} while(signature.charAt(dim) == '[');
// Recurse, but just once, if the signature is ok
Type t = getType(signature.substring(dim));
consumed_chars += dim; // update counter
return new ArrayType(t, dim);
} else { // type == T_REFERENCE
int index = signature.indexOf(';'); // Look for closing `;'
if(index < 0)
throw new ClassFormatException("Invalid signature: " + signature);
consumed_chars = index + 1; // "Lblabla;" `L' and `;' are removed
return new ObjectType(signature.substring(1, index).replace('/', '.'));
}
}
/**
* Convert return value of a method (signature) to a Type object.
*
* @param signature signature string such as (Ljava/lang/String;)V
* @return return type
*/
public static Type getReturnType(String signature) {
try {
// Read return type after `)'
int index = signature.lastIndexOf(')') + 1;
return getType(signature.substring(index));
} catch(StringIndexOutOfBoundsException e) { // Should never occur
throw new ClassFormatException("Invalid method signature: " + signature);
}
}
/**
* Convert arguments of a method (signature) to an array of Type objects.
* @param signature signature string such as (Ljava/lang/String;)V
* @return array of argument types
*/
public static Type[] getArgumentTypes(String signature) {
ArrayList vec = new ArrayList();
int index;
Type[] types;
try { // Read all declarations between for `(' and `)'
if(signature.charAt(0) != '(')
throw new ClassFormatException("Invalid method signature: " + signature);
index = 1; // current string position
while(signature.charAt(index) != ')') {
vec.add(getType(signature.substring(index)));
index += consumed_chars; // update position
}
} catch(StringIndexOutOfBoundsException e) { // Should never occur
throw new ClassFormatException("Invalid method signature: " + signature);
}
types = new Type[vec.size()];
vec.toArray(types);
return types;
}
/** Convert runtime java.lang.Class to BCEL Type object.
* @param cl Java class
* @return corresponding Type object
*/
public static Type getType(java.lang.Class cl) {
if(cl == null) {
throw new IllegalArgumentException("Class must not be null");
}
/* That's an amzingly easy case, because getName() returns
* the signature. That's what we would have liked anyway.
*/
if(cl.isArray()) {
return getType(cl.getName());
} else if(cl.isPrimitive()) {
if(cl == Integer.TYPE) {
return INT;
} else if(cl == Void.TYPE) {
return VOID;
} else if(cl == Double.TYPE) {
return DOUBLE;
} else if(cl == Float.TYPE) {
return FLOAT;
} else if(cl == Boolean.TYPE) {
return BOOLEAN;
} else if(cl == Byte.TYPE) {
return BYTE;
} else if(cl == Short.TYPE) {
return SHORT;
} else if(cl == Byte.TYPE) {
return BYTE;
} else if(cl == Long.TYPE) {
return LONG;
} else if(cl == Character.TYPE) {
return CHAR;
} else {
throw new IllegalStateException("Ooops, what primitive type is " + cl);
}
} else { // "Real" class
return new ObjectType(cl.getName());
}
}
public static String getSignature(java.lang.reflect.Method meth) {
StringBuffer sb = new StringBuffer("(");
Class[] params = meth.getParameterTypes(); // avoid clone
for(int j = 0; j < params.length; j++) {
sb.append(getType(params[j]).getSignature());
}
sb.append(")");
sb.append(getType(meth.getReturnType()).getSignature());
return sb.toString();
}
}