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 }