001 package serp.bytecode;
002
003 import java.io.*;
004 import java.util.*;
005
006 import serp.bytecode.visitor.*;
007
008 /**
009 * Attribute describing all referenced classes that are not package
010 * members. This includes all member interfaces and classes.
011 *
012 * @author Abe White
013 */
014 public class InnerClasses extends Attribute {
015 private List _innerClasses = new LinkedList();
016
017 InnerClasses(int nameIndex, Attributes owner) {
018 super(nameIndex, owner);
019 }
020
021 /**
022 * Return all referenced inner classes, or empty array if none.
023 */
024 public InnerClass[] getInnerClasses() {
025 return (InnerClass[]) _innerClasses.toArray
026 (new InnerClass[_innerClasses.size()]);
027 }
028
029 /**
030 * Return the inner class with the given name. If multiple inner classes
031 * share the name, which is returned is undefined. Use null to retrieve
032 * anonymous classes.
033 */
034 public InnerClass getInnerClass(String name) {
035 InnerClass[] inners = getInnerClasses();
036 String inner;
037 for (int i = 0; i < inners.length; i++) {
038 inner = inners[i].getName();
039 if ((inner == null && name == null)
040 || (inner != null && inner.equals(name)))
041 return inners[i];
042 }
043 return null;
044 }
045
046 /**
047 * Return all inner classes with the given name, or empty array if none.
048 * Use null to retrieve anonymous classes.
049 */
050 public InnerClass[] getInnerClasses(String name) {
051 List matches = new LinkedList();
052 InnerClass[] inners = getInnerClasses();
053 String inner;
054 for (int i = 0; i < inners.length; i++) {
055 inner = inners[i].getName();
056 if ((inner == null && name == null)
057 || (inner != null && inner.equals(name)))
058 matches.add(inners[i]);
059 }
060 return (InnerClass[]) matches.toArray(new InnerClass[matches.size()]);
061 }
062
063 /**
064 * Set the inner class references for this class. This method is
065 * useful when importing inner class references from another class.
066 */
067 public void setInnerClasses(InnerClass[] inners) {
068 clear();
069 if (inners != null)
070 for (int i = 0; i < inners.length; i++)
071 addInnerClass(inners[i]);
072 }
073
074 /**
075 * Import an inner class from another entity, or make a copy of one
076 * on this entity.
077 *
078 * @return the newly added inner class
079 */
080 public InnerClass addInnerClass(InnerClass inner) {
081 InnerClass newInner = addInnerClass(inner.getName(),
082 inner.getTypeName(), inner.getDeclarerName());
083 newInner.setAccessFlags(inner.getAccessFlags());
084 return newInner;
085 }
086
087 /**
088 * Add an inner class.
089 */
090 public InnerClass addInnerClass() {
091 InnerClass inner = new InnerClass(this);
092 _innerClasses.add(inner);
093 return inner;
094 }
095
096 /**
097 * Add an inner class.
098 *
099 * @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 }