125 }
126
127 /**
128 * Get a finder used to locate the API dependencies for a class.
129 * These include the superclass, superinterfaces, and classes referenced in
130 * the declarations of fields and methods. The fields and methods that
131 * are checked can be limited according to a specified access.
132 * The access parameter must be one of {@link AccessFlags#ACC_PUBLIC ACC_PUBLIC},
133 * {@link AccessFlags#ACC_PRIVATE ACC_PRIVATE},
134 * {@link AccessFlags#ACC_PROTECTED ACC_PROTECTED}, or 0 for
135 * package private access. Members with greater than or equal accessibility
136 * to that specified will be searched for dependencies.
137 * @param access the access of members to be checked
138 * @return an API finder
139 */
140 public static Finder getAPIFinder(int access) {
141 return new APIDependencyFinder(access);
142 }
143
144 /**
145 * Get the finder used to locate the dependencies for a class.
146 * @return the finder
147 */
148 public Finder getFinder() {
149 if (finder == null)
150 finder = getDefaultFinder();
151 return finder;
152 }
153
154 /**
155 * Set the finder used to locate the dependencies for a class.
156 * @param f the finder
157 */
158 public void setFinder(Finder f) {
159 f.getClass(); // null check
160 finder = f;
161 }
162
163 /**
164 * Get the default filter used to determine included when searching
229 * named in any filtered dependencies that are found.
230 * @return the set of dependencies that were found
231 * @throws ClassFileNotFoundException if a required class file cannot be found
232 * @throws ClassFileError if an error occurs while processing a class file,
233 * such as an error in the internal class file structure.
234 */
235 public Set<Dependency> findAllDependencies(
236 ClassFileReader classFinder, Set<String> rootClassNames,
237 boolean transitiveClosure)
238 throws ClassFileNotFoundException {
239 final Set<Dependency> results = new HashSet<Dependency>();
240 Recorder r = new Recorder() {
241 public void addDependency(Dependency d) {
242 results.add(d);
243 }
244 };
245 findAllDependencies(classFinder, rootClassNames, transitiveClosure, r);
246 return results;
247 }
248
249
250
251 /**
252 * Find the dependencies of a class, using the current
253 * {@link Dependencies#getFinder finder} and
254 * {@link Dependencies#getFilter filter}.
255 * The search may optionally include the transitive closure of all the
256 * filtered dependencies, by also searching in the classes named in those
257 * dependencies.
258 * @param classFinder a finder to locate class files
259 * @param rootClassNames the names of the root classes from which to begin
260 * searching
261 * @param transitiveClosure whether or not to also search those classes
262 * named in any filtered dependencies that are found.
263 * @param recorder a recorder for handling the results
264 * @throws ClassFileNotFoundException if a required class file cannot be found
265 * @throws ClassFileError if an error occurs while processing a class file,
266 * such as an error in the internal class file structure.
267 */
268 public void findAllDependencies(
269 ClassFileReader classFinder, Set<String> rootClassNames,
270 boolean transitiveClosure, Recorder recorder)
289 // The following code just applies the filter to the dependencies
290 // followed for the transitive closure.
291 for (Dependency d: finder.findDependencies(cf)) {
292 recorder.addDependency(d);
293 if (transitiveClosure && filter.accepts(d)) {
294 String cn = d.getTarget().getClassName();
295 if (!doneClasses.contains(cn))
296 deque.add(cn);
297 }
298 }
299 }
300 }
301
302 private Filter filter;
303 private Finder finder;
304
305 /**
306 * A location identifying a class.
307 */
308 static class SimpleLocation implements Location {
309 public SimpleLocation(String className) {
310 this.className = className;
311 }
312
313 /**
314 * Get the name of the class being depended on. This name will be used to
315 * locate the class file for transitive dependency analysis.
316 * @return the name of the class being depended on
317 */
318 public String getClassName() {
319 return className;
320 }
321
322 @Override
323 public boolean equals(Object other) {
324 if (this == other)
325 return true;
326 if (!(other instanceof SimpleLocation))
327 return false;
328 return (className.equals(((SimpleLocation) other).className));
329 }
330
331 @Override
332 public int hashCode() {
333 return className.hashCode();
334 }
335
336 @Override
337 public String toString() {
338 return className;
339 }
340
341 private String className;
342 }
343
344 /**
345 * A dependency of one class on another.
346 */
347 static class SimpleDependency implements Dependency {
348 public SimpleDependency(Location origin, Location target) {
349 this.origin = origin;
350 this.target = target;
351 }
352
353 public Location getOrigin() {
354 return origin;
355 }
356
357 public Location getTarget() {
358 return target;
359 }
360
414 }
415
416 private final Pattern pattern;
417 }
418
419 /**
420 * This class accepts those dependencies whose class name is in a given
421 * package.
422 */
423 static class TargetPackageFilter implements Filter {
424 TargetPackageFilter(Set<String> packageNames, boolean matchSubpackages) {
425 for (String pn: packageNames) {
426 if (pn.length() == 0) // implies null check as well
427 throw new IllegalArgumentException();
428 }
429 this.packageNames = packageNames;
430 this.matchSubpackages = matchSubpackages;
431 }
432
433 public boolean accepts(Dependency dependency) {
434 String cn = dependency.getTarget().getClassName();
435 int lastSep = cn.lastIndexOf("/");
436 String pn = (lastSep == -1 ? "" : cn.substring(0, lastSep));
437 if (packageNames.contains(pn))
438 return true;
439
440 if (matchSubpackages) {
441 for (String n: packageNames) {
442 if (pn.startsWith(n + "."))
443 return true;
444 }
445 }
446
447 return false;
448 }
449
450 private final Set<String> packageNames;
451 private final boolean matchSubpackages;
452 }
453
454
455
456 /**
457 * This class identifies class names directly or indirectly in the constant pool.
458 */
459 static class ClassDependencyFinder extends BasicDependencyFinder {
460 public Iterable<? extends Dependency> findDependencies(ClassFile classfile) {
461 Visitor v = new Visitor(classfile);
462 for (CPInfo cpInfo: classfile.constant_pool.entries()) {
463 v.scan(cpInfo);
464 }
465 return v.deps;
466 }
467 }
468
469 /**
470 * This class identifies class names in the signatures of classes, fields,
471 * and methods in a class.
472 */
473 static class APIDependencyFinder extends BasicDependencyFinder {
474 APIDependencyFinder(int access) {
475 switch (access) {
476 case AccessFlags.ACC_PUBLIC:
477 case AccessFlags.ACC_PROTECTED:
478 case AccessFlags.ACC_PRIVATE:
479 case 0:
480 showAccess = access;
481 break;
482 default:
483 throw new IllegalArgumentException("invalid access 0x"
484 + Integer.toHexString(access));
541 }
542
543 class Visitor implements ConstantPool.Visitor<Void,Void>, Type.Visitor<Void, Void> {
544 private ConstantPool constant_pool;
545 private Location origin;
546 Set<Dependency> deps;
547
548 Visitor(ClassFile classFile) {
549 try {
550 constant_pool = classFile.constant_pool;
551 origin = getLocation(classFile.getName());
552 deps = new HashSet<Dependency>();
553 } catch (ConstantPoolException e) {
554 throw new ClassFileError(e);
555 }
556 }
557
558 void scan(Descriptor d, Attributes attrs) {
559 try {
560 scan(new Signature(d.index).getType(constant_pool));
561 Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature);
562 if (sa != null)
563 scan(new Signature(sa.signature_index).getType(constant_pool));
564 } catch (ConstantPoolException e) {
565 throw new ClassFileError(e);
566 }
567 }
568
569 void scan(CPInfo cpInfo) {
570 cpInfo.accept(this, null);
571 }
572
573 void scan(Type t) {
574 t.accept(this, null);
575 }
576
577 void addClass(int index) throws ConstantPoolException {
578 if (index != 0) {
579 String name = constant_pool.getClassInfo(index).getBaseName();
580 if (name != null)
581 addDependency(name);
582 }
583 }
584
585 void addClasses(int[] indices) throws ConstantPoolException {
586 for (int i: indices)
587 addClass(i);
588 }
589
590 private void addDependency(String name) {
591 deps.add(new SimpleDependency(origin, getLocation(name)));
592 }
593
594 // ConstantPool.Visitor methods
595
596 public Void visitClass(CONSTANT_Class_info info, Void p) {
681 private void findDependencies(List<? extends Type> ts) {
682 if (ts != null) {
683 for (Type t: ts)
684 t.accept(this, null);
685 }
686 }
687
688 public Void visitSimpleType(SimpleType type, Void p) {
689 return null;
690 }
691
692 public Void visitArrayType(ArrayType type, Void p) {
693 findDependencies(type.elemType);
694 return null;
695 }
696
697 public Void visitMethodType(MethodType type, Void p) {
698 findDependencies(type.paramTypes);
699 findDependencies(type.returnType);
700 findDependencies(type.throwsTypes);
701 return null;
702 }
703
704 public Void visitClassSigType(ClassSigType type, Void p) {
705 findDependencies(type.superclassType);
706 findDependencies(type.superinterfaceTypes);
707 return null;
708 }
709
710 public Void visitClassType(ClassType type, Void p) {
711 findDependencies(type.outerType);
712 addDependency(type.name);
713 findDependencies(type.typeArgs);
714 return null;
715 }
716
717 public Void visitTypeParamType(TypeParamType type, Void p) {
718 findDependencies(type.classBound);
719 findDependencies(type.interfaceBounds);
720 return null;
721 }
722
723 public Void visitWildcardType(WildcardType type, Void p) {
724 findDependencies(type.boundType);
725 return null;
726 }
727 }
728 }
729 }
|
125 }
126
127 /**
128 * Get a finder used to locate the API dependencies for a class.
129 * These include the superclass, superinterfaces, and classes referenced in
130 * the declarations of fields and methods. The fields and methods that
131 * are checked can be limited according to a specified access.
132 * The access parameter must be one of {@link AccessFlags#ACC_PUBLIC ACC_PUBLIC},
133 * {@link AccessFlags#ACC_PRIVATE ACC_PRIVATE},
134 * {@link AccessFlags#ACC_PROTECTED ACC_PROTECTED}, or 0 for
135 * package private access. Members with greater than or equal accessibility
136 * to that specified will be searched for dependencies.
137 * @param access the access of members to be checked
138 * @return an API finder
139 */
140 public static Finder getAPIFinder(int access) {
141 return new APIDependencyFinder(access);
142 }
143
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 /**
154 * Get the finder used to locate the dependencies for a class.
155 * @return the finder
156 */
157 public Finder getFinder() {
158 if (finder == null)
159 finder = getDefaultFinder();
160 return finder;
161 }
162
163 /**
164 * Set the finder used to locate the dependencies for a class.
165 * @param f the finder
166 */
167 public void setFinder(Finder f) {
168 f.getClass(); // null check
169 finder = f;
170 }
171
172 /**
173 * Get the default filter used to determine included when searching
238 * named in any filtered dependencies that are found.
239 * @return the set of dependencies that were found
240 * @throws ClassFileNotFoundException if a required class file cannot be found
241 * @throws ClassFileError if an error occurs while processing a class file,
242 * such as an error in the internal class file structure.
243 */
244 public Set<Dependency> findAllDependencies(
245 ClassFileReader classFinder, Set<String> rootClassNames,
246 boolean transitiveClosure)
247 throws ClassFileNotFoundException {
248 final Set<Dependency> results = new HashSet<Dependency>();
249 Recorder r = new Recorder() {
250 public void addDependency(Dependency d) {
251 results.add(d);
252 }
253 };
254 findAllDependencies(classFinder, rootClassNames, transitiveClosure, r);
255 return results;
256 }
257
258 /**
259 * Find the dependencies of a class, using the current
260 * {@link Dependencies#getFinder finder} and
261 * {@link Dependencies#getFilter filter}.
262 * The search may optionally include the transitive closure of all the
263 * filtered dependencies, by also searching in the classes named in those
264 * dependencies.
265 * @param classFinder a finder to locate class files
266 * @param rootClassNames the names of the root classes from which to begin
267 * searching
268 * @param transitiveClosure whether or not to also search those classes
269 * named in any filtered dependencies that are found.
270 * @param recorder a recorder for handling the results
271 * @throws ClassFileNotFoundException if a required class file cannot be found
272 * @throws ClassFileError if an error occurs while processing a class file,
273 * such as an error in the internal class file structure.
274 */
275 public void findAllDependencies(
276 ClassFileReader classFinder, Set<String> rootClassNames,
277 boolean transitiveClosure, Recorder recorder)
296 // The following code just applies the filter to the dependencies
297 // followed for the transitive closure.
298 for (Dependency d: finder.findDependencies(cf)) {
299 recorder.addDependency(d);
300 if (transitiveClosure && filter.accepts(d)) {
301 String cn = d.getTarget().getClassName();
302 if (!doneClasses.contains(cn))
303 deque.add(cn);
304 }
305 }
306 }
307 }
308
309 private Filter filter;
310 private Finder finder;
311
312 /**
313 * A location identifying a class.
314 */
315 static class SimpleLocation implements Location {
316 public SimpleLocation(String name) {
317 this.name = name;
318 this.className = name.replace('/', '.');
319 }
320
321 public String getName() {
322 return name;
323 }
324
325 public String getClassName() {
326 return className;
327 }
328
329 public String getPackageName() {
330 int i = className.lastIndexOf('.');
331 return (i > 0) ? className.substring(0, i) : "";
332 }
333
334 @Override
335 public boolean equals(Object other) {
336 if (this == other)
337 return true;
338 if (!(other instanceof SimpleLocation))
339 return false;
340 return (name.equals(((SimpleLocation) other).name));
341 }
342
343 @Override
344 public int hashCode() {
345 return name.hashCode();
346 }
347
348 @Override
349 public String toString() {
350 return name;
351 }
352
353 private String name;
354 private String className;
355 }
356
357 /**
358 * A dependency of one class on another.
359 */
360 static class SimpleDependency implements Dependency {
361 public SimpleDependency(Location origin, Location target) {
362 this.origin = origin;
363 this.target = target;
364 }
365
366 public Location getOrigin() {
367 return origin;
368 }
369
370 public Location getTarget() {
371 return target;
372 }
373
427 }
428
429 private final Pattern pattern;
430 }
431
432 /**
433 * This class accepts those dependencies whose class name is in a given
434 * package.
435 */
436 static class TargetPackageFilter implements Filter {
437 TargetPackageFilter(Set<String> packageNames, boolean matchSubpackages) {
438 for (String pn: packageNames) {
439 if (pn.length() == 0) // implies null check as well
440 throw new IllegalArgumentException();
441 }
442 this.packageNames = packageNames;
443 this.matchSubpackages = matchSubpackages;
444 }
445
446 public boolean accepts(Dependency dependency) {
447 String pn = dependency.getTarget().getPackageName();
448 if (packageNames.contains(pn))
449 return true;
450
451 if (matchSubpackages) {
452 for (String n: packageNames) {
453 if (pn.startsWith(n + "."))
454 return true;
455 }
456 }
457
458 return false;
459 }
460
461 private final Set<String> packageNames;
462 private final boolean matchSubpackages;
463 }
464
465 /**
466 * This class identifies class names directly or indirectly in the constant pool.
467 */
468 static class ClassDependencyFinder extends BasicDependencyFinder {
469 public Iterable<? extends Dependency> findDependencies(ClassFile classfile) {
470 Visitor v = new Visitor(classfile);
471 for (CPInfo cpInfo: classfile.constant_pool.entries()) {
472 v.scan(cpInfo);
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
494 return v.deps;
495 }
496 }
497
498 /**
499 * This class identifies class names in the signatures of classes, fields,
500 * and methods in a class.
501 */
502 static class APIDependencyFinder extends BasicDependencyFinder {
503 APIDependencyFinder(int access) {
504 switch (access) {
505 case AccessFlags.ACC_PUBLIC:
506 case AccessFlags.ACC_PROTECTED:
507 case AccessFlags.ACC_PRIVATE:
508 case 0:
509 showAccess = access;
510 break;
511 default:
512 throw new IllegalArgumentException("invalid access 0x"
513 + Integer.toHexString(access));
570 }
571
572 class Visitor implements ConstantPool.Visitor<Void,Void>, Type.Visitor<Void, Void> {
573 private ConstantPool constant_pool;
574 private Location origin;
575 Set<Dependency> deps;
576
577 Visitor(ClassFile classFile) {
578 try {
579 constant_pool = classFile.constant_pool;
580 origin = getLocation(classFile.getName());
581 deps = new HashSet<Dependency>();
582 } catch (ConstantPoolException e) {
583 throw new ClassFileError(e);
584 }
585 }
586
587 void scan(Descriptor d, Attributes attrs) {
588 try {
589 scan(new Signature(d.index).getType(constant_pool));
590 scan(attrs);
591 } catch (ConstantPoolException e) {
592 throw new ClassFileError(e);
593 }
594 }
595
596 void scan(CPInfo cpInfo) {
597 cpInfo.accept(this, null);
598 }
599
600 void scan(Type t) {
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 }
639 }
640
641 void addClass(int index) throws ConstantPoolException {
642 if (index != 0) {
643 String name = constant_pool.getClassInfo(index).getBaseName();
644 if (name != null)
645 addDependency(name);
646 }
647 }
648
649 void addClasses(int[] indices) throws ConstantPoolException {
650 for (int i: indices)
651 addClass(i);
652 }
653
654 private void addDependency(String name) {
655 deps.add(new SimpleDependency(origin, getLocation(name)));
656 }
657
658 // ConstantPool.Visitor methods
659
660 public Void visitClass(CONSTANT_Class_info info, Void p) {
745 private void findDependencies(List<? extends Type> ts) {
746 if (ts != null) {
747 for (Type t: ts)
748 t.accept(this, null);
749 }
750 }
751
752 public Void visitSimpleType(SimpleType type, Void p) {
753 return null;
754 }
755
756 public Void visitArrayType(ArrayType type, Void p) {
757 findDependencies(type.elemType);
758 return null;
759 }
760
761 public Void visitMethodType(MethodType type, Void p) {
762 findDependencies(type.paramTypes);
763 findDependencies(type.returnType);
764 findDependencies(type.throwsTypes);
765 findDependencies(type.typeParamTypes);
766 return null;
767 }
768
769 public Void visitClassSigType(ClassSigType type, Void p) {
770 findDependencies(type.superclassType);
771 findDependencies(type.superinterfaceTypes);
772 return null;
773 }
774
775 public Void visitClassType(ClassType type, Void p) {
776 findDependencies(type.outerType);
777 addDependency(type.getBinaryName());
778 findDependencies(type.typeArgs);
779 return null;
780 }
781
782 public Void visitTypeParamType(TypeParamType type, Void p) {
783 findDependencies(type.classBound);
784 findDependencies(type.interfaceBounds);
785 return null;
786 }
787
788 public Void visitWildcardType(WildcardType type, Void p) {
789 findDependencies(type.boundType);
790 return null;
791 }
792 }
793 }
794 }
|