--- /dev/null
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.cst;
+
+import com.android.dexgen.rop.type.Type;
+
+import java.util.HashMap;
+
+/**
+ * Constants that represent an arbitrary type (reference or primitive).
+ */
+public final class CstType extends TypedConstant {
+ /** {@code non-null;} map of interned types */
+ private static final HashMap<Type, CstType> interns =
+ new HashMap<Type, CstType>(100);
+
+ /** {@code non-null;} instance corresponding to the class {@code Object} */
+ public static final CstType OBJECT = intern(Type.OBJECT);
+
+ /** {@code non-null;} instance corresponding to the class {@code Boolean} */
+ public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS);
+
+ /** {@code non-null;} instance corresponding to the class {@code Byte} */
+ public static final CstType BYTE = intern(Type.BYTE_CLASS);
+
+ /** {@code non-null;} instance corresponding to the class {@code Character} */
+ public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS);
+
+ /** {@code non-null;} instance corresponding to the class {@code Double} */
+ public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS);
+
+ /** {@code non-null;} instance corresponding to the class {@code Float} */
+ public static final CstType FLOAT = intern(Type.FLOAT_CLASS);
+
+ /** {@code non-null;} instance corresponding to the class {@code Long} */
+ public static final CstType LONG = intern(Type.LONG_CLASS);
+
+ /** {@code non-null;} instance corresponding to the class {@code Integer} */
+ public static final CstType INTEGER = intern(Type.INTEGER_CLASS);
+
+ /** {@code non-null;} instance corresponding to the class {@code Short} */
+ public static final CstType SHORT = intern(Type.SHORT_CLASS);
+
+ /** {@code non-null;} instance corresponding to the class {@code Void} */
+ public static final CstType VOID = intern(Type.VOID_CLASS);
+
+ /** {@code non-null;} instance corresponding to the type {@code boolean[]} */
+ public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY);
+
+ /** {@code non-null;} instance corresponding to the type {@code byte[]} */
+ public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY);
+
+ /** {@code non-null;} instance corresponding to the type {@code char[]} */
+ public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY);
+
+ /** {@code non-null;} instance corresponding to the type {@code double[]} */
+ public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY);
+
+ /** {@code non-null;} instance corresponding to the type {@code float[]} */
+ public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY);
+
+ /** {@code non-null;} instance corresponding to the type {@code long[]} */
+ public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY);
+
+ /** {@code non-null;} instance corresponding to the type {@code int[]} */
+ public static final CstType INT_ARRAY = intern(Type.INT_ARRAY);
+
+ /** {@code non-null;} instance corresponding to the type {@code short[]} */
+ public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY);
+
+ /** {@code non-null;} the underlying type */
+ private final Type type;
+
+ /**
+ * {@code null-ok;} the type descriptor corresponding to this instance, if
+ * calculated
+ */
+ private CstUtf8 descriptor;
+
+ /**
+ * Returns an instance of this class that represents the wrapper
+ * class corresponding to a given primitive type. For example, if
+ * given {@link Type#INT}, this method returns the class reference
+ * {@code java.lang.Integer}.
+ *
+ * @param primitiveType {@code non-null;} the primitive type
+ * @return {@code non-null;} the corresponding wrapper class
+ */
+ public static CstType forBoxedPrimitiveType(Type primitiveType) {
+ switch (primitiveType.getBasicType()) {
+ case Type.BT_BOOLEAN: return BOOLEAN;
+ case Type.BT_BYTE: return BYTE;
+ case Type.BT_CHAR: return CHARACTER;
+ case Type.BT_DOUBLE: return DOUBLE;
+ case Type.BT_FLOAT: return FLOAT;
+ case Type.BT_INT: return INTEGER;
+ case Type.BT_LONG: return LONG;
+ case Type.BT_SHORT: return SHORT;
+ case Type.BT_VOID: return VOID;
+ }
+
+ throw new IllegalArgumentException("not primitive: " + primitiveType);
+ }
+
+ /**
+ * Returns an interned instance of this class for the given type.
+ *
+ * @param type {@code non-null;} the underlying type
+ * @return {@code non-null;} an appropriately-constructed instance
+ */
+ public static CstType intern(Type type) {
+ CstType cst = interns.get(type);
+
+ if (cst == null) {
+ cst = new CstType(type);
+ interns.put(type, cst);
+ }
+
+ return cst;
+ }
+
+ /**
+ * Constructs an instance.
+ *
+ * @param type {@code non-null;} the underlying type
+ */
+ public CstType(Type type) {
+ if (type == null) {
+ throw new NullPointerException("type == null");
+ }
+
+ if (type == type.KNOWN_NULL) {
+ throw new UnsupportedOperationException(
+ "KNOWN_NULL is not representable");
+ }
+
+ this.type = type;
+ this.descriptor = null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CstType)) {
+ return false;
+ }
+
+ return type == ((CstType) other).type;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return type.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected int compareTo0(Constant other) {
+ String thisDescriptor = type.getDescriptor();
+ String otherDescriptor = ((CstType) other).type.getDescriptor();
+ return thisDescriptor.compareTo(otherDescriptor);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return "type{" + toHuman() + '}';
+ }
+
+ /** {@inheritDoc} */
+ public Type getType() {
+ return Type.CLASS;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String typeName() {
+ return "type";
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isCategory2() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public String toHuman() {
+ return type.toHuman();
+ }
+
+ /**
+ * Gets the underlying type (as opposed to the type corresponding
+ * to this instance as a constant, which is always
+ * {@code Class}).
+ *
+ * @return {@code non-null;} the type corresponding to the name
+ */
+ public Type getClassType() {
+ return type;
+ }
+
+ /**
+ * Gets the type descriptor for this instance.
+ *
+ * @return {@code non-null;} the descriptor
+ */
+ public CstUtf8 getDescriptor() {
+ if (descriptor == null) {
+ descriptor = new CstUtf8(type.getDescriptor());
+ }
+
+ return descriptor;
+ }
+}