src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java
changeset 52650 c16b6cc93272
parent 47357 74700c8e39e9
equal deleted inserted replaced
52649:e00cf18e2593 52650:c16b6cc93272
    47  *
    47  *
    48  */
    48  */
    49 public class ModuleExportsAnalyzer extends DepsAnalyzer {
    49 public class ModuleExportsAnalyzer extends DepsAnalyzer {
    50     // source archive to its dependences and JDK internal APIs it references
    50     // source archive to its dependences and JDK internal APIs it references
    51     private final Map<Archive, Map<Archive,Set<String>>> deps = new HashMap<>();
    51     private final Map<Archive, Map<Archive,Set<String>>> deps = new HashMap<>();
    52     private final boolean showJdkInternals;
    52     private final Map<String, Set<String>> missingDeps = new HashMap<>();
       
    53     private final boolean showInternals;
    53     private final boolean reduced;
    54     private final boolean reduced;
    54     private final PrintWriter writer;
    55     private final PrintWriter writer;
    55     private final String separator;
    56     private final String separator;
    56     public ModuleExportsAnalyzer(JdepsConfiguration config,
    57     public ModuleExportsAnalyzer(JdepsConfiguration config,
    57                                  JdepsFilter filter,
    58                                  JdepsFilter filter,
    58                                  boolean showJdkInternals,
    59                                  boolean showInternals,
    59                                  boolean reduced,
    60                                  boolean reduced,
    60                                  PrintWriter writer,
    61                                  PrintWriter writer,
    61                                  String separator) {
    62                                  String separator) {
    62         super(config, filter, null,
    63         super(config, filter, null,
    63               Analyzer.Type.PACKAGE,
    64               Analyzer.Type.PACKAGE,
    64               false /* all classes */);
    65               false /* all classes */);
    65         this.showJdkInternals = showJdkInternals;
    66         this.showInternals = showInternals;
    66         this.reduced = reduced;
    67         this.reduced = reduced;
    67         this.writer = writer;
    68         this.writer = writer;
    68         this.separator = separator;
    69         this.separator = separator;
    69     }
    70     }
    70 
    71 
    71     @Override
    72     public boolean run(int maxDepth, boolean ignoreMissingDeps) throws IOException {
    72     public boolean run() throws IOException {
    73         // use compile time view so that the entire archive on classpath is analyzed
    73         // analyze dependences
    74         boolean rc = super.run(true, maxDepth);
    74         boolean rc = super.run();
       
    75 
    75 
    76         // A visitor to record the module-level dependences as well as
    76         // A visitor to record the module-level dependences as well as
    77         // use of JDK internal APIs
    77         // use of internal APIs
    78         Analyzer.Visitor visitor = (origin, originArchive, target, targetArchive) -> {
    78         Analyzer.Visitor visitor = (origin, originArchive, target, targetArchive) -> {
    79             Set<String> jdkInternals =
    79             Set<String> internals =
    80                 deps.computeIfAbsent(originArchive, _k -> new HashMap<>())
    80                 deps.computeIfAbsent(originArchive, _k -> new HashMap<>())
    81                     .computeIfAbsent(targetArchive, _k -> new HashSet<>());
    81                     .computeIfAbsent(targetArchive, _k -> new HashSet<>());
    82 
    82 
    83             Module module = targetArchive.getModule();
    83             Module module = targetArchive.getModule();
    84             if (showJdkInternals && originArchive.getModule() != module &&
    84             if (showInternals && originArchive.getModule() != module &&
    85                     module.isJDK() && !module.isExported(target)) {
    85                     module.isNamed() && !module.isExported(target, module.name())) {
    86                 // use of JDK internal APIs
    86                 // use of internal APIs
    87                 jdkInternals.add(target);
    87                 internals.add(target);
       
    88             }
       
    89             if (!ignoreMissingDeps && Analyzer.notFound(targetArchive)) {
       
    90                 Set<String> notFound =
       
    91                     missingDeps.computeIfAbsent(origin, _k -> new HashSet<>());
       
    92                 notFound.add(target);
    88             }
    93             }
    89         };
    94         };
    90 
    95 
    91         // visit the dependences
    96         // visit the dependences
    92         archives.stream()
    97         archives.stream()
    93             .filter(analyzer::hasDependences)
    98             .filter(analyzer::hasDependences)
    94             .sorted(Comparator.comparing(Archive::getName))
    99             .sorted(Comparator.comparing(Archive::getName))
    95             .forEach(archive -> analyzer.visitDependences(archive, visitor));
   100             .forEach(archive -> analyzer.visitDependences(archive, visitor));
    96 
   101 
       
   102         // error if any missing dependence
       
   103         if (!rc || !missingDeps.isEmpty()) {
       
   104             return false;
       
   105         }
       
   106 
       
   107         Map<Module, Set<String>> internalPkgs = internalPackages();
    97         Set<Module> modules = modules();
   108         Set<Module> modules = modules();
    98         if (showJdkInternals) {
   109         if (showInternals) {
    99             // print modules and JDK internal API dependences
   110             // print modules and JDK internal API dependences
   100             printDependences(modules);
   111             Stream.concat(modules.stream(), internalPkgs.keySet().stream())
       
   112                     .sorted(Comparator.comparing(Module::name))
       
   113                     .distinct()
       
   114                     .forEach(m -> {
       
   115                         if (internalPkgs.containsKey(m)) {
       
   116                             internalPkgs.get(m).stream()
       
   117                                 .forEach(pn -> writer.format("   %s/%s%s", m, pn, separator));
       
   118                         } else {
       
   119                             writer.format("   %s%s", m, separator);
       
   120                         }
       
   121                     });
   101         } else {
   122         } else {
   102             // print module dependences
   123             // print module dependences
   103             writer.println(modules.stream().map(Module::name).sorted()
   124             writer.println(modules.stream().map(Module::name).sorted()
   104                                   .collect(Collectors.joining(separator)));
   125                                   .collect(Collectors.joining(separator)));
   105         }
   126         }
   106         return rc;
   127         return rc;
   107     }
   128     }
   108 
   129 
       
   130     /*
       
   131      * Prints missing dependences
       
   132      */
       
   133     void visitMissingDeps(Analyzer.Visitor visitor) {
       
   134         archives.stream()
       
   135             .filter(analyzer::hasDependences)
       
   136             .sorted(Comparator.comparing(Archive::getName))
       
   137             .filter(m -> analyzer.requires(m).anyMatch(Analyzer::notFound))
       
   138             .forEach(m -> {
       
   139                 analyzer.visitDependences(m, visitor, Analyzer.Type.VERBOSE, Analyzer::notFound);
       
   140             });
       
   141     }
       
   142 
   109     private Set<Module> modules() {
   143     private Set<Module> modules() {
   110         // build module graph
   144         // build module graph
   111         ModuleGraphBuilder builder = new ModuleGraphBuilder(configuration);
   145         ModuleGraphBuilder builder = new ModuleGraphBuilder(configuration);
   112         Module root = new RootModule("root");
   146         Module root = new RootModule();
   113         builder.addModule(root);
   147         builder.addModule(root);
   114         // find named module dependences
   148         // find named module dependences
   115         dependenceStream()
   149         dependenceStream()
   116             .flatMap(map -> map.keySet().stream())
   150             .flatMap(map -> map.keySet().stream())
   117             .filter(m -> m.getModule().isNamed()
   151             .filter(m -> m.getModule().isNamed() && !configuration.rootModules().contains(m))
   118                 && !configuration.rootModules().contains(m))
       
   119             .map(Archive::getModule)
   152             .map(Archive::getModule)
   120             .forEach(m -> builder.addEdge(root, m));
   153             .forEach(m -> builder.addEdge(root, m));
   121 
   154 
   122         // build module dependence graph
   155         // build module dependence graph
   123         // if reduced is set, apply transition reduction
   156         // if reduced is set, apply transition reduction
   124         Graph<Module> g = reduced ? builder.reduced() : builder.build();
   157         Graph<Module> g = reduced ? builder.reduced() : builder.build();
   125         return g.adjacentNodes(root);
   158         return g.adjacentNodes(root);
   126     }
   159     }
   127 
   160 
   128     private void printDependences(Set<Module> modules) {
   161     private Map<Module, Set<String>> internalPackages() {
   129         // find use of JDK internals
   162         Map<Module, Set<String>> internalPkgs = new HashMap<>();
   130         Map<Module, Set<String>> jdkinternals = new HashMap<>();
       
   131         dependenceStream()
   163         dependenceStream()
   132             .flatMap(map -> map.entrySet().stream())
   164             .flatMap(map -> map.entrySet().stream())
   133             .filter(e -> e.getValue().size() > 0)
   165             .filter(e -> e.getValue().size() > 0)
   134             .forEach(e -> jdkinternals.computeIfAbsent(e.getKey().getModule(),
   166             .forEach(e -> internalPkgs.computeIfAbsent(e.getKey().getModule(),
   135                                                        _k -> new TreeSet<>())
   167                                                              _k -> new TreeSet<>())
   136                                       .addAll(e.getValue()));
   168                                       .addAll(e.getValue()));
   137 
   169         return internalPkgs;
   138         // print modules and JDK internal API dependences
       
   139         Stream.concat(modules.stream(), jdkinternals.keySet().stream())
       
   140               .sorted(Comparator.comparing(Module::name))
       
   141               .distinct()
       
   142               .forEach(m -> {
       
   143                   if (jdkinternals.containsKey(m)) {
       
   144                       jdkinternals.get(m).stream()
       
   145                           .forEach(pn -> writer.format("   %s/%s%s", m, pn, separator));
       
   146                   } else {
       
   147                       writer.format("   %s%s", m, separator);
       
   148                   }
       
   149               });
       
   150     }
   170     }
   151 
   171 
   152     /*
   172     /*
   153      * Returns a stream of dependence map from an Archive to the set of JDK
   173      * Returns a stream of dependence map from an Archive to the set of JDK
   154      * internal APIs being used.
   174      * internal APIs being used.
   158                    .filter(source -> !source.getModule().isNamed()
   178                    .filter(source -> !source.getModule().isNamed()
   159                             || configuration.rootModules().contains(source))
   179                             || configuration.rootModules().contains(source))
   160                    .map(deps::get);
   180                    .map(deps::get);
   161     }
   181     }
   162 
   182 
   163     private class RootModule extends Module {
   183     /*
   164         final ModuleDescriptor descriptor;
   184      * RootModule serves as the root node for building the module graph
   165         RootModule(String name) {
   185      */
   166             super(name);
   186     private static class RootModule extends Module {
   167 
   187         static final String NAME = "root";
   168             ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(name);
   188         RootModule() {
   169             this.descriptor = builder.build();
   189             super(NAME, ModuleDescriptor.newModule(NAME).build(), false);
   170         }
       
   171 
       
   172         @Override
       
   173         public ModuleDescriptor descriptor() {
       
   174             return descriptor;
       
   175         }
   190         }
   176     }
   191     }
   177 
   192 
   178 }
   193 }