All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aspectj.apache.bcel.generic.Type Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
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 (https://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 [email protected].
 *
 * 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
 * .
 */

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 M. Dahm
 *
 *         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, "") {
	};
	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 commonTypes = new HashMap<>();

	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 argumentTypes = 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) != ')') {
				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) {
		StringBuilder sb = new StringBuilder("(");
		Class[] params = meth.getParameterTypes(); // avoid clone

		for (Class param : params) {
			sb.append(getType(param).getSignature());
		}

		sb.append(")");
		sb.append(getType(meth.getReturnType()).getSignature());
		return sb.toString();
	}

	public static String getSignature(java.lang.reflect.Constructor cons) {
		StringBuilder sb = new StringBuilder("(");
		Class[] params = cons.getParameterTypes(); // avoid clone

		for (Class param : params) {
			sb.append(getType(param).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;
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy