169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* 269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit. 369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba, and others. All Rights Reserved. 469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version 669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with 769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License. Alternatively, the contents of this file may be used under 869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later. 969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis, 1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the 1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License. 1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.bytecode.analysis; 1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.ArrayList; 1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.HashMap; 1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.IdentityHashMap; 2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Iterator; 2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Map; 2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.ClassPool; 2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtClass; 2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.NotFoundException; 2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/** 2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Represents a JVM type in data-flow analysis. This abstraction is necessary since 2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * a JVM type not only includes all normal Java types, but also a few special types 3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * that are used by the JVM internally. See the static field types on this class for 3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * more info on these special types. 3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * All primitive and special types reuse the same instance, so identity comparison can 3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * be used when examining them. Normal java types must use {@link #equals(Object)} to 3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * compare type instances. 3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * In most cases, applications which consume this API, only need to call {@link #getCtClass()} 3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * to obtain the needed type information. 3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author Jason T. Greene 4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class Type { 4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private final CtClass clazz; 4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private final boolean special; 4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static final Map prims = new IdentityHashMap(); 4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the double primitive type */ 4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type DOUBLE = new Type(CtClass.doubleType); 4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the boolean primitive type */ 5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type BOOLEAN = new Type(CtClass.booleanType); 5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the long primitive type */ 5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type LONG = new Type(CtClass.longType); 5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the char primitive type */ 5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type CHAR = new Type(CtClass.charType); 5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the byte primitive type */ 5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type BYTE = new Type(CtClass.byteType); 5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the short primitive type */ 5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type SHORT = new Type(CtClass.shortType); 5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the integer primitive type */ 6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type INTEGER = new Type(CtClass.intType); 6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the float primitive type */ 6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type FLOAT = new Type(CtClass.floatType); 6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the void primitive type */ 6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type VOID = new Type(CtClass.voidType); 6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Represents an unknown, or null type. This occurs when aconst_null is used. 6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It is important not to treat this type as java.lang.Object, since a null can 6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * be assigned to any reference type. The analyzer will replace these with 7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * an actual known type if it can be determined by a merged path with known type 7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * information. If this type is encountered on a frame then it is guaranteed to 7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * be null, and the type information is simply not available. Any attempts to 7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * infer the type, without further information from the compiler would be a guess. 7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type UNINIT = new Type(null); 7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Represents an internal JVM return address, which is used by the RET 7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * instruction to return to a JSR that invoked the subroutine. 8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type RETURN_ADDRESS = new Type(null, true); 8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** A placeholder used by the analyzer for the second word position of a double-word type */ 8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type TOP = new Type(null, true); 8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Represents a non-accessible value. Code cannot access the value this type 8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * represents. It occurs when bytecode reuses a local variable table 8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * position with non-mergable types. An example would be compiled code which 9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * uses the same position for a primitive type in one branch, and a reference type 9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * in another branch. 9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type BOGUS = new Type(null, true); 9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the java.lang.Object reference type */ 9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type OBJECT = lookupType("java.lang.Object"); 9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the java.io.Serializable reference type */ 9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type SERIALIZABLE = lookupType("java.io.Serializable"); 9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the java.lang.Coneable reference type */ 10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type CLONEABLE = lookupType("java.lang.Cloneable"); 10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** Represents the java.lang.Throwable reference type */ 10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static final Type THROWABLE = lookupType("java.lang.Throwable"); 10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal static { 10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal prims.put(CtClass.doubleType, DOUBLE); 10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal prims.put(CtClass.longType, LONG); 10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal prims.put(CtClass.charType, CHAR); 10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal prims.put(CtClass.shortType, SHORT); 10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal prims.put(CtClass.intType, INTEGER); 11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal prims.put(CtClass.floatType, FLOAT); 11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal prims.put(CtClass.byteType, BYTE); 11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal prims.put(CtClass.booleanType, BOOLEAN); 11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal prims.put(CtClass.voidType, VOID); 11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Obtain the Type for a given class. If the class is a primitive, 11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the the unique type instance for the primitive will be returned. 12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Otherwise a new Type instance representing the class is returned. 12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param clazz The java class 12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return a type instance for this class 12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static Type get(CtClass clazz) { 12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type type = (Type)prims.get(clazz); 12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return type != null ? type : new Type(clazz); 12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static Type lookupType(String name) { 13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return new Type(ClassPool.getDefault().get(name)); 13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (NotFoundException e) { 13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type(CtClass clazz) { 13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this(clazz, false); 14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Type(CtClass clazz, boolean special) { 14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.clazz = clazz; 14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.special = special; 14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Used to indicate a merge internally triggered a change 14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal boolean popChanged() { 14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return false; 15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Gets the word size of this type. Double-word types, such as long and double 15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * will occupy two positions on the local variable table or stack. 15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return the number of words needed to hold this type 15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public int getSize() { 15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return clazz == CtClass.doubleType || clazz == CtClass.longType || this == TOP ? 2 : 1; 16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns the class this type represents. If the type is special, null will be returned. 16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return the class for this type, or null if special 16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public CtClass getCtClass() { 16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return clazz; 16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns whether or not this type is a normal java reference, i.e. it is or extends java.lang.Object. 17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return true if a java reference, false if a primitive or special 17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public boolean isReference() { 17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return !special && (clazz == null || !clazz.isPrimitive()); 17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns whether or not the type is special. A special type is one that is either used 18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for internal tracking, or is only used internally by the JVM. 18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return true if special, false if not 18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public boolean isSpecial() { 18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return special; 18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns whether or not this type is an array. 19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return true if an array, false if not 19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public boolean isArray() { 19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return clazz != null && clazz.isArray(); 19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns the number of dimensions of this array. If the type is not an 20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * array zero is returned. 20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return zero if not an array, otherwise the number of array dimensions. 20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public int getDimensions() { 20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (!isArray()) return 0; 20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String name = clazz.getName(); 20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int pos = name.length() - 1; 21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int count = 0; 21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (name.charAt(pos) == ']' ) { 21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal pos -= 2; 21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal count++; 21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return count; 21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns the array component if this type is an array. If the type 22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * is not an array null is returned. 22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return the array component if an array, otherwise null 22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Type getComponent() { 22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (this.clazz == null || !this.clazz.isArray()) 22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return null; 22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass component; 23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal component = this.clazz.getComponentType(); 23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (NotFoundException e) { 23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type type = (Type)prims.get(component); 23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return (type != null) ? type : new Type(component); 23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Determines whether this type is assignable, to the passed type. 24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A type is assignable to another if it is either the same type, or 24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * a sub-type. 24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param type the type to test assignability to 24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return true if this is assignable to type, otherwise false 24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public boolean isAssignableFrom(Type type) { 24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (this == type) 25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return true; 25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if ((type == UNINIT && isReference()) || this == UNINIT && type.isReference()) 25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return true; 25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (type instanceof MultiType) 25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return ((MultiType)type).isAssignableTo(this); 25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (type instanceof MultiArrayType) 25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return ((MultiArrayType)type).isAssignableTo(this); 26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Primitives and Special types must be identical 26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (clazz == null || clazz.isPrimitive()) 26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return false; 26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return type.clazz.subtypeOf(clazz); 26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (Exception e) { 26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Finds the common base type, or interface which both this and the specified 27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * type can be assigned. If there is more than one possible answer, then a {@link MultiType}, 27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * or a {@link MultiArrayType} is returned. Multi-types have special rules, 27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * and successive merges and assignment tests on them will alter their internal state, 27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * as well as other multi-types they have been merged with. This method is used by 27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the data-flow analyzer to merge the type state from multiple branches. 28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param type the type to merge with 28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return the merged type 28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Type merge(Type type) { 28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (type == this) 28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return this; 28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (type == null) 28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return this; 28969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (type == Type.UNINIT) 29069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return this; 29169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (this == Type.UNINIT) 29269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return type; 29369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 29469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Unequal primitives and special types can not be merged 29569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (! type.isReference() || ! this.isReference()) 29669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return BOGUS; 29769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 29869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Centralize merging of multi-interface types 29969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (type instanceof MultiType) 30069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return type.merge(this); 30169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 30269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (type.isArray() && this.isArray()) 30369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return mergeArray(type); 30469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 30569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 30669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return mergeClasses(type); 30769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (NotFoundException e) { 30869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 30969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 31069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 31169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 31269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type getRootComponent(Type type) { 31369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (type.isArray()) 31469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal type = type.getComponent(); 31569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 31669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return type; 31769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 31869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 31969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Type createArray(Type rootComponent, int dims) { 32069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (rootComponent instanceof MultiType) 32169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return new MultiArrayType((MultiType) rootComponent, dims); 32269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 32369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String name = arrayName(rootComponent.clazz.getName(), dims); 32469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 32569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type type; 32669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 32769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal type = Type.get(getClassPool(rootComponent).get(name)); 32869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (NotFoundException e) { 32969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 33069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 33169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 33269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return type; 33369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 33469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 33569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String arrayName(String component, int dims) { 33669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Using char[] since we have no StringBuilder in JDK4, and StringBuffer is slow. 33769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Although, this is more efficient even if we did have one. 33869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int i = component.length(); 33969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int size = i + dims * 2; 34069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal char[] string = new char[size]; 34169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal component.getChars(0, i, string, 0); 34269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (i < size) { 34369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal string[i++] = '['; 34469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal string[i++] = ']'; 34569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 34669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal component = new String(string); 34769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return component; 34869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 34969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 35069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private ClassPool getClassPool(Type rootComponent) { 35169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ClassPool pool = rootComponent.clazz.getClassPool(); 35269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return pool != null ? pool : ClassPool.getDefault(); 35369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 35469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 35569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Type mergeArray(Type type) { 35669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type typeRoot = getRootComponent(type); 35769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type thisRoot = getRootComponent(this); 35869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int typeDims = type.getDimensions(); 35969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int thisDims = this.getDimensions(); 36069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 36169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Array commponents can be merged when the dimensions are equal 36269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (typeDims == thisDims) { 36369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type mergedComponent = thisRoot.merge(typeRoot); 36469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 36569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // If the components can not be merged (a primitive component mixed with a different type) 36669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // then Object is the common type. 36769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (mergedComponent == Type.BOGUS) 36869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return Type.OBJECT; 36969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 37069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return createArray(mergedComponent, thisDims); 37169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 37269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 37369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Type targetRoot; 37469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int targetDims; 37569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 37669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (typeDims < thisDims) { 37769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal targetRoot = typeRoot; 37869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal targetDims = typeDims; 37969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } else { 38069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal targetRoot = thisRoot; 38169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal targetDims = thisDims; 38269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 38369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 38469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Special case, arrays are cloneable and serializable, so prefer them when dimensions differ 38569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (eq(CLONEABLE.clazz, targetRoot.clazz) || eq(SERIALIZABLE.clazz, targetRoot.clazz)) 38669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return createArray(targetRoot, targetDims); 38769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 38869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return createArray(OBJECT, targetDims); 38969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 39069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 39169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static CtClass findCommonSuperClass(CtClass one, CtClass two) throws NotFoundException { 39269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass deep = one; 39369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass shallow = two; 39469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass backupShallow = shallow; 39569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass backupDeep = deep; 39669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 39769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Phase 1 - Find the deepest hierarchy, set deep and shallow correctly 39869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (;;) { 39969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // In case we get lucky, and find a match early 40069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (eq(deep, shallow) && deep.getSuperclass() != null) 40169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return deep; 40269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 40369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass deepSuper = deep.getSuperclass(); 40469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass shallowSuper = shallow.getSuperclass(); 40569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 40669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (shallowSuper == null) { 40769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // right, now reset shallow 40869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal shallow = backupShallow; 40969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal break; 41069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 41169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 41269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (deepSuper == null) { 41369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // wrong, swap them, since deep is now useless, its our tmp before we swap it 41469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal deep = backupDeep; 41569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal backupDeep = backupShallow; 41669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal backupShallow = deep; 41769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 41869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal deep = shallow; 41969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal shallow = backupShallow; 42069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal break; 42169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 42269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 42369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal deep = deepSuper; 42469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal shallow = shallowSuper; 42569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 42669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 42769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Phase 2 - Move deepBackup up by (deep end - deep) 42869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (;;) { 42969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal deep = deep.getSuperclass(); 43069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (deep == null) 43169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal break; 43269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 43369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal backupDeep = backupDeep.getSuperclass(); 43469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 43569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 43669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal deep = backupDeep; 43769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 43869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Phase 3 - The hierarchy positions are now aligned 43969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // The common super class is easy to find now 44069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (!eq(deep, shallow)) { 44169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal deep = deep.getSuperclass(); 44269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal shallow = shallow.getSuperclass(); 44369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 44469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 44569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return deep; 44669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 44769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 44869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Type mergeClasses(Type type) throws NotFoundException { 44969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass superClass = findCommonSuperClass(this.clazz, type.clazz); 45069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 45169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // If its Object, then try and find a common interface(s) 45269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (superClass.getSuperclass() == null) { 45369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Map interfaces = findCommonInterfaces(type); 45469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (interfaces.size() == 1) 45569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return new Type((CtClass) interfaces.values().iterator().next()); 45669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (interfaces.size() > 1) 45769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return new MultiType(interfaces); 45869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 45969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Only Object is in common 46069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return new Type(superClass); 46169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 46269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 46369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Check for a common interface that is not on the found supertype 46469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Map commonDeclared = findExclusiveDeclaredInterfaces(type, superClass); 46569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (commonDeclared.size() > 0) { 46669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return new MultiType(commonDeclared, new Type(superClass)); 46769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 46869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 46969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return new Type(superClass); 47069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 47169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 47269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Map findCommonInterfaces(Type type) { 47369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Map typeMap = getAllInterfaces(type.clazz, null); 47469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Map thisMap = getAllInterfaces(this.clazz, null); 47569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 47669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return findCommonInterfaces(typeMap, thisMap); 47769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 47869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 47969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Map findExclusiveDeclaredInterfaces(Type type, CtClass exclude) { 48069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Map typeMap = getDeclaredInterfaces(type.clazz, null); 48169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Map thisMap = getDeclaredInterfaces(this.clazz, null); 48269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Map excludeMap = getAllInterfaces(exclude, null); 48369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 48469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Iterator i = excludeMap.keySet().iterator(); 48569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (i.hasNext()) { 48669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Object intf = i.next(); 48769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal typeMap.remove(intf); 48869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal thisMap.remove(intf); 48969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 49069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 49169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return findCommonInterfaces(typeMap, thisMap); 49269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 49369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 49469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 49569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Map findCommonInterfaces(Map typeMap, Map alterMap) { 49669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Iterator i = alterMap.keySet().iterator(); 49769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (i.hasNext()) { 49869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (! typeMap.containsKey(i.next())) 49969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal i.remove(); 50069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 50169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 50269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // Reduce to subinterfaces 50369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // This does not need to be recursive since we make a copy, 50469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // and that copy contains all super types for the whole hierarchy 50569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal i = new ArrayList(alterMap.values()).iterator(); 50669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while (i.hasNext()) { 50769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass intf = (CtClass) i.next(); 50869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass[] interfaces; 50969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 51069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal interfaces = intf.getInterfaces(); 51169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (NotFoundException e) { 51269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 51369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 51469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 51569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (int c = 0; c < interfaces.length; c++) 51669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal alterMap.remove(interfaces[c].getName()); 51769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 51869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 51969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return alterMap; 52069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 52169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 52269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Map getAllInterfaces(CtClass clazz, Map map) { 52369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (map == null) 52469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal map = new HashMap(); 52569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 52669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (clazz.isInterface()) 52769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal map.put(clazz.getName(), clazz); 52869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal do { 52969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 53069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass[] interfaces = clazz.getInterfaces(); 53169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (int i = 0; i < interfaces.length; i++) { 53269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass intf = interfaces[i]; 53369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal map.put(intf.getName(), intf); 53469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal getAllInterfaces(intf, map); 53569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 53669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 53769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal clazz = clazz.getSuperclass(); 53869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (NotFoundException e) { 53969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 54069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 54169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } while (clazz != null); 54269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 54369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return map; 54469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 54569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 54669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Map getDeclaredInterfaces(CtClass clazz, Map map) { 54769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (map == null) 54869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal map = new HashMap(); 54969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 55069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (clazz.isInterface()) 55169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal map.put(clazz.getName(), clazz); 55269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 55369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass[] interfaces; 55469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 55569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal interfaces = clazz.getInterfaces(); 55669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } catch (NotFoundException e) { 55769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new RuntimeException(e); 55869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 55969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 56069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal for (int i = 0; i < interfaces.length; i++) { 56169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal CtClass intf = interfaces[i]; 56269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal map.put(intf.getName(), intf); 56369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal getDeclaredInterfaces(intf, map); 56469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 56569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 56669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return map; 56769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 56869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 56969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public boolean equals(Object o) { 57069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (! (o instanceof Type)) 57169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return false; 57269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 57369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return o.getClass() == getClass() && eq(clazz, ((Type)o).clazz); 57469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 57569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 57669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal static boolean eq(CtClass one, CtClass two) { 57769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return one == two || (one != null && two != null && one.getName().equals(two.getName())); 57869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 57969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 58069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public String toString() { 58169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (this == BOGUS) 58269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return "BOGUS"; 58369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (this == UNINIT) 58469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return "UNINIT"; 58569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (this == RETURN_ADDRESS) 58669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return "RETURN ADDRESS"; 58769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (this == TOP) 58869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return "TOP"; 58969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 59069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return clazz == null ? "null" : clazz.getName(); 59169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 59269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal} 593