| package org.aspectj.apache.bcel.generic; |
| |
| /* ==================================================================== |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2001 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Apache" and "Apache Software Foundation" and |
| * "Apache BCEL" must not be used to endorse or promote products |
| * derived from this software without prior written permission. For |
| * written permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * "Apache BCEL", nor may "Apache" appear in their name, without |
| * prior written permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.aspectj.apache.bcel.Constants; |
| import org.aspectj.apache.bcel.ConstantsInitializer; |
| import org.aspectj.apache.bcel.classfile.ClassFormatException; |
| import org.aspectj.apache.bcel.classfile.Utility; |
| |
| /** |
| * Abstract super class for all possible java types, namely basic types such as int, object types like String and array types, e.g. |
| * int[] |
| * |
| * @version $Id: Type.java,v 1.14 2011/09/28 01:14:54 aclement Exp $ |
| * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> |
| * |
| * modified: AndyClement 2-mar-05: Removed unnecessary static and optimized |
| */ |
| public abstract class Type { |
| protected byte type; |
| protected String signature; |
| |
| /* 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 ArrayType OBJECT_ARRAY = new ArrayType("java.lang.Object",1); |
| public static final ArrayType STRING_ARRAY = new ArrayType("java.lang.String",1); |
| public static final ArrayType CLASS_ARRAY = new ArrayType("java.lang.Class",1); |
| public static final ObjectType STRINGBUFFER = new ObjectType("java.lang.StringBuffer"); |
| public static final ObjectType STRINGBUILDER = new ObjectType("java.lang.StringBuilder"); |
| public static final ObjectType THROWABLE = new ObjectType("java.lang.Throwable"); |
| public static final ObjectType CLASS = new ObjectType("java.lang.Class"); |
| public static final ObjectType INTEGER = new ObjectType("java.lang.Integer"); |
| public static final ObjectType EXCEPTION = new ObjectType("java.lang.Exception"); |
| public static final ObjectType LIST = new ObjectType("java.util.List"); |
| public static final ObjectType ITERATOR = new ObjectType("java.util.Iterator"); |
| 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>") { |
| }; |
| public static final Type[] STRINGARRAY1 = new Type[] { STRING }; |
| public static final Type[] STRINGARRAY2 = new Type[] { STRING, STRING }; |
| public static final Type[] STRINGARRAY3 = new Type[] { STRING, STRING, STRING }; |
| public static final Type[] STRINGARRAY4 = new Type[] { STRING, STRING, STRING, STRING }; |
| public static final Type[] STRINGARRAY5 = new Type[] { STRING, STRING, STRING, STRING, STRING }; |
| public static final Type[] STRINGARRAY6 = new Type[] { STRING, STRING, STRING, STRING, STRING, STRING }; |
| public static final Type[] STRINGARRAY7 = new Type[] { STRING, STRING, STRING, STRING, STRING, STRING, STRING }; |
| |
| private static Map<String, Type> commonTypes = new HashMap<String, Type>(); |
| |
| static { |
| commonTypes.put(STRING.getSignature(), STRING); |
| commonTypes.put(THROWABLE.getSignature(), THROWABLE); |
| commonTypes.put(VOID.getSignature(), VOID); |
| commonTypes.put(BOOLEAN.getSignature(), BOOLEAN); |
| commonTypes.put(BYTE.getSignature(), BYTE); |
| commonTypes.put(SHORT.getSignature(), SHORT); |
| commonTypes.put(CHAR.getSignature(), CHAR); |
| commonTypes.put(INT.getSignature(), INT); |
| commonTypes.put(LONG.getSignature(), LONG); |
| commonTypes.put(DOUBLE.getSignature(), DOUBLE); |
| commonTypes.put(FLOAT.getSignature(), FLOAT); |
| commonTypes.put(CLASS.getSignature(), CLASS); |
| commonTypes.put(OBJECT.getSignature(), OBJECT); |
| commonTypes.put(STRING_ARRAY.getSignature(), STRING_ARRAY); |
| commonTypes.put(CLASS_ARRAY.getSignature(), CLASS_ARRAY); |
| commonTypes.put(OBJECT_ARRAY.getSignature(), OBJECT_ARRAY); |
| commonTypes.put(INTEGER.getSignature(), INTEGER); |
| commonTypes.put(EXCEPTION.getSignature(), EXCEPTION); |
| commonTypes.put(STRINGBUFFER.getSignature(), STRINGBUFFER); |
| commonTypes.put(STRINGBUILDER.getSignature(), STRINGBUILDER); |
| commonTypes.put(LIST.getSignature(), LIST); |
| commonTypes.put(ITERATOR.getSignature(), ITERATOR); |
| ConstantsInitializer.initialize(); // needs calling because it will not have run properly the first time |
| } |
| |
| protected Type(byte t, String s) { |
| type = t; |
| signature = s; |
| } |
| |
| public String getSignature() { |
| return signature; |
| } |
| |
| 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[]' |
| */ |
| @Override |
| public String toString() { |
| return ((this.equals(Type.NULL) || (type >= Constants.T_UNKNOWN))) ? signature : Utility |
| .signatureToString(signature, false); |
| } |
| |
| public static final Type getType(String signature) { |
| Type t = commonTypes.get(signature); |
| if (t != null) { |
| return t; |
| } |
| byte type = Utility.typeOfSignature(signature); |
| if (type <= Constants.T_VOID) { |
| return BasicType.getType(type); |
| } else if (type == Constants.T_ARRAY) { |
| int dim = 0; |
| do { |
| dim++; |
| } while (signature.charAt(dim) == '['); |
| // Recurse, but just once, if the signature is ok |
| Type componentType = getType(signature.substring(dim)); |
| return new ArrayType(componentType, dim); |
| } else { // type == T_REFERENCE |
| // generics awareness |
| int nextAngly = signature.indexOf('<'); |
| // Format is 'Lblahblah;' |
| int index = signature.indexOf(';'); // Look for closing ';' |
| |
| String typeString = null; |
| if (nextAngly == -1 || nextAngly > index) { |
| typeString = signature.substring(1, index).replace('/', '.'); |
| } else { |
| boolean endOfSigReached = false; |
| int posn = nextAngly; |
| int genericDepth = 0; |
| while (!endOfSigReached) { |
| switch (signature.charAt(posn++)) { |
| case '<': |
| genericDepth++; |
| break; |
| case '>': |
| genericDepth--; |
| break; |
| case ';': |
| if (genericDepth == 0) { |
| endOfSigReached = true; |
| } |
| break; |
| default: |
| } |
| } |
| index = posn - 1; |
| typeString = signature.substring(1, nextAngly).replace('/', '.'); |
| } |
| // ObjectType doesn't currently store parameterized info |
| return new ObjectType(typeString); |
| } |
| } |
| |
| /** |
| * Convert signature to a Type object. |
| * |
| * @param signature signature string such as Ljava/lang/String; |
| * @return type object |
| */ |
| public static final TypeHolder getTypeInternal(String signature) throws StringIndexOutOfBoundsException { |
| byte type = Utility.typeOfSignature(signature); |
| |
| if (type <= Constants.T_VOID) { |
| return new TypeHolder(BasicType.getType(type), 1); |
| } else if (type == Constants.T_ARRAY) { |
| int dim = 0; |
| do { |
| dim++; |
| } while (signature.charAt(dim) == '['); |
| // Recurse, but just once, if the signature is ok |
| TypeHolder th = getTypeInternal(signature.substring(dim)); |
| return new TypeHolder(new ArrayType(th.getType(), dim), dim + th.getConsumed()); |
| } else { // type == T_REFERENCE |
| // Format is 'Lblahblah;' |
| int index = signature.indexOf(';'); // Look for closing ';' |
| if (index < 0) { |
| throw new ClassFormatException("Invalid signature: " + signature); |
| } |
| |
| // generics awareness |
| int nextAngly = signature.indexOf('<'); |
| String typeString = null; |
| if (nextAngly == -1 || nextAngly > index) { |
| typeString = signature.substring(1, index).replace('/', '.'); |
| } else { |
| boolean endOfSigReached = false; |
| int posn = nextAngly; |
| int genericDepth = 0; |
| while (!endOfSigReached) { |
| switch (signature.charAt(posn++)) { |
| case '<': |
| genericDepth++; |
| break; |
| case '>': |
| genericDepth--; |
| break; |
| case ';': |
| if (genericDepth == 0) { |
| endOfSigReached = true; |
| } |
| break; |
| default: |
| } |
| } |
| index = posn - 1; |
| typeString = signature.substring(1, nextAngly).replace('/', '.'); |
| } |
| // ObjectType doesn't currently store parameterized info |
| return new TypeHolder(new ObjectType(typeString), index + 1); |
| } |
| } |
| |
| /** |
| * 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 |
| */ |
| // OPTIMIZE crap impl |
| public static Type[] getArgumentTypes(String signature) { |
| List<Type> argumentTypes = new ArrayList<Type>(); |
| 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) != ')') { |
| TypeHolder th = getTypeInternal(signature.substring(index)); |
| argumentTypes.add(th.getType()); |
| index += th.getConsumed(); // update position |
| } |
| } catch (StringIndexOutOfBoundsException e) { // Should never occur |
| throw new ClassFormatException("Invalid method signature: " + signature); |
| } |
| |
| types = new Type[argumentTypes.size()]; |
| argumentTypes.toArray(types); |
| return types; |
| } |
| |
| /** |
| * Work out the type of each argument in the signature and return the cumulative sizes of all the types (size means number of |
| * stack slots it consumes, eg double=2, int=1). Unlike the call above, this does minimal unpacking |
| */ |
| public static int getArgumentSizes(String signature) { |
| int size = 0; |
| if (signature.charAt(0) != '(') { |
| throw new ClassFormatException("Invalid method signature: " + signature); |
| } |
| |
| int index = 1; // current string position |
| try { |
| while (signature.charAt(index) != ')') { |
| byte type = Utility.typeOfSignature(signature.charAt(index)); |
| if (type <= Constants.T_VOID) { |
| size += BasicType.getType(type).getSize(); |
| index++; |
| } else if (type == Constants.T_ARRAY) { |
| int dim = 0; |
| do { |
| dim++; |
| } while (signature.charAt(dim + index) == '['); |
| TypeHolder th = getTypeInternal(signature.substring(dim + index)); |
| size += 1; |
| index += dim + th.getConsumed(); |
| } else { // type == T_REFERENCE |
| // Format is 'Lblahblah;' |
| int index2 = signature.indexOf(';', index); // Look for closing ';' |
| |
| // generics awareness |
| int nextAngly = signature.indexOf('<', index); |
| if (nextAngly == -1 || nextAngly > index2) { |
| } else { |
| boolean endOfSigReached = false; |
| int posn = nextAngly; |
| int genericDepth = 0; |
| while (!endOfSigReached) { |
| switch (signature.charAt(posn++)) { |
| case '<': |
| genericDepth++; |
| break; |
| case '>': |
| genericDepth--; |
| break; |
| case ';': |
| if (genericDepth == 0) { |
| endOfSigReached = true; |
| } |
| break; |
| default: |
| } |
| } |
| index2 = posn - 1; |
| } |
| size++; |
| index = index2 + 1; |
| } |
| } |
| } catch (StringIndexOutOfBoundsException e) { // Should never occur |
| throw new ClassFormatException("Invalid method signature: " + signature); |
| } |
| return size; |
| } |
| |
| /** |
| * Return the size of the type expressed in the signature. The signature should contain only one type. |
| */ |
| public static int getTypeSize(String signature) { |
| byte type = Utility.typeOfSignature(signature.charAt(0)); |
| if (type <= Constants.T_VOID) { |
| return BasicType.getType(type).getSize(); |
| } else if (type == Constants.T_ARRAY) { |
| return 1; |
| } else { // type == T_REFERENCE |
| return 1; |
| } |
| } |
| |
| /** |
| * 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 amazingly 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(); |
| } |
| |
| public static String getSignature(java.lang.reflect.Constructor<?> cons) { |
| StringBuffer sb = new StringBuffer("("); |
| Class<?>[] params = cons.getParameterTypes(); // avoid clone |
| |
| for (int j = 0; j < params.length; j++) { |
| sb.append(getType(params[j]).getSignature()); |
| } |
| |
| sb.append(")V"); |
| return sb.toString(); |
| } |
| |
| public static class TypeHolder { |
| private Type t; |
| private int consumed; |
| |
| public Type getType() { |
| return t; |
| } |
| |
| public int getConsumed() { |
| return consumed; |
| } |
| |
| public TypeHolder(Type t, int i) { |
| this.t = t; |
| this.consumed = i; |
| } |
| } |
| |
| } |