1 cananian 1.1.2.1 // ClassHierarchy.java, created Wed Sep  8 14:34:46 1999 by cananian
  2 cananian 1.1.2.1 // Copyright (C) 1999 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1 package harpoon.Analysis;
  5 cananian 1.1.2.1 
  6 cananian 1.1.2.1 import harpoon.ClassFile.HClass;
  7 cananian 1.1.2.4 import harpoon.ClassFile.HConstructor;
  8 cananian 1.1.2.4 import harpoon.ClassFile.HMethod;
  9 cananian 1.1.2.3 import harpoon.Util.ArraySet;
 10 cananian 1.5     import net.cscott.jutil.Default;
 11 cananian 1.1.2.3 import harpoon.Util.HClassUtil;
 12 cananian 1.1.2.5 import harpoon.Util.Util;
 13 cananian 1.5     import net.cscott.jutil.WorkSet;
 14 cananian 1.1.2.1 
 15 cananian 1.1.2.4 import java.lang.reflect.Modifier;
 16 cananian 1.1.2.3 import java.util.Collections;
 17 cananian 1.1.2.4 import java.util.Iterator;
 18 cananian 1.1.2.1 import java.util.Set;
 19 cananian 1.1.2.1 /**
 20 cananian 1.1.2.1  * A <code>ClassHierarchy</code> enumerates reachable/usable classes
 21 cananian 1.1.2.1  * and methods.
 22 cananian 1.1.2.1  * 
 23 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 24 cananian 1.5      * @version $Id: ClassHierarchy.java,v 1.5 2004/02/08 01:49:03 cananian Exp $
 25 cananian 1.1.2.1  */
 26 cananian 1.1.2.1 public abstract class ClassHierarchy {
 27 cananian 1.1.2.1     // tree of callable classes
 28 cananian 1.1.2.1     /** Returns all usable/reachable children of an <code>HClass</code>.
 29 cananian 1.1.2.3      *  For an interface class <code>c</code>, the children include all
 30 cananian 1.1.2.3      *  reachable classes which implement it as well as any reachable
 31 cananian 1.1.2.3      *  interfaces which extend it.  For a non-interface class, children
 32 cananian 1.1.2.3      *  are all reachable subclasses.
 33 cananian 1.1.2.1      *  @return <code>Set</code> of <code>HClass</code>es.
 34 cananian 1.1.2.1      */
 35 cananian 1.3.2.2     public abstract Set<HClass> children(HClass c);
 36 cananian 1.1.2.3     /** Return the parents of an <code>HClass</code>.
 37 cananian 1.1.2.3      *  The parents of a class <code>c</code> are its superclass and 
 38 cananian 1.1.2.3      *  interfaces.  The results should be complementary to the 
 39 cananian 1.1.2.3      *  <code>children()</code> method:
 40 cananian 1.1.2.3      *  <code>parent(c)</code> of any class <code>c</code> returned
 41 cananian 1.1.2.3      *  by <code>children(cc)</code> should include <code>cc</code>.
 42 cananian 1.1.2.3      */
 43 cananian 1.3.2.2     public final Set<HClass> parents(HClass c) {
 44 cananian 1.1.2.5         // odd inheritance properties:
 45 cananian 1.1.2.5         //  interfaces: all instances of an interface are also instances of
 46 cananian 1.1.2.5         //              java.lang.Object, so root all interfaces there.
 47 cananian 1.1.2.5         //  arrays: Integer[][]->Number[][]->Object[][]->Object[]->Object
 48 cananian 1.1.2.5         //      but also Set[][]->Collection[][]->Object[][]->Object[]->Object
 49 cananian 1.1.2.5         //      (i.e. interfaces are just as rooted here)
 50 cananian 1.1.2.5         // note every use of c.getLinker() below is safe because c is
 51 cananian 1.1.2.5         // guaranteed non-primitive in every context.
 52 cananian 1.1.2.5         HClass base = HClassUtil.baseClass(c); int dims=HClassUtil.dims(c);
 53 cananian 1.1.2.5         HClass su = base.getSuperclass();
 54 cananian 1.1.2.5         HClass[] interfaces = base.getInterfaces();
 55 cananian 1.1.2.5         boolean isObjArray = c.getDescriptor().endsWith("[Ljava/lang/Object;");
 56 cananian 1.1.2.6         boolean isPrimArray = c.isArray() && base.isPrimitive();
 57 cananian 1.1.2.5         // root interface inheritance hierarchy at Object.
 58 cananian 1.1.2.5         if (interfaces.length==0 && base.isInterface())
 59 cananian 1.1.2.5             su = c.getLinker().forName("java.lang.Object");// c not prim.
 60 cananian 1.1.2.5         // create return value array.
 61 cananian 1.1.2.5         HClass[] parents = new HClass[interfaces.length +
 62 cananian 1.1.2.6                                       ((su!=null || isObjArray || isPrimArray)
 63 cananian 1.1.2.6                                        ? 1 : 0)];
 64 cananian 1.1.2.5         int n=0;
 65 cananian 1.1.2.5         if (su!=null)
 66 cananian 1.1.2.5             parents[n++] = HClassUtil.arrayClass(c.getLinker(),//c not prim.
 67 cananian 1.1.2.5                                                  su, dims);
 68 cananian 1.1.2.5         for (int i=0; i<interfaces.length; i++)
 69 cananian 1.1.2.5             parents[n++] = HClassUtil.arrayClass(c.getLinker(),//c not prim.
 70 cananian 1.1.2.5                                                  interfaces[i], dims);
 71 cananian 1.1.2.5         // don't forget Object[][]->Object[]->Object
 72 cananian 1.1.2.5         // (but remember also Object[][]->Cloneable->Object)
 73 cananian 1.1.2.5         if (isObjArray)
 74 cananian 1.1.2.5             parents[n++] = HClassUtil.arrayClass(c.getLinker(), base, dims-1);
 75 cananian 1.1.2.6         // also!  int[] -> Object.
 76 cananian 1.1.2.6         if (isPrimArray) // c not prim.
 77 cananian 1.1.2.6             parents[n++] = c.getLinker().forName("java.lang.Object");
 78 cananian 1.1.2.5         // okay, done.  Did we size the array correctly?
 79 cananian 1.3.2.1         assert n==parents.length;
 80 cananian 1.1.2.5         // okay, return as Set.
 81 cananian 1.3.2.2         return new ArraySet<HClass>(parents);
 82 cananian 1.1.2.4     }
 83 cananian 1.1.2.4     /** Returns a set of methods in the hierarchy (not necessary reachable
 84 cananian 1.1.2.4      *  methods) which override the given method.  The set is only one
 85 cananian 1.1.2.4      *  level deep; invoke children() again on each member of the returned
 86 cananian 1.1.2.4      *  set to find the rest of the possible overriding methods.  Note
 87 cananian 1.1.2.4      *  however that interface methods may introduce some imprecision:
 88 cananian 1.1.2.4      *  in particular, for some hm2 in children(hm1) (where hm1 is an
 89 cananian 1.1.2.4      *  interface method), hm2.getDeclaringClass() may not implement
 90 cananian 1.1.2.4      *  hm1.getDeclaringClass().   For example, ListIterator.next() may
 91 cananian 1.1.2.4      *  be implemented by A, but B (a subclass of A which doesn't override
 92 cananian 1.1.2.4      *  A.next()) may be the class which implements ListIterator. */
 93 cananian 1.3.2.2     public final Set<HMethod> overrides(HMethod hm) {
 94 cananian 1.1.2.4         return overrides(hm.getDeclaringClass(), hm, false);
 95 cananian 1.1.2.4     }
 96 cananian 1.1.2.4     /** Returns the set of methods, excluding <code>hm</code>, declared
 97 cananian 1.1.2.4      *  in classes which are instances of <code>hc</code>, which override
 98 cananian 1.1.2.4      *  <code>hm</code>.  If <code>all</code> is true, returns all such
 99 cananian 1.1.2.4      *  methods in the class hierarchy; otherwise returns only the methods
100 cananian 1.1.2.4      *  which *immediately* override <code>hm</code>. */
101 cananian 1.3.2.2     public Set<HMethod> overrides(HClass hc, HMethod hm, boolean all) {
102 cananian 1.1.2.4         // non-virtual methods have no overrides.
103 cananian 1.1.2.4         if (hm.isStatic() || Modifier.isPrivate(hm.getModifiers()) ||
104 cananian 1.3.2.2             hm instanceof HConstructor) return Default.EMPTY_SET();
105 cananian 1.1.2.4         // determine overrides for virtual methods.
106 cananian 1.3.2.2         Set<HMethod> result = new WorkSet<HMethod>();
107 cananian 1.3.2.2         WorkSet<HClass> ws = new WorkSet<HClass>(this.children(hc));
108 cananian 1.1.2.4         while (!ws.isEmpty()) {
109 cananian 1.3.2.2             HClass hcc = ws.pop();
110 cananian 1.1.2.4             // note we don't catch MethodNotFoundError 'cuz we should find hm.
111 cananian 1.1.2.4             HMethod hmm = hcc.getMethod(hm.getName(), hm.getDescriptor());
112 cananian 1.1.2.4             if (!hm.equals(hmm)) {
113 cananian 1.1.2.4                 // this is an overriding method!
114 cananian 1.1.2.4                 result.add(hmm);
115 cananian 1.1.2.4                 if (all) result.addAll(overrides(hcc, hmm, all));
116 cananian 1.1.2.4             } else
117 cananian 1.1.2.4                 // keep looking for subclasses that declare method:
118 cananian 1.1.2.4                 // add all subclasses of this one to the worklist.
119 cananian 1.1.2.4                 ws.addAll(this.children(hcc));
120 cananian 1.1.2.4         }
121 cananian 1.1.2.4         return result;
122 cananian 1.1.2.3     }
123 cananian 1.1.2.1 
124 cananian 1.1.2.1     // other methods.
125 cananian 1.1.2.1     /** Returns set of all callable methods. 
126 cananian 1.1.2.1      *  @return <code>Set</code> of <code>HMethod</code>s.
127 cananian 1.1.2.1      */
128 cananian 1.3.2.2     public abstract Set<HMethod> callableMethods();
129 cananian 1.1.2.1     /** Returns the set of all reachable/usable classes.
130 cananian 1.1.2.2      *  If any method in a class is callable (including static methods),
131 cananian 1.1.2.2      *  then the class will be a member of the returned set.
132 cananian 1.1.2.1      *  @return <code>Set</code> of <code>HClass</code>es.
133 cananian 1.1.2.1      */
134 cananian 1.3.2.2     public abstract Set<HClass> classes();
135 cananian 1.1.2.2     /** Returns the set of all *instantiated* classes.
136 cananian 1.1.2.2      *  This is a subset of the set returned by the <code>classes()</code>
137 cananian 1.1.2.2      *  method.  A class is included in the return set only if an
138 cananian 1.1.2.2      *  object of that type is at some point created.
139 cananian 1.1.2.2      */
140 cananian 1.3.2.2     public abstract Set<HClass> instantiatedClasses();
141 cananian 1.2     }