001package serp.bytecode;
002
003import java.io.*;
004
005import serp.bytecode.lowlevel.*;
006import serp.bytecode.visitor.*;
007import serp.util.*;
008
009/**
010 * Any referenced class that is not a package member is represented by
011 * this structure. This includes member classes and interfaces.
012 *
013 * @author Abe White
014 */
015public class InnerClass implements BCEntity, VisitAcceptor {
016    private int _index = 0;
017    private int _nameIndex = 0;
018    private int _ownerIndex = 0;
019    private int _access = Constants.ACCESS_PRIVATE;
020    private InnerClasses _owner = null;
021
022    InnerClass(InnerClasses owner) {
023        _owner = owner;
024    }
025
026    /**
027     * Inner classes are stored in an {@link InnerClasses} attribute.
028     */
029    public InnerClasses getOwner() {
030        return _owner;
031    }
032
033    void invalidate() {
034        _owner = null;
035    }
036
037    /////////////////////
038    // Access operations
039    /////////////////////
040
041    /**
042     * Return the access flags of the inner class.
043     */
044    public int getAccessFlags() {
045        return _access;
046    }
047
048    /**
049     * Set the access flags of the inner class.
050     */
051    public void setAccessFlags(int accessFlags) {
052        _access = accessFlags;
053    }
054
055    /**
056     * Manipulate the inner class access flags.
057     */
058    public boolean isPublic() {
059        return (getAccessFlags() & Constants.ACCESS_PUBLIC) > 0;
060    }
061
062    /**
063     * Manipulate the inner class 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 inner class access flags.
073     */
074    public boolean isProtected() {
075        return (getAccessFlags() & Constants.ACCESS_PROTECTED) > 0;
076    }
077
078    /**
079     * Manipulate the inner class 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 inner class access flags.
089     */
090    public boolean isPrivate() {
091        return (getAccessFlags() & Constants.ACCESS_PRIVATE) > 0;
092    }
093
094    /**
095     * Manipulate the inner class 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 inner class access flags.
105     */
106    public boolean isFinal() {
107        return (getAccessFlags() & Constants.ACCESS_FINAL) > 0;
108    }
109
110    /**
111     * Manipulate the inner class access flags.
112     */
113    public void setFinal(boolean on) {
114        if (on)
115            setAccessFlags(getAccessFlags() | Constants.ACCESS_FINAL);
116        else
117            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_FINAL);
118    }
119
120    /**
121     * Manipulate the inner class access flags.
122     */
123    public boolean isStatic() {
124        return (getAccessFlags() & Constants.ACCESS_STATIC) > 0;
125    }
126
127    /**
128     * Manipulate the inner class access flags.
129     */
130    public void setStatic(boolean on) {
131        if (on)
132            setAccessFlags(getAccessFlags() | Constants.ACCESS_STATIC);
133        else
134            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_STATIC);
135    }
136
137    /**
138     * Manipulate the class access flags.
139     */
140    public boolean isInterface() {
141        return (getAccessFlags() & Constants.ACCESS_INTERFACE) > 0;
142    }
143
144    /**
145     * Manipulate the class access flags.
146     */
147    public void setInterface(boolean on) {
148        if (on) {
149            setAccessFlags(getAccessFlags() | Constants.ACCESS_INTERFACE);
150            setAbstract(true);
151        } else
152            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_INTERFACE);
153    }
154
155    /**
156     * Manipulate the class access flags.
157     */
158    public boolean isAbstract() {
159        return (getAccessFlags() & Constants.ACCESS_ABSTRACT) > 0;
160    }
161
162    /**
163     * Manipulate the class access flags.
164     */
165    public void setAbstract(boolean on) {
166        if (on)
167            setAccessFlags(getAccessFlags() | Constants.ACCESS_INTERFACE);
168        else
169            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_INTERFACE);
170    }
171
172    /**
173     * Manipulate the inner class access flags.
174     */
175    public boolean isSynthetic() {
176        return (getAccessFlags() & Constants.ACCESS_SYNTHETIC) > 0;
177    }
178
179    /**
180     * Manipulate the inner class access flags.
181     */
182    public void setSynthetic(boolean on) {
183        if (on)
184            setAccessFlags(getAccessFlags() | Constants.ACCESS_SYNTHETIC);
185        else
186            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_SYNTHETIC);
187    }
188
189    /**
190     * Manipulate the inner class access flags.
191     */
192    public boolean isAnnotation() {
193        return (getAccessFlags() & Constants.ACCESS_ANNOTATION) > 0;
194    }
195
196    /**
197     * Manipulate the inner class access flags.  Setting to true also makes this
198     * an interface.
199     */
200    public void setAnnotation(boolean on) {
201        if (on) {
202            setAccessFlags(getAccessFlags() | Constants.ACCESS_ANNOTATION);
203            setAccessFlags(getAccessFlags() | Constants.ACCESS_INTERFACE);
204        } else
205            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ANNOTATION);
206    }
207
208    /**
209     * Manipulate the inner class access flags.
210     */
211    public boolean isEnum() {
212        return (getAccessFlags() & Constants.ACCESS_ENUM) > 0;
213    }
214
215    /**
216     * Manipulate the inner class access flags.
217     */
218    public void setEnum(boolean on) {
219        if (on)
220            setAccessFlags(getAccessFlags() | Constants.ACCESS_ENUM);
221        else
222            setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ENUM);
223    }
224
225    ////////////////////////////////
226    // Name, type, owner operations
227    ////////////////////////////////
228
229    /**
230     * Return the {@link ConstantPool} index of the {@link UTF8Entry} that
231     * describes the simple name this class is referred to in source, or
232     * 0 for anonymous classes.
233     */
234    public int getNameIndex() {
235        return _nameIndex;
236    }
237
238    /**
239     * Set the {@link ConstantPool} index of the {@link UTF8Entry} that
240     * describes the simple name this class is referred to in source, or
241     * 0 for anonymous classes.
242     */
243    public void setNameIndex(int nameIndex) {
244        _nameIndex = nameIndex;
245    }
246
247    /**
248     * Return the simple name of this inner class, or null if anonymous.
249     */
250    public String getName() {
251        if (getNameIndex() == 0)
252            return null;
253        return ((UTF8Entry) getPool().getEntry(getNameIndex())).getValue();
254    }
255
256    /**
257     * Set the simple name of this inner class.
258     */
259    public void setName(String name) {
260        if (name == null)
261            setNameIndex(0);
262        else
263            setNameIndex(getPool().findUTF8Entry(name, true));
264    }
265
266    /**
267     * Return the {@link ConstantPool} index of the {@link ClassEntry} that
268     * describes this class, or 0 if none.
269     */
270    public int getTypeIndex() {
271        return _index;
272    }
273
274    /**
275     * Set the {@link ConstantPool} index of the {@link ClassEntry} that
276     * describes this class.
277     */
278    public void setTypeIndex(int index) {
279        _index = index;
280    }
281
282    /**
283     * Return the full name of the inner class, or null if unset.
284     */
285    public String getTypeName() {
286        if (getTypeIndex() == 0)
287            return null;
288        ClassEntry entry = (ClassEntry) getPool().getEntry(getTypeIndex());
289        return getProject().getNameCache().getExternalForm(entry.getNameEntry().
290            getValue(), false);
291    }
292
293    /**
294     * Return the type of the inner class.
295     * If the type has not been set, this method will return null.
296     */
297    public Class getType() {
298        String type = getTypeName();
299        if (type == null)
300            return null;
301        return Strings.toClass(type, getClassLoader());
302    }
303
304    /**
305     * Return the type for this instruction.
306     * If the type has not been set, this method will return null.
307     */
308    public BCClass getTypeBC() {
309        String type = getTypeName();
310        if (type == null)
311            return null;
312        return getProject().loadClass(type, getClassLoader());
313    }
314
315    /**
316     * Set the type of this inner class.
317     */
318    public void setType(String type) {
319        if (type == null)
320            setTypeIndex(0);
321        else {
322            type = getProject().getNameCache().getInternalForm(type, false);
323            setTypeIndex(getPool().findClassEntry(type, true));
324        }
325    }
326
327    /**
328     * Set the type of this inner class.
329     */
330    public void setType(Class type) {
331        if (type == null)
332            setType((String) null);
333        else
334            setType(type.getName());
335    }
336
337    /**
338     * Set the type of this inner class.
339     */
340    public void setType(BCClass type) {
341        if (type == null)
342            setType((String) null);
343        else
344            setType(type.getName());
345    }
346
347    /**
348     * Return the {@link ConstantPool} index of the {@link ClassEntry} that
349     * describes the declaring class, or 0 if this class is not a member class.
350     */
351    public int getDeclarerIndex() {
352        return _ownerIndex;
353    }
354
355    /**
356     * Set the {@link ConstantPool} index of the {@link ClassEntry} that
357     * describes the declaring class, or 0 if this class is not a member class.
358     */
359    public void setDeclarerIndex(int ownerIndex) {
360        _ownerIndex = ownerIndex;
361    }
362
363    /**
364     * Return the full name of the declaring class, or null if unset/not a
365     * member.
366     */
367    public String getDeclarerName() {
368        if (getDeclarerIndex() == 0)
369            return null;
370        ClassEntry entry = (ClassEntry) getPool().getEntry(getDeclarerIndex());
371        return getProject().getNameCache().getExternalForm(entry.getNameEntry().
372            getValue(), false);
373    }
374
375    /**
376     * Return the type of the declaring class.
377     * If the type has not been set or the class is not a member, this method
378     * will return null.
379     */
380    public Class getDeclarerType() {
381        String type = getDeclarerName();
382        if (type == null)
383            return null;
384        return Strings.toClass(type, getClassLoader());
385    }
386
387    /**
388     * Return the type for this instruction.
389     * If the type has not been set or the class is not a member, this method
390     * will return null.
391     */
392    public BCClass getDeclarerBC() {
393        String type = getDeclarerName();
394        if (type == null)
395            return null;
396        return getProject().loadClass(type, getClassLoader());
397    }
398
399    /**
400     * Set the type of this declaring class.
401     */
402    public void setDeclarer(String type) {
403        if (type == null)
404            setDeclarerIndex(0);
405        else {
406            type = getProject().getNameCache().getInternalForm(type, false);
407            setDeclarerIndex(getPool().findClassEntry(type, true));
408        }
409    }
410
411    /**
412     * Set the type of this declaring class.
413     */
414    public void setDeclarer(Class type) {
415        if (type == null)
416            setDeclarer((String) null);
417        else
418            setDeclarer(type.getName());
419    }
420
421    /**
422     * Set the type of this declaring class.
423     */
424    public void setDeclarer(BCClass type) {
425        if (type == null)
426            setDeclarer((String) null);
427        else
428            setDeclarer(type.getName());
429    }
430
431    ///////////////////////////
432    // BCEntity implementation
433    ///////////////////////////
434
435    public Project getProject() {
436        return _owner.getProject();
437    }
438
439    public ConstantPool getPool() {
440        return _owner.getPool();
441    }
442
443    public ClassLoader getClassLoader() {
444        return _owner.getClassLoader();
445    }
446
447    public boolean isValid() {
448        return _owner != null;
449    }
450
451    public void acceptVisit(BCVisitor visit) {
452        visit.enterInnerClass(this);
453        visit.exitInnerClass(this);
454    }
455
456    //////////////////
457    // I/O operations
458    //////////////////
459
460    void read(DataInput in) throws IOException {
461        setTypeIndex(in.readUnsignedShort());
462        setDeclarerIndex(in.readUnsignedShort());
463        setNameIndex(in.readUnsignedShort());
464        setAccessFlags(in.readUnsignedShort());
465    }
466
467    void write(DataOutput out) throws IOException {
468        out.writeShort(getTypeIndex());
469        out.writeShort(getDeclarerIndex());
470        out.writeShort(getNameIndex());
471        out.writeShort(getAccessFlags());
472    }
473}