< prev index next >

src/share/classes/com/sun/tools/jdeps/JdepsTask.java

Print this page
rev 2788 : 8068937: jdeps shows "not found" if target class has no reference other than its own package
Reviewed-by: alanb


 472      * or if it's a public class if -apionly option is specified
 473      */
 474     private boolean matches(String classname, AccessFlags flags) {
 475         if (options.apiOnly && !flags.is(AccessFlags.ACC_PUBLIC)) {
 476             return false;
 477         } else if (options.includePattern != null) {
 478             return options.includePattern.matcher(classname.replace('/', '.')).matches();
 479         } else {
 480             return true;
 481         }
 482     }
 483 
 484     private void findDependencies() throws IOException {
 485         Dependency.Finder finder =
 486             options.apiOnly ? Dependencies.getAPIFinder(AccessFlags.ACC_PROTECTED)
 487                             : Dependencies.getClassDependencyFinder();
 488         Dependency.Filter filter = new DependencyFilter();
 489 
 490         List<Archive> archives = new ArrayList<>();
 491         Deque<String> roots = new LinkedList<>();

 492         for (String s : classes) {
 493             Path p = Paths.get(s);
 494             if (Files.exists(p)) {

 495                 archives.add(Archive.getInstance(p));
 496             } else {
 497                 if (isValidClassName(s)) {
 498                     roots.add(s);
 499                 } else {
 500                     warning("warn.invalid.arg", s);
 501                 }
 502             }
 503         }
 504         sourceLocations.addAll(archives);
 505 
 506         List<Archive> classpaths = new ArrayList<>(); // for class file lookup
 507         classpaths.addAll(getClassPathArchives(options.classpath));
 508         if (options.includePattern != null) {
 509             archives.addAll(classpaths);
 510         }
 511         classpaths.addAll(PlatformClassPath.getArchives());
 512 
 513         // add all classpath archives to the source locations for reporting
 514         sourceLocations.addAll(classpaths);
 515 
 516         // Work queue of names of classfiles to be searched.
 517         // Entries will be unique, and for classes that do not yet have
 518         // dependencies in the results map.
 519         Deque<String> deque = new LinkedList<>();
 520         Set<String> doneClasses = new HashSet<>();
 521 
 522         // get the immediate dependencies of the input files
 523         for (Archive a : archives) {
 524             for (ClassFile cf : a.reader().getClassFiles()) {
 525                 String classFileName;
 526                 try {
 527                     classFileName = cf.getName();
 528                 } catch (ConstantPoolException e) {
 529                     throw new ClassFileError(e);
 530                 }
 531 
 532                 // tests if this class matches the -include or -apiOnly option if specified
 533                 if (!matches(classFileName, cf.access_flags)) {
 534                     continue;
 535                 }
 536 
 537                 if (!doneClasses.contains(classFileName)) {
 538                     doneClasses.add(classFileName);
 539                 }
 540 
 541                 for (Dependency d : finder.findDependencies(cf)) {
 542                     if (filter.accepts(d)) {
 543                         String cn = d.getTarget().getName();
 544                         if (!doneClasses.contains(cn) && !deque.contains(cn)) {
 545                             deque.add(cn);
 546                         }
 547                         a.addClass(d.getOrigin(), d.getTarget());



 548                     }
 549                 }
 550                 for (String name : a.reader().skippedEntries()) {
 551                     warning("warn.skipped.entry", name, a.getPathName());
 552                 }
 553             }
 554         }
 555 
 556         // add Archive for looking up classes from the classpath
 557         // for transitive dependency analysis
 558         Deque<String> unresolved = roots;
 559         int depth = options.depth > 0 ? options.depth : Integer.MAX_VALUE;
 560         do {
 561             String name;
 562             while ((name = unresolved.poll()) != null) {
 563                 if (doneClasses.contains(name)) {
 564                     continue;
 565                 }
 566                 ClassFile cf = null;
 567                 for (Archive a : classpaths) {


 575                         }
 576                         if (!doneClasses.contains(classFileName)) {
 577                             // if name is a fully-qualified class name specified
 578                             // from command-line, this class might already be parsed
 579                             doneClasses.add(classFileName);
 580                             // process @jdk.Exported for JDK classes
 581                             if (isJDKArchive(a)) {
 582                                 ((JDKArchive)a).processJdkExported(cf);
 583                             }
 584                             for (Dependency d : finder.findDependencies(cf)) {
 585                                 if (depth == 0) {
 586                                     // ignore the dependency
 587                                     a.addClass(d.getOrigin());
 588                                     break;
 589                                 } else if (filter.accepts(d)) {
 590                                     a.addClass(d.getOrigin(), d.getTarget());
 591                                     String cn = d.getTarget().getName();
 592                                     if (!doneClasses.contains(cn) && !deque.contains(cn)) {
 593                                         deque.add(cn);
 594                                     }



 595                                 }
 596                             }
 597                         }
 598                         break;
 599                     }
 600                 }
 601                 if (cf == null) {
 602                     doneClasses.add(name);
 603                 }
 604             }
 605             unresolved = deque;
 606             deque = new LinkedList<>();
 607         } while (!unresolved.isEmpty() && depth-- > 0);
 608     }
 609 
 610     public void handleOptions(String[] args) throws BadArgs {
 611         // process options
 612         for (int i=0; i < args.length; i++) {
 613             if (args[i].charAt(0) == '-') {
 614                 String name = args[i];


 726         static {
 727             Locale locale = Locale.getDefault();
 728             try {
 729                 bundle = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdeps", locale);
 730             } catch (MissingResourceException e) {
 731                 throw new InternalError("Cannot find jdeps resource bundle for locale " + locale);
 732             }
 733             try {
 734                 versionRB = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.version");
 735             } catch (MissingResourceException e) {
 736                 throw new InternalError("version.resource.missing");
 737             }
 738             try {
 739                 jdkinternals = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdkinternals");
 740             } catch (MissingResourceException e) {
 741                 throw new InternalError("Cannot find jdkinternals resource bundle");
 742             }
 743         }
 744     }
 745 
 746     private List<Archive> getClassPathArchives(String paths) throws IOException {






 747         List<Archive> result = new ArrayList<>();
 748         if (paths.isEmpty()) {
 749             return result;
 750         }
 751         for (String p : paths.split(File.pathSeparator)) {


 752             if (p.length() > 0) {
 753                 List<Path> files = new ArrayList<>();
 754                 // wildcard to parse all JAR files e.g. -classpath dir/*
 755                 int i = p.lastIndexOf(".*");
 756                 if (i > 0) {
 757                     Path dir = Paths.get(p.substring(0, i));
 758                     try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.jar")) {
 759                         for (Path entry : stream) {
 760                             files.add(entry);
 761                         }
 762                     }
 763                 } else {
 764                     files.add(Paths.get(p));
 765                 }
 766                 for (Path f : files) {
 767                     if (Files.exists(f)) {
 768                         result.add(Archive.getInstance(f));
 769                     }
 770                 }



 771             }
 772         }
 773         return result;









 774     }
 775 
 776     class RawOutputFormatter implements Analyzer.Visitor {
 777         private final PrintWriter writer;
 778         private String pkg = "";
 779         RawOutputFormatter(PrintWriter writer) {
 780             this.writer = writer;
 781         }
 782         @Override
 783         public void visitDependence(String origin, Archive originArchive,
 784                                     String target, Archive targetArchive) {
 785             String tag = toTag(target, targetArchive);
 786             if (options.verbose == VERBOSE) {
 787                 writer.format("   %-50s -> %-50s %s%n", origin, target, tag);
 788             } else {
 789                 if (!origin.equals(pkg)) {
 790                     pkg = origin;
 791                     writer.format("   %s (%s)%n", origin, originArchive.getName());
 792                 }
 793                 writer.format("      -> %-50s %s%n", target, tag);




 472      * or if it's a public class if -apionly option is specified
 473      */
 474     private boolean matches(String classname, AccessFlags flags) {
 475         if (options.apiOnly && !flags.is(AccessFlags.ACC_PUBLIC)) {
 476             return false;
 477         } else if (options.includePattern != null) {
 478             return options.includePattern.matcher(classname.replace('/', '.')).matches();
 479         } else {
 480             return true;
 481         }
 482     }
 483 
 484     private void findDependencies() throws IOException {
 485         Dependency.Finder finder =
 486             options.apiOnly ? Dependencies.getAPIFinder(AccessFlags.ACC_PROTECTED)
 487                             : Dependencies.getClassDependencyFinder();
 488         Dependency.Filter filter = new DependencyFilter();
 489 
 490         List<Archive> archives = new ArrayList<>();
 491         Deque<String> roots = new LinkedList<>();
 492         List<Path> paths = new ArrayList<>();
 493         for (String s : classes) {
 494             Path p = Paths.get(s);
 495             if (Files.exists(p)) {
 496                 paths.add(p);
 497                 archives.add(Archive.getInstance(p));
 498             } else {
 499                 if (isValidClassName(s)) {
 500                     roots.add(s);
 501                 } else {
 502                     warning("warn.invalid.arg", s);
 503                 }
 504             }
 505         }
 506         sourceLocations.addAll(archives);
 507 
 508         List<Archive> classpaths = new ArrayList<>(); // for class file lookup
 509         classpaths.addAll(getClassPathArchives(options.classpath, paths));
 510         if (options.includePattern != null) {
 511             archives.addAll(classpaths);
 512         }
 513         classpaths.addAll(PlatformClassPath.getArchives());
 514 
 515         // add all classpath archives to the source locations for reporting
 516         sourceLocations.addAll(classpaths);
 517 
 518         // Work queue of names of classfiles to be searched.
 519         // Entries will be unique, and for classes that do not yet have
 520         // dependencies in the results map.
 521         Deque<String> deque = new LinkedList<>();
 522         Set<String> doneClasses = new HashSet<>();
 523 
 524         // get the immediate dependencies of the input files
 525         for (Archive a : archives) {
 526             for (ClassFile cf : a.reader().getClassFiles()) {
 527                 String classFileName;
 528                 try {
 529                     classFileName = cf.getName();
 530                 } catch (ConstantPoolException e) {
 531                     throw new ClassFileError(e);
 532                 }
 533 
 534                 // tests if this class matches the -include or -apiOnly option if specified
 535                 if (!matches(classFileName, cf.access_flags)) {
 536                     continue;
 537                 }
 538 
 539                 if (!doneClasses.contains(classFileName)) {
 540                     doneClasses.add(classFileName);
 541                 }
 542 
 543                 for (Dependency d : finder.findDependencies(cf)) {
 544                     if (filter.accepts(d)) {
 545                         String cn = d.getTarget().getName();
 546                         if (!doneClasses.contains(cn) && !deque.contains(cn)) {
 547                             deque.add(cn);
 548                         }
 549                         a.addClass(d.getOrigin(), d.getTarget());
 550                     } else {
 551                         // ensure that the parsed class is added the archive
 552                         a.addClass(d.getOrigin());
 553                     }
 554                 }
 555                 for (String name : a.reader().skippedEntries()) {
 556                     warning("warn.skipped.entry", name, a.getPathName());
 557                 }
 558             }
 559         }
 560 
 561         // add Archive for looking up classes from the classpath
 562         // for transitive dependency analysis
 563         Deque<String> unresolved = roots;
 564         int depth = options.depth > 0 ? options.depth : Integer.MAX_VALUE;
 565         do {
 566             String name;
 567             while ((name = unresolved.poll()) != null) {
 568                 if (doneClasses.contains(name)) {
 569                     continue;
 570                 }
 571                 ClassFile cf = null;
 572                 for (Archive a : classpaths) {


 580                         }
 581                         if (!doneClasses.contains(classFileName)) {
 582                             // if name is a fully-qualified class name specified
 583                             // from command-line, this class might already be parsed
 584                             doneClasses.add(classFileName);
 585                             // process @jdk.Exported for JDK classes
 586                             if (isJDKArchive(a)) {
 587                                 ((JDKArchive)a).processJdkExported(cf);
 588                             }
 589                             for (Dependency d : finder.findDependencies(cf)) {
 590                                 if (depth == 0) {
 591                                     // ignore the dependency
 592                                     a.addClass(d.getOrigin());
 593                                     break;
 594                                 } else if (filter.accepts(d)) {
 595                                     a.addClass(d.getOrigin(), d.getTarget());
 596                                     String cn = d.getTarget().getName();
 597                                     if (!doneClasses.contains(cn) && !deque.contains(cn)) {
 598                                         deque.add(cn);
 599                                     }
 600                                 } else {
 601                                     // ensure that the parsed class is added the archive
 602                                     a.addClass(d.getOrigin());
 603                                 }
 604                             }
 605                         }
 606                         break;
 607                     }
 608                 }
 609                 if (cf == null) {
 610                     doneClasses.add(name);
 611                 }
 612             }
 613             unresolved = deque;
 614             deque = new LinkedList<>();
 615         } while (!unresolved.isEmpty() && depth-- > 0);
 616     }
 617 
 618     public void handleOptions(String[] args) throws BadArgs {
 619         // process options
 620         for (int i=0; i < args.length; i++) {
 621             if (args[i].charAt(0) == '-') {
 622                 String name = args[i];


 734         static {
 735             Locale locale = Locale.getDefault();
 736             try {
 737                 bundle = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdeps", locale);
 738             } catch (MissingResourceException e) {
 739                 throw new InternalError("Cannot find jdeps resource bundle for locale " + locale);
 740             }
 741             try {
 742                 versionRB = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.version");
 743             } catch (MissingResourceException e) {
 744                 throw new InternalError("version.resource.missing");
 745             }
 746             try {
 747                 jdkinternals = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdkinternals");
 748             } catch (MissingResourceException e) {
 749                 throw new InternalError("Cannot find jdkinternals resource bundle");
 750             }
 751         }
 752     }
 753 
 754     /*
 755      * Returns the list of Archive specified in cpaths and not included
 756      * initialArchives
 757      */
 758     private List<Archive> getClassPathArchives(String cpaths, List<Path> initialArchives)
 759             throws IOException
 760     {
 761         List<Archive> result = new ArrayList<>();
 762         if (cpaths.isEmpty()) {
 763             return result;
 764         }
 765 
 766         List<Path> paths = new ArrayList<>();
 767         for (String p : cpaths.split(File.pathSeparator)) {
 768             if (p.length() > 0) {

 769                 // wildcard to parse all JAR files e.g. -classpath dir/*
 770                 int i = p.lastIndexOf(".*");
 771                 if (i > 0) {
 772                     Path dir = Paths.get(p.substring(0, i));
 773                     try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.jar")) {
 774                         for (Path entry : stream) {
 775                             paths.add(entry);
 776                         }
 777                     }
 778                 } else {
 779                     paths.add(Paths.get(p));
 780                 }



 781             }
 782         }
 783         for (Path p : paths) {
 784             if (Files.exists(p) && !hasSameFile(initialArchives, p)) {
 785                 result.add(Archive.getInstance(p));
 786             }
 787         }
 788         return result;
 789     }
 790 
 791     private boolean hasSameFile(List<Path> paths, Path p2) throws IOException {
 792         for (Path p1 : paths) {
 793             if (Files.isSameFile(p1, p2)) {
 794                 return true;
 795             }
 796         }
 797         return false;
 798     }
 799 
 800     class RawOutputFormatter implements Analyzer.Visitor {
 801         private final PrintWriter writer;
 802         private String pkg = "";
 803         RawOutputFormatter(PrintWriter writer) {
 804             this.writer = writer;
 805         }
 806         @Override
 807         public void visitDependence(String origin, Archive originArchive,
 808                                     String target, Archive targetArchive) {
 809             String tag = toTag(target, targetArchive);
 810             if (options.verbose == VERBOSE) {
 811                 writer.format("   %-50s -> %-50s %s%n", origin, target, tag);
 812             } else {
 813                 if (!origin.equals(pkg)) {
 814                     pkg = origin;
 815                     writer.format("   %s (%s)%n", origin, originArchive.getName());
 816                 }
 817                 writer.format("      -> %-50s %s%n", target, tag);


< prev index next >