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 }