001 package edu.rice.cs.cunit.classFile.attributes;
002
003 import edu.rice.cs.cunit.classFile.ClassFileTools;
004 import edu.rice.cs.cunit.classFile.attributes.visitors.IAttributeVisitor;
005 import edu.rice.cs.cunit.classFile.code.instructions.LineNumberTable;
006 import edu.rice.cs.cunit.classFile.constantPool.*;
007 import edu.rice.cs.cunit.classFile.constantPool.visitors.*;
008 import edu.rice.cs.cunit.util.Types;
009
010 /**
011 * Represents the InnerClasses attribute in a class file.
012 *
013 * @author Mathias Ricken
014 */
015 public class InnerClassesAttributeInfo extends AAttributeInfo {
016 /**
017 * Storage class for line number/program counter _pairs.
018 */
019 public static class InnerClassesRecord {
020 public APoolInfo innerClass;
021 public APoolInfo outerClass;
022 public APoolInfo innerName;
023 public short innerFlags;
024
025 public InnerClassesRecord(APoolInfo innerClass, APoolInfo outerClass, APoolInfo innerName, short innerFlags) {
026 this.innerClass = innerClass;
027 this.outerClass = outerClass;
028 this.innerName = innerName;
029 this.innerFlags = innerFlags;
030 }
031 }
032
033 /**
034 * Constructor.
035 *
036 * @param name attribute name
037 * @param data attribute data
038 * @param cp constant pool
039 *
040 * @throws ClassFormatError
041 */
042 public InnerClassesAttributeInfo(AUTFPoolInfo name, byte[] data, ConstantPool cp) throws ClassFormatError {
043 super(name, data, cp);
044 }
045
046 /**
047 * Return the number of inner class records.
048 *
049 * @return number of inner class
050 *
051 * @throws ClassFormatError
052 */
053 public int getInnerClassCount() {
054 int res = Types.ushortFromBytes(_data, 0);
055 assert(res <= 0xffff);
056 return res;
057 }
058
059 /**
060 * Return a copy of the inner class records.
061 *
062 * @return array of inner class records
063 *
064 * @throws ClassFormatError
065 */
066 public InnerClassesRecord[] getInnerClasses() throws ClassFormatError {
067 int count = getInnerClassCount();
068 assert(count <= 0xffff);
069 InnerClassesRecord[] arr = new InnerClassesRecord[count];
070 for(short i = 0; i < count; ++i) {
071 arr[i] = new InnerClassesRecord(
072 _constantPool.get(Types.ushortFromBytes(_data, 2 + 8 * i)).execute(CheckClassOrEmptyVisitor.singleton(), null),
073 _constantPool.get(Types.ushortFromBytes(_data, 4 + 8 * i)).execute(CheckClassOrEmptyVisitor.singleton(), null),
074 _constantPool.get(Types.ushortFromBytes(_data, 6 + 8 * i)).execute(CheckUTFOrEmptyVisitor.singleton(), null),
075 (short)(Types.ushortFromBytes(_data, 8 + 8 * i) & 0xffff));
076 }
077 return arr;
078 }
079
080 /**
081 * Set the inner class records.
082 *
083 * @param arr array of inner class records
084 */
085 public void setLocalVariables(InnerClassesRecord[] arr) {
086 byte[] newData = new byte[2 + 8 * arr.length];
087 Types.bytesFromShort((short)arr.length, newData, 0);
088 for(int i = 0; i < arr.length; ++i) {
089 Types.bytesFromShort(_constantPool.indexOf(arr[i].innerClass), newData, 2 + 8 * i);
090 Types.bytesFromShort(_constantPool.indexOf(arr[i].outerClass), newData, 4 + 8 * i);
091 Types.bytesFromShort(_constantPool.indexOf(arr[i].innerName), newData, 6 + 8 * i);
092 Types.bytesFromShort(arr[i].innerFlags, newData, 8 + 8 * i);
093 }
094 setData(newData);
095 }
096
097 /**
098 * Execute a visitor on this attribute.
099 *
100 * @param visitor visitor
101 * @param param visitor-specific parameter
102 *
103 * @return visitor-specific return value
104 */
105 public <R, D> R execute(IAttributeVisitor<R, D> visitor, D param) {
106 return visitor.innerClassesCase(this, param);
107 }
108
109 /**
110 * Return a human-readable version of this attribute.
111 *
112 * @return string
113 */
114 public String toString() {
115 StringBuilder x = new StringBuilder();
116 x.append(_name + " <" + getInnerClassCount() + " inner classes { ");
117 boolean first = true;
118 for(InnerClassesRecord inc : getInnerClasses()) {
119 if (first) {
120 first = false;
121 }
122 else {
123 x.append(", ");
124 }
125 x.append("(inner class=" +
126 inc.innerClass.execute(new ADefaultPoolInfoVisitor<String, Object>() {
127 public String defaultCase(APoolInfo host, Object param) {
128 return null;
129 }
130 public String emptyCase(EmptyPoolInfo host, Object param) {
131 return "null";
132 }
133 public String classCase(ClassPoolInfo host, Object param) {
134 return host.getName().toString();
135 }
136 }, null) + ", outer class=" +
137 inc.outerClass.execute(new ADefaultPoolInfoVisitor<String, Object>() {
138 public String defaultCase(APoolInfo host, Object param) {
139 return null;
140 }
141 public String emptyCase(EmptyPoolInfo host, Object param) {
142 return "<not a member>";
143 }
144 public String classCase(ClassPoolInfo host, Object param) {
145 return host.getName().toString();
146 }
147 }, null) + ", inner name=" +
148 inc.innerName.execute(new ADefaultPoolInfoVisitor<String, Object>() {
149 public String defaultCase(APoolInfo host, Object param) {
150 return null;
151 }
152 public String emptyCase(EmptyPoolInfo host, Object param) {
153 return "<anonymous>";
154 }
155 public String asciizCase(ASCIIPoolInfo host, Object param) {
156 return host.toString();
157 }
158 public String unicodeCase(UnicodePoolInfo host, Object param) {
159 return host.toString();
160 }
161 }, null) + ", flags=" +
162 ClassFileTools.getAccessString(inc.innerFlags) + ")");
163 }
164 x.append(" } >");
165 return x.toString();
166 }
167
168 /**
169 * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them.
170 *
171 * @param startPC program counter to start at
172 * @param deltaPC change in program counter values
173 */
174 public void adjustPC(int startPC, int deltaPC) {
175 // nothing to do
176 }
177
178 /**
179 * Translate the program counter values contained in this attribute from an old line number table to a new one.
180 *
181 * @param index critical point (insertion or deletion point)
182 * @param deltaIndex delta value to add to all old line numbers greater than the critical point
183 * @param oldLnt old line number table
184 * @param newLnt new line number table
185 */
186 public void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt) {
187 // nothing to do
188 }
189
190 /**
191 * Creates and returns a copy of this object.
192 */
193 public Object clone() throws CloneNotSupportedException {
194 return super.clone();
195 }
196
197 /**
198 * Returns the name of the attribute as it appears in the class file.
199 *
200 * @return name of the attribute.
201 */
202 public static String getAttributeName() {
203 return "InnerClasses";
204 }
205 }