1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.dx.rop.cst; 18 19import com.android.dx.rop.type.Type; 20import java.util.HashMap; 21 22/** 23 * Constants that represent an arbitrary type (reference or primitive). 24 */ 25public final class CstType extends TypedConstant { 26 /** {@code non-null;} map of interned types */ 27 private static final HashMap<Type, CstType> interns = 28 new HashMap<Type, CstType>(100); 29 30 /** {@code non-null;} instance corresponding to the class {@code Object} */ 31 public static final CstType OBJECT = intern(Type.OBJECT); 32 33 /** {@code non-null;} instance corresponding to the class {@code Boolean} */ 34 public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS); 35 36 /** {@code non-null;} instance corresponding to the class {@code Byte} */ 37 public static final CstType BYTE = intern(Type.BYTE_CLASS); 38 39 /** {@code non-null;} instance corresponding to the class {@code Character} */ 40 public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS); 41 42 /** {@code non-null;} instance corresponding to the class {@code Double} */ 43 public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS); 44 45 /** {@code non-null;} instance corresponding to the class {@code Float} */ 46 public static final CstType FLOAT = intern(Type.FLOAT_CLASS); 47 48 /** {@code non-null;} instance corresponding to the class {@code Long} */ 49 public static final CstType LONG = intern(Type.LONG_CLASS); 50 51 /** {@code non-null;} instance corresponding to the class {@code Integer} */ 52 public static final CstType INTEGER = intern(Type.INTEGER_CLASS); 53 54 /** {@code non-null;} instance corresponding to the class {@code Short} */ 55 public static final CstType SHORT = intern(Type.SHORT_CLASS); 56 57 /** {@code non-null;} instance corresponding to the class {@code Void} */ 58 public static final CstType VOID = intern(Type.VOID_CLASS); 59 60 /** {@code non-null;} instance corresponding to the type {@code boolean[]} */ 61 public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY); 62 63 /** {@code non-null;} instance corresponding to the type {@code byte[]} */ 64 public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY); 65 66 /** {@code non-null;} instance corresponding to the type {@code char[]} */ 67 public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY); 68 69 /** {@code non-null;} instance corresponding to the type {@code double[]} */ 70 public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY); 71 72 /** {@code non-null;} instance corresponding to the type {@code float[]} */ 73 public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY); 74 75 /** {@code non-null;} instance corresponding to the type {@code long[]} */ 76 public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY); 77 78 /** {@code non-null;} instance corresponding to the type {@code int[]} */ 79 public static final CstType INT_ARRAY = intern(Type.INT_ARRAY); 80 81 /** {@code non-null;} instance corresponding to the type {@code short[]} */ 82 public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY); 83 84 /** {@code non-null;} the underlying type */ 85 private final Type type; 86 87 /** 88 * {@code null-ok;} the type descriptor corresponding to this instance, if 89 * calculated 90 */ 91 private CstString descriptor; 92 93 /** 94 * Returns an instance of this class that represents the wrapper 95 * class corresponding to a given primitive type. For example, if 96 * given {@link Type#INT}, this method returns the class reference 97 * {@code java.lang.Integer}. 98 * 99 * @param primitiveType {@code non-null;} the primitive type 100 * @return {@code non-null;} the corresponding wrapper class 101 */ 102 public static CstType forBoxedPrimitiveType(Type primitiveType) { 103 switch (primitiveType.getBasicType()) { 104 case Type.BT_BOOLEAN: return BOOLEAN; 105 case Type.BT_BYTE: return BYTE; 106 case Type.BT_CHAR: return CHARACTER; 107 case Type.BT_DOUBLE: return DOUBLE; 108 case Type.BT_FLOAT: return FLOAT; 109 case Type.BT_INT: return INTEGER; 110 case Type.BT_LONG: return LONG; 111 case Type.BT_SHORT: return SHORT; 112 case Type.BT_VOID: return VOID; 113 } 114 115 throw new IllegalArgumentException("not primitive: " + primitiveType); 116 } 117 118 /** 119 * Returns an interned instance of this class for the given type. 120 * 121 * @param type {@code non-null;} the underlying type 122 * @return {@code non-null;} an appropriately-constructed instance 123 */ 124 public static CstType intern(Type type) { 125 synchronized (interns) { 126 CstType cst = interns.get(type); 127 128 if (cst == null) { 129 cst = new CstType(type); 130 interns.put(type, cst); 131 } 132 133 return cst; 134 } 135 } 136 137 /** 138 * Constructs an instance. 139 * 140 * @param type {@code non-null;} the underlying type 141 */ 142 public CstType(Type type) { 143 if (type == null) { 144 throw new NullPointerException("type == null"); 145 } 146 147 if (type == type.KNOWN_NULL) { 148 throw new UnsupportedOperationException( 149 "KNOWN_NULL is not representable"); 150 } 151 152 this.type = type; 153 this.descriptor = null; 154 } 155 156 /** {@inheritDoc} */ 157 @Override 158 public boolean equals(Object other) { 159 if (!(other instanceof CstType)) { 160 return false; 161 } 162 163 return type == ((CstType) other).type; 164 } 165 166 /** {@inheritDoc} */ 167 @Override 168 public int hashCode() { 169 return type.hashCode(); 170 } 171 172 /** {@inheritDoc} */ 173 @Override 174 protected int compareTo0(Constant other) { 175 String thisDescriptor = type.getDescriptor(); 176 String otherDescriptor = ((CstType) other).type.getDescriptor(); 177 return thisDescriptor.compareTo(otherDescriptor); 178 } 179 180 /** {@inheritDoc} */ 181 @Override 182 public String toString() { 183 return "type{" + toHuman() + '}'; 184 } 185 186 /** {@inheritDoc} */ 187 public Type getType() { 188 return Type.CLASS; 189 } 190 191 /** {@inheritDoc} */ 192 @Override 193 public String typeName() { 194 return "type"; 195 } 196 197 /** {@inheritDoc} */ 198 @Override 199 public boolean isCategory2() { 200 return false; 201 } 202 203 /** {@inheritDoc} */ 204 public String toHuman() { 205 return type.toHuman(); 206 } 207 208 /** 209 * Gets the underlying type (as opposed to the type corresponding 210 * to this instance as a constant, which is always 211 * {@code Class}). 212 * 213 * @return {@code non-null;} the type corresponding to the name 214 */ 215 public Type getClassType() { 216 return type; 217 } 218 219 /** 220 * Gets the type descriptor for this instance. 221 * 222 * @return {@code non-null;} the descriptor 223 */ 224 public CstString getDescriptor() { 225 if (descriptor == null) { 226 descriptor = new CstString(type.getDescriptor()); 227 } 228 229 return descriptor; 230 } 231 232 /** 233 * Returns a human readable package name for this type, like "java.util". 234 * If this is an array type, this returns the package name of the array's 235 * component type. If this is a primitive type, this returns "default". 236 */ 237 public String getPackageName() { 238 // descriptor is a string like "[[Ljava/util/String;" 239 String descriptor = getDescriptor().getString(); 240 int lastSlash = descriptor.lastIndexOf('/'); 241 int lastLeftSquare = descriptor.lastIndexOf('['); // -1 unless this is an array 242 if (lastSlash == -1) { 243 return "default"; 244 } else { 245 // +2 to skip the '[' and the 'L' prefix 246 return descriptor.substring(lastLeftSquare + 2, lastSlash).replace('/', '.'); 247 } 248 } 249} 250