001 package edu.rice.cs.cunit.classFile.attributes;
002
003 import edu.rice.cs.cunit.classFile.constantPool.AUTFPoolInfo;
004 import edu.rice.cs.cunit.classFile.constantPool.ConstantPool;
005 import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckUTFVisitor;
006 import edu.rice.cs.cunit.classFile.code.instructions.LineNumberTable;
007 import edu.rice.cs.cunit.util.Types;
008
009 import java.io.ByteArrayOutputStream;
010 import java.io.IOException;
011
012 /**
013 * @author Mathias Ricken
014 */
015 public abstract class AMultipleNamedAnnotationsAttributeInfo extends AAnnotationsAttributeInfo {
016 /**
017 * Storage class for name and annotations.
018 */
019 public static class NamedAnnotationsRecord {
020 private final AUTFPoolInfo name;
021 private final AAnnotationsAttributeInfo.Annotation[] annotations;
022
023 public NamedAnnotationsRecord(AUTFPoolInfo name,
024 AAnnotationsAttributeInfo.Annotation[] annotations) {
025 this.name = name;
026 this.annotations = new AAnnotationsAttributeInfo.Annotation[annotations.length];
027 System.arraycopy(annotations,0,this.annotations,0,annotations.length);
028 }
029
030 public AUTFPoolInfo getName() {
031 return name;
032 }
033
034 public Annotation[] getAnnotations() {
035 AAnnotationsAttributeInfo.Annotation[] as = new AAnnotationsAttributeInfo.Annotation[annotations.length];
036 System.arraycopy(annotations,0,as,0,annotations.length);
037 return as;
038 }
039 }
040
041 public AMultipleNamedAnnotationsAttributeInfo(AUTFPoolInfo name, byte data[], ConstantPool cp) {
042 super(name, data, cp);
043 }
044
045 /**
046 * Return the number of entities.
047 *
048 * @return number of entities
049 *
050 * @throws ClassFormatError
051 */
052 public int getEntityCount() {
053 return _data[0];
054 }
055
056 /**
057 * Return an array of entity annotations records.
058 *
059 * @return array of entity annotations records.
060 *
061 * @throws ClassFormatError if the attribute has an incorrect format
062 */
063 public NamedAnnotationsRecord[] getEntityAnnotations() throws ClassFormatError {
064 int count = getEntityCount();
065 NamedAnnotationsRecord[] nar = new NamedAnnotationsRecord[count];
066 int index = 1;
067 for(int i = 0; i < count; ++i) {
068 AUTFPoolInfo name = _constantPool.get(Types.ushortFromBytes(_data, index+0)).execute(CheckUTFVisitor.singleton(), null);
069 short annCount = (short)(0xffff & Types.ushortFromBytes(_data, index+2));
070
071 index += 4;
072
073 AAnnotationsAttributeInfo.Annotation[] ann = new AAnnotationsAttributeInfo.Annotation[annCount];
074 for(short annIndex = 0; annIndex < annCount; ++annIndex) {
075 ann[annIndex] = new AAnnotationsAttributeInfo.Annotation(_constantPool,_data,index);
076 index += ann[annIndex].getSize();
077 }
078
079 nar[i] = new NamedAnnotationsRecord(name, ann);
080 }
081 return nar;
082 }
083
084 /**
085 * Set the array of entity annotations records.
086 *
087 * @param nars array of entity annotations records
088 */
089 public void setLocalVariableAnnotations(NamedAnnotationsRecord[] nars) {
090 ByteArrayOutputStream baos = new ByteArrayOutputStream();
091 baos.write((byte)nars.length);
092 for(NamedAnnotationsRecord r: nars) {
093 byte[] header = new byte[10];
094 Types.bytesFromShort((short)(0xffff & _constantPool.indexOf(r.name)), header, 0);
095 Types.bytesFromShort((short)(0xffff & r.annotations.length), header, 2);
096 baos.write(header, 0, 4);
097 for(int i = 0; i < r.annotations.length; ++i) {
098 try {
099 r.annotations[i].writeToByteArrayOutputStream(_constantPool,baos);
100 }
101 catch(IOException e) {
102 throw new ClassFormatError("Error while writing out annotations");
103 }
104 }
105 }
106 setData(baos.toByteArray());
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);
117 x.append(" <");
118 x.append(getEntityCount());
119 x.append(' ');
120 x.append(getEntityName());
121 x.append("(s) { ");
122 boolean first = true;
123 for(NamedAnnotationsRecord nars : getEntityAnnotations()) {
124 if (first) {
125 first = false;
126 }
127 else {
128 x.append(", ");
129 }
130 x.append("(name=");
131 x.append(nars.name.toString());
132 x.append(", annotations ");
133 x.append(nars.annotations.length);
134 x.append(": {");
135
136 boolean firstAnn = true;
137 for(AAnnotationsAttributeInfo.Annotation ann : nars.annotations) {
138 if (firstAnn) {
139 firstAnn = false;
140 }
141 else {
142 x.append(", ");
143 }
144 x.append(ann.toString());
145 }
146 x.append(" }");
147 }
148 x.append(" } >");
149 return x.toString();
150 }
151
152 /**
153 * Return the name of the entity, e.g. "parameter" or "local variable".
154 * @return name of tne entity
155 */
156 public abstract String getEntityName();
157
158 /**
159 * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them.
160 *
161 * @param startPC program counter to start at
162 * @param deltaPC change in program counter values
163 */
164 public void adjustPC(int startPC, int deltaPC) {
165 // nothing to do
166 }
167
168 /**
169 * Translate the program counter values contained in this attribute from an old line number table to a new one.
170 *
171 * @param index critical point (insertion or deletion point)
172 * @param deltaIndex delta value to add to all old line numbers greater than the critical point
173 * @param oldLnt old line number table
174 * @param newLnt new line number table
175 */
176 public void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt) {
177 // nothing to do
178 }
179
180 /**
181 * Creates and returns a copy of this object.
182 */
183 public Object clone() throws CloneNotSupportedException {
184 return super.clone();
185 }
186 }