summaryrefslogtreecommitdiffstats
path: root/dx/src/com/android/dx/rop/cst/CstType.java
blob: 8624028aa2d0d77e96ae66589d855accfc86453f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/*
 * 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.dx.rop.cst;

import com.android.dx.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 CstString 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) {
        synchronized (interns) {
            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 CstString getDescriptor() {
        if (descriptor == null) {
            descriptor = new CstString(type.getDescriptor());
        }

        return descriptor;
    }
}