KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jode > type > ClassInterfacesType


1 /* ClassInterfacesType Copyright (C) 1998-2002 Jochen Hoenicke.
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; see the file COPYING. If not, write to
15  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
16  *
17  * $Id: ClassInterfacesType.java,v 4.28.2.3 2002/05/28 17:34:21 hoenicke Exp $
18  */

19
20 package jode.type;
21 import jode.bytecode.ClassInfo;
22 import java.util.Vector JavaDoc;
23 import java.util.Stack JavaDoc;
24 import java.util.Hashtable JavaDoc;
25
26 /**
27  * This class represents a type aproximation, consisting of multiple
28  * interfaces and a class type.<p>
29  *
30  * If this is the bottom boundary, this specifies, which class our
31  * type must extend and which interfaces it must implement.
32  *
33  * If this is the top boundary, this gives all interfaces and classes
34  * that may extend the type. I.e. at least one interface or class extends
35  * the searched type.
36  *
37  * @author Jochen Hoenicke */

38 public class ClassInterfacesType extends ReferenceType {
39
40     ClassInfo clazz;
41     ClassInfo ifaces[];
42
43     public ClassInfo getClazz() {
44         return clazz != null ? clazz : ClassInfo.javaLangObject;
45     }
46
47     public ClassInterfacesType(String JavaDoc clazzName) {
48         super(TC_CLASS);
49         ClassInfo clazz = ClassInfo.forName(clazzName);
50         if (clazz.isInterface()) {
51             this.clazz = null;
52             ifaces = new ClassInfo[] {clazz};
53         } else {
54             this.clazz =
55                 (clazz == ClassInfo.javaLangObject) ? null : clazz;
56             ifaces = new ClassInfo[0];
57         }
58     }
59
60     public ClassInterfacesType(ClassInfo clazz) {
61         super(TC_CLASS);
62         if (clazz.isInterface()) {
63             this.clazz = null;
64             ifaces = new ClassInfo[] { clazz };
65         } else {
66             this.clazz =
67                 (clazz == ClassInfo.javaLangObject) ? null : clazz;
68             ifaces = new ClassInfo[0];
69         }
70     }
71
72     public ClassInterfacesType(ClassInfo clazz, ClassInfo[] ifaces) {
73         super(TC_CLASS);
74         this.clazz = clazz;
75         this.ifaces = ifaces;
76     }
77
78     static ClassInterfacesType create(ClassInfo clazz, ClassInfo[] ifaces) {
79         /* Make sure that every {java.lang.Object} equals tObject */
80         if (ifaces.length == 0 && clazz == null)
81             return tObject;
82     if (ifaces.length == 0)
83         return tClass(clazz);
84     if (ifaces.length == 1 && clazz == null)
85         return tClass(ifaces[0]);
86         return new ClassInterfacesType(clazz, ifaces);
87     }
88
89     public Type getSubType() {
90     if ((clazz == null && ifaces.length == 1)
91         || ifaces.length == 0)
92         return tRange(this, tNull);
93     
94     /* We don't implement the set of types, that are castable to some
95      * of the given classes or interfaces.
96      */

97     throw new jode.AssertError
98         ("getSubType called on set of classes and interfaces!");
99     }
100
101     public Type getHint() {
102     if (ifaces.length == 0
103         || (clazz == null && ifaces.length == 1))
104         return this;
105     if (clazz != null)
106         return Type.tClass(clazz.getName());
107     else
108         return Type.tClass(ifaces[0].getName());
109     }
110
111     public Type getCanonic() {
112     if (ifaces.length == 0
113         || (clazz == null && ifaces.length == 1))
114         return this;
115     if (clazz != null)
116         return Type.tClass(clazz.getName());
117     else
118         return Type.tClass(ifaces[0].getName());
119     }
120
121     /**
122      * Create the type corresponding to the range from bottomType to
123      * this. Checks if the given type range may be not empty. This
124      * means, that bottom.clazz is extended by this.clazz and that all
125      * interfaces in bottom are implemented by an interface or by
126      * clazz.
127      * @param bottom the start point of the range
128      * @return the range type, or tError if range is empty.
129      */

130     public Type createRangeType(ReferenceType bottomType) {
131         if (bottomType.typecode != TC_CLASS)
132             return tError;
133
134     ClassInterfacesType bottom = (ClassInterfacesType) bottomType;
135
136         if (bottomType == tObject)
137             return (this == tObject) ? tObject : tRange(tObject, this);
138         
139         if (bottom.clazz != null) {
140             /* The searched type must be a class type.
141              */

142             if (!bottom.clazz.superClassOf(this.clazz))
143                 return tError;
144             
145             /* All interfaces must be implemented by this.clazz
146              */

147             for (int i=0; i < bottom.ifaces.length; i++) {
148                 if (!bottom.ifaces[i].implementedBy(this.clazz))
149                     return tError;
150             }
151
152             if (bottom.clazz == this.clazz
153                 && bottom.ifaces.length == 0)
154                 return bottom;
155
156         if (this.ifaces.length != 0)
157         return tRange(bottom, create(this.clazz, new ClassInfo[0]));
158             return tRange(bottom, this);
159             
160         } else {
161             
162             /* Now bottom.clazz is null (or tObject), find all
163              * classes/interfaces that implement all bottom.ifaces.
164              */

165
166             ClassInfo clazz = this.clazz;
167             if (clazz != null) {
168                 for (int i=0; i < bottom.ifaces.length; i++) {
169                     if (!bottom.ifaces[i].implementedBy(clazz)) {
170                         clazz = null;
171                         break;
172                     }
173                 }
174             }
175
176             /* If bottom is a single interface and equals some top
177              * interface, then bottom is the only possible type.
178              */

179             if (clazz == null && bottom.ifaces.length == 1) {
180                 for (int i=0; i< this.ifaces.length; i++) {
181                     if (this.ifaces[i] == bottom.ifaces[0])
182                         return bottom;
183                 }
184             }
185
186             ClassInfo[] ifaces = new ClassInfo[this.ifaces.length];
187             int count = 0;
188         big_loop:
189             for (int j=0; j < this.ifaces.length; j++) {
190                 for (int i=0; i < bottom.ifaces.length; i++) {
191                     if (!bottom.ifaces[i].implementedBy(this.ifaces[j]))
192                         continue big_loop;
193                 }
194                 ifaces[count++] = (this.ifaces[j]);
195             }
196
197         if (clazz == null && count == 0) {
198         /* There are no more possible interfaces or classes left.
199          * This is a type error.
200          */

201         return tError;
202         } else if (count < ifaces.length) {
203                 ClassInfo[] shortIfaces = new ClassInfo[count];
204                 System.arraycopy(ifaces, 0, shortIfaces, 0, count);
205                 ifaces = shortIfaces;
206             } else if (clazz == this.clazz)
207                 return tRange(bottom, this);
208             return tRange(bottom, create(clazz, ifaces));
209         }
210     }
211     
212     /**
213      * Returns the specialized type of this and type.
214      * We have two classes and multiple interfaces. The result
215      * should be the object that extends both objects
216      * and the union of all interfaces.
217      */

218     public Type getSpecializedType(Type type) {
219         int code = type.typecode;
220     if (code == TC_RANGE) {
221         type = ((RangeType) type).getBottom();
222         code = type.typecode;
223     }
224     if (code == TC_NULL)
225         return this;
226         if (code == TC_ARRAY)
227         return ((ArrayType) type).getSpecializedType(this);
228         if (code != TC_CLASS)
229             return tError;
230
231         ClassInterfacesType other = (ClassInterfacesType) type;
232         ClassInfo clazz;
233
234         /* First determine the clazz, one of the two classes must be a sub
235          * class of the other or null.
236          */

237
238         if (this.clazz == null)
239             clazz = other.clazz;
240         else if (other.clazz == null)
241             clazz = this.clazz;
242         else if (this.clazz.superClassOf(other.clazz))
243             clazz = other.clazz;
244         else if (other.clazz.superClassOf(this.clazz))
245             clazz = this.clazz;
246         else
247             return tError;
248
249         /* Most times (99.9999999 %) one of the two classes is already
250          * more specialized. Optimize for this case. (I know of one
251          * class where at one intersection this doesn't succeed)
252      */

253         if (clazz == this.clazz
254             && implementsAllIfaces(this.clazz, this.ifaces, other.ifaces))
255             return this;
256         else if (clazz == other.clazz
257                  && implementsAllIfaces(other.clazz, other.ifaces,
258                     this.ifaces))
259             return other;
260
261         /* The interfaces are simply the union of both interfaces set.
262          * But we can simplify this, if an interface is implemented by
263          * another or by the class, we can omit it.
264          */

265         Vector JavaDoc ifaces = new Vector JavaDoc();
266     big_loop_this:
267         for (int i=0; i< this.ifaces.length; i++) {
268             ClassInfo iface = this.ifaces[i];
269             if (clazz != null && iface.implementedBy(clazz)) {
270                 continue big_loop_this;
271             }
272             for (int j=0; j<other.ifaces.length; j++) {
273                 if (iface.implementedBy(other.ifaces[j])) {
274                     continue big_loop_this;
275                 }
276             }
277
278             /* This interface is not implemented by any of the other
279              * ifaces. Add it to the interfaces vector.
280              */

281             ifaces.addElement(iface);
282         }
283     big_loop_other:
284         for (int i=0; i< other.ifaces.length; i++) {
285             ClassInfo iface = other.ifaces[i];
286             if (clazz != null && iface.implementedBy(clazz)) {
287                 continue big_loop_other;
288             }
289             for (int j=0; j<ifaces.size(); j++) {
290                 if (iface.implementedBy((ClassInfo)
291                                         ifaces.elementAt(j))) {
292                     continue big_loop_other;
293                 }
294             }
295
296             /* This interface is not implemented by any of the other
297              * ifaces. Add it to the interfaces vector.
298              */

299             ifaces.addElement(iface);
300         }
301             
302         ClassInfo[] ifaceArray = new ClassInfo[ifaces.size()];
303         ifaces.copyInto(ifaceArray);
304         return create(clazz, ifaceArray);
305     }
306
307     /**
308      * Returns the generalized type of this and type. We have two
309      * classes and multiple interfaces. The result should be the
310      * object that is the the super class of both objects and all
311      * interfaces, that one class or interface of each type
312      * implements. */

313     public Type getGeneralizedType(Type type) {
314         int code = type.typecode;
315     if (code == TC_RANGE) {
316         type = ((RangeType) type).getTop();
317         code = type.typecode;
318     }
319         if (code == TC_NULL)
320             return this;
321     if (code == TC_ARRAY)
322         return ((ArrayType) type).getGeneralizedType(this);
323         if (code != TC_CLASS)
324             return tError;
325         ClassInterfacesType other = (ClassInterfacesType) type;
326         ClassInfo clazz;
327
328         /* First the easy part, determine the clazz */
329         if (this.clazz == null || other.clazz == null)
330             clazz = null;
331         else {
332             clazz = this.clazz;
333                 
334             while(clazz != null) {
335                 if (clazz.superClassOf(other.clazz))
336                     break;
337                 clazz = clazz.getSuperclass();
338             }
339             if (clazz == ClassInfo.javaLangObject)
340                 clazz = null;
341         }
342
343         if (clazz == this.clazz
344             && implementsAllIfaces(other.clazz, other.ifaces, this.ifaces))
345             return this;
346         else if (clazz == other.clazz
347                  && implementsAllIfaces(this.clazz, this.ifaces, other.ifaces))
348             return other;
349
350         /* Now the more complicated part: find all interfaces, that are
351          * implemented by one interface or class in each group.
352          *
353          * First get all interfaces of this.clazz and this.ifaces.
354          */

355             
356         Stack JavaDoc allIfaces = new Stack JavaDoc();
357         if (this.clazz != null) {
358             ClassInfo c = this.clazz;
359             while (clazz != c) {
360                 ClassInfo clazzIfaces[] = c.getInterfaces();
361                 for (int i=0; i<clazzIfaces.length; i++)
362                     allIfaces.push(clazzIfaces[i]);
363                 c = c.getSuperclass();
364             }
365         }
366
367         Vector JavaDoc ifaces = new Vector JavaDoc();
368
369         for (int i=0; i<this.ifaces.length; i++)
370             allIfaces.push(this.ifaces[i]);
371             
372             /* Now consider each interface. If any clazz or interface
373              * in other implements it, add it to the ifaces vector.
374              * Otherwise consider all sub interfaces.
375              */

376     iface_loop:
377         while (!allIfaces.isEmpty()) {
378             ClassInfo iface = (ClassInfo) allIfaces.pop();
379             if ((clazz != null && iface.implementedBy(clazz))
380                 || ifaces.contains(iface))
381                 /* We can skip this, as clazz or ifaces already imply it.
382                  */

383                 continue iface_loop;
384
385             if (other.clazz != null && iface.implementedBy(other.clazz)) {
386                 ifaces.addElement(iface);
387                 continue iface_loop;
388             }
389             for (int i=0; i<other.ifaces.length; i++) {
390                 if (iface.implementedBy(other.ifaces[i])) {
391                     ifaces.addElement(iface);
392                     continue iface_loop;
393                 }
394             }
395
396             /* This interface is not implemented by any of the other
397              * ifaces. Try its parent interfaces now.
398              */

399             ClassInfo clazzIfaces[] = iface.getInterfaces();
400             for (int i=0; i<clazzIfaces.length; i++)
401                 allIfaces.push(clazzIfaces[i]);
402         }
403                 
404         ClassInfo[] ifaceArray = new ClassInfo[ifaces.size()];
405         ifaces.copyInto(ifaceArray);
406         return create(clazz, ifaceArray);
407     }
408
409     public String JavaDoc getTypeSignature() {
410     if (clazz != null)
411         return "L" + clazz.getName().replace('.','/') + ";";
412     else if (ifaces.length > 0)
413         return "L" + ifaces[0].getName().replace('.','/') + ";";
414     else
415         return "Ljava/lang/Object;";
416     }
417
418     public Class JavaDoc getTypeClass() throws ClassNotFoundException JavaDoc {
419     if (clazz != null)
420         return Class.forName(clazz.getName());
421     else if (ifaces.length > 0)
422         return Class.forName(ifaces[0].getName());
423     else
424         return Class.forName("java.lang.Object");
425     }
426
427     public ClassInfo getClassInfo() {
428     if (clazz != null)
429         return clazz;
430     else if (ifaces.length > 0)
431         return ifaces[0];
432     else
433         return ClassInfo.javaLangObject;
434     }
435
436     public String JavaDoc toString()
437     {
438     if (this == tObject)
439         return "java.lang.Object";
440     
441     if (ifaces.length == 0)
442         return clazz.getName();
443     if (clazz == null && ifaces.length == 1)
444         return ifaces[0].getName();
445
446     StringBuffer JavaDoc sb = new StringBuffer JavaDoc("{");
447     String JavaDoc comma = "";
448     if (clazz != null) {
449         sb = sb.append(clazz.getName());
450                 comma = ", ";
451     }
452     for (int i=0; i< ifaces.length; i++) {
453         sb.append(comma).append(ifaces[i].getName());
454         comma = ", ";
455     }
456     return sb.append("}").toString();
457     }
458
459     /**
460      * Checks if we need to cast to a middle type, before we can cast from
461      * fromType to this type.
462      * @return the middle type, or null if it is not necessary.
463      */

464     public Type getCastHelper(Type fromType) {
465     Type hintType = fromType.getHint();
466     switch (hintType.getTypeCode()) {
467     case TC_ARRAY:
468         if (clazz == null
469         && implementsAllIfaces(null, ArrayType.arrayIfaces,
470                        this.ifaces))
471         return null;
472         else
473         return tObject;
474     case TC_CLASS:
475         ClassInterfacesType hint = (ClassInterfacesType) hintType;
476         if (hint.clazz == null || clazz == null
477         || clazz.superClassOf(hint.clazz)
478         || hint.clazz.superClassOf(clazz))
479         return null;
480         ClassInfo superClazz = clazz.getSuperclass();
481         while (superClazz != null
482            && !superClazz.superClassOf(hint.clazz)) {
483         superClazz = superClazz.getSuperclass();
484         }
485         return tClass(superClazz.getName());
486     case TC_UNKNOWN:
487         return null;
488     }
489     return tObject;
490     }
491
492     /**
493      * Checks if this type represents a valid type instead of a list
494      * of minimum types.
495      */

496     public boolean isValidType() {
497     return ifaces.length == 0
498         || (clazz == null && ifaces.length == 1);
499     }
500
501     /**
502      * Checks if this is a class or array type (but not a null type).
503      * @XXX remove this?
504      * @return true if this is a class or array type.
505      */

506     public boolean isClassType() {
507         return true;
508     }
509
510     private final static Hashtable JavaDoc keywords = new Hashtable JavaDoc();
511     static {
512     keywords.put("abstract", Boolean.TRUE);
513     keywords.put("default", Boolean.TRUE);
514     keywords.put("if", Boolean.TRUE);
515     keywords.put("private", Boolean.TRUE);
516     keywords.put("throw", Boolean.TRUE);
517     keywords.put("boolean", Boolean.TRUE);
518     keywords.put("do", Boolean.TRUE);
519     keywords.put("implements", Boolean.TRUE);
520     keywords.put("protected", Boolean.TRUE);
521     keywords.put("throws", Boolean.TRUE);
522     keywords.put("break", Boolean.TRUE);
523     keywords.put("double", Boolean.TRUE);
524     keywords.put("import", Boolean.TRUE);
525     keywords.put("public", Boolean.TRUE);
526     keywords.put("transient", Boolean.TRUE);
527     keywords.put("byte", Boolean.TRUE);
528     keywords.put("else", Boolean.TRUE);
529     keywords.put("instanceof", Boolean.TRUE);
530     keywords.put("return", Boolean.TRUE);
531     keywords.put("try", Boolean.TRUE);
532     keywords.put("case", Boolean.TRUE);
533     keywords.put("extends", Boolean.TRUE);
534     keywords.put("int", Boolean.TRUE);
535     keywords.put("short", Boolean.TRUE);
536     keywords.put("void", Boolean.TRUE);
537     keywords.put("catch", Boolean.TRUE);
538     keywords.put("final", Boolean.TRUE);
539     keywords.put("interface", Boolean.TRUE);
540     keywords.put("static", Boolean.TRUE);
541     keywords.put("volatile", Boolean.TRUE);
542     keywords.put("char", Boolean.TRUE);
543     keywords.put("finally", Boolean.TRUE);
544     keywords.put("long", Boolean.TRUE);
545     keywords.put("super", Boolean.TRUE);
546     keywords.put("while", Boolean.TRUE);
547     keywords.put("class", Boolean.TRUE);
548     keywords.put("float", Boolean.TRUE);
549     keywords.put("native", Boolean.TRUE);
550     keywords.put("switch", Boolean.TRUE);
551     keywords.put("const", Boolean.TRUE);
552     keywords.put("for", Boolean.TRUE);
553     keywords.put("new", Boolean.TRUE);
554     keywords.put("synchronized", Boolean.TRUE);
555     keywords.put("continue", Boolean.TRUE);
556     keywords.put("goto", Boolean.TRUE);
557     keywords.put("package", Boolean.TRUE);
558     keywords.put("this", Boolean.TRUE);
559     keywords.put("strictfp", Boolean.TRUE);
560     keywords.put("null", Boolean.TRUE);
561     keywords.put("true", Boolean.TRUE);
562     keywords.put("false", Boolean.TRUE);
563     }
564
565     /**
566      * Generates the default name, that is the `natural' choice for
567      * local of this type.
568      * @return the default name of a local of this type.
569      */

570     public String JavaDoc getDefaultName() {
571         ClassInfo type;
572         if (clazz != null)
573             type = clazz;
574         else if (ifaces.length > 0)
575             type = ifaces[0];
576         else
577             type = ClassInfo.javaLangObject;
578         String JavaDoc name = type.getName();
579         int dot = Math.max(name.lastIndexOf('.'), name.lastIndexOf('$'));
580         if (dot >= 0)
581             name = name.substring(dot+1);
582         if (Character.isUpperCase(name.charAt(0))) {
583         name = name.toLowerCase();
584         if (keywords.get(name) != null)
585         return "var_" + name;
586             return name;
587         } else
588             return "var_" + name;
589     }
590     
591     public int hashCode() {
592     int hash = clazz == null ? 0 : clazz.hashCode();
593     for (int i=0; i < ifaces.length; i++) {
594         hash ^= ifaces[i].hashCode();
595     }
596     return hash;
597     }
598
599     public boolean equals(Object JavaDoc o) {
600         if (o == this)
601             return true;
602         if (o instanceof Type && ((Type)o).typecode == TC_CLASS) {
603             ClassInterfacesType type = (ClassInterfacesType) o;
604             if (type.clazz == clazz
605                 && type.ifaces.length == ifaces.length) {
606                 big_loop:
607                 for (int i=0; i< type.ifaces.length; i++) {
608                     for (int j=0; j<ifaces.length; j++) {
609                         if (type.ifaces[i] == ifaces[j])
610                             continue big_loop;
611                     }
612                     return false;
613                 }
614                 return true;
615             }
616         }
617         return false;
618     }
619 }
620
Popular Tags