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 }