001    package serp.bytecode;
002    
003    import java.io.*;
004    
005    import serp.bytecode.lowlevel.*;
006    import serp.bytecode.visitor.*;
007    import 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     */
015    public 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    }