# HG changeset patch # User mchung # Date 1542868441 28800 # Node ID c16b6cc93272762253e92e1f6046b4dc13bed2b2 # Parent e00cf18e2593e9d97aa640eb41c726a8de5c6c9a 8213909: jdeps --print-module-deps should report missing dependences 8168869: jdeps: localized messages don't use proper line breaks Reviewed-by: sundar diff -r e00cf18e2593 -r c16b6cc93272 src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java Wed Nov 21 22:33:33 2018 -0800 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java Wed Nov 21 22:34:01 2018 -0800 @@ -32,6 +32,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.UncheckedIOException; +import java.lang.module.ModuleDescriptor; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -39,6 +40,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -74,6 +76,7 @@ protected final Map locationToArchive = new HashMap<>(); static final Archive NOT_FOUND = new Archive(JdepsTask.getMessage("artifact.not.found")); + static final Predicate ANY = a -> true; /** * Constructs an Analyzer instance. @@ -161,7 +164,7 @@ * Visit the dependencies of the given source. * If the requested level is SUMMARY, it will visit the required archives list. */ - void visitDependences(Archive source, Visitor v, Type level) { + void visitDependences(Archive source, Visitor v, Type level, Predicate targetFilter) { if (level == Type.SUMMARY) { final Dependences result = results.get(source); final Set reqs = result.requires(); @@ -184,7 +187,7 @@ Dependences result = results.get(source); if (level != type) { // requesting different level of analysis - result = new Dependences(source, level); + result = new Dependences(source, level, targetFilter); source.visitDependences(result); } result.dependencies().stream() @@ -196,7 +199,11 @@ } void visitDependences(Archive source, Visitor v) { - visitDependences(source, v, type); + visitDependences(source, v, type, ANY); + } + + void visitDependences(Archive source, Visitor v, Type level) { + visitDependences(source, v, level, ANY); } /** @@ -208,12 +215,17 @@ protected final Set requires; protected final Set deps; protected final Type level; + protected final Predicate targetFilter; private Profile profile; Dependences(Archive archive, Type level) { + this(archive, level, ANY); + } + Dependences(Archive archive, Type level, Predicate targetFilter) { this.archive = archive; this.deps = new HashSet<>(); this.requires = new HashSet<>(); this.level = level; + this.targetFilter = targetFilter; } Set dependencies() { @@ -266,7 +278,7 @@ @Override public void visit(Location o, Location t) { Archive targetArchive = findArchive(t); - if (filter.accepts(o, archive, t, targetArchive)) { + if (filter.accepts(o, archive, t, targetArchive) && targetFilter.test(targetArchive)) { addDep(o, t); if (archive != targetArchive && !requires.contains(targetArchive)) { requires.add(targetArchive); @@ -368,13 +380,21 @@ } } + /* + * Returns true if the given archive represents not found. + */ + static boolean notFound(Archive archive) { + return archive == NOT_FOUND || archive == REMOVED_JDK_INTERNALS; + } + static final Jdk8Internals REMOVED_JDK_INTERNALS = new Jdk8Internals(); static class Jdk8Internals extends Module { - private final String JDK8_INTERNALS = "/com/sun/tools/jdeps/resources/jdk8_internals.txt"; + private static final String NAME = "JDK removed internal API"; + private static final String JDK8_INTERNALS = "/com/sun/tools/jdeps/resources/jdk8_internals.txt"; private final Set jdk8Internals; private Jdk8Internals() { - super("JDK removed internal API"); + super(NAME, ModuleDescriptor.newModule("jdk8internals").build(), true); try (InputStream in = JdepsTask.class.getResourceAsStream(JDK8_INTERNALS); BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { this.jdk8Internals = reader.lines() @@ -394,11 +414,6 @@ } @Override - public String name() { - return getName(); - } - - @Override public boolean isJDK() { return true; } diff -r e00cf18e2593 -r c16b6cc93272 src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java Wed Nov 21 22:33:33 2018 -0800 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/DependencyFinder.java Wed Nov 21 22:34:01 2018 -0800 @@ -38,6 +38,7 @@ import java.io.IOException; import java.io.UncheckedIOException; +import java.nio.file.Paths; import java.util.Collections; import java.util.Deque; import java.util.HashMap; @@ -172,7 +173,7 @@ parsedArchives.get(finder).add(archive); - trace("parsing %s %s%n", archive.getName(), archive.path()); + trace("parsing %s %s%n", archive.getName(), archive.getPathName()); FutureTask> task = new FutureTask<>(() -> { Set targets = new HashSet<>(); for (ClassFile cf : archive.reader().getClassFiles()) { @@ -206,7 +207,6 @@ parsedClasses.putIfAbsent(d.getOrigin(), archive); } } - return targets; }); tasks.add(task); @@ -264,8 +264,7 @@ FutureTask> task; while ((task = tasks.poll()) != null) { // wait for completion - if (!task.isDone()) - targets.addAll(task.get()); + targets.addAll(task.get()); } return targets; } catch (InterruptedException|ExecutionException e) { diff -r e00cf18e2593 -r c16b6cc93272 src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Wed Nov 21 22:33:33 2018 -0800 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Wed Nov 21 22:34:01 2018 -0800 @@ -83,42 +83,27 @@ private final List classpathArchives = new ArrayList<>(); private final List initialArchives = new ArrayList<>(); private final Set rootModules = new HashSet<>(); - private final Configuration configuration; private final Runtime.Version version; - private JdepsConfiguration(SystemModuleFinder systemModulePath, + private JdepsConfiguration(Configuration config, + SystemModuleFinder systemModulePath, ModuleFinder finder, Set roots, List classpaths, List initialArchives, - Set tokens, Runtime.Version version) throws IOException { trace("root: %s%n", roots); - + trace("initial archives: %s%n", initialArchives); + trace("class path: %s%n", classpaths); this.system = systemModulePath; this.finder = finder; this.version = version; - // build root set for resolution - Set mods = new HashSet<>(roots); - if (tokens.contains(ALL_SYSTEM)) { - systemModulePath.findAll().stream() - .map(mref -> mref.descriptor().name()) - .forEach(mods::add); - } - - if (tokens.contains(ALL_DEFAULT)) { - mods.addAll(systemModulePath.defaultSystemRoots()); - } - - this.configuration = Configuration.empty() - .resolve(finder, ModuleFinder.of(), mods); - - this.configuration.modules().stream() - .map(ResolvedModule::reference) - .forEach(this::addModuleReference); + config.modules().stream() + .map(ResolvedModule::reference) + .forEach(this::addModuleReference); // packages in unnamed module initialArchives.forEach(archive -> { @@ -538,14 +523,6 @@ .forEach(rootModules::add); } - // add all modules to the root set for unnamed module or set explicitly - boolean unnamed = !initialArchives.isEmpty() || !classPaths.isEmpty(); - if ((unnamed || tokens.contains(ALL_MODULE_PATH)) && appModulePath != null) { - appModulePath.findAll().stream() - .map(mref -> mref.descriptor().name()) - .forEach(rootModules::add); - } - // no archive is specified for analysis // add all system modules as root if --add-modules ALL-SYSTEM is specified if (tokens.contains(ALL_SYSTEM) && rootModules.isEmpty() && @@ -556,16 +533,41 @@ .forEach(rootModules::add); } - if (unnamed && !tokens.contains(ALL_DEFAULT)) { - tokens.add(ALL_SYSTEM); + // add all modules on app module path as roots if ALL-MODULE-PATH is specified + if ((tokens.contains(ALL_MODULE_PATH)) && appModulePath != null) { + appModulePath.findAll().stream() + .map(mref -> mref.descriptor().name()) + .forEach(rootModules::add); } - return new JdepsConfiguration(systemModulePath, + + // build root set for module resolution + Set mods = new HashSet<>(rootModules); + // if archives are specified for analysis, then consider as unnamed module + boolean unnamed = !initialArchives.isEmpty() || !classPaths.isEmpty(); + if (tokens.contains(ALL_DEFAULT)) { + mods.addAll(systemModulePath.defaultSystemRoots()); + } else if (tokens.contains(ALL_SYSTEM) || unnamed) { + // resolve all system modules as unnamed module may reference any class + systemModulePath.findAll().stream() + .map(mref -> mref.descriptor().name()) + .forEach(mods::add); + } + if (unnamed && appModulePath != null) { + // resolve all modules on module path as unnamed module may reference any class + appModulePath.findAll().stream() + .map(mref -> mref.descriptor().name()) + .forEach(mods::add); + } + + // resolve the module graph + Configuration config = Configuration.empty().resolve(finder, ModuleFinder.of(), mods); + return new JdepsConfiguration(config, + systemModulePath, finder, rootModules, classPaths, initialArchives, - tokens, version); } diff -r e00cf18e2593 -r c16b6cc93272 src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java Wed Nov 21 22:33:33 2018 -0800 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsFilter.java Wed Nov 21 22:34:01 2018 -0800 @@ -55,6 +55,7 @@ private final boolean filterSamePackage; private final boolean filterSameArchive; private final boolean findJDKInternals; + private final boolean findMissingDeps; private final Pattern includePattern; private final Set requires; @@ -64,6 +65,7 @@ boolean filterSamePackage, boolean filterSameArchive, boolean findJDKInternals, + boolean findMissingDeps, Pattern includePattern, Set requires) { this.filter = filter; @@ -71,6 +73,7 @@ this.filterSamePackage = filterSamePackage; this.filterSameArchive = filterSameArchive; this.findJDKInternals = findJDKInternals; + this.findMissingDeps = findMissingDeps; this.includePattern = includePattern; this.requires = requires; } @@ -153,6 +156,8 @@ Module module = targetArchive.getModule(); return originArchive != targetArchive && isJDKInternalPackage(module, target.getPackageName()); + } else if (findMissingDeps) { + return Analyzer.notFound(targetArchive); } else if (filterSameArchive) { // accepts origin and target that from different archive return originArchive != targetArchive; @@ -188,6 +193,7 @@ boolean filterSamePackage; boolean filterSameArchive; boolean findJDKInterals; + boolean findMissingDeps; // source filters Pattern includePattern; Set requires = new HashSet<>(); @@ -221,6 +227,10 @@ this.findJDKInterals = value; return this; } + public Builder findMissingDeps(boolean value) { + this.findMissingDeps = value; + return this; + } public Builder includePattern(Pattern regex) { this.includePattern = regex; return this; @@ -238,6 +248,7 @@ filterSamePackage, filterSameArchive, findJDKInterals, + findMissingDeps, includePattern, requires); } diff -r e00cf18e2593 -r c16b6cc93272 src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Wed Nov 21 22:33:33 2018 -0800 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Wed Nov 21 22:34:01 2018 -0800 @@ -357,6 +357,11 @@ task.command = task.listModuleDeps(CommandOption.PRINT_MODULE_DEPS); } }, + new Option(false, "--ignore-missing-deps") { + void process(JdepsTask task, String opt, String arg) { + task.options.ignoreMissingDeps = true; + } + }, // ---- Target filtering options ---- new Option(true, "-p", "-package", "--package") { @@ -401,6 +406,11 @@ } } }, + new Option(false, "--missing-deps") { + void process(JdepsTask task, String opt, String arg) { + task.options.findMissingDeps = true; + } + }, // ---- Source filtering options ---- new Option(true, "-include") { @@ -415,15 +425,19 @@ } }, - new Option(false, "-R", "-recursive") { - void process(JdepsTask task, String opt, String arg) { - task.options.depth = 0; + new Option(false, "-R", "-recursive", "--recursive") { + void process(JdepsTask task, String opt, String arg) throws BadArgs { + task.options.recursive = Options.RECURSIVE; // turn off filtering task.options.filterSameArchive = false; task.options.filterSamePackage = false; } }, - + new Option(false, "--no-recursive") { + void process(JdepsTask task, String opt, String arg) throws BadArgs { + task.options.recursive = Options.NO_RECURSIVE; + } + }, new Option(false, "-I", "--inverse") { void process(JdepsTask task, String opt, String arg) { task.options.inverse = true; @@ -437,9 +451,9 @@ new Option(false, "--compile-time") { void process(JdepsTask task, String opt, String arg) { task.options.compileTimeView = true; + task.options.recursive = Options.RECURSIVE; task.options.filterSamePackage = true; task.options.filterSameArchive = true; - task.options.depth = 0; } }, @@ -611,6 +625,13 @@ } private ListModuleDeps listModuleDeps(CommandOption option) throws BadArgs { + // do transitive dependence analysis unless --no-recursive is set + if (options.recursive != Options.NO_RECURSIVE) { + options.recursive = Options.RECURSIVE; + } + // no need to record the dependences on the same archive or same package + options.filterSameArchive = true; + options.filterSamePackage = true; switch (option) { case LIST_DEPS: return new ListModuleDeps(option, true, false); @@ -677,16 +698,16 @@ @Override boolean checkOptions() { - if (options.findJDKInternals) { + if (options.findJDKInternals || options.findMissingDeps) { // cannot set any filter, -verbose and -summary option if (options.showSummary || options.verbose != null) { reportError("err.invalid.options", "-summary or -verbose", - "-jdkinternals"); + options.findJDKInternals ? "-jdkinternals" : "--missing-deps"); return false; } if (options.hasFilter()) { reportError("err.invalid.options", "--package, --regex, --require", - "-jdkinternals"); + options.findJDKInternals ? "-jdkinternals" : "--missing-deps"); return false; } } @@ -715,7 +736,7 @@ if (options.showSummary) return Type.SUMMARY; - if (options.findJDKInternals) + if (options.findJDKInternals || options.findMissingDeps) return Type.CLASS; // default to package-level verbose @@ -744,7 +765,7 @@ type, options.apiOnly); - boolean ok = analyzer.run(options.compileTimeView, options.depth); + boolean ok = analyzer.run(options.compileTimeView, options.depth()); // print skipped entries, if any if (!options.nowarning) { @@ -797,8 +818,8 @@ @Override boolean checkOptions() { - if (options.depth != 1) { - reportError("err.invalid.options", "-R", "--inverse"); + if (options.recursive != -1 || options.depth != -1) { + reportError("err.invalid.options", "--recursive and --no-recursive", "--inverse"); return false; } @@ -925,12 +946,7 @@ if (!ok && !options.nowarning) { reportError("err.missing.dependences"); - builder.visitMissingDeps( - (origin, originArchive, target, targetArchive) -> { - if (builder.notFound(targetArchive)) - log.format(" %-50s -> %-50s %s%n", - origin, target, targetArchive.getName()); - }); + builder.visitMissingDeps(new SimpleDepVisitor()); } return ok; } @@ -993,13 +1009,15 @@ @Override boolean checkOptions() { if (options.showSummary || options.verbose != null) { - reportError("err.invalid.options", "-summary or -verbose", - option); + reportError("err.invalid.options", "-summary or -verbose", option); return false; } if (options.findJDKInternals) { - reportError("err.invalid.options", "-jdkinternals", - option); + reportError("err.invalid.options", "-jdkinternals", option); + return false; + } + if (options.findMissingDeps) { + reportError("err.invalid.options", "--missing-deps", option); return false; } @@ -1015,16 +1033,22 @@ @Override boolean run(JdepsConfiguration config) throws IOException { - return new ModuleExportsAnalyzer(config, - dependencyFilter(config), - jdkinternals, - reduced, - log, - separator).run(); + ModuleExportsAnalyzer analyzer = new ModuleExportsAnalyzer(config, + dependencyFilter(config), + jdkinternals, + reduced, + log, + separator); + boolean ok = analyzer.run(options.depth(), options.ignoreMissingDeps); + if (!ok) { + reportError("err.cant.list.module.deps"); + log.println(); + analyzer.visitMissingDeps(new SimpleDepVisitor()); + } + return ok; } } - class GenDotFile extends AnalyzeDeps { final Path dotOutputDir; GenDotFile(Path dotOutputDir) { @@ -1053,6 +1077,18 @@ } } + class SimpleDepVisitor implements Analyzer.Visitor { + private Archive source; + @Override + public void visitDependence(String origin, Archive originArchive, String target, Archive targetArchive) { + if (source != originArchive) { + source = originArchive; + log.format("%s%n", originArchive); + } + log.format(" %-50s -> %-50s %s%n", origin, target, targetArchive.getName()); + } + } + /** * Returns a filter used during dependency analysis */ @@ -1066,6 +1102,7 @@ // target filters builder.filter(options.filterSamePackage, options.filterSameArchive); builder.findJDKInternals(options.findJDKInternals); + builder.findMissingDeps(options.findMissingDeps); // --require if (!options.requires.isEmpty()) { @@ -1158,11 +1195,8 @@ private String version(String key) { // key=version: mm.nn.oo[-milestone] // key=full: mm.mm.oo[-milestone]-build - if (ResourceBundleHelper.versionRB == null) { - return System.getProperty("java.version"); - } try { - return ResourceBundleHelper.versionRB.getString(key); + return ResourceBundleHelper.getVersion(key); } catch (MissingResourceException e) { return getMessage("version.unknown", System.getProperty("java.version")); } @@ -1170,13 +1204,15 @@ static String getMessage(String key, Object... args) { try { - return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args); + return MessageFormat.format(ResourceBundleHelper.getMessage(key), args); } catch (MissingResourceException e) { throw new InternalError("Missing message: " + key); } } private static class Options { + static final int NO_RECURSIVE = 0; + static final int RECURSIVE = 1; boolean help; boolean version; boolean fullVersion; @@ -1186,6 +1222,8 @@ boolean apiOnly; boolean showLabel; boolean findJDKInternals; + boolean findMissingDeps; + boolean ignoreMissingDeps; boolean nowarning = false; Analyzer.Type verbose; // default filter references from same package @@ -1193,7 +1231,8 @@ boolean filterSameArchive = false; Pattern filterRegex; String classpath; - int depth = 1; + int recursive = -1; // 0: --no-recursive, 1: --recursive + int depth = -1; Set requires = new HashSet<>(); Set packageNames = new HashSet<>(); Pattern regex; // apply to the dependences @@ -1222,9 +1261,23 @@ if (packageNames.size() > 0) count++; return count; } + + int depth() { + // ignore -depth if --no-recursive is set + if (recursive == NO_RECURSIVE) + return 1; + + // depth == 0 if recursive + if (recursive == RECURSIVE && depth == -1) + return 0; + + // default depth is 1 unless specified via -depth option + return depth == -1 ? 1 : depth; + } } private static class ResourceBundleHelper { + static final String LS = System.lineSeparator(); static final ResourceBundle versionRB; static final ResourceBundle bundle; static final ResourceBundle jdkinternals; @@ -1247,6 +1300,21 @@ throw new InternalError("Cannot find jdkinternals resource bundle"); } } + + static String getMessage(String key) { + return bundle.getString(key).replace("\n", LS); + } + + static String getVersion(String key) { + if (ResourceBundleHelper.versionRB == null) { + return System.getProperty("java.version"); + } + return versionRB.getString(key).replace("\n", LS); + } + + static String getSuggestedReplacement(String key) { + return ResourceBundleHelper.jdkinternals.getString(key).replace("\n", LS); + } } /** @@ -1258,7 +1326,7 @@ String value = null; while (value == null && name != null) { try { - value = ResourceBundleHelper.jdkinternals.getString(name); + value = ResourceBundleHelper.getSuggestedReplacement(name); } catch (MissingResourceException e) { // go up one subpackage level int i = name.lastIndexOf('.'); diff -r e00cf18e2593 -r c16b6cc93272 src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java Wed Nov 21 22:33:33 2018 -0800 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Module.java Wed Nov 21 22:34:01 2018 -0800 @@ -58,12 +58,16 @@ private final URI location; protected Module(String name) { + this(name, null, false); + } + + protected Module(String name, ModuleDescriptor descriptor, boolean isSystem) { super(name); - this.descriptor = null; + this.descriptor = descriptor; this.location = null; this.exports = Collections.emptyMap(); this.opens = Collections.emptyMap(); - this.isSystem = true; + this.isSystem = isSystem; } private Module(String name, @@ -89,11 +93,11 @@ } public boolean isNamed() { - return true; + return descriptor != null; } public boolean isAutomatic() { - return descriptor.isAutomatic(); + return descriptor != null && descriptor.isAutomatic(); } public Module getModule() { @@ -232,9 +236,7 @@ private static class UnnamedModule extends Module { private UnnamedModule() { - super("unnamed", null, null, - Collections.emptyMap(), Collections.emptyMap(), - false, null); + super("unnamed", null, false); } @Override @@ -243,16 +245,6 @@ } @Override - public boolean isNamed() { - return false; - } - - @Override - public boolean isAutomatic() { - return false; - } - - @Override public boolean isExported(String pn) { return true; } diff -r e00cf18e2593 -r c16b6cc93272 src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java Wed Nov 21 22:33:33 2018 -0800 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleExportsAnalyzer.java Wed Nov 21 22:34:01 2018 -0800 @@ -49,42 +49,47 @@ public class ModuleExportsAnalyzer extends DepsAnalyzer { // source archive to its dependences and JDK internal APIs it references private final Map>> deps = new HashMap<>(); - private final boolean showJdkInternals; + private final Map> missingDeps = new HashMap<>(); + private final boolean showInternals; private final boolean reduced; private final PrintWriter writer; private final String separator; public ModuleExportsAnalyzer(JdepsConfiguration config, JdepsFilter filter, - boolean showJdkInternals, + boolean showInternals, boolean reduced, PrintWriter writer, String separator) { super(config, filter, null, Analyzer.Type.PACKAGE, false /* all classes */); - this.showJdkInternals = showJdkInternals; + this.showInternals = showInternals; this.reduced = reduced; this.writer = writer; this.separator = separator; } - @Override - public boolean run() throws IOException { - // analyze dependences - boolean rc = super.run(); + public boolean run(int maxDepth, boolean ignoreMissingDeps) throws IOException { + // use compile time view so that the entire archive on classpath is analyzed + boolean rc = super.run(true, maxDepth); // A visitor to record the module-level dependences as well as - // use of JDK internal APIs + // use of internal APIs Analyzer.Visitor visitor = (origin, originArchive, target, targetArchive) -> { - Set jdkInternals = + Set internals = deps.computeIfAbsent(originArchive, _k -> new HashMap<>()) .computeIfAbsent(targetArchive, _k -> new HashSet<>()); Module module = targetArchive.getModule(); - if (showJdkInternals && originArchive.getModule() != module && - module.isJDK() && !module.isExported(target)) { - // use of JDK internal APIs - jdkInternals.add(target); + if (showInternals && originArchive.getModule() != module && + module.isNamed() && !module.isExported(target, module.name())) { + // use of internal APIs + internals.add(target); + } + if (!ignoreMissingDeps && Analyzer.notFound(targetArchive)) { + Set notFound = + missingDeps.computeIfAbsent(origin, _k -> new HashSet<>()); + notFound.add(target); } }; @@ -94,10 +99,26 @@ .sorted(Comparator.comparing(Archive::getName)) .forEach(archive -> analyzer.visitDependences(archive, visitor)); + // error if any missing dependence + if (!rc || !missingDeps.isEmpty()) { + return false; + } + + Map> internalPkgs = internalPackages(); Set modules = modules(); - if (showJdkInternals) { + if (showInternals) { // print modules and JDK internal API dependences - printDependences(modules); + Stream.concat(modules.stream(), internalPkgs.keySet().stream()) + .sorted(Comparator.comparing(Module::name)) + .distinct() + .forEach(m -> { + if (internalPkgs.containsKey(m)) { + internalPkgs.get(m).stream() + .forEach(pn -> writer.format(" %s/%s%s", m, pn, separator)); + } else { + writer.format(" %s%s", m, separator); + } + }); } else { // print module dependences writer.println(modules.stream().map(Module::name).sorted() @@ -106,16 +127,28 @@ return rc; } + /* + * Prints missing dependences + */ + void visitMissingDeps(Analyzer.Visitor visitor) { + archives.stream() + .filter(analyzer::hasDependences) + .sorted(Comparator.comparing(Archive::getName)) + .filter(m -> analyzer.requires(m).anyMatch(Analyzer::notFound)) + .forEach(m -> { + analyzer.visitDependences(m, visitor, Analyzer.Type.VERBOSE, Analyzer::notFound); + }); + } + private Set modules() { // build module graph ModuleGraphBuilder builder = new ModuleGraphBuilder(configuration); - Module root = new RootModule("root"); + Module root = new RootModule(); builder.addModule(root); // find named module dependences dependenceStream() .flatMap(map -> map.keySet().stream()) - .filter(m -> m.getModule().isNamed() - && !configuration.rootModules().contains(m)) + .filter(m -> m.getModule().isNamed() && !configuration.rootModules().contains(m)) .map(Archive::getModule) .forEach(m -> builder.addEdge(root, m)); @@ -125,28 +158,15 @@ return g.adjacentNodes(root); } - private void printDependences(Set modules) { - // find use of JDK internals - Map> jdkinternals = new HashMap<>(); + private Map> internalPackages() { + Map> internalPkgs = new HashMap<>(); dependenceStream() .flatMap(map -> map.entrySet().stream()) .filter(e -> e.getValue().size() > 0) - .forEach(e -> jdkinternals.computeIfAbsent(e.getKey().getModule(), - _k -> new TreeSet<>()) + .forEach(e -> internalPkgs.computeIfAbsent(e.getKey().getModule(), + _k -> new TreeSet<>()) .addAll(e.getValue())); - - // print modules and JDK internal API dependences - Stream.concat(modules.stream(), jdkinternals.keySet().stream()) - .sorted(Comparator.comparing(Module::name)) - .distinct() - .forEach(m -> { - if (jdkinternals.containsKey(m)) { - jdkinternals.get(m).stream() - .forEach(pn -> writer.format(" %s/%s%s", m, pn, separator)); - } else { - writer.format(" %s%s", m, separator); - } - }); + return internalPkgs; } /* @@ -160,18 +180,13 @@ .map(deps::get); } - private class RootModule extends Module { - final ModuleDescriptor descriptor; - RootModule(String name) { - super(name); - - ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(name); - this.descriptor = builder.build(); - } - - @Override - public ModuleDescriptor descriptor() { - return descriptor; + /* + * RootModule serves as the root node for building the module graph + */ + private static class RootModule extends Module { + static final String NAME = "root"; + RootModule() { + super(NAME, ModuleDescriptor.newModule(NAME).build(), false); } } diff -r e00cf18e2593 -r c16b6cc93272 src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleInfoBuilder.java --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleInfoBuilder.java Wed Nov 21 22:33:33 2018 -0800 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ModuleInfoBuilder.java Wed Nov 21 22:34:01 2018 -0800 @@ -137,17 +137,13 @@ } } - boolean notFound(Archive m) { - return m == NOT_FOUND || m == REMOVED_JDK_INTERNALS; - } - private Module toNormalModule(Module module, Set requiresTransitive) throws IOException { // done analysis module.close(); - if (analyzer.requires(module).anyMatch(this::notFound)) { + if (analyzer.requires(module).anyMatch(Analyzer::notFound)) { // missing dependencies return null; } @@ -182,9 +178,9 @@ void visitMissingDeps(Analyzer.Visitor visitor) { automaticModules().stream() - .filter(m -> analyzer.requires(m).anyMatch(this::notFound)) + .filter(m -> analyzer.requires(m).anyMatch(Analyzer::notFound)) .forEach(m -> { - analyzer.visitDependences(m, visitor, Analyzer.Type.VERBOSE); + analyzer.visitDependences(m, visitor, Analyzer.Type.VERBOSE, Analyzer::notFound); }); } diff -r e00cf18e2593 -r c16b6cc93272 src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Wed Nov 21 22:33:33 2018 -0800 +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Wed Nov 21 22:34:01 2018 -0800 @@ -57,6 +57,13 @@ \ name (may be given multiple times). --package,\n\ \ --regex, --require are mutual exclusive. +main.opt.missing-deps=\ +\ --missing-deps Finds missing dependences. This option\n\ +\ cannot be used with -p, -e and -s options. + +main.opt.ignore-missing-deps=\ +\ --ignore-missing-deps Ignore missing dependences. + main.opt.include=\n\ \Options to filter classes to be analyzed:\n\ \ -include Restrict analysis to classes matching pattern\n\ @@ -86,13 +93,18 @@ \ Adds modules to the root set for analysis main.opt.R=\ -\ -R -recursive Recursively traverse all run-time dependences.\n\ +\ -R\n\ +\ --recursive Recursively traverse all run-time dependences.\n\ \ The -R option implies -filter:none. If -p,\n\ \ -e, -f option is specified, only the matching\n\ \ dependences are analyzed. +main.opt.no-recursive=\ +\ --no-recursive Do not recursively traverse dependences. + main.opt.I=\ -\ -I --inverse Analyzes the dependences per other given options\n\ +\ -I\n\ +\ --inverse Analyzes the dependences per other given options\n\ \ and then find all artifacts that directly\n\ \ and indirectly depend on the matching nodes.\n\ \ This is equivalent to the inverse of\n\ @@ -157,9 +169,11 @@ main.opt.list-deps=\ \ --list-deps Lists the module dependences. It also prints\n\ -\ any JDK internal API packages if referenced.\n\ -\ This option does not show dependences on the\n\ -\ class path or not found. +\ any internal API packages if referenced.\n\ +\ This option transitively analyzes libraries on\n\ +\ class path and module path if referenced.\n\ +\ Use --no-recursive option for non-transitive\n\ +\ dependency analysis. main.opt.list-reduced-deps=\ \ --list-reduced-deps Same as --list-deps with not listing\n\ @@ -207,6 +221,10 @@ err.multirelease.option.notfound={0} is a multi-release jar file but --multi-release option is not set err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2} err.multirelease.jar.malformed=malformed multi-release jar, {0}, bad entry: {1} +err.cant.list.module.deps=\ +Missing dependencies from the module path and classpath.\n\ +To suppress this error, use --ignore-missing-deps to continue. + warn.invalid.arg=Path does not exist: {0} warn.skipped.entry={0} warn.split.package=split package: {0} {1} diff -r e00cf18e2593 -r c16b6cc93272 test/langtools/tools/jdeps/Basic.java --- a/test/langtools/tools/jdeps/Basic.java Wed Nov 21 22:33:33 2018 -0800 +++ b/test/langtools/tools/jdeps/Basic.java Wed Nov 21 22:34:01 2018 -0800 @@ -37,6 +37,7 @@ import java.io.StringWriter; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; import java.util.regex.*; import java.util.stream.Collectors; @@ -135,6 +136,19 @@ new String[] {"java.lang.Object", "java.lang.String", "p.Foo", "p.Bar"}, new String[] {"compact1", "compact1", dir1.toFile().getName(), dir2.toFile().getName()}, new String[] {"-v", "-classpath", cpath.toString(), "Test.class"}); + + // tests --missing-deps option + test(new File(testDir, "Test.class"), + new String[] {"p.Foo", "p.Bar"}, + new String[] {"not found", "not found"}, + new String[] {"--missing-deps"}); + + // no missing dependence + test(new File(testDir, "Test.class"), + new String[0], + new String[0], + new String[] {"--missing-deps", "-classpath", cpath.toString()}); + return errors; } diff -r e00cf18e2593 -r c16b6cc93272 test/langtools/tools/jdeps/MultiReleaseJar.java --- a/test/langtools/tools/jdeps/MultiReleaseJar.java Wed Nov 21 22:33:33 2018 -0800 +++ b/test/langtools/tools/jdeps/MultiReleaseJar.java Wed Nov 21 22:34:01 2018 -0800 @@ -27,7 +27,7 @@ * @summary Tests for jdeps tool with multi-release jar files * @modules jdk.jdeps/com.sun.tools.jdeps * @library mrjar mrjar/base mrjar/9 mrjar/10 mrjar/v9 mrjar/v10 - * @build test.* p.* q.* foo/* + * @build test.* p.* q.* foo/* Main * @run testng MultiReleaseJar */ @@ -59,10 +59,7 @@ testJdk = System.getProperty("test.jdk"); fileSep = System.getProperty("file.separator"); cmdPath = Paths.get(testJdk, "bin"); - } - @Test - public void basic() throws Exception { // build Version.jar, Version_9.jar and main.jar Result r = run("jar -cf Version.jar -C base test --release 9 -C 9 test --release 10 -C 10 test"); checkResult(r); @@ -70,11 +67,20 @@ r = run("jar -cf Version_9.jar -C base test --release 9 -C 9 test"); checkResult(r); - r = run("jar -cf Main.jar test/Main.class"); + r = run("jar -cf Main.jar Main.class"); + checkResult(r); + + r = run("jar -cf Foo.jar -C base p"); checkResult(r); - // try out a bunch of things - r = run("jdeps --multi-release 9 -v missing.jar"); + Path foo = Paths.get(System.getProperty("test.classes")).resolve("modules").resolve("foo"); + r = run("jar -uf Foo.jar --release 9 -C " + foo.toString() + " module-info.class --release 10 -C v10 q"); + checkResult(r); + } + + @Test + public void basic() throws Exception { + Result r = run("jdeps --multi-release 9 -v missing.jar"); checkResult(r, false, "Warning: Path does not exist: missing.jar"); r = run("jdeps -v Version.jar"); @@ -115,7 +121,7 @@ r = run("jdeps --multi-release 9.1 -v Version.jar"); checkResult(r, false, "Error: invalid argument for option: 9.1"); - runJdeps("test/Main.class"); + runJdeps("Main.class"); runJdeps("Main.jar"); } @@ -124,14 +130,14 @@ Result r = run("jdeps -v -R -cp Version.jar " + path); checkResult(r, false, "--multi-release option is not set"); - r = run("jdeps -v -R -cp Version.jar -multi-release 9 " + path); + r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar -multi-release 9 " + path); checkResult(r, false, "Error: unknown option: -multi-release", "Usage: jdeps ", - name + " ->", - "test.Main", - "test.Main", - "test.Main", - "Version.jar ->", + name + " -> Version.jar", + name + " -> foo", + name + " -> java.base", + "Main", + "Main", + "Main", + "Main", + "Version.jar -> java.base", "9/test.NonPublic", "9/test.NonPublic", "9/test.Version", "9/test.Version", "9/test.Version", - "9/test.Version" + "9/test.Version", + "foo", + "Foo.jar", + "requires mandated java.base", + "foo -> java.base", + "p.Foo" ); - r = run("jdeps -v -R -cp Version.jar --multi-release 10 " + path); + r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar --multi-release 10 " + path); checkResult(r, true, - name + " ->", - name + " ->", - "test.Main", - "test.Main", - "test.Main", + name + " -> Version.jar", + name + " -> foo", + name + " -> java.base", + "Main", + "Main", + "Main", + "Main", "Version.jar ->", "10/test.Version", "10/test.Version", "10/test.Version", "10/test.Version", "9/test.NonPublic", - "9/test.NonPublic" + "9/test.NonPublic", + "foo", + "Foo.jar", + "requires mandated java.base", + "foo -> java.base", + "p.Foo" ); - r = run("jdeps -v -R -cp Version.jar --multi-release base " + path); + r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar --multi-release base " + path); checkResult(r, true, - name + " ->", - name + " ->", - "test.Main", - "test.Main", - "test.Main", + name + " -> Version.jar", + name + " -> foo", + name + " -> java.base", + "Main", + "Main", + "Main", + "Main", "Version.jar ->", "test.Version", - "test.Version" + "test.Version", + "foo", + "Foo.jar", + "requires mandated java.base", + "foo -> java.base", + "p.Foo" ); - r = run("jdeps -v -R -cp Version.jar --multi-release 9.1 " + path); + r = run("jdeps -v -R -cp Version.jar --module-path Foo.jar --multi-release 9.1 " + path); checkResult(r, false, "Error: invalid argument for option: 9.1"); // Version_9.jar does not have any version 10 entry - r = run("jdeps -v -R -cp Version_9.jar --multi-release 10 " + path); + r = run("jdeps -v -R -cp Version_9.jar --module-path Foo.jar --multi-release 10 " + path); checkResult(r, true, - name + " ->", - name + " ->", - "test.Main", - "test.Main", - "test.Main", + name + " -> Version_9.jar", + name + " -> foo", + name + " -> java.base", + "Main", + "Main", + "Main", + "Main", "Version_9.jar ->", "9/test.NonPublic", "9/test.NonPublic", "9/test.Version", "9/test.Version", "9/test.Version", - "9/test.Version" + "9/test.Version", + "foo", + "Foo.jar", + "requires mandated java.base", + "foo -> java.base", + "p.Foo" ); } @@ -236,17 +270,10 @@ @Test public void modularJar() throws Exception { - Result r = run("jar -cf foo.jar -C base p"); - checkResult(r); - - Path foo = Paths.get(System.getProperty("test.classes")).resolve("modules").resolve("foo"); - r = run("jar -uf foo.jar --release 9 -C " + foo.toString() + " module-info.class --release 10 -C v10 q"); - checkResult(r); - - r = run("jdeps -v --multi-release 10 --module-path foo.jar -m foo"); + Result r = run("jdeps -v --multi-release 10 --module-path Foo.jar -m foo"); checkResult(r, true, "foo", // module name - "foo.jar", // the path to foo.jar + "Foo.jar", // the path to Foo.jar "requires mandated java.base", // module dependences "foo -> java.base", "10/q.Bar", @@ -255,27 +282,24 @@ "p.Foo" ); - r = run("jdeps --multi-release 9 --module-path foo.jar Main.jar"); + r = run("jdeps --multi-release 9 -cp Version.jar --module-path Foo.jar Main.jar"); checkResult(r, true, - "Main.jar ->", - "test", - "foo", // module name - "foo.jar", // the path to foo.jar - "requires mandated java.base", // module dependences - "foo -> java.base", - "p" + "Main.jar -> Version.jar", + "Main.jar -> foo", + "Main.jar -> java.base", + "-> java.lang", + "-> p", + "-> test" ); - r = run("jdeps --multi-release 10 --module-path foo.jar Main.jar"); + r = run("jdeps --multi-release 10 -cp Version.jar --module-path Foo.jar Main.jar"); checkResult(r, true, - "Main.jar ->", - "test", - "foo", // module name - "foo.jar", // the path to foo.jar - "requires mandated java.base", // module dependences - "foo -> java.base", - "p", - "q" + "Main.jar -> Version.jar", + "Main.jar -> foo", + "Main.jar -> java.base", + "-> java.lang", + "-> p", + "-> test" ); } diff -r e00cf18e2593 -r c16b6cc93272 test/langtools/tools/jdeps/Options.java --- a/test/langtools/tools/jdeps/Options.java Wed Nov 21 22:33:33 2018 -0800 +++ b/test/langtools/tools/jdeps/Options.java Wed Nov 21 22:34:01 2018 -0800 @@ -53,7 +53,15 @@ }, { new String[] { "-jdkinternal", "-p", "java.lang", TEST_CLASSES }, - "--package, --regex, --require cannot be used with -jdkinternals option" + "--package, --regex, --require cannot be used with -jdkinternals option" + }, + { + new String[] { "--missing-deps", "-summary", TEST_CLASSES }, + "-summary or -verbose cannot be used with --missing-deps option" + }, + { + new String[] { "--missing-deps", "-p", "java.lang", TEST_CLASSES }, + "--package, --regex, --require cannot be used with --missing-deps option" }, { new String[] { "--inverse", TEST_CLASSES }, diff -r e00cf18e2593 -r c16b6cc93272 test/langtools/tools/jdeps/listdeps/ListModuleDeps.java --- a/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java Wed Nov 21 22:33:33 2018 -0800 +++ b/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java Wed Nov 21 22:34:01 2018 -0800 @@ -35,9 +35,11 @@ * @run testng ListModuleDeps */ +import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.List; import java.util.stream.Collectors; import org.testng.annotations.BeforeTest; @@ -53,6 +55,7 @@ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); private static final Path CLASSES_DIR = Paths.get("classes"); private static final Path LIB_DIR = Paths.get("lib"); + private static final Path LIB2_DIR = Paths.get("lib2"); private static final Path HI_CLASS = CLASSES_DIR.resolve("hi").resolve("Hi.class"); @@ -69,7 +72,8 @@ @BeforeTest public void compileAll() throws Exception { // compile library - assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "lib"), LIB_DIR)); + assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "lib2"), LIB2_DIR)); + assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "lib"), LIB_DIR, "-cp", LIB2_DIR.toString())); // simple program depends only on java.base assertTrue(CompilerUtils.compile(Paths.get(TEST_SRC, "src", "hi"), CLASSES_DIR)); @@ -111,7 +115,7 @@ @Test(dataProvider = "listdeps") public void testListDeps(Path classes, String[] expected) { JdepsRunner jdeps = JdepsRunner.run( - "--class-path", LIB_DIR.toString(), + "--class-path", LIB_DIR.toString() + File.pathSeparator + LIB2_DIR.toString(), "--list-deps", classes.toString() ); String[] output = Arrays.stream(jdeps.output()) @@ -123,7 +127,7 @@ @Test(dataProvider = "reduceddeps") public void testListReducedDeps(Path classes, String[] expected) { JdepsRunner jdeps = JdepsRunner.run( - "--class-path", LIB_DIR.toString(), + "--class-path", LIB_DIR.toString() + File.pathSeparator + LIB2_DIR.toString(), "--list-reduced-deps", classes.toString() ); String[] output = Arrays.stream(jdeps.output()) @@ -140,6 +144,7 @@ "java.base/jdk.internal.misc", "java.base/sun.security.util", "java.logging", + "java.management", "java.sql", "java.xml/jdk.xml.internal", "jdk.unsupported" @@ -154,6 +159,7 @@ { FOO_CLASS, new String[] { "java.base", "java.logging", + "java.management", "java.sql", "java.xml" } @@ -181,6 +187,7 @@ { CLASSES_DIR, new String[] { "java.base/jdk.internal.misc", "java.base/sun.security.util", + "java.management", "java.sql", "java.xml/jdk.xml.internal", "jdk.unsupported" @@ -194,6 +201,7 @@ { FOO_CLASS, new String[] { "java.base", + "java.management", "java.sql" } }, @@ -215,7 +223,7 @@ @Test(dataProvider = "moduledeps") public void testPrintModuleDeps(Path classes, String expected) { JdepsRunner jdeps = JdepsRunner.run( - "--class-path", LIB_DIR.toString(), + "--class-path", LIB_DIR.toString() + File.pathSeparator + LIB2_DIR.toString(), "--print-module-deps", classes.toString() ); String output = Arrays.stream(jdeps.output()) @@ -231,6 +239,32 @@ return new Object[][] { // java.xml is an implied reads edge from java.sql + { CLASSES_DIR, "java.base,java.management,java.sql,jdk.unsupported"}, + { HI_CLASS, "java.base"}, + { FOO_CLASS, "java.base,java.management,java.sql"}, + { BAR_CLASS, "java.base,java.xml"}, + { UNSAFE_CLASS, "java.base,jdk.unsupported"}, + }; + } + + @Test(dataProvider = "noRecursiveModuledeps") + public void testNoRecursiveModuleDeps(Path classes, String expected) { + JdepsRunner jdeps = JdepsRunner.run( + "--class-path", LIB_DIR.toString() + File.pathSeparator + LIB2_DIR.toString(), + "--print-module-deps", "--no-recursive", classes.toString() + ); + String output = Arrays.stream(jdeps.output()) + .map(s -> s.trim()) + .collect(Collectors.joining(",")); + assertEquals(output, expected); + } + + @DataProvider(name = "noRecursiveModuledeps") + public Object[][] noRecursiveModuledeps() { + Path barClass = CLASSES_DIR.resolve("z").resolve("Bar.class"); + + return new Object[][] { + // java.xml is an implied reads edge from java.sql { CLASSES_DIR, "java.base,java.sql,jdk.unsupported"}, { HI_CLASS, "java.base"}, { FOO_CLASS, "java.base,java.sql"}, @@ -238,4 +272,47 @@ { UNSAFE_CLASS, "java.base,jdk.unsupported"}, }; } + + @DataProvider(name = "recursiveDeps") + public Object[][] recursiveDeps() { + return new Object[][] { + { // lib2 is classpath but not analyzed because lib.Lib is not present + // but it is the only class depending on lib2.Lib2 + List.of("--list-deps", "--class-path", LIB2_DIR.toString(), + "--ignore-missing-deps", CLASSES_DIR.toString()), + new String[] { + "java.base/jdk.internal.misc", + "java.base/sun.security.util", + "java.logging", + "java.sql", + "java.xml/jdk.xml.internal", + "jdk.unsupported" + } + }, + { // lib2 is classpath but not analyzed because lib.Lib is not present + // but it is the only class depending on lib2.Lib2 + List.of("--print-module-deps", "--class-path", LIB2_DIR.toString(), + "--ignore-missing-deps", CLASSES_DIR.toString()), + new String[] { + "java.base,java.sql,jdk.unsupported" + } + }, + { // Foo depends on lib.Lib which depends on lib2.Libs + List.of("--print-module-deps", + "--ignore-missing-deps", FOO_CLASS.toString()), + new String[] { + "java.base,java.sql" + } + }, + }; + } + + @Test(dataProvider = "recursiveDeps") + public void testRecursiveDeps(List options, String[] expected) { + JdepsRunner jdeps = JdepsRunner.run(options.toArray(new String[0])); + String[] output = Arrays.stream(jdeps.output()) + .map(s -> s.trim()) + .toArray(String[]::new); + assertEquals(output, expected); + } } diff -r e00cf18e2593 -r c16b6cc93272 test/langtools/tools/jdeps/listdeps/src/lib/Lib.java --- a/test/langtools/tools/jdeps/listdeps/src/lib/Lib.java Wed Nov 21 22:33:33 2018 -0800 +++ b/test/langtools/tools/jdeps/listdeps/src/lib/Lib.java Wed Nov 21 22:34:01 2018 -0800 @@ -28,4 +28,5 @@ public class Lib { public static final String isCoalescing = XMLInputFactory.IS_COALESCING; public static boolean check() { return true; } + public static long getPid() { return lib2.Lib2.getPid(); } } diff -r e00cf18e2593 -r c16b6cc93272 test/langtools/tools/jdeps/mrjar/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/jdeps/mrjar/Main.java Wed Nov 21 22:34:01 2018 -0800 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import test.Version; +import p.Foo; + +public class Main { + public void run() { + Version v = new Version(); + v.getVersion(); + } + + public static void main(String[] args) { + (new Main()).run(); + Foo foo = new Foo(); + } +} diff -r e00cf18e2593 -r c16b6cc93272 test/langtools/tools/jdeps/mrjar/test/Main.java --- a/test/langtools/tools/jdeps/mrjar/test/Main.java Wed Nov 21 22:33:33 2018 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package test; - -public class Main { - public void run() { - Version v = new Version(); - v.getVersion(); - } - - public static void main(String[] args) { - (new Main()).run(); - } -}