140 public static Finder getAPIFinder(int access) { |
140 public static Finder getAPIFinder(int access) { |
141 return new APIDependencyFinder(access); |
141 return new APIDependencyFinder(access); |
142 } |
142 } |
143 |
143 |
144 /** |
144 /** |
|
145 * Get a finder to do class dependency analysis. |
|
146 * |
|
147 * @return a Class dependency finder |
|
148 */ |
|
149 public static Finder getClassDependencyFinder() { |
|
150 return new ClassDependencyFinder(); |
|
151 } |
|
152 |
|
153 /** |
145 * Get the finder used to locate the dependencies for a class. |
154 * Get the finder used to locate the dependencies for a class. |
146 * @return the finder |
155 * @return the finder |
147 */ |
156 */ |
148 public Finder getFinder() { |
157 public Finder getFinder() { |
149 if (finder == null) |
158 if (finder == null) |
244 }; |
253 }; |
245 findAllDependencies(classFinder, rootClassNames, transitiveClosure, r); |
254 findAllDependencies(classFinder, rootClassNames, transitiveClosure, r); |
246 return results; |
255 return results; |
247 } |
256 } |
248 |
257 |
249 |
|
250 |
|
251 /** |
258 /** |
252 * Find the dependencies of a class, using the current |
259 * Find the dependencies of a class, using the current |
253 * {@link Dependencies#getFinder finder} and |
260 * {@link Dependencies#getFinder finder} and |
254 * {@link Dependencies#getFilter filter}. |
261 * {@link Dependencies#getFilter filter}. |
255 * The search may optionally include the transitive closure of all the |
262 * The search may optionally include the transitive closure of all the |
304 |
311 |
305 /** |
312 /** |
306 * A location identifying a class. |
313 * A location identifying a class. |
307 */ |
314 */ |
308 static class SimpleLocation implements Location { |
315 static class SimpleLocation implements Location { |
309 public SimpleLocation(String className) { |
316 public SimpleLocation(String name) { |
310 this.className = className; |
317 this.name = name; |
311 } |
318 this.className = name.replace('/', '.').replace('$', '.'); |
312 |
319 } |
313 /** |
320 |
314 * Get the name of the class being depended on. This name will be used to |
321 public String getName() { |
315 * locate the class file for transitive dependency analysis. |
322 return name; |
316 * @return the name of the class being depended on |
323 } |
317 */ |
324 |
318 public String getClassName() { |
325 public String getClassName() { |
319 return className; |
326 return className; |
|
327 } |
|
328 |
|
329 public String getPackageName() { |
|
330 int i = name.lastIndexOf('/'); |
|
331 return (i > 0) ? name.substring(0, i).replace('/', '.') : ""; |
320 } |
332 } |
321 |
333 |
322 @Override |
334 @Override |
323 public boolean equals(Object other) { |
335 public boolean equals(Object other) { |
324 if (this == other) |
336 if (this == other) |
325 return true; |
337 return true; |
326 if (!(other instanceof SimpleLocation)) |
338 if (!(other instanceof SimpleLocation)) |
327 return false; |
339 return false; |
328 return (className.equals(((SimpleLocation) other).className)); |
340 return (name.equals(((SimpleLocation) other).name)); |
329 } |
341 } |
330 |
342 |
331 @Override |
343 @Override |
332 public int hashCode() { |
344 public int hashCode() { |
333 return className.hashCode(); |
345 return name.hashCode(); |
334 } |
346 } |
335 |
347 |
336 @Override |
348 @Override |
337 public String toString() { |
349 public String toString() { |
338 return className; |
350 return name; |
339 } |
351 } |
340 |
352 |
|
353 private String name; |
341 private String className; |
354 private String className; |
342 } |
355 } |
343 |
356 |
344 /** |
357 /** |
345 * A dependency of one class on another. |
358 * A dependency of one class on another. |
429 this.packageNames = packageNames; |
442 this.packageNames = packageNames; |
430 this.matchSubpackages = matchSubpackages; |
443 this.matchSubpackages = matchSubpackages; |
431 } |
444 } |
432 |
445 |
433 public boolean accepts(Dependency dependency) { |
446 public boolean accepts(Dependency dependency) { |
434 String cn = dependency.getTarget().getClassName(); |
447 String pn = dependency.getTarget().getPackageName(); |
435 int lastSep = cn.lastIndexOf("/"); |
|
436 String pn = (lastSep == -1 ? "" : cn.substring(0, lastSep)); |
|
437 if (packageNames.contains(pn)) |
448 if (packageNames.contains(pn)) |
438 return true; |
449 return true; |
439 |
450 |
440 if (matchSubpackages) { |
451 if (matchSubpackages) { |
441 for (String n: packageNames) { |
452 for (String n: packageNames) { |
448 } |
459 } |
449 |
460 |
450 private final Set<String> packageNames; |
461 private final Set<String> packageNames; |
451 private final boolean matchSubpackages; |
462 private final boolean matchSubpackages; |
452 } |
463 } |
453 |
|
454 |
|
455 |
464 |
456 /** |
465 /** |
457 * This class identifies class names directly or indirectly in the constant pool. |
466 * This class identifies class names directly or indirectly in the constant pool. |
458 */ |
467 */ |
459 static class ClassDependencyFinder extends BasicDependencyFinder { |
468 static class ClassDependencyFinder extends BasicDependencyFinder { |
460 public Iterable<? extends Dependency> findDependencies(ClassFile classfile) { |
469 public Iterable<? extends Dependency> findDependencies(ClassFile classfile) { |
461 Visitor v = new Visitor(classfile); |
470 Visitor v = new Visitor(classfile); |
462 for (CPInfo cpInfo: classfile.constant_pool.entries()) { |
471 for (CPInfo cpInfo: classfile.constant_pool.entries()) { |
463 v.scan(cpInfo); |
472 v.scan(cpInfo); |
464 } |
473 } |
|
474 try { |
|
475 v.addClass(classfile.super_class); |
|
476 v.addClasses(classfile.interfaces); |
|
477 v.scan(classfile.attributes); |
|
478 |
|
479 for (Field f : classfile.fields) { |
|
480 v.scan(f.descriptor, f.attributes); |
|
481 } |
|
482 for (Method m : classfile.methods) { |
|
483 v.scan(m.descriptor, m.attributes); |
|
484 Exceptions_attribute e = |
|
485 (Exceptions_attribute)m.attributes.get(Attribute.Exceptions); |
|
486 if (e != null) { |
|
487 v.addClasses(e.exception_index_table); |
|
488 } |
|
489 } |
|
490 } catch (ConstantPoolException e) { |
|
491 throw new ClassFileError(e); |
|
492 } |
|
493 |
465 return v.deps; |
494 return v.deps; |
466 } |
495 } |
467 } |
496 } |
468 |
497 |
469 /** |
498 /** |
556 } |
585 } |
557 |
586 |
558 void scan(Descriptor d, Attributes attrs) { |
587 void scan(Descriptor d, Attributes attrs) { |
559 try { |
588 try { |
560 scan(new Signature(d.index).getType(constant_pool)); |
589 scan(new Signature(d.index).getType(constant_pool)); |
561 Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature); |
590 scan(attrs); |
562 if (sa != null) |
|
563 scan(new Signature(sa.signature_index).getType(constant_pool)); |
|
564 } catch (ConstantPoolException e) { |
591 } catch (ConstantPoolException e) { |
565 throw new ClassFileError(e); |
592 throw new ClassFileError(e); |
566 } |
593 } |
567 } |
594 } |
568 |
595 |
570 cpInfo.accept(this, null); |
597 cpInfo.accept(this, null); |
571 } |
598 } |
572 |
599 |
573 void scan(Type t) { |
600 void scan(Type t) { |
574 t.accept(this, null); |
601 t.accept(this, null); |
|
602 } |
|
603 |
|
604 void scan(Attributes attrs) { |
|
605 try { |
|
606 Signature_attribute sa = (Signature_attribute)attrs.get(Attribute.Signature); |
|
607 if (sa != null) |
|
608 scan(sa.getParsedSignature().getType(constant_pool)); |
|
609 |
|
610 scan((RuntimeVisibleAnnotations_attribute) |
|
611 attrs.get(Attribute.RuntimeVisibleAnnotations)); |
|
612 scan((RuntimeVisibleParameterAnnotations_attribute) |
|
613 attrs.get(Attribute.RuntimeVisibleParameterAnnotations)); |
|
614 } catch (ConstantPoolException e) { |
|
615 throw new ClassFileError(e); |
|
616 } |
|
617 } |
|
618 |
|
619 private void scan(RuntimeAnnotations_attribute attr) throws ConstantPoolException { |
|
620 if (attr == null) { |
|
621 return; |
|
622 } |
|
623 for (int i = 0; i < attr.annotations.length; i++) { |
|
624 int index = attr.annotations[i].type_index; |
|
625 scan(new Signature(index).getType(constant_pool)); |
|
626 } |
|
627 } |
|
628 |
|
629 private void scan(RuntimeParameterAnnotations_attribute attr) throws ConstantPoolException { |
|
630 if (attr == null) { |
|
631 return; |
|
632 } |
|
633 for (int param = 0; param < attr.parameter_annotations.length; param++) { |
|
634 for (int i = 0; i < attr.parameter_annotations[param].length; i++) { |
|
635 int index = attr.parameter_annotations[param][i].type_index; |
|
636 scan(new Signature(index).getType(constant_pool)); |
|
637 } |
|
638 } |
575 } |
639 } |
576 |
640 |
577 void addClass(int index) throws ConstantPoolException { |
641 void addClass(int index) throws ConstantPoolException { |
578 if (index != 0) { |
642 if (index != 0) { |
579 String name = constant_pool.getClassInfo(index).getBaseName(); |
643 String name = constant_pool.getClassInfo(index).getBaseName(); |
696 |
760 |
697 public Void visitMethodType(MethodType type, Void p) { |
761 public Void visitMethodType(MethodType type, Void p) { |
698 findDependencies(type.paramTypes); |
762 findDependencies(type.paramTypes); |
699 findDependencies(type.returnType); |
763 findDependencies(type.returnType); |
700 findDependencies(type.throwsTypes); |
764 findDependencies(type.throwsTypes); |
|
765 findDependencies(type.typeParamTypes); |
701 return null; |
766 return null; |
702 } |
767 } |
703 |
768 |
704 public Void visitClassSigType(ClassSigType type, Void p) { |
769 public Void visitClassSigType(ClassSigType type, Void p) { |
705 findDependencies(type.superclassType); |
770 findDependencies(type.superclassType); |
707 return null; |
772 return null; |
708 } |
773 } |
709 |
774 |
710 public Void visitClassType(ClassType type, Void p) { |
775 public Void visitClassType(ClassType type, Void p) { |
711 findDependencies(type.outerType); |
776 findDependencies(type.outerType); |
712 addDependency(type.name); |
777 addDependency(type.getBinaryName()); |
713 findDependencies(type.typeArgs); |
778 findDependencies(type.typeArgs); |
714 return null; |
779 return null; |
715 } |
780 } |
716 |
781 |
717 public Void visitTypeParamType(TypeParamType type, Void p) { |
782 public Void visitTypeParamType(TypeParamType type, Void p) { |