001    package serp.bytecode;
002    
003    import java.io.*;
004    import java.util.*;
005    
006    import serp.bytecode.lowlevel.*;
007    
008    /**
009     * A member field or method of a class.
010     *
011     * @author Abe White
012     */
013    public abstract class BCMember extends Annotated {
014        private BCClass _owner = null;
015        private int _access = Constants.ACCESS_PRIVATE;
016        private int _nameIndex = 0;
017        private int _descriptorIndex = 0;
018        private Collection _attrs = new LinkedList();
019    
020        BCMember(BCClass owner) {
021            _owner = owner;
022        }
023    
024        /**
025         * Return the {@link BCClass} that declares this member.
026         */
027        public BCClass getDeclarer() {
028            return _owner;
029        }
030    
031        /////////////////////
032        // Access operations
033        /////////////////////
034    
035        /**
036         * Return the access flags for this member as a bit array of
037         * ACCESS_XXX constants from {@link Constants}. This can be used to
038         * transfer access flags between members without getting/setting each
039         * possible access flag. Defaults to {@link Constants#ACCESS_PRIVATE}
040         */
041        public int getAccessFlags() {
042            return _access;
043        }
044    
045        /**
046         * Set the access flags for this member as a bit array of
047         * ACCESS_XXX constants from {@link Constants}. This can be used to
048         * transfer access flags between members without getting/setting each
049         * possible access flag. Defaults to {@link Constants#ACCESS_PRIVATE}
050         */
051        public void setAccessFlags(int access) {
052            _access = access;
053        }
054    
055        /**
056         * Manipulate the member access flags.
057         */
058        public boolean isPublic() {
059            return (getAccessFlags() & Constants.ACCESS_PUBLIC) > 0;
060        }
061    
062        /**
063         * Manipulate the member access flags.
064         */
065        public void makePublic() {
066            setAccessFlags(getAccessFlags() | Constants.ACCESS_PUBLIC);
067            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PRIVATE);
068            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PROTECTED);
069        }
070    
071        /**
072         * Manipulate the member access flags.
073         */
074        public boolean isProtected() {
075            return (getAccessFlags() & Constants.ACCESS_PROTECTED) > 0;
076        }
077    
078        /**
079         * Manipulate the member access flags.
080         */
081        public void makeProtected() {
082            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PUBLIC);
083            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PRIVATE);
084            setAccessFlags(getAccessFlags() | Constants.ACCESS_PROTECTED);
085        }
086    
087        /**
088         * Manipulate the member access flags.
089         */
090        public boolean isPrivate() {
091            return (getAccessFlags() & Constants.ACCESS_PRIVATE) > 0;
092        }
093    
094        /**
095         * Manipulate the member access flags.
096         */
097        public void makePrivate() {
098            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PUBLIC);
099            setAccessFlags(getAccessFlags() | Constants.ACCESS_PRIVATE);
100            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PROTECTED);
101        }
102    
103        /**
104         * Manipulate the member access flags.
105         */
106        public boolean isPackage() {
107            boolean hasAccess = false;
108            hasAccess |= (getAccessFlags() & Constants.ACCESS_PRIVATE) > 0;
109            hasAccess |= (getAccessFlags() & Constants.ACCESS_PROTECTED) > 0;
110            hasAccess |= (getAccessFlags() & Constants.ACCESS_PUBLIC) > 0;
111            return !hasAccess;
112        }
113    
114        /**
115         * Manipulate the member access flags.
116         */
117        public void makePackage() {
118            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PUBLIC);
119            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PRIVATE);
120            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PROTECTED);
121        }
122    
123        /**
124         * Manipulate the member access flags.
125         */
126        public boolean isFinal() {
127            return (getAccessFlags() & Constants.ACCESS_FINAL) > 0;
128        }
129    
130        /**
131         * Manipulate the member access flags.
132         */
133        public void setFinal(boolean on) {
134            if (on)
135                setAccessFlags(getAccessFlags() | Constants.ACCESS_FINAL);
136            else
137                setAccessFlags(getAccessFlags() & ~Constants.ACCESS_FINAL);
138        }
139    
140        /**
141         * Manipulate the member access flags.
142         */
143        public boolean isStatic() {
144            return (getAccessFlags() & Constants.ACCESS_STATIC) > 0;
145        }
146    
147        /**
148         * Manipulate the member access flags.
149         */
150        public void setStatic(boolean on) {
151            if (on)
152                setAccessFlags(getAccessFlags() | Constants.ACCESS_STATIC);
153            else
154                setAccessFlags(getAccessFlags() & ~Constants.ACCESS_STATIC);
155        }
156    
157        /**
158         * Manipulate the field access flags.  This method also checks the synthetic
159         * member attribute.
160         */
161        public boolean isSynthetic() {
162            return (getAccessFlags() & Constants.ACCESS_SYNTHETIC) > 0
163                || getAttribute(Constants.ATTR_SYNTHETIC) != null;
164        }
165    
166        /**
167         * Manipulate the field access flags.  This method also manipulates the
168         * synthetic member attribute.
169         */
170        public void setSynthetic(boolean on) {
171            if (on) {
172                setAccessFlags(getAccessFlags() | Constants.ACCESS_SYNTHETIC);
173                addAttribute(Constants.ATTR_SYNTHETIC);
174            } else {
175                setAccessFlags(getAccessFlags() & ~Constants.ACCESS_SYNTHETIC);
176                removeAttribute(Constants.ATTR_SYNTHETIC);
177            }
178        }
179    
180        /////////////////////////
181        // Descriptor operations
182        /////////////////////////
183    
184        /**
185         * Return the index in the class {@link ConstantPool} of the
186         * {@link UTF8Entry} holding the name of this member.
187         */
188        public int getNameIndex() {
189            return _nameIndex;
190        }
191    
192        /**
193         * Set the index in the class {@link ConstantPool} of the
194         * {@link UTF8Entry} holding the name of this member.
195         */
196        public void setNameIndex(int index) {
197            String origName = getName();
198            _nameIndex = index;
199            // change all the references in the owning class
200            setEntry(origName, getDescriptor());
201        }
202    
203        /**
204         * Return the index in the class {@link ConstantPool} of the
205         * {@link UTF8Entry} holding the descriptor of this member.
206         */
207        public int getDescriptorIndex() {
208            return _descriptorIndex;
209        }
210    
211        /**
212         * Set the index in the class {@link ConstantPool} of the
213         * {@link UTF8Entry} holding the descriptor of this member.
214         */
215        public void setDescriptorIndex(int index) {
216            String origDesc = getDescriptor();
217            _descriptorIndex = index;
218            // change all the references in the owning class
219            setEntry(getName(), origDesc);
220        }
221    
222        /**
223         * Return the name of this member.
224         */
225        public String getName() {
226            return ((UTF8Entry) getPool().getEntry(_nameIndex)).getValue();
227        }
228    
229        /**
230         * Set the name of this member.
231         */
232        public void setName(String name) {
233            String origName = getName();
234            // reset the name
235            _nameIndex = getPool().findUTF8Entry(name, true);
236            // change all references in the owning class
237            setEntry(origName, getDescriptor());
238        }
239    
240        /**
241         * Return the descriptor of this member, in internal form.
242         */
243        public String getDescriptor() {
244            return ((UTF8Entry) getPool().getEntry(_descriptorIndex)).getValue();
245        }
246    
247        /**
248         * Set the descriptor of this member.
249         */
250        public void setDescriptor(String desc) {
251            String origDesc = getDescriptor();
252            // reset the desc
253            desc = getProject().getNameCache().getInternalForm(desc, true);
254            _descriptorIndex = getPool().findUTF8Entry(desc, true);
255            // change all the references in the owning class
256            setEntry(getName(), origDesc);
257        }
258    
259        /**
260         * Resets the {@link ComplexEntry} of the owning class corresponding to
261         * this member. Changes in the member will therefore propogate to all
262         * code in the class.
263         */
264        private void setEntry(String origName, String origDesc) {
265            // find the entry matching this member, if any
266            String owner = getProject().getNameCache().getInternalForm
267                (_owner.getName(), false);
268            ConstantPool pool = getPool();
269            int index;
270            if (this instanceof BCField)
271                index = pool.findFieldEntry(origName, origDesc, owner, false);
272            else if (!_owner.isInterface())
273                index = pool.findMethodEntry(origName, origDesc, owner, false);
274            else
275                index = pool.findInterfaceMethodEntry(origName, origDesc, owner,
276                    false);
277    
278            // change the entry to match the new info; this is dones so
279            // that refs to the member in code will still be valid after the 
280            // change, without changing any other constants that happened to match
281            // the old name and/or descriptor
282            if (index != 0) {
283                ComplexEntry complex = (ComplexEntry) pool.getEntry(index);
284                int ntIndex = pool.findNameAndTypeEntry(getName(), getDescriptor(),
285                    true);
286                complex.setNameAndTypeIndex(ntIndex);
287            }
288        }
289    
290        ///////////////////////
291        // Convenience methods
292        ///////////////////////
293    
294        /**
295         * Convenience method to return deprecation information for the member.
296         * Acts internally through the {@link Attributes} interface.
297         */
298        public boolean isDeprecated() {
299            return getAttribute(Constants.ATTR_DEPRECATED) != null;
300        }
301    
302        /**
303         * Convenience method to set whether this member should be considered
304         * deprecated. Acts internally through the {@link Attributes} interface.
305         */
306        public void setDeprecated(boolean on) {
307            if (!on)
308                removeAttribute(Constants.ATTR_DEPRECATED);
309            else if (!isDeprecated())
310                addAttribute(Constants.ATTR_DEPRECATED);
311        }
312    
313        ////////////////////////////////
314        // Implementation of Attributes
315        ////////////////////////////////
316    
317        public Project getProject() {
318            return _owner.getProject();
319        }
320    
321        public ConstantPool getPool() {
322            return _owner.getPool();
323        }
324    
325        public ClassLoader getClassLoader() {
326            return _owner.getClassLoader();
327        }
328    
329        public boolean isValid() {
330            return _owner != null;
331        }
332    
333        Collection getAttributesHolder() {
334            return _attrs;
335        }
336    
337        /**
338         * Either this method or {@link #read} must be called prior to use
339         * of this class. The given descriptor must be in internal form.
340         */
341        void initialize(String name, String descriptor) {
342            _nameIndex = getPool().findUTF8Entry(name, true);
343            _descriptorIndex = getPool().findUTF8Entry(descriptor, true);
344        }
345    
346        ///////////////////////////////
347        // Implementation of Annotated
348        ///////////////////////////////
349    
350        BCClass getBCClass() {
351            return _owner;
352        }
353    
354        /**
355         * Used when this member is deleted from its class.
356         */
357        void invalidate() {
358            _owner = null;
359        }
360    
361        void read(DataInput in) throws IOException {
362            _access = in.readUnsignedShort();
363            _nameIndex = in.readUnsignedShort();
364            _descriptorIndex = in.readUnsignedShort();
365            readAttributes(in);
366        }
367    
368        void write(DataOutput out) throws IOException {
369            out.writeShort(_access);
370            out.writeShort(_nameIndex);
371            out.writeShort(_descriptorIndex);
372            writeAttributes(out);
373        }
374    }