001    package serp.bytecode;
002    
003    import java.io.*;
004    import java.lang.reflect.*;
005    import java.util.*;
006    
007    import serp.bytecode.lowlevel.*;
008    import serp.bytecode.visitor.*;
009    import serp.util.*;
010    
011    /**
012     * In bytecode attributes are used to represent anything that is not
013     * part of the class structure. This includes the source file name, code of
014     * methods, the line number table, etc. All attributes contain at a minimum
015     * an immutable name that also determines the attribute's type.
016     *
017     * @author Abe White
018     */
019    public abstract class Attribute extends Attributes implements VisitAcceptor {
020        private int _nameIndex = 0;
021        private Attributes _owner = null;
022    
023        Attribute(int nameIndex, Attributes owner) {
024            _owner = owner;
025            _nameIndex = nameIndex;
026        }
027    
028        /**
029         * Create an attribute of the appropriate type based on the
030         * the attribute name.
031         */
032        static Attribute create(String name, Attributes owner) {
033            // special case for annotations
034            int nameIndex = owner.getPool().findUTF8Entry(name, true);
035            if ("RuntimeVisibleAnnotations".equals(name)
036                || "RuntimeInvisibleAnnotations".equals(name))
037                return new Annotations(nameIndex, owner);
038    
039            try {
040                Class type = Class.forName("serp.bytecode." + name);
041                Constructor cons = type.getDeclaredConstructor(new Class[] {
042                    int.class, Attributes.class
043                });
044                return (Attribute) cons.newInstance(new Object[] {
045                    Numbers.valueOf(nameIndex), owner
046                });
047            } catch (Throwable t) {
048                return new UnknownAttribute(nameIndex, owner);
049            }
050        }
051    
052        /**
053         * Return the {@link Attributes} that owns this attribute. The entity
054         * might be a {@link BCClass}, {@link BCField}, {@link BCMethod}, or other
055         * attribute.
056         */
057        public Attributes getOwner() {
058            return _owner;
059        }
060    
061        /**
062         * Return the index in the {@link ConstantPool} of the {@link UTF8Entry}
063         * holding the name of this attribute.
064         */
065        public int getNameIndex() {
066            return _nameIndex;
067        }
068    
069        /**
070         * Return the name of this attribute.
071         */
072        public String getName() {
073            return ((UTF8Entry) getPool().getEntry(_nameIndex)).getValue();
074        }
075    
076        public Project getProject() {
077            return _owner.getProject();
078        }
079    
080        public ConstantPool getPool() {
081            return _owner.getPool();
082        }
083    
084        public ClassLoader getClassLoader() {
085            return _owner.getClassLoader();
086        }
087    
088        public boolean isValid() {
089            return _owner != null;
090        }
091    
092        Collection getAttributesHolder() {
093            return Collections.EMPTY_LIST;
094        }
095    
096        /**
097         * Invalidate this attribute.
098         */
099        void invalidate() {
100            _owner = null;
101        }
102    
103        /**
104         * Return the length of the bytecode representation of this attribute
105         * in bytes, excluding the name index.
106         */
107        int getLength() {
108            return 0;
109        }
110    
111        /**
112         * Copy the information from the given attribute to this one. Does
113         * nothing by default.
114         */
115        void read(Attribute other) {
116        }
117    
118        /**
119         * Read the attribute bytecode from the given stream, up to length
120         * bytes, excluding the name index. Does nothing by default.
121         */
122        void read(DataInput in, int length) throws IOException {
123        }
124    
125        /**
126         * Write the attribute bytecode to the given stream, up to length bytes,
127         * excluding the name index. Does nothing by default.
128         */
129        void write(DataOutput out, int length) throws IOException {
130        }
131    }