blob: 391bf4596ba07c93d32f710ab1d07bcf577aaf35 [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 McCullocha5e1e902013-01-15 18:08:21 +0000864 else if ("AnnotationDefault".equals(attributeName))
865 doElementValue(in, member, RetentionPolicy.RUNTIME, cd!=null, access_flags);
Stuart McCullochb215bfd2012-09-06 18:28:06 +0000866 else if ("Exceptions".equals(attributeName))
867 doExceptions(in, access_flags);
868 else {
Stuart McCullochbb014372012-06-07 21:57:32 +0000869 if (attribute_length > 0x7FFFFFFF) {
870 throw new IllegalArgumentException("Attribute > 2Gb");
871 }
872 in.skipBytes((int) attribute_length);
873 }
874 }
875
876 /**
877 * <pre>
878 * EnclosingMethod_attribute {
879 * u2 attribute_name_index;
880 * u4 attribute_length;
881 * u2 class_index
882 * u2 method_index;
883 * }
884 * </pre>
885 *
Stuart McCullochbb014372012-06-07 21:57:32 +0000886 * @param in
887 * @throws IOException
888 */
889 private void doEnclosingMethod(DataInputStream in) throws IOException {
890 int cIndex = in.readShort();
891 int mIndex = in.readShort();
892
893 if (cd != null) {
894 int nameIndex = intPool[cIndex];
895 TypeRef cName = analyzer.getTypeRef((String) pool[nameIndex]);
896
897 String mName = null;
898 String mDescriptor = null;
899
900 if (mIndex != 0) {
901 Assoc nameAndType = (Assoc) pool[mIndex];
902 mName = (String) pool[nameAndType.a];
903 mDescriptor = (String) pool[nameAndType.b];
904 }
905 cd.enclosingMethod(cName, mName, mDescriptor);
906 }
907 }
908
909 /**
910 * <pre>
911 * InnerClasses_attribute {
912 * u2 attribute_name_index;
913 * u4 attribute_length;
914 * u2 number_of_classes; {
915 * u2 inner_class_info_index;
916 * u2 outer_class_info_index;
917 * u2 inner_name_index;
918 * u2 inner_class_access_flags;
919 * } classes[number_of_classes];
920 * }
921 * </pre>
922 *
923 * @param in
924 * @throws Exception
925 */
926 private void doInnerClasses(DataInputStream in) throws Exception {
927 int number_of_classes = in.readShort();
928 for (int i = 0; i < number_of_classes; i++) {
929 int inner_class_info_index = in.readShort();
930 int outer_class_info_index = in.readShort();
931 int inner_name_index = in.readShort();
932 int inner_class_access_flags = in.readShort() & 0xFFFF;
933
934 if (cd != null) {
935 TypeRef innerClass = null;
936 TypeRef outerClass = null;
937 String innerName = null;
938
939 if (inner_class_info_index != 0) {
940 int nameIndex = intPool[inner_class_info_index];
941 innerClass = analyzer.getTypeRef((String) pool[nameIndex]);
942 }
943
944 if (outer_class_info_index != 0) {
945 int nameIndex = intPool[outer_class_info_index];
946 outerClass = analyzer.getTypeRef((String) pool[nameIndex]);
947 }
948
949 if (inner_name_index != 0)
950 innerName = (String) pool[inner_name_index];
951
952 cd.innerClass(innerClass, outerClass, innerName, inner_class_access_flags);
953 }
954 }
955 }
956
957 /**
958 * Handle a signature
959 *
960 * <pre>
961 * Signature_attribute {
962 * u2 attribute_name_index;
963 * u4 attribute_length;
964 * u2 signature_index;
965 * }
966 * </pre>
967 *
968 * @param member
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +0000969 * @param access_flags
Stuart McCullochbb014372012-06-07 21:57:32 +0000970 */
971
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000972 void doSignature(DataInputStream in, ElementType member, int access_flags) throws IOException {
Stuart McCullochbb014372012-06-07 21:57:32 +0000973 int signature_index = in.readUnsignedShort();
974 String signature = (String) pool[signature_index];
975
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +0000976 parseDescriptor(signature, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +0000977
978 if (last != null)
979 last.signature = signature;
980
981 if (cd != null)
982 cd.signature(signature);
983 }
984
985 /**
986 * Handle a constant value call the data collector with it
987 */
988 void doConstantValue(DataInputStream in) throws IOException {
989 int constantValue_index = in.readUnsignedShort();
990 if (cd == null)
991 return;
992
993 Object object = pool[constantValue_index];
994 if (object == null)
995 object = pool[intPool[constantValue_index]];
996
997 last.constant = object;
998 cd.constant(object);
999 }
1000
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001001 void doExceptions(DataInputStream in, int access_flags) throws IOException {
1002 int exception_count = in.readUnsignedShort();
1003 for (int i = 0; i < exception_count; i++) {
1004 int index = in.readUnsignedShort();
1005 if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags))) {
1006 ClassConstant cc = (ClassConstant) pool[index];
1007 String descr = (String) pool[cc.cname];
1008
1009 TypeRef clazz = analyzer.getTypeRef(descr);
1010 referTo(clazz, access_flags);
1011 }
1012 }
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001013 }
1014
Stuart McCullochbb014372012-06-07 21:57:32 +00001015 /**
1016 * <pre>
1017 * Code_attribute {
1018 * u2 attribute_name_index;
1019 * u4 attribute_length;
1020 * u2 max_stack;
1021 * u2 max_locals;
1022 * u4 code_length;
1023 * u1 code[code_length];
1024 * u2 exception_table_length;
1025 * { u2 start_pc;
1026 * u2 end_pc;
1027 * u2 handler_pc;
1028 * u2 catch_type;
1029 * } exception_table[exception_table_length];
1030 * u2 attributes_count;
1031 * attribute_info attributes[attributes_count];
1032 * }
1033 * </pre>
1034 *
1035 * @param in
1036 * @param pool
1037 * @throws Exception
1038 */
1039 private void doCode(DataInputStream in) throws Exception {
1040 /* int max_stack = */in.readUnsignedShort();
1041 /* int max_locals = */in.readUnsignedShort();
1042 int code_length = in.readInt();
1043 byte code[] = new byte[code_length];
1044 in.readFully(code);
1045 crawl(code);
1046 int exception_table_length = in.readUnsignedShort();
1047 in.skipBytes(exception_table_length * 8);
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001048 doAttributes(in, ElementType.METHOD, false, 0);
Stuart McCullochbb014372012-06-07 21:57:32 +00001049 }
1050
1051 /**
1052 * We must find Class.forName references ...
1053 *
1054 * @param code
1055 */
1056 protected void crawl(byte[] code) {
1057 ByteBuffer bb = ByteBuffer.wrap(code);
1058 bb.order(ByteOrder.BIG_ENDIAN);
1059 int lastReference = -1;
1060
1061 while (bb.remaining() > 0) {
1062 int instruction = 0xFF & bb.get();
1063 switch (instruction) {
Stuart McCulloch2286f232012-06-15 13:27:53 +00001064 case OpCodes.ldc :
1065 lastReference = 0xFF & bb.get();
1066 break;
Stuart McCullochbb014372012-06-07 21:57:32 +00001067
Stuart McCulloch2286f232012-06-15 13:27:53 +00001068 case OpCodes.ldc_w :
1069 lastReference = 0xFFFF & bb.getShort();
1070 break;
Stuart McCullochbb014372012-06-07 21:57:32 +00001071
Stuart McCulloch2286f232012-06-15 13:27:53 +00001072 case OpCodes.invokespecial : {
1073 int mref = 0xFFFF & bb.getShort();
1074 if (cd != null)
1075 getMethodDef(0, mref);
1076 break;
1077 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001078
Stuart McCulloch2286f232012-06-15 13:27:53 +00001079 case OpCodes.invokevirtual : {
1080 int mref = 0xFFFF & bb.getShort();
1081 if (cd != null)
1082 getMethodDef(0, mref);
1083 break;
1084 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001085
Stuart McCulloch2286f232012-06-15 13:27:53 +00001086 case OpCodes.invokeinterface : {
1087 int mref = 0xFFFF & bb.getShort();
1088 if (cd != null)
1089 getMethodDef(0, mref);
1090 break;
1091 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001092
Stuart McCulloch2286f232012-06-15 13:27:53 +00001093 case OpCodes.invokestatic : {
1094 int methodref = 0xFFFF & bb.getShort();
1095 if (cd != null)
1096 getMethodDef(0, methodref);
Stuart McCullochbb014372012-06-07 21:57:32 +00001097
Stuart McCulloch2286f232012-06-15 13:27:53 +00001098 if ((methodref == forName || methodref == class$) && lastReference != -1
1099 && pool[intPool[lastReference]] instanceof String) {
1100 String fqn = (String) pool[intPool[lastReference]];
1101 if (!fqn.equals("class") && fqn.indexOf('.') > 0) {
1102 TypeRef clazz = analyzer.getTypeRefFromFQN(fqn);
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001103 referTo(clazz, 0);
Stuart McCulloch2286f232012-06-15 13:27:53 +00001104 }
1105 lastReference = -1;
1106 }
1107 break;
1108 }
1109
1110 case OpCodes.tableswitch :
1111 // Skip to place divisible by 4
1112 while ((bb.position() & 0x3) != 0)
1113 bb.get();
1114 /* int deflt = */
1115 bb.getInt();
1116 int low = bb.getInt();
1117 int high = bb.getInt();
1118 try {
1119 bb.position(bb.position() + (high - low + 1) * 4);
1120 }
1121 catch (Exception e) {
1122 // TODO Auto-generated catch block
1123 e.printStackTrace();
Stuart McCullochbb014372012-06-07 21:57:32 +00001124 }
1125 lastReference = -1;
Stuart McCulloch2286f232012-06-15 13:27:53 +00001126 break;
Stuart McCullochbb014372012-06-07 21:57:32 +00001127
Stuart McCulloch2286f232012-06-15 13:27:53 +00001128 case OpCodes.lookupswitch :
1129 // Skip to place divisible by 4
1130 while ((bb.position() & 0x3) != 0)
1131 bb.get();
1132 /* deflt = */
1133 bb.getInt();
1134 int npairs = bb.getInt();
1135 bb.position(bb.position() + npairs * 8);
1136 lastReference = -1;
1137 break;
Stuart McCullochbb014372012-06-07 21:57:32 +00001138
Stuart McCulloch2286f232012-06-15 13:27:53 +00001139 default :
1140 lastReference = -1;
1141 bb.position(bb.position() + OpCodes.OFFSETS[instruction]);
Stuart McCullochbb014372012-06-07 21:57:32 +00001142 }
1143 }
1144 }
1145
1146 private void doSourceFile(DataInputStream in) throws IOException {
1147 int sourcefile_index = in.readUnsignedShort();
1148 this.sourceFile = pool[sourcefile_index].toString();
1149 }
1150
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001151 private void doParameterAnnotations(DataInputStream in, ElementType member, RetentionPolicy policy, int access_flags)
Stuart McCulloch2286f232012-06-15 13:27:53 +00001152 throws IOException {
Stuart McCullochbb014372012-06-07 21:57:32 +00001153 int num_parameters = in.readUnsignedByte();
1154 for (int p = 0; p < num_parameters; p++) {
1155 if (cd != null)
1156 cd.parameter(p);
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001157 doAnnotations(in, member, policy, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +00001158 }
1159 }
1160
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001161 private void doAnnotations(DataInputStream in, ElementType member, RetentionPolicy policy, int access_flags)
1162 throws IOException {
Stuart McCullochbb014372012-06-07 21:57:32 +00001163 int num_annotations = in.readUnsignedShort(); // # of annotations
1164 for (int a = 0; a < num_annotations; a++) {
1165 if (cd == null)
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001166 doAnnotation(in, member, policy, false, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +00001167 else {
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001168 Annotation annotion = doAnnotation(in, member, policy, true, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +00001169 cd.annotation(annotion);
1170 }
1171 }
1172 }
1173
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001174 private Annotation doAnnotation(DataInputStream in, ElementType member, RetentionPolicy policy, boolean collect,
1175 int access_flags) throws IOException {
Stuart McCullochbb014372012-06-07 21:57:32 +00001176 int type_index = in.readUnsignedShort();
1177 if (annotations == null)
1178 annotations = new HashSet<TypeRef>();
1179
1180 TypeRef tr = analyzer.getTypeRef(pool[type_index].toString());
1181 annotations.add(tr);
1182
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001183 TypeRef name = analyzer.getTypeRef((String) pool[type_index]);
Stuart McCullochbb014372012-06-07 21:57:32 +00001184 if (policy == RetentionPolicy.RUNTIME) {
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001185 referTo(type_index, 0);
Stuart McCullochbb014372012-06-07 21:57:32 +00001186 hasRuntimeAnnotations = true;
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001187 if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags)))
1188 api.add(name.getPackageRef());
Stuart McCullochbb014372012-06-07 21:57:32 +00001189 } else {
1190 hasClassAnnotations = true;
1191 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001192 int num_element_value_pairs = in.readUnsignedShort();
Stuart McCulloch2286f232012-06-15 13:27:53 +00001193 Map<String,Object> elements = null;
Stuart McCullochbb014372012-06-07 21:57:32 +00001194 for (int v = 0; v < num_element_value_pairs; v++) {
1195 int element_name_index = in.readUnsignedShort();
1196 String element = (String) pool[element_name_index];
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001197 Object value = doElementValue(in, member, policy, collect, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +00001198 if (collect) {
1199 if (elements == null)
Stuart McCulloch2286f232012-06-15 13:27:53 +00001200 elements = new LinkedHashMap<String,Object>();
Stuart McCullochbb014372012-06-07 21:57:32 +00001201 elements.put(element, value);
1202 }
1203 }
1204 if (collect)
1205 return new Annotation(name, elements, member, policy);
Stuart McCullochd4826102012-06-26 16:34:24 +00001206 return null;
Stuart McCullochbb014372012-06-07 21:57:32 +00001207 }
1208
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001209 private Object doElementValue(DataInputStream in, ElementType member, RetentionPolicy policy, boolean collect,
1210 int access_flags) throws IOException {
Stuart McCullochbb014372012-06-07 21:57:32 +00001211 char tag = (char) in.readUnsignedByte();
1212 switch (tag) {
Stuart McCulloch2286f232012-06-15 13:27:53 +00001213 case 'B' : // Byte
1214 case 'C' : // Character
1215 case 'I' : // Integer
1216 case 'S' : // Short
1217 int const_value_index = in.readUnsignedShort();
1218 return intPool[const_value_index];
Stuart McCullochbb014372012-06-07 21:57:32 +00001219
Stuart McCulloch2286f232012-06-15 13:27:53 +00001220 case 'D' : // Double
1221 case 'F' : // Float
1222 case 's' : // String
1223 case 'J' : // Long
1224 const_value_index = in.readUnsignedShort();
1225 return pool[const_value_index];
Stuart McCullochbb014372012-06-07 21:57:32 +00001226
Stuart McCulloch2286f232012-06-15 13:27:53 +00001227 case 'Z' : // Boolean
1228 const_value_index = in.readUnsignedShort();
1229 return pool[const_value_index] == null || pool[const_value_index].equals(0) ? false : true;
Stuart McCullochbb014372012-06-07 21:57:32 +00001230
Stuart McCulloch2286f232012-06-15 13:27:53 +00001231 case 'e' : // enum constant
1232 int type_name_index = in.readUnsignedShort();
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001233 if (policy == RetentionPolicy.RUNTIME) {
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001234 referTo(type_name_index, 0);
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001235 if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags))) {
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001236 TypeRef name = analyzer.getTypeRef((String) pool[type_name_index]);
1237 api.add(name.getPackageRef());
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001238 }
1239 }
Stuart McCulloch2286f232012-06-15 13:27:53 +00001240 int const_name_index = in.readUnsignedShort();
1241 return pool[const_name_index];
Stuart McCullochbb014372012-06-07 21:57:32 +00001242
Stuart McCulloch2286f232012-06-15 13:27:53 +00001243 case 'c' : // Class
1244 int class_info_index = in.readUnsignedShort();
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001245 if (policy == RetentionPolicy.RUNTIME) {
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001246 referTo(class_info_index, 0);
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001247 if (api != null && (Modifier.isPublic(access_flags) || Modifier.isProtected(access_flags))) {
Stuart McCullochb215bfd2012-09-06 18:28:06 +00001248 TypeRef name = analyzer.getTypeRef((String) pool[class_info_index]);
1249 api.add(name.getPackageRef());
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001250 }
1251 }
Stuart McCulloch2286f232012-06-15 13:27:53 +00001252 return pool[class_info_index];
Stuart McCullochbb014372012-06-07 21:57:32 +00001253
Stuart McCulloch2286f232012-06-15 13:27:53 +00001254 case '@' : // Annotation type
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001255 return doAnnotation(in, member, policy, collect, access_flags);
Stuart McCullochbb014372012-06-07 21:57:32 +00001256
Stuart McCulloch2286f232012-06-15 13:27:53 +00001257 case '[' : // Array
1258 int num_values = in.readUnsignedShort();
1259 Object[] result = new Object[num_values];
1260 for (int i = 0; i < num_values; i++) {
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001261 result[i] = doElementValue(in, member, policy, collect, access_flags);
Stuart McCulloch2286f232012-06-15 13:27:53 +00001262 }
1263 return result;
Stuart McCullochbb014372012-06-07 21:57:32 +00001264
Stuart McCulloch2286f232012-06-15 13:27:53 +00001265 default :
1266 throw new IllegalArgumentException("Invalid value for Annotation ElementValue tag " + tag);
Stuart McCullochbb014372012-06-07 21:57:32 +00001267 }
1268 }
1269
1270 /**
1271 * Add a new package reference.
1272 *
1273 * @param packageRef
1274 * A '.' delimited package name
1275 */
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001276 void referTo(TypeRef typeRef, int modifiers) {
Stuart McCullochbb014372012-06-07 21:57:32 +00001277 if (xref != null)
1278 xref.add(typeRef);
1279 if (typeRef.isPrimitive())
1280 return;
1281
1282 PackageRef packageRef = typeRef.getPackageRef();
1283 if (packageRef.isPrimitivePackage())
1284 return;
1285
1286 imports.add(packageRef);
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001287
1288 if (api != null && (Modifier.isPublic(modifiers) || Modifier.isProtected(modifiers)))
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001289 api.add(packageRef);
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001290
1291 if (cd != null)
1292 cd.referTo(typeRef, modifiers);
1293
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001294 }
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001295
1296 void referTo(int index, int modifiers) {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001297 String descriptor = (String) pool[index];
1298 parseDescriptor(descriptor, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001299 }
1300
1301 /**
1302 * This method parses a descriptor and adds the package of the descriptor to
Stuart McCulloch2286f232012-06-15 13:27:53 +00001303 * the referenced packages. The syntax of the descriptor is:
Stuart McCullochbb014372012-06-07 21:57:32 +00001304 *
1305 * <pre>
1306 * descriptor ::= ( '(' reference * ')' )? reference
1307 * reference ::= 'L' classname ( '&lt;' references '&gt;' )? ';' | 'B' | 'Z' | ... | '+' | '-' | '['
1308 * </pre>
1309 *
1310 * This methods uses heavy recursion to parse the descriptor and a roving
1311 * pointer to limit the creation of string objects.
1312 *
1313 * @param descriptor
1314 * The to be parsed descriptor
1315 * @param rover
1316 * The pointer to start at
1317 */
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001318
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001319 public void parseDescriptor(String descriptor, int modifiers) {
Stuart McCullochbb014372012-06-07 21:57:32 +00001320 // Some descriptors are weird, they start with a generic
1321 // declaration that contains ':', not sure what they mean ...
1322 int rover = 0;
1323 if (descriptor.charAt(0) == '<') {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001324 rover = parseFormalTypeParameters(descriptor, rover, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001325 }
1326
1327 if (descriptor.charAt(rover) == '(') {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001328 rover = parseReferences(descriptor, rover + 1, ')', modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001329 rover++;
1330 }
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001331 parseReferences(descriptor, rover, (char) 0, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001332 }
1333
1334 /**
1335 * Parse a sequence of references. A sequence ends with a given character or
1336 * when the string ends.
1337 *
1338 * @param descriptor
1339 * The whole descriptor.
1340 * @param rover
1341 * The index in the descriptor
1342 * @param delimiter
1343 * The end character or 0
1344 * @return the last index processed, one character after the delimeter
1345 */
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001346 int parseReferences(String descriptor, int rover, char delimiter, int modifiers) {
Stuart McCullochbb014372012-06-07 21:57:32 +00001347 int r = rover;
1348 while (r < descriptor.length() && descriptor.charAt(r) != delimiter) {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001349 r = parseReference(descriptor, r, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001350 }
1351 return r;
1352 }
1353
1354 /**
1355 * Parse a single reference. This can be a single character or an object
1356 * reference when it starts with 'L'.
1357 *
1358 * @param descriptor
1359 * The descriptor
1360 * @param rover
1361 * The place to start
1362 * @return The return index after the reference
1363 */
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001364 int parseReference(String descriptor, int rover, int modifiers) {
Stuart McCullochbb014372012-06-07 21:57:32 +00001365 int r = rover;
1366 char c = descriptor.charAt(r);
1367 while (c == '[')
1368 c = descriptor.charAt(++r);
1369
1370 if (c == '<') {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001371 r = parseReferences(descriptor, r + 1, '>', modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001372 } else if (c == 'T') {
1373 // Type variable name
1374 r++;
1375 while (descriptor.charAt(r) != ';')
1376 r++;
1377 } else if (c == 'L') {
1378 StringBuilder sb = new StringBuilder();
1379 r++;
1380 while ((c = descriptor.charAt(r)) != ';') {
1381 if (c == '<') {
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001382 r = parseReferences(descriptor, r + 1, '>', modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001383 } else
1384 sb.append(c);
1385 r++;
1386 }
1387 TypeRef ref = analyzer.getTypeRef(sb.toString());
1388 if (cd != null)
1389 cd.addReference(ref);
1390
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001391 referTo(ref, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001392 } else {
1393 if ("+-*BCDFIJSZV".indexOf(c) < 0)
1394 ;// System.err.println("Should not skip: " + c);
1395 }
1396
1397 // this skips a lot of characters
1398 // [, *, +, -, B, etc.
1399
1400 return r + 1;
1401 }
1402
1403 /**
1404 * FormalTypeParameters
1405 *
1406 * @param descriptor
1407 * @param index
1408 * @return
1409 */
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001410 private int parseFormalTypeParameters(String descriptor, int index, int modifiers) {
Stuart McCullochbb014372012-06-07 21:57:32 +00001411 index++;
1412 while (descriptor.charAt(index) != '>') {
1413 // Skip IDENTIFIER
1414 index = descriptor.indexOf(':', index) + 1;
1415 if (index == 0)
1416 throw new IllegalArgumentException("Expected IDENTIFIER: " + descriptor);
1417
1418 // ClassBound? InterfaceBounds
1419
1420 char c = descriptor.charAt(index);
1421
1422 // Class Bound?
1423 if (c == 'L' || c == 'T') {
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001424 index = parseReference(descriptor, index, modifiers); // class
1425 // reference
Stuart McCullochbb014372012-06-07 21:57:32 +00001426 c = descriptor.charAt(index);
1427 }
1428
1429 // Interface Bounds
1430 while (c == ':') {
1431 index++;
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001432 index = parseReference(descriptor, index, modifiers);
Stuart McCullochbb014372012-06-07 21:57:32 +00001433 c = descriptor.charAt(index);
1434 } // for each interface
1435
1436 } // for each formal parameter
1437 return index + 1; // skip >
1438 }
1439
1440 public Set<PackageRef> getReferred() {
1441 return imports;
1442 }
1443
1444 public String getAbsolutePath() {
1445 return path;
1446 }
1447
1448 public String getSourceFile() {
1449 return sourceFile;
1450 }
1451
1452 /**
Stuart McCulloch2286f232012-06-15 13:27:53 +00001453 * .class construct for different compilers sun 1.1 Detect static variable
1454 * class$com$acme$MyClass 1.2 " 1.3 " 1.4 " 1.5 ldc_w (class) 1.6 " eclipse
1455 * 1.1 class$0, ldc (string), invokestatic Class.forName 1.2 " 1.3 " 1.5 ldc
1456 * (class) 1.6 " 1.5 and later is not an issue, sun pre 1.5 is easy to
1457 * detect the static variable that decodes the class name. For eclipse, the
1458 * class$0 gives away we have a reference encoded in a string.
Stuart McCullochbb014372012-06-07 21:57:32 +00001459 * compilerversions/compilerversions.jar contains test versions of all
1460 * versions/compilers.
1461 */
1462
1463 public void reset() {
1464 pool = null;
1465 intPool = null;
1466 xref = null;
Stuart McCullochbb014372012-06-07 21:57:32 +00001467 }
1468
1469 public boolean is(QUERY query, Instruction instr, Analyzer analyzer) throws Exception {
1470 switch (query) {
Stuart McCulloch2286f232012-06-15 13:27:53 +00001471 case ANY :
1472 return true;
Stuart McCullochbb014372012-06-07 21:57:32 +00001473
Stuart McCulloch2286f232012-06-15 13:27:53 +00001474 case NAMED :
1475 if (instr.matches(getClassName().getDottedOnly()))
Stuart McCullochbb014372012-06-07 21:57:32 +00001476 return !instr.isNegated();
Stuart McCullochbb014372012-06-07 21:57:32 +00001477 return false;
1478
Stuart McCulloch2286f232012-06-15 13:27:53 +00001479 case VERSION :
1480 String v = major + "." + minor;
1481 if (instr.matches(v))
1482 return !instr.isNegated();
Stuart McCullochbb014372012-06-07 21:57:32 +00001483 return false;
1484
Stuart McCulloch2286f232012-06-15 13:27:53 +00001485 case IMPLEMENTS :
1486 for (int i = 0; interfaces != null && i < interfaces.length; i++) {
1487 if (instr.matches(interfaces[i].getDottedOnly()))
1488 return !instr.isNegated();
1489 }
1490 break;
1491
1492 case EXTENDS :
1493 if (zuper == null)
1494 return false;
1495
1496 if (instr.matches(zuper.getDottedOnly()))
Stuart McCullochbb014372012-06-07 21:57:32 +00001497 return !instr.isNegated();
Stuart McCulloch2286f232012-06-15 13:27:53 +00001498 break;
Stuart McCullochbb014372012-06-07 21:57:32 +00001499
Stuart McCulloch2286f232012-06-15 13:27:53 +00001500 case PUBLIC :
1501 return Modifier.isPublic(accessx);
Stuart McCullochbb014372012-06-07 21:57:32 +00001502
Stuart McCulloch2286f232012-06-15 13:27:53 +00001503 case CONCRETE :
1504 return !Modifier.isAbstract(accessx);
Stuart McCullochbb014372012-06-07 21:57:32 +00001505
Stuart McCulloch2286f232012-06-15 13:27:53 +00001506 case ANNOTATED :
1507 if (annotations == null)
1508 return false;
Stuart McCullochbb014372012-06-07 21:57:32 +00001509
Stuart McCulloch2286f232012-06-15 13:27:53 +00001510 for (TypeRef annotation : annotations) {
1511 if (instr.matches(annotation.getFQN()))
1512 return !instr.isNegated();
1513 }
1514
1515 return false;
1516
1517 case RUNTIMEANNOTATIONS :
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +00001518 return hasRuntimeAnnotations;
Stuart McCulloch2286f232012-06-15 13:27:53 +00001519 case CLASSANNOTATIONS :
1520 return hasClassAnnotations;
1521
1522 case ABSTRACT :
1523 return Modifier.isAbstract(accessx);
1524
1525 case IMPORTS :
1526 for (PackageRef imp : imports) {
1527 if (instr.matches(imp.getFQN()))
1528 return !instr.isNegated();
1529 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001530 }
1531
1532 if (zuper == null)
1533 return false;
1534
1535 Clazz clazz = analyzer.findClass(zuper);
1536 if (clazz == null)
1537 return false;
1538
1539 return clazz.is(query, instr, analyzer);
1540 }
1541
Stuart McCulloch55d4dfe2012-08-07 10:57:21 +00001542 @Override
Stuart McCullochbb014372012-06-07 21:57:32 +00001543 public String toString() {
1544 return className.getFQN();
1545 }
1546
1547 /**
1548 * Called when crawling the byte code and a method reference is found
Stuart McCullochbb014372012-06-07 21:57:32 +00001549 */
1550 void getMethodDef(int access, int methodRefPoolIndex) {
Stuart McCulloch2286f232012-06-15 13:27:53 +00001551 if (methodRefPoolIndex == 0)
Stuart McCullochbb014372012-06-07 21:57:32 +00001552 return;
Stuart McCulloch2286f232012-06-15 13:27:53 +00001553
Stuart McCullochbb014372012-06-07 21:57:32 +00001554 Object o = pool[methodRefPoolIndex];
1555 if (o != null && o instanceof Assoc) {
1556 Assoc assoc = (Assoc) o;
1557 if (assoc.tag == 10) {
1558 int string_index = intPool[assoc.a];
1559 TypeRef className = analyzer.getTypeRef((String) pool[string_index]);
1560 int name_and_type_index = assoc.b;
1561 Assoc name_and_type = (Assoc) pool[name_and_type_index];
1562 if (name_and_type.tag == 12) {
1563 // Name and Type
1564 int name_index = name_and_type.a;
1565 int type_index = name_and_type.b;
1566 String method = (String) pool[name_index];
1567 String descriptor = (String) pool[type_index];
1568 cd.referenceMethod(access, className, method, descriptor);
1569 } else
1570 throw new IllegalArgumentException(
1571 "Invalid class file (or parsing is wrong), assoc is not type + name (12)");
1572 } else
1573 throw new IllegalArgumentException(
1574 "Invalid class file (or parsing is wrong), Assoc is not method ref! (10)");
1575 } else
Stuart McCulloch2286f232012-06-15 13:27:53 +00001576 throw new IllegalArgumentException("Invalid class file (or parsing is wrong), Not an assoc at a method ref");
Stuart McCullochbb014372012-06-07 21:57:32 +00001577 }
1578
1579 public boolean isPublic() {
1580 return Modifier.isPublic(accessx);
1581 }
1582
1583 public boolean isProtected() {
1584 return Modifier.isProtected(accessx);
1585 }
1586
1587 public boolean isEnum() {
1588 return zuper != null && zuper.getBinary().equals("java/lang/Enum");
1589 }
1590
1591 public JAVA getFormat() {
1592 return JAVA.format(major);
1593
1594 }
1595
1596 public static String objectDescriptorToFQN(String string) {
1597 if (string.startsWith("L") && string.endsWith(";"))
1598 return string.substring(1, string.length() - 1).replace('/', '.');
1599
1600 switch (string.charAt(0)) {
Stuart McCulloch2286f232012-06-15 13:27:53 +00001601 case 'V' :
1602 return "void";
1603 case 'B' :
1604 return "byte";
1605 case 'C' :
1606 return "char";
1607 case 'I' :
1608 return "int";
1609 case 'S' :
1610 return "short";
1611 case 'D' :
1612 return "double";
1613 case 'F' :
1614 return "float";
1615 case 'J' :
1616 return "long";
1617 case 'Z' :
1618 return "boolean";
1619 case '[' : // Array
1620 return objectDescriptorToFQN(string.substring(1)) + "[]";
Stuart McCullochbb014372012-06-07 21:57:32 +00001621 }
1622 throw new IllegalArgumentException("Invalid type character in descriptor " + string);
1623 }
1624
1625 public static String unCamel(String id) {
1626 StringBuilder out = new StringBuilder();
1627 for (int i = 0; i < id.length(); i++) {
1628 char c = id.charAt(i);
1629 if (c == '_' || c == '$' || c == '.') {
1630 if (out.length() > 0 && !Character.isWhitespace(out.charAt(out.length() - 1)))
1631 out.append(' ');
1632 continue;
1633 }
1634
1635 int n = i;
1636 while (n < id.length() && Character.isUpperCase(id.charAt(n))) {
1637 n++;
1638 }
1639 if (n == i)
1640 out.append(id.charAt(i));
1641 else {
1642 boolean tolower = (n - i) == 1;
1643 if (i > 0 && !Character.isWhitespace(out.charAt(out.length() - 1)))
1644 out.append(' ');
1645
1646 for (; i < n;) {
1647 if (tolower)
1648 out.append(Character.toLowerCase(id.charAt(i)));
1649 else
1650 out.append(id.charAt(i));
1651 i++;
1652 }
1653 i--;
1654 }
1655 }
1656 if (id.startsWith("."))
1657 out.append(" *");
1658 out.replace(0, 1, Character.toUpperCase(out.charAt(0)) + "");
1659 return out.toString();
1660 }
1661
1662 public boolean isInterface() {
1663 return Modifier.isInterface(accessx);
1664 }
1665
1666 public boolean isAbstract() {
1667 return Modifier.isAbstract(accessx);
1668 }
1669
1670 public int getAccess() {
1671 if (innerAccess == -1)
1672 return accessx;
Stuart McCullochd4826102012-06-26 16:34:24 +00001673 return innerAccess;
Stuart McCullochbb014372012-06-07 21:57:32 +00001674 }
1675
1676 public TypeRef getClassName() {
1677 return className;
1678 }
1679
1680 /**
1681 * To provide an enclosing instance
1682 *
1683 * @param access
1684 * @param name
1685 * @param descriptor
1686 * @return
1687 */
1688 public MethodDef getMethodDef(int access, String name, String descriptor) {
1689 return new MethodDef(access, name, descriptor);
1690 }
1691
1692 public TypeRef getSuper() {
1693 return zuper;
1694 }
1695
1696 public String getFQN() {
1697 return className.getFQN();
1698 }
1699
1700 public TypeRef[] getInterfaces() {
1701 return interfaces;
1702 }
1703
1704 public void setInnerAccess(int access) {
1705 innerAccess = access;
1706 }
1707
1708 public boolean isFinal() {
1709 return Modifier.isFinal(accessx);
1710 }
1711
1712 public void setDeprecated(boolean b) {
1713 deprecated = b;
1714 }
1715
1716 public boolean isDeprecated() {
1717 return deprecated;
1718 }
1719
1720 public boolean isAnnotation() {
1721 return (accessx & ACC_ANNOTATION) != 0;
1722 }
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001723
1724 public Set<PackageRef> getAPIUses() {
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001725 if (api == null)
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001726 return Collections.emptySet();
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001727 return api;
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00001728 }
Stuart McCulloch3b7e6af2012-07-16 14:10:57 +00001729
1730 public Clazz.TypeDef getExtends(TypeRef type) {
1731 return new TypeDef(type, false);
1732 }
1733
1734 public Clazz.TypeDef getImplements(TypeRef type) {
1735 return new TypeDef(type, true);
1736 }
Stuart McCullochbb014372012-06-07 21:57:32 +00001737}