📄 typerepository.java
字号:
/* * Bytecode Analysis Framework * Copyright (C) 2004, University of Maryland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package edu.umd.cs.findbugs.ba.type;import java.util.*;import edu.umd.cs.findbugs.ba.ClassNotFoundExceptionParser;import edu.umd.cs.findbugs.ba.Debug;import org.apache.bcel.Constants;/** * Factory/repository class to ensure that all abstract Java types * are represented by a unique Type object. * Queries on the type hierarchy can be performed * on the types instantiated by the repository. * <p/> * <p> Typically, this class is used by specifying a * {@link ClassResolver ClassResolver} that does the work of * finding class representations, which will determine * whether particular types are classes or interfaces, * and what the superclasses and superinterfaces of * class and interface types are. The {@link #isSubtype} * method will automatically construct the class hierarchy * using the ClassResolver to determine the hierarchy. * <p/> * <p> Another way to use TypeRepository is to explicitly mark * ClassType objects as interfaces or classes, and add the * subtype relationships using {@link #addSuperclassLink} * and {@link #addInterfaceLink} for ClassTypes. Subtype * relationships for array types are always added automatically * based on the class hierarchy. Note that if you use this * approach, you must explicitly add <code>java.lang.Object</code>, * <code>java.io.Serializable</code>, and <code>java.lang.Cloneable</code> * to the repository. * * @author David Hovemeyer * @see Type * @see ClassResolver */public class TypeRepository { // FIXME: // - signatures should probably be interned // (do experiment, see if it makes any difference in memory use) /* ---------------------------------------------------------------------- * Static data * ---------------------------------------------------------------------- */ private static final boolean DEBUG = Boolean.getBoolean("tr.debug"); /** * Basic type codes to signatures. * FIXME: change to array? */ private static final HashMap<Byte, String> basicTypeCodeToSignatureMap = new HashMap<Byte, String>(); static { basicTypeCodeToSignatureMap.put(new Byte(Constants.T_BOOLEAN), "Z"); basicTypeCodeToSignatureMap.put(new Byte(Constants.T_CHAR), "C"); basicTypeCodeToSignatureMap.put(new Byte(Constants.T_FLOAT), "F"); basicTypeCodeToSignatureMap.put(new Byte(Constants.T_DOUBLE), "D"); basicTypeCodeToSignatureMap.put(new Byte(Constants.T_BYTE), "B"); basicTypeCodeToSignatureMap.put(new Byte(Constants.T_SHORT), "S"); basicTypeCodeToSignatureMap.put(new Byte(Constants.T_INT), "I"); basicTypeCodeToSignatureMap.put(new Byte(Constants.T_LONG), "J"); basicTypeCodeToSignatureMap.put(new Byte(Constants.T_VOID), "V"); } private static final String JAVA_LANG_OBJECT_SIGNATURE = "Ljava/lang/Object;"; /* ---------------------------------------------------------------------- * Fields * ---------------------------------------------------------------------- */ private HashMap<String, Type> signatureToTypeMap; private InheritanceGraph inheritanceGraph; private ClassResolver resolver; // Store basic and special types in fields so they // can be accessed easily and without worrying about // InvalidSignatureExceptions. private BasicType booleanType; private BasicType byteType; private BasicType charType; private BasicType shortType; private BasicType intType; private BasicType longType; private BasicType floatType; private BasicType doubleType; private BasicType voidType; private Type topType; private Type bottomType; private Type nullType; private Type longExtraType; private Type doubleExtraType; private Type returnAddressType; /* ---------------------------------------------------------------------- * Public methods * ---------------------------------------------------------------------- */ /** * Constructor. * Creates a type repository that has basic and special * types, but no class or array types. * * @param resolver the ClassResolver that will be used to * find inheritance hierarchy information for classes */ public TypeRepository(ClassResolver resolver) { this.signatureToTypeMap = new HashMap<String, Type>(); this.inheritanceGraph = new InheritanceGraph(); this.resolver = resolver; addBasicTypes(); addSpecialTypes(); } /** * Get a ClassType from a signature, e.g., * JAVA_LANG_OBJECT_SIGNATURE. * * @param signature the class signature * @return the ClassType representing the class */ public ClassType classTypeFromSignature(String signature) { if (Debug.CHECK_ASSERTIONS && !signature.startsWith("L") && !signature.endsWith(";")) throw new IllegalArgumentException("Illegal class type signature: " + signature); return createClassType(signature); } /** * Get a ClassType from a class or interface name * using slashes to separate package components, * creating it if it doesn't exist. * (A name with components separated by slashes * is the native format for bare class names * in class files.) * * @param slashedClassName class name in slashed format * @return the ClassType representing the class */ public ClassType classTypeFromSlashedClassName(String slashedClassName) { if (Debug.CHECK_ASSERTIONS && slashedClassName.endsWith(";")) throw new IllegalArgumentException("Illegal slashed class name: " + slashedClassName); String signature = "L" + slashedClassName + ";"; return createClassType(signature); } /** * Get a ClassType from a class or interface name * using dots to separate package components, * creating it if it doesn't exist. * * @param dottedClassName the class name in dotted format * @return the ClassType representing the class */ public ClassType classTypeFromDottedClassName(String dottedClassName) { StringBuffer buf = new StringBuffer(); buf.append('L'); buf.append(dottedClassName.replace('.', '/')); buf.append(';'); return createClassType(buf.toString()); } /** * Get an ArrayType from an array signature, * creating it if it doesn't exist. * * @param signature the array signature * @return the ArrayType representing the array type */ public ArrayType arrayTypeFromSignature(String signature) throws InvalidSignatureException { return createArrayType(signature); } /** * Get an ArrayType from number of dimensions and base type. * The base type must not be an array type. * * @param numDimensions the number of dimensions * @param baseType the base type (e.g, "Object" in the array type * "Object[][]"): must be created from this type repository * @return the array type */ public ArrayType arrayTypeFromDimensionsAndBaseType(int numDimensions, Type baseType) { if (!baseType.isValidArrayBaseType()) throw new IllegalArgumentException("Type " + baseType.getSignature() + " is not a valid array base type"); return createArrayType(numDimensions, baseType); } /** * Create a one-dimensional array type with given element type, * which can be an array type. Sometimes it is easier to * think of all arrays as being one dimensional. * * @param elementType the element type * @return an array type with the given element type */ public ArrayType arrayTypeFromElementType(Type elementType) { if (!elementType.isValidArrayElementType()) throw new IllegalArgumentException("Type " + elementType.getSignature() + " is not a valid array element type"); int numDimensions; Type baseType; if (elementType.isBasicType()) { numDimensions = 1; baseType = elementType; } else { ObjectType elementObjectType = (ObjectType) elementType; if (elementObjectType.isArray()) { ArrayType arrayType = (ArrayType) elementObjectType; numDimensions = 1 + arrayType.getNumDimensions(); baseType = arrayType.getBaseType(); } else { numDimensions = 1; baseType = elementType; } } return arrayTypeFromDimensionsAndBaseType(numDimensions, baseType); } /** * Create an BasicType from a type code. * * @param typeCode the basic type code (T_BOOLEAN, etc.) * @return the BasicType representing the basic type */ public BasicType basicTypeFromTypeCode(byte typeCode) { String signature = basicTypeCodeToSignatureMap.get(new Byte(typeCode)); if (signature == null) throw new IllegalArgumentException("Invalid basic type code: " + typeCode); BasicType type = (BasicType) signatureToTypeMap.get(signature); if (type == null) { type = new BasicType(typeCode); signatureToTypeMap.put(signature, type); } return type; } /** * Create an BasicType from a basic type signature. * * @param signature the signature * @return the BasicType representing the basic type */ public BasicType basicTypeFromSignature(String signature) throws InvalidSignatureException { if (signature.length() != 1 && "ZBCSIJFDV".indexOf(signature) < 0) throw new InvalidSignatureException("Bad type signature: " + signature); return (BasicType) signatureToTypeMap.get(signature); } /** * Create a special type from a signature. * The signature must be one of the constants defined in * {@link SpecialTypeSignatures}. * * @param signature special type signature * @return the special Type */ public Type specialTypeFromSignature(String signature) throws InvalidSignatureException { if (!signature.startsWith(SpecialTypeSignatures.SPECIAL_TYPE_PREFIX)) throw new InvalidSignatureException("Invalid special type signature: " + signature); return signatureToTypeMap.get(signature); } /** * Get an Type object representing the type whose JVM signature * is given, creating it if it doesn't exist. * * @param signature the JVM signature of the type: something * like "B" (the byte basic type), "Ljava/lang/String;" * (the type of a reference to java.lang.String), or * "[Ljava/lang/Object;" (the type of a reference to an array of * java.lang.Object references). * @return the Type object representing the type */ public Type typeFromSignature(String signature) throws InvalidSignatureException { Type type = signatureToTypeMap.get(signature); if (type != null) return type; else if (signature.startsWith("L")) return classTypeFromSignature(signature); else if (signature.startsWith("[")) return arrayTypeFromSignature(signature); else if (signature.startsWith(SpecialTypeSignatures.SPECIAL_TYPE_PREFIX)) return specialTypeFromSignature(signature); else return basicTypeFromSignature(signature); } /** * Get the void type. * * @return the void type */ public BasicType getVoidType() { return voidType; } /** * Get the boolean type. * * @return the boolean type */ public BasicType getBooleanType() { return booleanType; } /** * Get the byte type. * * @return the byte type */ public BasicType getByteType() { return byteType; } /** * Get the char type. * * @return the char type */ public BasicType getCharType() { return charType; } /** * Get the short type. * * @return the short type */ public BasicType getShortType() { return shortType; } /** * Get the int type. * * @return the int type */ public BasicType getIntType() { return intType; } /** * Get the long type. * * @return the long type */ public BasicType getLongType() { return longType; } /** * Get the float type. * * @return the float type */ public BasicType getFloatType() {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -