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 }