001    package edu.rice.cs.cunit.classFile.attributes;
002    
003    import edu.rice.cs.cunit.classFile.code.instructions.LineNumberTable;
004    import edu.rice.cs.cunit.classFile.constantPool.AUTFPoolInfo;
005    import edu.rice.cs.cunit.classFile.constantPool.ConstantPool;
006    import edu.rice.cs.cunit.util.Types;
007    
008    import java.io.ByteArrayOutputStream;
009    import java.io.IOException;
010    import java.util.ArrayList;
011    import java.util.List;
012    
013    /**
014     * Represents an abstract annotations attribute in a class file that can contain annotations for multiple entities,
015     * like for method parameters or local variables.
016     *
017     * @author Mathias Ricken
018     */
019    public abstract class AMultipleAnnotationsAttributeInfo extends AAnnotationsAttributeInfo {
020        /**
021         * Creates a new abstract multiple annotations attribute.
022         * @param name name of attribute
023         * @param data data array
024         * @param cp constant pool
025         */
026        public AMultipleAnnotationsAttributeInfo(AUTFPoolInfo name, byte data[], ConstantPool cp) {
027            super(name, data, cp);
028        }
029    
030        /**
031         * Return the number of entities.
032         *
033         * @return number of entities
034         *
035         * @throws ClassFormatError
036         */
037        public short getEntityCount() throws ClassFormatError {
038            return _data[0];
039        }
040        
041        /**
042         * Return the list of entity annotations arrays.
043         *
044         * @return list of arrays of entity annotations.
045         *
046         * @throws ClassFormatError
047         */
048        public List<Annotation[]> getEntityAnnotations() throws ClassFormatError {
049            ArrayList<Annotation[]> entityAnnots = new ArrayList<Annotation[]>();
050            int index = 1;
051            for(int entity=0; entity<getEntityCount(); ++entity) {
052                int count = Types.ushortFromBytes(_data, index);
053                assert(count <= 0xffff);
054                index += 2;
055                Annotation[] ann = new Annotation[count];
056                for(short i = 0; i < count; ++i) {
057                    ann[i] = new Annotation(_constantPool,_data,index);
058                    index += ann[i].getSize();
059                }
060                entityAnnots.add(ann);
061            }
062            return entityAnnots;
063        }
064    
065        /**
066         * Set the entity annotations list.
067         *
068         * @param entityAnnots list of arrays of entity anotations
069         *
070         * @throws ClassFormatError
071         */
072        public void setEntityAnnotations(List<Annotation[]> entityAnnots) throws IOException {
073            ByteArrayOutputStream baos = new ByteArrayOutputStream();
074            baos.write((byte)entityAnnots.size());
075            for(Annotation[] ann: entityAnnots) {
076                baos.write(Types.bytesFromShort((short)ann.length));
077                for(int i = 0; i < ann.length; ++i) {
078                    ann[i].writeToByteArrayOutputStream(_constantPool,baos);
079                }
080            }
081            setData(baos.toByteArray());
082        }
083    
084        /**
085         * Return a human-readable version of this attribute.
086         *
087         * @return string
088         */
089        public String toString() {
090            StringBuilder x = new StringBuilder();
091            x.append(_name);
092            x.append(" <");
093            x.append(getEntityCount());
094            x.append(" ");
095            x.append(getEntityName());
096            x.append("(s) { ");
097            boolean first = true;
098            for(Annotation[] entityAnnot : getEntityAnnotations()) {
099                if (first) {
100                    first = false;
101                }
102                else {
103                    x.append(", ");
104                }
105                boolean firstAnn = true;
106                for(Annotation ann : entityAnnot) {
107                    if (firstAnn) {
108                        firstAnn = false;
109                    }
110                    else {
111                        x.append(", ");
112                    }
113                    x.append(ann.toString());
114                }
115                x.append(" }");
116            }
117            x.append(" } >");
118            return x.toString();
119        }
120    
121        /**
122         * Return the name of the entity, e.g. "parameter" or "local variable".
123         * @return name of tne entity
124         */
125        public abstract String getEntityName();
126    
127        /**
128         * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them.
129         *
130         * @param startPC program counter to start at
131         * @param deltaPC change in program counter values
132         */
133        public void adjustPC(int startPC, int deltaPC) {
134            // nothing to do
135        }
136    
137        /**
138         * Translate the program counter values contained in this attribute from an old line number table to a new one.
139         *
140         * @param index      critical point (insertion or deletion point)
141         * @param deltaIndex delta value to add to all old line numbers greater than the critical point
142         * @param oldLnt     old line number table
143         * @param newLnt     new line number table
144         */
145        public void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt) {
146            // nothing to do
147        }
148    
149        /**
150         * Creates and returns a copy of this object.
151         */
152        public Object clone() throws CloneNotSupportedException {
153            return super.clone();
154        }
155    }