blob: efab9a36da16a27834969559566f53279bc09149 [file] [log] [blame]
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001package aQute.bnd.osgi;
Stuart McCullochbb014372012-06-07 21:57:32 +00002
3import java.io.*;
4import java.lang.annotation.*;
5import java.lang.reflect.*;
6import java.nio.*;
7import java.util.*;
8import java.util.regex.*;
9
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +000010import aQute.bnd.osgi.Descriptors.Descriptor;
11import aQute.bnd.osgi.Descriptors.PackageRef;
12import aQute.bnd.osgi.Descriptors.TypeRef;
Stuart McCullochbb014372012-06-07 21:57:32 +000013import aQute.libg.generics.*;
14
15public class Clazz {
16
17 static Pattern METHOD_DESCRIPTOR = Pattern.compile("\\((.*)\\)(.+)");
18
19 public class ClassConstant {
20 int cname;
21
22 public ClassConstant(int class_index) {
23 this.cname = class_index;
24 }
25
26 public String getName() {
27 return (String) pool[cname];
28 }
29 }
30
31 public static enum JAVA {
32 JDK1_1(45, "JRE-1.1"), JDK1_2(46, "J2SE-1.2"), //
33 JDK1_3(47, "J2SE-1.3"), //
34 JDK1_4(48, "J2SE-1.4"), //
35 J2SE5(49, "J2SE-1.5"), //
36 J2SE6(50, "JavaSE-1.6"), //
37 OpenJDK7(51, "JavaSE-1.7"), //
38 UNKNOWN(Integer.MAX_VALUE, "<>")//
39 ;
40
41 final int major;
42 final String ee;
43
44 JAVA(int major, String ee) {
45 this.major = major;
46 this.ee = ee;
47 }
48
49 static JAVA format(int n) {
50 for (JAVA e : JAVA.values())
51 if (e.major == n)
52 return e;
53 return UNKNOWN;
54 }
55
56 public int getMajor() {
57 return major;
58 }
59
60 public boolean hasAnnotations() {
61 return major >= J2SE5.major;
62 }
63
64 public boolean hasGenerics() {
65 return major >= J2SE5.major;
66 }
67
68 public boolean hasEnums() {
69 return major >= J2SE5.major;
70 }
71
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +000072 public static JAVA getJava(int major, @SuppressWarnings("unused")
73 int minor) {
Stuart McCullochbb014372012-06-07 21:57:32 +000074 for (JAVA j : JAVA.values()) {
75 if (j.major == major)
76 return j;
77 }
78 return UNKNOWN;
79 }
80
81 public String getEE() {
82 return ee;
83 }
84 }
85
86 public static enum QUERY {
87 IMPLEMENTS, EXTENDS, IMPORTS, NAMED, ANY, VERSION, CONCRETE, ABSTRACT, PUBLIC, ANNOTATED, RUNTIMEANNOTATIONS, CLASSANNOTATIONS;
88
89 }
90
Stuart McCulloch2286f232012-06-15 13:27:53 +000091 public final static EnumSet<QUERY> HAS_ARGUMENT = EnumSet.of(QUERY.IMPLEMENTS, QUERY.EXTENDS, QUERY.IMPORTS,
92 QUERY.NAMED, QUERY.VERSION, QUERY.ANNOTATED);
Stuart McCullochbb014372012-06-07 21:57:32 +000093
94 /**
95 * <pre>
96 * ACC_PUBLIC 0x0001 Declared public; may be accessed from outside its
97 * package.
98 * ACC_FINAL 0x0010 Declared final; no subclasses allowed.
99 * ACC_SUPER 0x0020 Treat superclass methods specially when invoked by the
100 * invokespecial instruction.
101 * ACC_INTERFACE 0x0200 Is an interface, not a
102 * class.
103 * ACC_ABSTRACT 0x0400 Declared abstract; may not be instantiated.
104 * </pre>
105 *
106 * @param mod
107 */
Stuart McCulloch2286f232012-06-15 13:27:53 +0000108 final static int ACC_PUBLIC = 0x0001; // Declared
Stuart McCullochbb014372012-06-07 21:57:32 +0000109 // public;
110 // may
111 // be
112 // accessed
113 // from outside its package.
Stuart McCulloch2286f232012-06-15 13:27:53 +0000114 final static int ACC_FINAL = 0x0010; // Declared
Stuart McCullochbb014372012-06-07 21:57:32 +0000115 // final;
116 // no
117 // subclasses
118 // allowed.
Stuart McCulloch2286f232012-06-15 13:27:53 +0000119 final static int ACC_SUPER = 0x0020; // Treat
Stuart McCullochbb014372012-06-07 21:57:32 +0000120 // superclass
121 // methods
122 // specially when invoked by the
123 // invokespecial instruction.
Stuart McCulloch2286f232012-06-15 13:27:53 +0000124 final static int ACC_INTERFACE = 0x0200; // Is
Stuart McCullochbb014372012-06-07 21:57:32 +0000125 // an
126 // interface,
127 // not
128 // a
129 // classs
Stuart McCulloch2286f232012-06-15 13:27:53 +0000130 final static int ACC_ABSTRACT = 0x0400; // Declared
Stuart McCullochbb014372012-06-07 21:57:32 +0000131
132 // a thing not in the source code
133 final static int ACC_SYNTHETIC = 0x1000;
134 final static int ACC_ANNOTATION = 0x2000;
135 final static int ACC_ENUM = 0x4000;
136
137 static protected class Assoc {
138 Assoc(byte tag, int a, int b) {
139 this.tag = tag;
140 this.a = a;
141 this.b = b;
142 }
143
144 byte tag;
145 int a;
146 int b;
147 }
148
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000149 public abstract class Def {
Stuart McCullochb215bfd2012-09-06 18:28:06 +0000150
Stuart McCullochbb014372012-06-07 21:57:32 +0000151 final int access;
152 Set<TypeRef> annotations;
153
154 public Def(int access) {
155 this.access = access;
156 }
157
158 public int getAccess() {
159 return access;
160 }
161
162 public boolean isEnum() {
163 return (access & ACC_ENUM) != 0;
164 }
165
166 public boolean isPublic() {
167 return Modifier.isPublic(access);
168 }
169
170 public boolean isAbstract() {
171 return Modifier.isAbstract(access);
172 }
173
174 public boolean isProtected() {
175 return Modifier.isProtected(access);
176 }
177
178 public boolean isFinal() {
179 return Modifier.isFinal(access) || Clazz.this.isFinal();
180 }
181
182 public boolean isStatic() {
183 return Modifier.isStatic(access);
184 }
185
186 public boolean isPrivate() {
187 return Modifier.isPrivate(access);
188 }
189
190 public boolean isNative() {
191 return Modifier.isNative(access);
192 }
193
194 public boolean isTransient() {
195 return Modifier.isTransient(access);
196 }
197
198 public boolean isVolatile() {
199 return Modifier.isVolatile(access);
200 }
201
202 public boolean isInterface() {
203 return Modifier.isInterface(access);
204 }
205
206 public boolean isSynthetic() {
207 return (access & ACC_SYNTHETIC) != 0;
208 }
209
210 void addAnnotation(Annotation a) {
211 if (annotations == null)
212 annotations = Create.set();
213 annotations.add(analyzer.getTypeRef(a.name.getBinary()));
214 }
215
216 public Collection<TypeRef> getAnnotations() {
217 return annotations;
218 }
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000219
220 public TypeRef getOwnerType() {
221 return className;
222 }
Stuart McCullochb215bfd2012-09-06 18:28:06 +0000223
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000224 public abstract String getName();
Stuart McCullochb215bfd2012-09-06 18:28:06 +0000225
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000226 public abstract TypeRef getType();
Stuart McCullochb215bfd2012-09-06 18:28:06 +0000227
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000228 public abstract TypeRef[] getPrototype();
229
230 public Object getClazz() {
231 return Clazz.this;
232 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000233 }
234
235 public class FieldDef extends Def {
236 final String name;
237 final Descriptor descriptor;
238 String signature;
239 Object constant;
240 boolean deprecated;
241
242 public boolean isDeprecated() {
243 return deprecated;
244 }
245
246 public void setDeprecated(boolean deprecated) {
247 this.deprecated = deprecated;
248 }
249
250 public FieldDef(int access, String name, String descriptor) {
251 super(access);
252 this.name = name;
253 this.descriptor = analyzer.getDescriptor(descriptor);
254 }
255
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +0000256 @Override
Stuart McCullochbb014372012-06-07 21:57:32 +0000257 public String getName() {
258 return name;
259 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000260
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +0000261 @Override
Stuart McCullochbb014372012-06-07 21:57:32 +0000262 public TypeRef getType() {
263 return descriptor.getType();
264 }
265
266 public TypeRef getContainingClass() {
267 return getClassName();
268 }
269
270 public Descriptor getDescriptor() {
271 return descriptor;
272 }
273
274 public void setConstant(Object o) {
275 this.constant = o;
276 }
277
278 public Object getConstant() {
279 return this.constant;
280 }
281
282 // TODO change to use proper generics
283 public String getGenericReturnType() {
284 String use = descriptor.toString();
285 if (signature != null)
286 use = signature;
287
288 Matcher m = METHOD_DESCRIPTOR.matcher(use);
289 if (!m.matches())
290 throw new IllegalArgumentException("Not a valid method descriptor: " + descriptor);
291
292 String returnType = m.group(2);
293 return objectDescriptorToFQN(returnType);
294 }
295
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +0000296 @Override
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000297 public TypeRef[] getPrototype() {
298 return null;
299 }
Stuart McCullochb215bfd2012-09-06 18:28:06 +0000300
Stuart McCullochbb014372012-06-07 21:57:32 +0000301 public String getSignature() {
302 return signature;
303 }
304
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +0000305 @Override
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000306 public String toString() {
307 return name;
308 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000309 }
310
311 public class MethodDef extends FieldDef {
312 public MethodDef(int access, String method, String descriptor) {
313 super(access, method, descriptor);
314 }
315
316 public boolean isConstructor() {
317 return name.equals("<init>") || name.equals("<clinit>");
318 }
319
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +0000320 @Override
Stuart McCullochbb014372012-06-07 21:57:32 +0000321 public TypeRef[] getPrototype() {
322 return descriptor.getPrototype();
323 }
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000324 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000325
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000326 public class TypeDef extends Def {
327 TypeRef type;
328 boolean interf;
329
330 public TypeDef(TypeRef type, boolean interf) {
331 super(Modifier.PUBLIC);
332 this.type = type;
333 this.interf = interf;
334 }
335
336 public TypeRef getReference() {
337 return type;
338 }
339
340 public boolean getImplements() {
341 return interf;
342 }
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000343
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +0000344 @Override
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000345 public String getName() {
346 if (interf)
347 return "<implements>";
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +0000348 return "<extends>";
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000349 }
Stuart McCullochb215bfd2012-09-06 18:28:06 +0000350
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +0000351 @Override
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000352 public TypeRef getType() {
353 return type;
354 }
Stuart McCullochb215bfd2012-09-06 18:28:06 +0000355
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +0000356 @Override
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000357 public TypeRef[] getPrototype() {
358 return null;
359 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000360 }
361
362 final static byte SkipTable[] = { //
Stuart McCulloch2286f232012-06-15 13:27:53 +0000363 0, // 0 non existent
Stuart McCullochbb014372012-06-07 21:57:32 +0000364 -1, // 1 CONSTANT_utf8 UTF 8, handled in
365 // method
366 -1, // 2
367 4, // 3 CONSTANT_Integer
368 4, // 4 CONSTANT_Float
369 8, // 5 CONSTANT_Long (index +=2!)
370 8, // 6 CONSTANT_Double (index +=2!)
371 -1, // 7 CONSTANT_Class
372 2, // 8 CONSTANT_String
373 4, // 9 CONSTANT_FieldRef
374 4, // 10 CONSTANT_MethodRef
375 4, // 11 CONSTANT_InterfaceMethodRef
376 4, // 12 CONSTANT_NameAndType
377 -1, // 13 Not defined
378 -1, // 14 Not defined
379 3, // 15 CONSTANT_MethodHandle
380 2, // 16 CONSTANT_MethodType
381 -1, // 17 Not defined
382 4, // 18 CONSTANT_InvokeDynamic
383 };
384
385 boolean hasRuntimeAnnotations;
386 boolean hasClassAnnotations;
387
388 TypeRef className;
389 Object pool[];
390 int intPool[];
391 Set<PackageRef> imports = Create.set();
392 String path;
393 int minor = 0;
394 int major = 0;
395 int innerAccess = -1;
396 int accessx = 0;
397 String sourceFile;
398 Set<TypeRef> xref;
Stuart McCullochbb014372012-06-07 21:57:32 +0000399 Set<TypeRef> annotations;
400 int forName = 0;
401 int class$ = 0;
402 TypeRef[] interfaces;
403 TypeRef zuper;
404 ClassDataCollector cd = null;
405 Resource resource;
406 FieldDef last = null;
407 boolean deprecated;
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000408 Set<PackageRef> api;
Stuart McCullochbb014372012-06-07 21:57:32 +0000409 final Analyzer analyzer;
410
411 public Clazz(Analyzer analyzer, String path, Resource resource) {
412 this.path = path;
413 this.resource = resource;
414 this.analyzer = analyzer;
415 }
416
417 public Set<TypeRef> parseClassFile() throws Exception {
418 return parseClassFileWithCollector(null);
419 }
420
421 public Set<TypeRef> parseClassFile(InputStream in) throws Exception {
422 return parseClassFile(in, null);
423 }
424
425 public Set<TypeRef> parseClassFileWithCollector(ClassDataCollector cd) throws Exception {
426 InputStream in = resource.openInputStream();
427 try {
428 return parseClassFile(in, cd);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000429 }
430 finally {
Stuart McCullochbb014372012-06-07 21:57:32 +0000431 in.close();
432 }
433 }
434
435 public Set<TypeRef> parseClassFile(InputStream in, ClassDataCollector cd) throws Exception {
436 DataInputStream din = new DataInputStream(in);
437 try {
438 this.cd = cd;
439 return parseClassFile(din);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000440 }
441 finally {
Stuart McCullochbb014372012-06-07 21:57:32 +0000442 cd = null;
443 din.close();
444 }
445 }
446
447 Set<TypeRef> parseClassFile(DataInputStream in) throws Exception {
448 xref = new HashSet<TypeRef>();
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000449
Stuart McCullochbb014372012-06-07 21:57:32 +0000450 boolean crawl = cd != null; // Crawl the byte code if we have a
451 // collector
452 int magic = in.readInt();
453 if (magic != 0xCAFEBABE)
454 throw new IOException("Not a valid class file (no CAFEBABE header)");
455
456 minor = in.readUnsignedShort(); // minor version
457 major = in.readUnsignedShort(); // major version
458 if (cd != null)
459 cd.version(minor, major);
460 int count = in.readUnsignedShort();
461 pool = new Object[count];
462 intPool = new int[count];
463
464 process: for (int poolIndex = 1; poolIndex < count; poolIndex++) {
465 byte tag = in.readByte();
466 switch (tag) {
Stuart McCulloch2286f232012-06-15 13:27:53 +0000467 case 0 :
468 break process;
469 case 1 :
470 constantUtf8(in, poolIndex);
471 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000472
Stuart McCulloch2286f232012-06-15 13:27:53 +0000473 case 3 :
474 constantInteger(in, poolIndex);
475 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000476
Stuart McCulloch2286f232012-06-15 13:27:53 +0000477 case 4 :
478 constantFloat(in, poolIndex);
479 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000480
Stuart McCulloch2286f232012-06-15 13:27:53 +0000481 // For some insane optimization reason are
482 // the long and the double two entries in the
483 // constant pool. See 4.4.5
484 case 5 :
485 constantLong(in, poolIndex);
486 poolIndex++;
487 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000488
Stuart McCulloch2286f232012-06-15 13:27:53 +0000489 case 6 :
490 constantDouble(in, poolIndex);
491 poolIndex++;
492 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000493
Stuart McCulloch2286f232012-06-15 13:27:53 +0000494 case 7 :
495 constantClass(in, poolIndex);
496 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000497
Stuart McCulloch2286f232012-06-15 13:27:53 +0000498 case 8 :
499 constantString(in, poolIndex);
500 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000501
Stuart McCulloch2286f232012-06-15 13:27:53 +0000502 case 10 : // Method ref
503 case 11 : // Interface Method ref
504 methodRef(in, poolIndex);
505 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000506
Stuart McCulloch2286f232012-06-15 13:27:53 +0000507 // Name and Type
508 case 12 :
509 nameAndType(in, poolIndex, tag);
510 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000511
Stuart McCulloch2286f232012-06-15 13:27:53 +0000512 // We get the skip count for each record type
513 // from the SkipTable. This will also automatically
514 // abort when
515 default :
516 if (tag == 2)
517 throw new IOException("Invalid tag " + tag);
518 in.skipBytes(SkipTable[tag]);
519 break;
Stuart McCullochbb014372012-06-07 21:57:32 +0000520 }
521 }
522
523 pool(pool, intPool);
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000524
525 // All name& type and class constant records contain descriptors we must
526 // treat
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000527 // as references, though not API
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000528
529 for (Object o : pool) {
530 if (o == null)
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000531 continue;
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000532
533 if (o instanceof Assoc && ((Assoc) o).tag == 12) {
534 referTo(((Assoc) o).b, 0); // Descriptor
535 } else if (o instanceof ClassConstant) {
536 String binaryClassName = (String) pool[((ClassConstant) o).cname];
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000537 TypeRef typeRef = analyzer.getTypeRef(binaryClassName);
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000538 referTo(typeRef, 0);
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000539 }
540 }
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000541
Stuart McCullochbb014372012-06-07 21:57:32 +0000542 /*
543 * Parse after the constant pool, code thanks to Hans Christian
544 * Falkenberg
545 */
546
547 accessx = in.readUnsignedShort(); // access
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000548 if (Modifier.isPublic(accessx))
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000549 api = new HashSet<PackageRef>();
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000550
Stuart McCullochbb014372012-06-07 21:57:32 +0000551 int this_class = in.readUnsignedShort();
552 className = analyzer.getTypeRef((String) pool[intPool[this_class]]);
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000553 referTo(className, Modifier.PUBLIC);
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000554
Stuart McCullochbb014372012-06-07 21:57:32 +0000555 try {
556
557 if (cd != null) {
558 if (!cd.classStart(accessx, className))
559 return null;
560 }
561
562 int super_class = in.readUnsignedShort();
563 String superName = (String) pool[intPool[super_class]];
564 if (superName != null) {
565 zuper = analyzer.getTypeRef(superName);
566 }
567
568 if (zuper != null) {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000569 referTo(zuper, accessx);
Stuart McCullochbb014372012-06-07 21:57:32 +0000570 if (cd != null)
571 cd.extendsClass(zuper);
572 }
573
574 int interfacesCount = in.readUnsignedShort();
575 if (interfacesCount > 0) {
576 interfaces = new TypeRef[interfacesCount];
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000577 for (int i = 0; i < interfacesCount; i++) {
Stuart McCulloch2286f232012-06-15 13:27:53 +0000578 interfaces[i] = analyzer.getTypeRef((String) pool[intPool[in.readUnsignedShort()]]);
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000579 referTo(interfaces[i], accessx);
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000580 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000581 if (cd != null)
582 cd.implementsInterfaces(interfaces);
583 }
584
585 int fieldsCount = in.readUnsignedShort();
586 for (int i = 0; i < fieldsCount; i++) {
587 int access_flags = in.readUnsignedShort(); // skip access flags
588 int name_index = in.readUnsignedShort();
589 int descriptor_index = in.readUnsignedShort();
590
591 // Java prior to 1.5 used a weird
592 // static variable to hold the com.X.class
593 // result construct. If it did not find it
594 // it would create a variable class$com$X
595 // that would be used to hold the class
596 // object gotten with Class.forName ...
597 // Stupidly, they did not actively use the
598 // class name for the field type, so bnd
599 // would not see a reference. We detect
600 // this case and add an artificial descriptor
601 String name = pool[name_index].toString(); // name_index
602 if (name.startsWith("class$")) {
603 crawl = true;
604 }
605 if (cd != null)
Stuart McCulloch2286f232012-06-15 13:27:53 +0000606 cd.field(last = new FieldDef(access_flags, name, pool[descriptor_index].toString()));
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000607
608 referTo(descriptor_index, access_flags);
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000609 doAttributes(in, ElementType.FIELD, false, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000610 }
611
612 //
613 // Check if we have to crawl the code to find
614 // the ldc(_w) <string constant> invokestatic Class.forName
615 // if so, calculate the method ref index so we
616 // can do this efficiently
617 //
618 if (crawl) {
Stuart McCulloch2286f232012-06-15 13:27:53 +0000619 forName = findMethodReference("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
620 class$ = findMethodReference(className.getBinary(), "class$", "(Ljava/lang/String;)Ljava/lang/Class;");
621 } else if (major == 48) {
622 forName = findMethodReference("java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
Stuart McCullochbb014372012-06-07 21:57:32 +0000623 if (forName > 0) {
624 crawl = true;
625 class$ = findMethodReference(className.getBinary(), "class$",
626 "(Ljava/lang/String;)Ljava/lang/Class;");
627 }
628 }
Stuart McCulloch2286f232012-06-15 13:27:53 +0000629
Stuart McCullochbb014372012-06-07 21:57:32 +0000630 // There are some serious changes in the
631 // class file format. So we do not do any crawling
632 // it has also become less important
Stuart McCulloch2286f232012-06-15 13:27:53 +0000633 if (major >= JAVA.OpenJDK7.major)
Stuart McCullochbb014372012-06-07 21:57:32 +0000634 crawl = false;
635
636 //
637 // Handle the methods
638 //
639 int methodCount = in.readUnsignedShort();
640 for (int i = 0; i < methodCount; i++) {
641 int access_flags = in.readUnsignedShort();
642 int name_index = in.readUnsignedShort();
643 int descriptor_index = in.readUnsignedShort();
Stuart McCullochbb014372012-06-07 21:57:32 +0000644 String name = pool[name_index].toString();
645 String descriptor = pool[descriptor_index].toString();
646 if (cd != null) {
647 MethodDef mdef = new MethodDef(access_flags, name, descriptor);
648 last = mdef;
649 cd.method(mdef);
650 }
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000651 referTo(descriptor_index, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000652
653 if ("<init>".equals(name)) {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000654 doAttributes(in, ElementType.CONSTRUCTOR, crawl, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000655 } else {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000656 doAttributes(in, ElementType.METHOD, crawl, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000657 }
658 }
659 if (cd != null)
660 cd.memberEnd();
661
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000662 doAttributes(in, ElementType.TYPE, false, accessx);
Stuart McCullochbb014372012-06-07 21:57:32 +0000663
664 //
665 // Parse all the descriptors we found
666 //
667
Stuart McCullochbb014372012-06-07 21:57:32 +0000668 Set<TypeRef> xref = this.xref;
669 reset();
670 return xref;
Stuart McCulloch2286f232012-06-15 13:27:53 +0000671 }
672 finally {
Stuart McCullochbb014372012-06-07 21:57:32 +0000673 if (cd != null)
674 cd.classEnd();
675 }
676 }
677
678 private void constantFloat(DataInputStream in, int poolIndex) throws IOException {
679 if (cd != null)
680 pool[poolIndex] = in.readFloat(); // ALU
681 else
682 in.skipBytes(4);
683 }
684
685 private void constantInteger(DataInputStream in, int poolIndex) throws IOException {
686 intPool[poolIndex] = in.readInt();
687 if (cd != null)
688 pool[poolIndex] = intPool[poolIndex];
689 }
690
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000691 protected void pool(@SuppressWarnings("unused")
692 Object[] pool, @SuppressWarnings("unused")
693 int[] intPool) {}
Stuart McCullochbb014372012-06-07 21:57:32 +0000694
695 /**
696 * @param in
697 * @param poolIndex
698 * @param tag
699 * @throws IOException
700 */
701 protected void nameAndType(DataInputStream in, int poolIndex, byte tag) throws IOException {
702 int name_index = in.readUnsignedShort();
703 int descriptor_index = in.readUnsignedShort();
Stuart McCullochbb014372012-06-07 21:57:32 +0000704 pool[poolIndex] = new Assoc(tag, name_index, descriptor_index);
705 }
706
707 /**
708 * @param in
709 * @param poolIndex
710 * @param tag
711 * @throws IOException
712 */
713 private void methodRef(DataInputStream in, int poolIndex) throws IOException {
714 int class_index = in.readUnsignedShort();
715 int name_and_type_index = in.readUnsignedShort();
716 pool[poolIndex] = new Assoc((byte) 10, class_index, name_and_type_index);
717 }
718
719 /**
720 * @param in
721 * @param poolIndex
722 * @throws IOException
723 */
724 private void constantString(DataInputStream in, int poolIndex) throws IOException {
725 int string_index = in.readUnsignedShort();
726 intPool[poolIndex] = string_index;
727 }
728
729 /**
730 * @param in
731 * @param poolIndex
732 * @throws IOException
733 */
734 protected void constantClass(DataInputStream in, int poolIndex) throws IOException {
735 int class_index = in.readUnsignedShort();
Stuart McCullochbb014372012-06-07 21:57:32 +0000736 intPool[poolIndex] = class_index;
737 ClassConstant c = new ClassConstant(class_index);
738 pool[poolIndex] = c;
739 }
740
741 /**
742 * @param in
743 * @throws IOException
744 */
745 protected void constantDouble(DataInputStream in, int poolIndex) throws IOException {
746 if (cd != null)
747 pool[poolIndex] = in.readDouble();
748 else
749 in.skipBytes(8);
750 }
751
752 /**
753 * @param in
754 * @throws IOException
755 */
756 protected void constantLong(DataInputStream in, int poolIndex) throws IOException {
757 if (cd != null) {
758 pool[poolIndex] = in.readLong();
759 } else
760 in.skipBytes(8);
761 }
762
763 /**
764 * @param in
765 * @param poolIndex
766 * @throws IOException
767 */
768 protected void constantUtf8(DataInputStream in, int poolIndex) throws IOException {
769 // CONSTANT_Utf8
770
771 String name = in.readUTF();
772 pool[poolIndex] = name;
773 }
774
775 /**
776 * Find a method reference in the pool that points to the given class,
777 * methodname and descriptor.
778 *
779 * @param clazz
780 * @param methodname
781 * @param descriptor
782 * @return index in constant pool
783 */
784 private int findMethodReference(String clazz, String methodname, String descriptor) {
785 for (int i = 1; i < pool.length; i++) {
786 if (pool[i] instanceof Assoc) {
787 Assoc methodref = (Assoc) pool[i];
788 if (methodref.tag == 10) {
789 // Method ref
790 int class_index = methodref.a;
791 int class_name_index = intPool[class_index];
792 if (clazz.equals(pool[class_name_index])) {
793 int name_and_type_index = methodref.b;
794 Assoc name_and_type = (Assoc) pool[name_and_type_index];
795 if (name_and_type.tag == 12) {
796 // Name and Type
797 int name_index = name_and_type.a;
798 int type_index = name_and_type.b;
799 if (methodname.equals(pool[name_index])) {
800 if (descriptor.equals(pool[type_index])) {
801 return i;
802 }
803 }
804 }
805 }
806 }
807 }
808 }
809 return -1;
810 }
811
812 /**
813 * Called for each attribute in the class, field, or method.
814 *
815 * @param in
816 * The stream
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000817 * @param access_flags
Stuart McCullochbb014372012-06-07 21:57:32 +0000818 * @throws Exception
819 */
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000820 private void doAttributes(DataInputStream in, ElementType member, boolean crawl, int access_flags) throws Exception {
Stuart McCullochbb014372012-06-07 21:57:32 +0000821 int attributesCount = in.readUnsignedShort();
822 for (int j = 0; j < attributesCount; j++) {
823 // skip name CONSTANT_Utf8 pointer
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000824 doAttribute(in, member, crawl, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000825 }
826 }
827
828 /**
829 * Process a single attribute, if not recognized, skip it.
830 *
831 * @param in
832 * the data stream
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000833 * @param access_flags
Stuart McCullochbb014372012-06-07 21:57:32 +0000834 * @throws Exception
835 */
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000836 private void doAttribute(DataInputStream in, ElementType member, boolean crawl, int access_flags) throws Exception {
Stuart McCullochbb014372012-06-07 21:57:32 +0000837 int attribute_name_index = in.readUnsignedShort();
838 String attributeName = (String) pool[attribute_name_index];
839 long attribute_length = in.readInt();
840 attribute_length &= 0xFFFFFFFF;
841 if ("Deprecated".equals(attributeName)) {
842 if (cd != null)
843 cd.deprecated();
844 } else if ("RuntimeVisibleAnnotations".equals(attributeName))
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +0000845 doAnnotations(in, member, RetentionPolicy.RUNTIME, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000846 else if ("RuntimeVisibleParameterAnnotations".equals(attributeName))
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +0000847 doParameterAnnotations(in, member, RetentionPolicy.RUNTIME, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000848 else if ("RuntimeInvisibleAnnotations".equals(attributeName))
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +0000849 doAnnotations(in, member, RetentionPolicy.CLASS, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000850 else if ("RuntimeInvisibleParameterAnnotations".equals(attributeName))
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +0000851 doParameterAnnotations(in, member, RetentionPolicy.CLASS, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000852 else if ("InnerClasses".equals(attributeName))
853 doInnerClasses(in);
854 else if ("EnclosingMethod".equals(attributeName))
855 doEnclosingMethod(in);
856 else if ("SourceFile".equals(attributeName))
857 doSourceFile(in);
858 else if ("Code".equals(attributeName) && crawl)
859 doCode(in);
860 else if ("Signature".equals(attributeName))
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000861 doSignature(in, member, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000862 else if ("ConstantValue".equals(attributeName))
863 doConstantValue(in);
Stuart McCullochb215bfd2012-09-06 18:28:06 +0000864 else if ("Exceptions".equals(attributeName))
865 doExceptions(in, access_flags);
866 else {
Stuart McCullochbb014372012-06-07 21:57:32 +0000867 if (attribute_length > 0x7FFFFFFF) {
868 throw new IllegalArgumentException("Attribute > 2Gb");
869 }
870 in.skipBytes((int) attribute_length);
871 }
872 }
873
874 /**
875 * <pre>
876 * EnclosingMethod_attribute {
877 * u2 attribute_name_index;
878 * u4 attribute_length;
879 * u2 class_index
880 * u2 method_index;
881 * }
882 * </pre>
883 *
Stuart McCullochbb014372012-06-07 21:57:32 +0000884 * @param in
885 * @throws IOException
886 */
887 private void doEnclosingMethod(DataInputStream in) throws IOException {
888 int cIndex = in.readShort();
889 int mIndex = in.readShort();
890
891 if (cd != null) {
892 int nameIndex = intPool[cIndex];
893 TypeRef cName = analyzer.getTypeRef((String) pool[nameIndex]);
894
895 String mName = null;
896 String mDescriptor = null;
897
898 if (mIndex != 0) {
899 Assoc nameAndType = (Assoc) pool[mIndex];
900 mName = (String) pool[nameAndType.a];
901 mDescriptor = (String) pool[nameAndType.b];
902 }
903 cd.enclosingMethod(cName, mName, mDescriptor);
904 }
905 }
906
907 /**
908 * <pre>
909 * InnerClasses_attribute {
910 * u2 attribute_name_index;
911 * u4 attribute_length;
912 * u2 number_of_classes; {
913 * u2 inner_class_info_index;
914 * u2 outer_class_info_index;
915 * u2 inner_name_index;
916 * u2 inner_class_access_flags;
917 * } classes[number_of_classes];
918 * }
919 * </pre>
920 *
921 * @param in
922 * @throws Exception
923 */
924 private void doInnerClasses(DataInputStream in) throws Exception {
925 int number_of_classes = in.readShort();
926 for (int i = 0; i < number_of_classes; i++) {
927 int inner_class_info_index = in.readShort();
928 int outer_class_info_index = in.readShort();
929 int inner_name_index = in.readShort();
930 int inner_class_access_flags = in.readShort() & 0xFFFF;
931
932 if (cd != null) {
933 TypeRef innerClass = null;
934 TypeRef outerClass = null;
935 String innerName = null;
936
937 if (inner_class_info_index != 0) {
938 int nameIndex = intPool[inner_class_info_index];
939 innerClass = analyzer.getTypeRef((String) pool[nameIndex]);
940 }
941
942 if (outer_class_info_index != 0) {
943 int nameIndex = intPool[outer_class_info_index];
944 outerClass = analyzer.getTypeRef((String) pool[nameIndex]);
945 }
946
947 if (inner_name_index != 0)
948 innerName = (String) pool[inner_name_index];
949
950 cd.innerClass(innerClass, outerClass, innerName, inner_class_access_flags);
951 }
952 }
953 }
954
955 /**
956 * Handle a signature
957 *
958 * <pre>
959 * Signature_attribute {
960 * u2 attribute_name_index;
961 * u4 attribute_length;
962 * u2 signature_index;
963 * }
964 * </pre>
965 *
966 * @param member
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000967 * @param access_flags
Stuart McCullochbb014372012-06-07 21:57:32 +0000968 */
969
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000970 void doSignature(DataInputStream in, ElementType member, int access_flags) throws IOException {
Stuart McCullochbb014372012-06-07 21:57:32 +0000971 int signature_index = in.readUnsignedShort();
972 String signature = (String) pool[signature_index];
973
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000974 parseDescriptor(signature, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000975
976 if (last != null)
977 last.signature = signature;
978
979 if (cd != null)
980 cd.signature(signature);
981 }
982
983 /**
984 * Handle a constant value call the data collector with it
985 */
986 void doConstantValue(DataInputStream in) throws IOException {
987 int constantValue_index = in.readUnsignedShort();
988 if (cd == null)
989 return;
990
991 Object object = pool[constantValue_index];
992 if (object == null)
993 object = pool[intPool[constantValue_index]];
994
995 last.constant = object;
996 cd.constant(object);
997 }
998
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +0000999 void doExceptions(DataInputStream in, int access_flags) throws IOException {
1000 int exception_count = in.readUnsignedShort();
1001 for (int i = 0; i < exception_count; i++) {
1002 int index = in.readUnsignedShort();
1003 if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags))) {
1004 ClassConstant cc = (ClassConstant) pool[index];
1005 String descr = (String) pool[cc.cname];
1006
1007 TypeRef clazz = analyzer.getTypeRef(descr);
1008 referTo(clazz, access_flags);
1009 }
1010 }
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001011 }
1012
Stuart McCullochbb014372012-06-07 21:57:32 +00001013 /**
1014 * <pre>
1015 * Code_attribute {
1016 * u2 attribute_name_index;
1017 * u4 attribute_length;
1018 * u2 max_stack;
1019 * u2 max_locals;
1020 * u4 code_length;
1021 * u1 code[code_length];
1022 * u2 exception_table_length;
1023 * { u2 start_pc;
1024 * u2 end_pc;
1025 * u2 handler_pc;
1026 * u2 catch_type;
1027 * } exception_table[exception_table_length];
1028 * u2 attributes_count;
1029 * attribute_info attributes[attributes_count];
1030 * }
1031 * </pre>
1032 *
1033 * @param in
1034 * @param pool
1035 * @throws Exception
1036 */
1037 private void doCode(DataInputStream in) throws Exception {
1038 /* int max_stack = */in.readUnsignedShort();
1039 /* int max_locals = */in.readUnsignedShort();
1040 int code_length = in.readInt();
1041 byte code[] = new byte[code_length];
1042 in.readFully(code);
1043 crawl(code);
1044 int exception_table_length = in.readUnsignedShort();
1045 in.skipBytes(exception_table_length * 8);
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001046 doAttributes(in, ElementType.METHOD, false, 0);
Stuart McCullochbb014372012-06-07 21:57:32 +00001047 }
1048
1049 /**
1050 * We must find Class.forName references ...
1051 *
1052 * @param code
1053 */
1054 protected void crawl(byte[] code) {
1055 ByteBuffer bb = ByteBuffer.wrap(code);
1056 bb.order(ByteOrder.BIG_ENDIAN);
1057 int lastReference = -1;
1058
1059 while (bb.remaining() > 0) {
1060 int instruction = 0xFF & bb.get();
1061 switch (instruction) {
Stuart McCulloch2286f232012-06-15 13:27:53 +00001062 case OpCodes.ldc :
1063 lastReference = 0xFF & bb.get();
1064 break;
Stuart McCullochbb014372012-06-07 21:57:32 +00001065
Stuart McCulloch2286f232012-06-15 13:27:53 +00001066 case OpCodes.ldc_w :
1067 lastReference = 0xFFFF & bb.getShort();
1068 break;
Stuart McCullochbb014372012-06-07 21:57:32 +00001069
Stuart McCulloch2286f232012-06-15 13:27:53 +00001070 case OpCodes.invokespecial : {
1071 int mref = 0xFFFF & bb.getShort();
1072 if (cd != null)
1073 getMethodDef(0, mref);
1074 break;
1075 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001076
Stuart McCulloch2286f232012-06-15 13:27:53 +00001077 case OpCodes.invokevirtual : {
1078 int mref = 0xFFFF & bb.getShort();
1079 if (cd != null)
1080 getMethodDef(0, mref);
1081 break;
1082 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001083
Stuart McCulloch2286f232012-06-15 13:27:53 +00001084 case OpCodes.invokeinterface : {
1085 int mref = 0xFFFF & bb.getShort();
1086 if (cd != null)
1087 getMethodDef(0, mref);
1088 break;
1089 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001090
Stuart McCulloch2286f232012-06-15 13:27:53 +00001091 case OpCodes.invokestatic : {
1092 int methodref = 0xFFFF & bb.getShort();
1093 if (cd != null)
1094 getMethodDef(0, methodref);
Stuart McCullochbb014372012-06-07 21:57:32 +00001095
Stuart McCulloch2286f232012-06-15 13:27:53 +00001096 if ((methodref == forName || methodref == class$) && lastReference != -1
1097 && pool[intPool[lastReference]] instanceof String) {
1098 String fqn = (String) pool[intPool[lastReference]];
1099 if (!fqn.equals("class") && fqn.indexOf('.') > 0) {
1100 TypeRef clazz = analyzer.getTypeRefFromFQN(fqn);
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001101 referTo(clazz, 0);
Stuart McCulloch2286f232012-06-15 13:27:53 +00001102 }
1103 lastReference = -1;
1104 }
1105 break;
1106 }
1107
1108 case OpCodes.tableswitch :
1109 // Skip to place divisible by 4
1110 while ((bb.position() & 0x3) != 0)
1111 bb.get();
1112 /* int deflt = */
1113 bb.getInt();
1114 int low = bb.getInt();
1115 int high = bb.getInt();
1116 try {
1117 bb.position(bb.position() + (high - low + 1) * 4);
1118 }
1119 catch (Exception e) {
1120 // TODO Auto-generated catch block
1121 e.printStackTrace();
Stuart McCullochbb014372012-06-07 21:57:32 +00001122 }
1123 lastReference = -1;
Stuart McCulloch2286f232012-06-15 13:27:53 +00001124 break;
Stuart McCullochbb014372012-06-07 21:57:32 +00001125
Stuart McCulloch2286f232012-06-15 13:27:53 +00001126 case OpCodes.lookupswitch :
1127 // Skip to place divisible by 4
1128 while ((bb.position() & 0x3) != 0)
1129 bb.get();
1130 /* deflt = */
1131 bb.getInt();
1132 int npairs = bb.getInt();
1133 bb.position(bb.position() + npairs * 8);
1134 lastReference = -1;
1135 break;
Stuart McCullochbb014372012-06-07 21:57:32 +00001136
Stuart McCulloch2286f232012-06-15 13:27:53 +00001137 default :
1138 lastReference = -1;
1139 bb.position(bb.position() + OpCodes.OFFSETS[instruction]);
Stuart McCullochbb014372012-06-07 21:57:32 +00001140 }
1141 }
1142 }
1143
1144 private void doSourceFile(DataInputStream in) throws IOException {
1145 int sourcefile_index = in.readUnsignedShort();
1146 this.sourceFile = pool[sourcefile_index].toString();
1147 }
1148
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001149 private void doParameterAnnotations(DataInputStream in, ElementType member, RetentionPolicy policy, int access_flags)
Stuart McCulloch2286f232012-06-15 13:27:53 +00001150 throws IOException {
Stuart McCullochbb014372012-06-07 21:57:32 +00001151 int num_parameters = in.readUnsignedByte();
1152 for (int p = 0; p < num_parameters; p++) {
1153 if (cd != null)
1154 cd.parameter(p);
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001155 doAnnotations(in, member, policy, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +00001156 }
1157 }
1158
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001159 private void doAnnotations(DataInputStream in, ElementType member, RetentionPolicy policy, int access_flags)
1160 throws IOException {
Stuart McCullochbb014372012-06-07 21:57:32 +00001161 int num_annotations = in.readUnsignedShort(); // # of annotations
1162 for (int a = 0; a < num_annotations; a++) {
1163 if (cd == null)
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001164 doAnnotation(in, member, policy, false, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +00001165 else {
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001166 Annotation annotion = doAnnotation(in, member, policy, true, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +00001167 cd.annotation(annotion);
1168 }
1169 }
1170 }
1171
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001172 private Annotation doAnnotation(DataInputStream in, ElementType member, RetentionPolicy policy, boolean collect,
1173 int access_flags) throws IOException {
Stuart McCullochbb014372012-06-07 21:57:32 +00001174 int type_index = in.readUnsignedShort();
1175 if (annotations == null)
1176 annotations = new HashSet<TypeRef>();
1177
1178 TypeRef tr = analyzer.getTypeRef(pool[type_index].toString());
1179 annotations.add(tr);
1180
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001181 TypeRef name = analyzer.getTypeRef((String) pool[type_index]);
Stuart McCullochbb014372012-06-07 21:57:32 +00001182 if (policy == RetentionPolicy.RUNTIME) {
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001183 referTo(type_index, 0);
Stuart McCullochbb014372012-06-07 21:57:32 +00001184 hasRuntimeAnnotations = true;
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001185 if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags)))
1186 api.add(name.getPackageRef());
Stuart McCullochbb014372012-06-07 21:57:32 +00001187 } else {
1188 hasClassAnnotations = true;
1189 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001190 int num_element_value_pairs = in.readUnsignedShort();
Stuart McCulloch2286f232012-06-15 13:27:53 +00001191 Map<String,Object> elements = null;
Stuart McCullochbb014372012-06-07 21:57:32 +00001192 for (int v = 0; v < num_element_value_pairs; v++) {
1193 int element_name_index = in.readUnsignedShort();
1194 String element = (String) pool[element_name_index];
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001195 Object value = doElementValue(in, member, policy, collect, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +00001196 if (collect) {
1197 if (elements == null)
Stuart McCulloch2286f232012-06-15 13:27:53 +00001198 elements = new LinkedHashMap<String,Object>();
Stuart McCullochbb014372012-06-07 21:57:32 +00001199 elements.put(element, value);
1200 }
1201 }
1202 if (collect)
1203 return new Annotation(name, elements, member, policy);
Stuart McCullochd4826102012-06-26 16:34:24 +00001204 return null;
Stuart McCullochbb014372012-06-07 21:57:32 +00001205 }
1206
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001207 private Object doElementValue(DataInputStream in, ElementType member, RetentionPolicy policy, boolean collect,
1208 int access_flags) throws IOException {
Stuart McCullochbb014372012-06-07 21:57:32 +00001209 char tag = (char) in.readUnsignedByte();
1210 switch (tag) {
Stuart McCulloch2286f232012-06-15 13:27:53 +00001211 case 'B' : // Byte
1212 case 'C' : // Character
1213 case 'I' : // Integer
1214 case 'S' : // Short
1215 int const_value_index = in.readUnsignedShort();
1216 return intPool[const_value_index];
Stuart McCullochbb014372012-06-07 21:57:32 +00001217
Stuart McCulloch2286f232012-06-15 13:27:53 +00001218 case 'D' : // Double
1219 case 'F' : // Float
1220 case 's' : // String
1221 case 'J' : // Long
1222 const_value_index = in.readUnsignedShort();
1223 return pool[const_value_index];
Stuart McCullochbb014372012-06-07 21:57:32 +00001224
Stuart McCulloch2286f232012-06-15 13:27:53 +00001225 case 'Z' : // Boolean
1226 const_value_index = in.readUnsignedShort();
1227 return pool[const_value_index] == null || pool[const_value_index].equals(0) ? false : true;
Stuart McCullochbb014372012-06-07 21:57:32 +00001228
Stuart McCulloch2286f232012-06-15 13:27:53 +00001229 case 'e' : // enum constant
1230 int type_name_index = in.readUnsignedShort();
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001231 if (policy == RetentionPolicy.RUNTIME) {
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001232 referTo(type_name_index, 0);
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001233 if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags))) {
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001234 TypeRef name = analyzer.getTypeRef((String) pool[type_name_index]);
1235 api.add(name.getPackageRef());
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001236 }
1237 }
Stuart McCulloch2286f232012-06-15 13:27:53 +00001238 int const_name_index = in.readUnsignedShort();
1239 return pool[const_name_index];
Stuart McCullochbb014372012-06-07 21:57:32 +00001240
Stuart McCulloch2286f232012-06-15 13:27:53 +00001241 case 'c' : // Class
1242 int class_info_index = in.readUnsignedShort();
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001243 if (policy == RetentionPolicy.RUNTIME) {
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001244 referTo(class_info_index, 0);
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001245 if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags))) {
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001246 TypeRef name = analyzer.getTypeRef((String) pool[class_info_index]);
1247 api.add(name.getPackageRef());
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001248 }
1249 }
Stuart McCulloch2286f232012-06-15 13:27:53 +00001250 return pool[class_info_index];
Stuart McCullochbb014372012-06-07 21:57:32 +00001251
Stuart McCulloch2286f232012-06-15 13:27:53 +00001252 case '@' : // Annotation type
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001253 return doAnnotation(in, member, policy, collect, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +00001254
Stuart McCulloch2286f232012-06-15 13:27:53 +00001255 case '[' : // Array
1256 int num_values = in.readUnsignedShort();
1257 Object[] result = new Object[num_values];
1258 for (int i = 0; i < num_values; i++) {
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001259 result[i] = doElementValue(in, member, policy, collect, access_flags);
Stuart McCulloch2286f232012-06-15 13:27:53 +00001260 }
1261 return result;
Stuart McCullochbb014372012-06-07 21:57:32 +00001262
Stuart McCulloch2286f232012-06-15 13:27:53 +00001263 default :
1264 throw new IllegalArgumentException("Invalid value for Annotation ElementValue tag " + tag);
Stuart McCullochbb014372012-06-07 21:57:32 +00001265 }
1266 }
1267
1268 /**
1269 * Add a new package reference.
1270 *
1271 * @param packageRef
1272 * A '.' delimited package name
1273 */
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001274 void referTo(TypeRef typeRef, int modifiers) {
Stuart McCullochbb014372012-06-07 21:57:32 +00001275 if (xref != null)
1276 xref.add(typeRef);
1277 if (typeRef.isPrimitive())
1278 return;
1279
1280 PackageRef packageRef = typeRef.getPackageRef();
1281 if (packageRef.isPrimitivePackage())
1282 return;
1283
1284 imports.add(packageRef);
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001285
1286 if (api != null && (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)))
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001287 api.add(packageRef);
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001288
1289 if (cd != null)
1290 cd.referTo(typeRef, modifiers);
1291
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001292 }
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001293
1294 void referTo(int index, int modifiers) {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001295 String descriptor = (String) pool[index];
1296 parseDescriptor(descriptor, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001297 }
1298
1299 /**
1300 * This method parses a descriptor and adds the package of the descriptor to
Stuart McCulloch2286f232012-06-15 13:27:53 +00001301 * the referenced packages. The syntax of the descriptor is:
Stuart McCullochbb014372012-06-07 21:57:32 +00001302 *
1303 * <pre>
1304 * descriptor ::= ( '(' reference * ')' )? reference
1305 * reference ::= 'L' classname ( '&lt;' references '&gt;' )? ';' | 'B' | 'Z' | ... | '+' | '-' | '['
1306 * </pre>
1307 *
1308 * This methods uses heavy recursion to parse the descriptor and a roving
1309 * pointer to limit the creation of string objects.
1310 *
1311 * @param descriptor
1312 * The to be parsed descriptor
1313 * @param rover
1314 * The pointer to start at
1315 */
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001316
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001317 public void parseDescriptor(String descriptor, int modifiers) {
Stuart McCullochbb014372012-06-07 21:57:32 +00001318 // Some descriptors are weird, they start with a generic
1319 // declaration that contains ':', not sure what they mean ...
1320 int rover = 0;
1321 if (descriptor.charAt(0) == '<') {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001322 rover = parseFormalTypeParameters(descriptor, rover, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001323 }
1324
1325 if (descriptor.charAt(rover) == '(') {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001326 rover = parseReferences(descriptor, rover + 1, ')', modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001327 rover++;
1328 }
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001329 parseReferences(descriptor, rover, (char) 0, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001330 }
1331
1332 /**
1333 * Parse a sequence of references. A sequence ends with a given character or
1334 * when the string ends.
1335 *
1336 * @param descriptor
1337 * The whole descriptor.
1338 * @param rover
1339 * The index in the descriptor
1340 * @param delimiter
1341 * The end character or 0
1342 * @return the last index processed, one character after the delimeter
1343 */
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001344 int parseReferences(String descriptor, int rover, char delimiter, int modifiers) {
Stuart McCullochbb014372012-06-07 21:57:32 +00001345 int r = rover;
1346 while (r < descriptor.length() && descriptor.charAt(r) != delimiter) {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001347 r = parseReference(descriptor, r, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001348 }
1349 return r;
1350 }
1351
1352 /**
1353 * Parse a single reference. This can be a single character or an object
1354 * reference when it starts with 'L'.
1355 *
1356 * @param descriptor
1357 * The descriptor
1358 * @param rover
1359 * The place to start
1360 * @return The return index after the reference
1361 */
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001362 int parseReference(String descriptor, int rover, int modifiers) {
Stuart McCullochbb014372012-06-07 21:57:32 +00001363 int r = rover;
1364 char c = descriptor.charAt(r);
1365 while (c == '[')
1366 c = descriptor.charAt(++r);
1367
1368 if (c == '<') {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001369 r = parseReferences(descriptor, r + 1, '>', modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001370 } else if (c == 'T') {
1371 // Type variable name
1372 r++;
1373 while (descriptor.charAt(r) != ';')
1374 r++;
1375 } else if (c == 'L') {
1376 StringBuilder sb = new StringBuilder();
1377 r++;
1378 while ((c = descriptor.charAt(r)) != ';') {
1379 if (c == '<') {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001380 r = parseReferences(descriptor, r + 1, '>', modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001381 } else
1382 sb.append(c);
1383 r++;
1384 }
1385 TypeRef ref = analyzer.getTypeRef(sb.toString());
1386 if (cd != null)
1387 cd.addReference(ref);
1388
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001389 referTo(ref, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001390 } else {
1391 if ("+-*BCDFIJSZV".indexOf(c) < 0)
1392 ;// System.err.println("Should not skip: " + c);
1393 }
1394
1395 // this skips a lot of characters
1396 // [, *, +, -, B, etc.
1397
1398 return r + 1;
1399 }
1400
1401 /**
1402 * FormalTypeParameters
1403 *
1404 * @param descriptor
1405 * @param index
1406 * @return
1407 */
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001408 private int parseFormalTypeParameters(String descriptor, int index, int modifiers) {
Stuart McCullochbb014372012-06-07 21:57:32 +00001409 index++;
1410 while (descriptor.charAt(index) != '>') {
1411 // Skip IDENTIFIER
1412 index = descriptor.indexOf(':', index) + 1;
1413 if (index == 0)
1414 throw new IllegalArgumentException("Expected IDENTIFIER: " + descriptor);
1415
1416 // ClassBound? InterfaceBounds
1417
1418 char c = descriptor.charAt(index);
1419
1420 // Class Bound?
1421 if (c == 'L' || c == 'T') {
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001422 index = parseReference(descriptor, index, modifiers); // class
1423 // reference
Stuart McCullochbb014372012-06-07 21:57:32 +00001424 c = descriptor.charAt(index);
1425 }
1426
1427 // Interface Bounds
1428 while (c == ':') {
1429 index++;
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001430 index = parseReference(descriptor, index, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001431 c = descriptor.charAt(index);
1432 } // for each interface
1433
1434 } // for each formal parameter
1435 return index + 1; // skip >
1436 }
1437
1438 public Set<PackageRef> getReferred() {
1439 return imports;
1440 }
1441
1442 public String getAbsolutePath() {
1443 return path;
1444 }
1445
1446 public String getSourceFile() {
1447 return sourceFile;
1448 }
1449
1450 /**
Stuart McCulloch2286f232012-06-15 13:27:53 +00001451 * .class construct for different compilers sun 1.1 Detect static variable
1452 * class$com$acme$MyClass 1.2 " 1.3 " 1.4 " 1.5 ldc_w (class) 1.6 " eclipse
1453 * 1.1 class$0, ldc (string), invokestatic Class.forName 1.2 " 1.3 " 1.5 ldc
1454 * (class) 1.6 " 1.5 and later is not an issue, sun pre 1.5 is easy to
1455 * detect the static variable that decodes the class name. For eclipse, the
1456 * class$0 gives away we have a reference encoded in a string.
Stuart McCullochbb014372012-06-07 21:57:32 +00001457 * compilerversions/compilerversions.jar contains test versions of all
1458 * versions/compilers.
1459 */
1460
1461 public void reset() {
1462 pool = null;
1463 intPool = null;
1464 xref = null;
Stuart McCullochbb014372012-06-07 21:57:32 +00001465 }
1466
1467 public boolean is(QUERY query, Instruction instr, Analyzer analyzer) throws Exception {
1468 switch (query) {
Stuart McCulloch2286f232012-06-15 13:27:53 +00001469 case ANY :
1470 return true;
Stuart McCullochbb014372012-06-07 21:57:32 +00001471
Stuart McCulloch2286f232012-06-15 13:27:53 +00001472 case NAMED :
1473 if (instr.matches(getClassName().getDottedOnly()))
Stuart McCullochbb014372012-06-07 21:57:32 +00001474 return !instr.isNegated();
Stuart McCullochbb014372012-06-07 21:57:32 +00001475 return false;
1476
Stuart McCulloch2286f232012-06-15 13:27:53 +00001477 case VERSION :
1478 String v = major + "." + minor;
1479 if (instr.matches(v))
1480 return !instr.isNegated();
Stuart McCullochbb014372012-06-07 21:57:32 +00001481 return false;
1482
Stuart McCulloch2286f232012-06-15 13:27:53 +00001483 case IMPLEMENTS :
1484 for (int i = 0; interfaces != null && i < interfaces.length; i++) {
1485 if (instr.matches(interfaces[i].getDottedOnly()))
1486 return !instr.isNegated();
1487 }
1488 break;
1489
1490 case EXTENDS :
1491 if (zuper == null)
1492 return false;
1493
1494 if (instr.matches(zuper.getDottedOnly()))
Stuart McCullochbb014372012-06-07 21:57:32 +00001495 return !instr.isNegated();
Stuart McCulloch2286f232012-06-15 13:27:53 +00001496 break;
Stuart McCullochbb014372012-06-07 21:57:32 +00001497
Stuart McCulloch2286f232012-06-15 13:27:53 +00001498 case PUBLIC :
1499 return Modifier.isPublic(accessx);
Stuart McCullochbb014372012-06-07 21:57:32 +00001500
Stuart McCulloch2286f232012-06-15 13:27:53 +00001501 case CONCRETE :
1502 return !Modifier.isAbstract(accessx);
Stuart McCullochbb014372012-06-07 21:57:32 +00001503
Stuart McCulloch2286f232012-06-15 13:27:53 +00001504 case ANNOTATED :
1505 if (annotations == null)
1506 return false;
Stuart McCullochbb014372012-06-07 21:57:32 +00001507
Stuart McCulloch2286f232012-06-15 13:27:53 +00001508 for (TypeRef annotation : annotations) {
1509 if (instr.matches(annotation.getFQN()))
1510 return !instr.isNegated();
1511 }
1512
1513 return false;
1514
1515 case RUNTIMEANNOTATIONS :
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001516 return hasRuntimeAnnotations;
Stuart McCulloch2286f232012-06-15 13:27:53 +00001517 case CLASSANNOTATIONS :
1518 return hasClassAnnotations;
1519
1520 case ABSTRACT :
1521 return Modifier.isAbstract(accessx);
1522
1523 case IMPORTS :
1524 for (PackageRef imp : imports) {
1525 if (instr.matches(imp.getFQN()))
1526 return !instr.isNegated();
1527 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001528 }
1529
1530 if (zuper == null)
1531 return false;
1532
1533 Clazz clazz = analyzer.findClass(zuper);
1534 if (clazz == null)
1535 return false;
1536
1537 return clazz.is(query, instr, analyzer);
1538 }
1539
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +00001540 @Override
Stuart McCullochbb014372012-06-07 21:57:32 +00001541 public String toString() {
1542 return className.getFQN();
1543 }
1544
1545 /**
1546 * Called when crawling the byte code and a method reference is found
Stuart McCullochbb014372012-06-07 21:57:32 +00001547 */
1548 void getMethodDef(int access, int methodRefPoolIndex) {
Stuart McCulloch2286f232012-06-15 13:27:53 +00001549 if (methodRefPoolIndex == 0)
Stuart McCullochbb014372012-06-07 21:57:32 +00001550 return;
Stuart McCulloch2286f232012-06-15 13:27:53 +00001551
Stuart McCullochbb014372012-06-07 21:57:32 +00001552 Object o = pool[methodRefPoolIndex];
1553 if (o != null && o instanceof Assoc) {
1554 Assoc assoc = (Assoc) o;
1555 if (assoc.tag == 10) {
1556 int string_index = intPool[assoc.a];
1557 TypeRef className = analyzer.getTypeRef((String) pool[string_index]);
1558 int name_and_type_index = assoc.b;
1559 Assoc name_and_type = (Assoc) pool[name_and_type_index];
1560 if (name_and_type.tag == 12) {
1561 // Name and Type
1562 int name_index = name_and_type.a;
1563 int type_index = name_and_type.b;
1564 String method = (String) pool[name_index];
1565 String descriptor = (String) pool[type_index];
1566 cd.referenceMethod(access, className, method, descriptor);
1567 } else
1568 throw new IllegalArgumentException(
1569 "Invalid class file (or parsing is wrong), assoc is not type + name (12)");
1570 } else
1571 throw new IllegalArgumentException(
1572 "Invalid class file (or parsing is wrong), Assoc is not method ref! (10)");
1573 } else
Stuart McCulloch2286f232012-06-15 13:27:53 +00001574 throw new IllegalArgumentException("Invalid class file (or parsing is wrong), Not an assoc at a method ref");
Stuart McCullochbb014372012-06-07 21:57:32 +00001575 }
1576
1577 public boolean isPublic() {
1578 return Modifier.isPublic(accessx);
1579 }
1580
1581 public boolean isProtected() {
1582 return Modifier.isProtected(accessx);
1583 }
1584
1585 public boolean isEnum() {
1586 return zuper != null && zuper.getBinary().equals("java/lang/Enum");
1587 }
1588
1589 public JAVA getFormat() {
1590 return JAVA.format(major);
1591
1592 }
1593
1594 public static String objectDescriptorToFQN(String string) {
1595 if (string.startsWith("L") && string.endsWith(";"))
1596 return string.substring(1, string.length() - 1).replace('/', '.');
1597
1598 switch (string.charAt(0)) {
Stuart McCulloch2286f232012-06-15 13:27:53 +00001599 case 'V' :
1600 return "void";
1601 case 'B' :
1602 return "byte";
1603 case 'C' :
1604 return "char";
1605 case 'I' :
1606 return "int";
1607 case 'S' :
1608 return "short";
1609 case 'D' :
1610 return "double";
1611 case 'F' :
1612 return "float";
1613 case 'J' :
1614 return "long";
1615 case 'Z' :
1616 return "boolean";
1617 case '[' : // Array
1618 return objectDescriptorToFQN(string.substring(1)) + "[]";
Stuart McCullochbb014372012-06-07 21:57:32 +00001619 }
1620 throw new IllegalArgumentException("Invalid type character in descriptor " + string);
1621 }
1622
1623 public static String unCamel(String id) {
1624 StringBuilder out = new StringBuilder();
1625 for (int i = 0; i < id.length(); i++) {
1626 char c = id.charAt(i);
1627 if (c == '_' || c == '$' || c == '.') {
1628 if (out.length() > 0 && !Character.isWhitespace(out.charAt(out.length() - 1)))
1629 out.append(' ');
1630 continue;
1631 }
1632
1633 int n = i;
1634 while (n < id.length() && Character.isUpperCase(id.charAt(n))) {
1635 n++;
1636 }
1637 if (n == i)
1638 out.append(id.charAt(i));
1639 else {
1640 boolean tolower = (n - i) == 1;
1641 if (i > 0 && !Character.isWhitespace(out.charAt(out.length() - 1)))
1642 out.append(' ');
1643
1644 for (; i < n;) {
1645 if (tolower)
1646 out.append(Character.toLowerCase(id.charAt(i)));
1647 else
1648 out.append(id.charAt(i));
1649 i++;
1650 }
1651 i--;
1652 }
1653 }
1654 if (id.startsWith("."))
1655 out.append(" *");
1656 out.replace(0, 1, Character.toUpperCase(out.charAt(0)) + "");
1657 return out.toString();
1658 }
1659
1660 public boolean isInterface() {
1661 return Modifier.isInterface(accessx);
1662 }
1663
1664 public boolean isAbstract() {
1665 return Modifier.isAbstract(accessx);
1666 }
1667
1668 public int getAccess() {
1669 if (innerAccess == -1)
1670 return accessx;
Stuart McCullochd4826102012-06-26 16:34:24 +00001671 return innerAccess;
Stuart McCullochbb014372012-06-07 21:57:32 +00001672 }
1673
1674 public TypeRef getClassName() {
1675 return className;
1676 }
1677
1678 /**
1679 * To provide an enclosing instance
1680 *
1681 * @param access
1682 * @param name
1683 * @param descriptor
1684 * @return
1685 */
1686 public MethodDef getMethodDef(int access, String name, String descriptor) {
1687 return new MethodDef(access, name, descriptor);
1688 }
1689
1690 public TypeRef getSuper() {
1691 return zuper;
1692 }
1693
1694 public String getFQN() {
1695 return className.getFQN();
1696 }
1697
1698 public TypeRef[] getInterfaces() {
1699 return interfaces;
1700 }
1701
1702 public void setInnerAccess(int access) {
1703 innerAccess = access;
1704 }
1705
1706 public boolean isFinal() {
1707 return Modifier.isFinal(accessx);
1708 }
1709
1710 public void setDeprecated(boolean b) {
1711 deprecated = b;
1712 }
1713
1714 public boolean isDeprecated() {
1715 return deprecated;
1716 }
1717
1718 public boolean isAnnotation() {
1719 return (accessx & ACC_ANNOTATION) != 0;
1720 }
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001721
1722 public Set<PackageRef> getAPIUses() {
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001723 if (api == null)
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001724 return Collections.emptySet();
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001725 return api;
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001726 }
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001727
1728 public Clazz.TypeDef getExtends(TypeRef type) {
1729 return new TypeDef(type, false);
1730 }
1731
1732 public Clazz.TypeDef getImplements(TypeRef type) {
1733 return new TypeDef(type, true);
1734 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001735}