View Javadoc

1   package serp.bytecode;
2   
3   import java.io.*;
4   import java.util.*;
5   
6   import serp.bytecode.visitor.*;
7   
8   /***
9    * Attribute describing all referenced classes that are not package
10   * members. This includes all member interfaces and classes.
11   *
12   * @author Abe White
13   */
14  public class InnerClasses extends Attribute {
15      private List _innerClasses = new LinkedList();
16  
17      InnerClasses(int nameIndex, Attributes owner) {
18          super(nameIndex, owner);
19      }
20  
21      /***
22       * Return all referenced inner classes, or empty array if none.
23       */
24      public InnerClass[] getInnerClasses() {
25          return (InnerClass[]) _innerClasses.toArray
26              (new InnerClass[_innerClasses.size()]);
27      }
28  
29      /***
30       * Return the inner class with the given name. If multiple inner classes
31       * share the name, which is returned is undefined. Use null to retrieve
32       * anonymous classes.
33       */
34      public InnerClass getInnerClass(String name) {
35          InnerClass[] inners = getInnerClasses();
36          String inner;
37          for (int i = 0; i < inners.length; i++) {
38              inner = inners[i].getName();
39              if ((inner == null && name == null) 
40                  || (inner != null && inner.equals(name)))
41                  return inners[i];
42          }
43          return null;
44      }
45  
46      /***
47       * Return all inner classes with the given name, or empty array if none.
48       * Use null to retrieve anonymous classes.
49       */
50      public InnerClass[] getInnerClasses(String name) {
51          List matches = new LinkedList();
52          InnerClass[] inners = getInnerClasses();
53          String inner;
54          for (int i = 0; i < inners.length; i++) {
55              inner = inners[i].getName();
56              if ((inner == null && name == null) 
57                  || (inner != null && inner.equals(name)))
58                  matches.add(inners[i]);
59          }
60          return (InnerClass[]) matches.toArray(new InnerClass[matches.size()]);
61      }
62  
63      /***
64       * Set the inner class references for this class. This method is
65       * useful when importing inner class references from another class.
66       */
67      public void setInnerClasses(InnerClass[] inners) {
68          clear();
69          if (inners != null)
70              for (int i = 0; i < inners.length; i++)
71                  addInnerClass(inners[i]);
72      }
73  
74      /***
75       * Import an inner class from another entity, or make a copy of one
76       * on this entity.
77       *
78       * @return the newly added inner class
79       */
80      public InnerClass addInnerClass(InnerClass inner) {
81          InnerClass newInner = addInnerClass(inner.getName(),
82              inner.getTypeName(), inner.getDeclarerName());
83          newInner.setAccessFlags(inner.getAccessFlags());
84          return newInner;
85      }
86  
87      /***
88       * Add an inner class.
89       */
90      public InnerClass addInnerClass() {
91          InnerClass inner = new InnerClass(this);
92          _innerClasses.add(inner);
93          return inner;
94      }
95  
96      /***
97       * Add an inner class.
98       *
99       * @param name the simple name of the class, or null if anonymous
100      * @param type the full class name of the inner class
101      * @param owner the declaring class, or null if not a member class
102      */
103     public InnerClass addInnerClass(String name, String type, String owner) {
104         InnerClass inner = addInnerClass();
105         inner.setName(name);
106         inner.setType(type);
107         inner.setDeclarer(owner);
108         return inner;
109     }
110 
111     /***
112      * Add an inner class.
113      *
114      * @param name the simple name of the class, or null if anonymous
115      * @param type the class of the inner class
116      * @param owner the declaring class, or null if not a member class
117      */
118     public InnerClass addInnerClass(String name, Class type, Class owner) {
119         String typeName = (type == null) ? null : type.getName();
120         String ownerName = (owner == null) ? null : owner.getName();
121         return addInnerClass(name, typeName, ownerName);
122     }
123 
124     /***
125      * Add an inner class.
126      *
127      * @param name the simple name of the class, or null if anonymous
128      * @param type the class of the inner class
129      * @param owner the declaring class, or null if not a member class
130      */
131     public InnerClass addInnerClass(String name, BCClass type, BCClass owner) {
132         String typeName = (type == null) ? null : type.getName();
133         String ownerName = (owner == null) ? null : owner.getName();
134         return addInnerClass(name, typeName, ownerName);
135     }
136 
137     /***
138      * Clear all inner classes from this entity.
139      */
140     public void clear() {
141         InnerClass inner;
142         for (Iterator itr = _innerClasses.iterator(); itr.hasNext();) {
143             inner = (InnerClass) itr.next();
144             itr.remove();
145             inner.invalidate();
146         }
147     }
148 
149     /***
150      * Remove the inner class with the given name. Use null for anonymous
151      * classes.
152      *
153      * @return true if an inner class was removed, false otherwise
154      */
155     public boolean removeInnerClass(String name) {
156         return removeInnerClass(getInnerClass(name));
157     }
158 
159     /***
160      * Remove the given inner class. After being removed, the given inner
161      * class is invalid, and the result of any operations on it are undefined.
162      *
163      * @return true if the inner class was removed, false otherwise
164      */
165     public boolean removeInnerClass(InnerClass innerClass) {
166         if (innerClass == null || !_innerClasses.remove(innerClass))
167             return false;
168         innerClass.invalidate();
169         return true;
170     }
171 
172     public void acceptVisit(BCVisitor visit) {
173         visit.enterInnerClasses(this);
174         InnerClass[] inners = getInnerClasses();
175         for (int i = 0; i < inners.length; i++)
176             inners[i].acceptVisit(visit);
177         visit.exitInnerClasses(this);
178     }
179 
180     int getLength() {
181         return 2 + (8 * _innerClasses.size());
182     }
183 
184     void read(Attribute other) {
185         setInnerClasses(((InnerClasses) other).getInnerClasses());
186     }
187 
188     void read(DataInput in, int length) throws IOException {
189         clear();
190         int numInnerClasses = in.readUnsignedShort();
191         InnerClass innerClass;
192         for (int i = 0; i < numInnerClasses; i++) {
193             innerClass = addInnerClass();
194             innerClass.read(in);
195         }
196     }
197 
198     void write(DataOutput out, int length) throws IOException {
199         InnerClass[] inners = getInnerClasses();
200         out.writeShort(inners.length);
201         for (int i = 0; i < inners.length; i++)
202             inners[i].write(out);
203     }
204 }