001: /* ArrayType Copyright (C) 1998-2002 Jochen Hoenicke.
002: *
003: * This program is free software; you can redistribute it and/or modify
004: * it under the terms of the GNU General Public License as published by
005: * the Free Software Foundation; either version 2, or (at your option)
006: * any later version.
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU General Public License for more details.
012: *
013: * You should have received a copy of the GNU General Public License
014: * along with this program; see the file COPYING. If not, write to
015: * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
016: *
017: * $Id: ArrayType.java,v 4.19.2.3 2002/05/28 17:34:21 hoenicke Exp $
018: */
019:
020: package jode.type;
021:
022: import jode.bytecode.ClassInfo;
023: import java.util.Vector;
024:
025: /**
026: * This type represents an array type.
027: *
028: * @author Jochen Hoenicke
029: */
030: public class ArrayType extends ReferenceType {
031: // The interfaces that an array implements:
032: final static ClassInfo[] arrayIfaces = {
033: // Make sure to list all interfaces, even if some interface
034: // implements another (or change code in getGeneralizedType().
035: ClassInfo.forName("java.lang.Cloneable"),
036: ClassInfo.forName("java.io.Serializable") };
037:
038: Type elementType;
039:
040: ArrayType(Type elementType) {
041: super (TC_ARRAY);
042: this .elementType = elementType;
043: }
044:
045: public Type getElementType() {
046: return elementType;
047: }
048:
049: public Type getSuperType() {
050: if (elementType instanceof IntegerType)
051: return tRange(tObject, this );
052: else
053: return tRange(tObject, (ReferenceType) tArray(elementType
054: .getSuperType()));
055: }
056:
057: public Type getSubType() {
058: if (elementType instanceof IntegerType)
059: return this ;
060: else
061: return tArray(elementType.getSubType());
062: }
063:
064: public Type getHint() {
065: return tArray(elementType.getHint());
066: }
067:
068: public Type getCanonic() {
069: return tArray(elementType.getCanonic());
070: }
071:
072: /**
073: * Create the type corresponding to the range from bottomType to this.
074: * @param bottomType the start point of the range
075: * @return the range type, or tError if not possible.
076: */
077: public Type createRangeType(ReferenceType bottom) {
078: /*
079: * tArray(y), tArray(x) -> tArray( y.intersection(x) )
080: * obj , tArray(x) -> <obj, tArray(x)>
081: * iff tArray extends and implements obj
082: */
083: if (bottom.getTypeCode() == TC_ARRAY)
084: return tArray(elementType
085: .intersection(((ArrayType) bottom).elementType));
086:
087: if (bottom.getTypeCode() == TC_CLASS) {
088: ClassInterfacesType bottomCIT = (ClassInterfacesType) bottom;
089: if (bottomCIT.clazz == null
090: && implements AllIfaces(null, arrayIfaces,
091: bottomCIT.ifaces))
092: return tRange(bottomCIT, this );
093: }
094: return tError;
095: }
096:
097: /**
098: * Returns the common sub type of this and type.
099: * @param type the other type.
100: * @return the common sub type.
101: */
102: public Type getSpecializedType(Type type) {
103: /*
104: * tArray(x), iface -> tArray(x) iff tArray implements iface
105: * tArray(x), tArray(y) -> tArray(x.intersection(y))
106: * tArray(x), other -> tError
107: */
108: if (type.getTypeCode() == TC_RANGE) {
109: type = ((RangeType) type).getBottom();
110: }
111: if (type == tNull)
112: return this ;
113: if (type.getTypeCode() == TC_ARRAY) {
114: Type elType = elementType
115: .intersection(((ArrayType) type).elementType);
116: return elType != tError ? tArray(elType) : tError;
117: }
118: if (type.getTypeCode() == TC_CLASS) {
119: ClassInterfacesType other = (ClassInterfacesType) type;
120: if (other.clazz == null
121: && implements AllIfaces(null, arrayIfaces,
122: other.ifaces))
123: return this ;
124: }
125: return tError;
126: }
127:
128: /**
129: * Returns the common super type of this and type.
130: * @param type the other type.
131: * @return the common super type.
132: */
133: public Type getGeneralizedType(Type type) {
134: /* tArray(x), tNull -> tArray(x)
135: * tArray(x), tClass(y) -> common ifaces of tArray and tClass
136: * tArray(x), tArray(y) -> tArray(x.intersection(y)) or tObject
137: * tArray(x), other -> tError
138: */
139: if (type.getTypeCode() == TC_RANGE) {
140: type = ((RangeType) type).getTop();
141: }
142: if (type == tNull)
143: return this ;
144: if (type.getTypeCode() == TC_ARRAY) {
145: Type elType = elementType
146: .intersection(((ArrayType) type).elementType);
147: if (elType != tError)
148: return tArray(elType);
149: return ClassInterfacesType.create(null, arrayIfaces);
150: }
151: if (type.getTypeCode() == TC_CLASS) {
152: ClassInterfacesType other = (ClassInterfacesType) type;
153: if (implements AllIfaces(other.clazz, other.ifaces,
154: arrayIfaces))
155: return ClassInterfacesType.create(null, arrayIfaces);
156: if (other.clazz == null
157: && implements AllIfaces(null, arrayIfaces,
158: other.ifaces))
159: return other;
160:
161: /* Now the more complicated part: find all interfaces, that are
162: * implemented by one interface or class in each group.
163: *
164: * First get all interfaces of this.clazz and this.ifaces.
165: */
166: Vector newIfaces = new Vector();
167: iface_loop: for (int i = 0; i < arrayIfaces.length; i++) {
168: /* Now consider each array interface. If any clazz or
169: * interface in other implements it, add it to the
170: * newIfaces vector. */
171: if (other.clazz != null
172: && arrayIfaces[i].implementedBy(other.clazz)) {
173: newIfaces.addElement(arrayIfaces[i]);
174: continue iface_loop;
175: }
176: for (int j = 0; j < other.ifaces.length; j++) {
177: if (arrayIfaces[i].implementedBy(other.ifaces[j])) {
178: newIfaces.addElement(arrayIfaces[i]);
179: continue iface_loop;
180: }
181: }
182: }
183: ClassInfo[] ifaceArray = new ClassInfo[newIfaces.size()];
184: newIfaces.copyInto(ifaceArray);
185: return ClassInterfacesType.create(null, ifaceArray);
186: }
187: return tError;
188: }
189:
190: /**
191: * Checks if we need to cast to a middle type, before we can cast from
192: * fromType to this type.
193: * @return the middle type, or null if it is not necessary.
194: */
195: public Type getCastHelper(Type fromType) {
196: Type hintType = fromType.getHint();
197: switch (hintType.getTypeCode()) {
198: case TC_ARRAY:
199: if (!elementType.isClassType()
200: || !((ArrayType) hintType).elementType
201: .isClassType())
202: return tObject;
203: Type middleType = elementType
204: .getCastHelper(((ArrayType) hintType).elementType);
205: if (middleType != null)
206: return tArray(middleType);
207: return null;
208: case TC_CLASS:
209: ClassInterfacesType hint = (ClassInterfacesType) hintType;
210: if (hint.clazz == null
211: && implements AllIfaces(null, arrayIfaces,
212: hint.ifaces))
213: return null;
214: return tObject;
215: case TC_UNKNOWN:
216: return null;
217: }
218: return tObject;
219: }
220:
221: /**
222: * Checks if this type represents a valid type instead of a list
223: * of minimum types.
224: */
225: public boolean isValidType() {
226: return elementType.isValidType();
227: }
228:
229: public boolean isClassType() {
230: return true;
231: }
232:
233: public String getTypeSignature() {
234: return "[" + elementType.getTypeSignature();
235: }
236:
237: public Class getTypeClass() throws ClassNotFoundException {
238: return Class.forName("[" + elementType.getTypeSignature());
239: }
240:
241: public String toString() {
242: return elementType.toString() + "[]";
243: }
244:
245: private static String pluralize(String singular) {
246: return singular
247: + ((singular.endsWith("s") || singular.endsWith("x")
248: || singular.endsWith("sh") || singular
249: .endsWith("ch")) ? "es" : "s");
250: }
251:
252: public String getDefaultName() {
253: if (elementType instanceof ArrayType)
254: return elementType.getDefaultName();
255: return pluralize(elementType.getDefaultName());
256: }
257:
258: public boolean equals(Object o) {
259: if (o == this )
260: return true;
261: if (o instanceof ArrayType) {
262: ArrayType type = (ArrayType) o;
263: return type.elementType.equals(elementType);
264: }
265: return false;
266: }
267: }
|