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.ADefaultPoolInfoVisitor;
008    import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckClassVisitor;
009    import edu.rice.cs.cunit.util.Types;
010    
011    import java.util.ArrayList;
012    
013    /**
014     * Represents the Exceptions attribute in a class file.
015     *
016     * @author Mathias Ricken
017     */
018    public class ExceptionsAttributeInfo extends AAttributeInfo {
019        /**
020         * Constructor.
021         *
022         * @param name attribute name
023         * @param data attribute data
024         * @param cp   constant pool
025         *
026         * @throws ClassFormatError
027         */
028        public ExceptionsAttributeInfo(AUTFPoolInfo name, byte[] data, ConstantPool cp) throws ClassFormatError {
029            super(name, data, cp);
030        }
031    
032        /**
033         * Return the number of checked exceptions.
034         *
035         * @return number of exceptions
036         *
037         * @throws ClassFormatError
038         */
039        public int getExceptionCount() throws ClassFormatError {
040            int res = Types.ushortFromBytes(_data, 0);
041            assert(res <= 0xffff);
042            return res;
043        }
044    
045        /**
046         * Return the checked exceptions list.
047         *
048         * @return list of checked exceptions. May contain null!
049         *
050         * @throws ClassFormatError
051         */
052        public ClassPoolInfo[] getExceptions() throws ClassFormatError {
053            int count = getExceptionCount();
054            assert(count <= 0xffff);
055            ClassPoolInfo[] cpi = new ClassPoolInfo[count];
056            for(short i = 0; i < count; ++i) {
057                cpi[i] = _constantPool.get(Types.ushortFromBytes(_data, 2 + 2 * i)).execute(new ADefaultPoolInfoVisitor<ClassPoolInfo, Object>() {
058                    public ClassPoolInfo defaultCase(APoolInfo host, Object o) {
059                        throw new ClassFormatError("Checked exceptions list must contain class or empty items.");
060                    }
061    
062                    public ClassPoolInfo classCase(ClassPoolInfo host, Object o) {
063                        return host;
064                    }
065    
066                    public ClassPoolInfo emptyCase(EmptyPoolInfo host, Object o) {
067                        return null;
068                    }
069                }, null);
070            }
071            return cpi;
072        }
073    
074        /**
075         * Set the checked exceptions list.
076         *
077         * @param cpi list of checked exceptions
078         *
079         * @throws ClassFormatError
080         */
081        public void setExceptions(ClassPoolInfo[] cpi) {
082            byte[] newData = new byte[2 + 2 * cpi.length];
083            Types.bytesFromShort((short)cpi.length, newData, 0);
084            for(int i = 0; i < cpi.length; ++i) {
085                if (cpi[i] != null) {
086                    Types.bytesFromShort(
087                        _constantPool.indexOf(cpi[i].execute(CheckClassVisitor.singleton(), null)),
088                        newData,
089                        2 + 2 * i);
090                }
091                else {
092                    newData[2 + 2 * i] = 0;
093                    newData[3 + 2 * i] = 0;
094                }
095            }
096            setData(newData);
097        }
098    
099        /**
100         * Return a human-readable version of this attribute.
101         *
102         * @return string
103         */
104        public String toString() {
105            StringBuilder x = new StringBuilder();
106            x.append(_name + " <" + getExceptionCount() + " exceptions { ");
107            boolean first = true;
108            for(ClassPoolInfo cpi : getExceptions()) {
109                if (first) {
110                    first = false;
111                }
112                else {
113                    x.append(", ");
114                }
115                if (cpi != null) {
116                    x.append(ClassFileTools.getClassName(cpi.getName().toString()));
117                }
118                else {
119                    x.append("empty item");
120                }
121            }
122            x.append(" } >");
123            return x.toString();
124        }
125    
126        /**
127         * Execute a visitor on this attribute.
128         *
129         * @param visitor visitor
130         * @param param   visitor-specific parameter
131         *
132         * @return visitor-specific return value
133         */
134        public <R, D> R execute(IAttributeVisitor<R, D> visitor, D param) {
135            return visitor.exceptionsCase(this, param);
136        }
137    
138        /**
139         * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them.
140         *
141         * @param startPC program counter to start at
142         * @param deltaPC change in program counter values
143         */
144        public void adjustPC(int startPC, int deltaPC) {
145            // nothing to do
146        }
147    
148        /**
149         * Translate the program counter values contained in this attribute from an old line number table to a new one.
150         *
151         * @param index      critical point (insertion or deletion point)
152         * @param deltaIndex delta value to add to all old line numbers greater than the critical point
153         * @param oldLnt     old line number table
154         * @param newLnt     new line number table
155         */
156        public void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt) {
157            // nothing to do
158        }
159    
160        /**
161         * Creates and returns a copy of this object.
162         */
163        public Object clone() throws CloneNotSupportedException {
164            return super.clone();
165        }
166    
167        /**
168         * Returns the name of the attribute as it appears in the class file.
169         *
170         * @return name of the attribute.
171         */
172        public static String getAttributeName() {
173            return "Exceptions";
174        }
175    }