001package serp.bytecode;
002
003import java.io.*;
004import java.util.*;
005
006import serp.bytecode.lowlevel.*;
007
008/**
009 * A member field or method of a class.
010 *
011 * @author Abe White
012 */
013public 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}