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 }