langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/JdepsTask.java
changeset 30848 c275389a3680
parent 30842 b02fa8bb730c
parent 30847 9385b9c8506b
child 30849 fcfa8eb95c23
--- a/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu May 28 16:13:55 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1099 +0,0 @@
-/*
- * Copyright (c) 2012, 2014, 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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 com.sun.tools.jdeps;
-
-import com.sun.tools.classfile.AccessFlags;
-import com.sun.tools.classfile.ClassFile;
-import com.sun.tools.classfile.ConstantPoolException;
-import com.sun.tools.classfile.Dependencies;
-import com.sun.tools.classfile.Dependencies.ClassFileError;
-import com.sun.tools.classfile.Dependency;
-import com.sun.tools.classfile.Dependency.Location;
-import static com.sun.tools.jdeps.Analyzer.Type.*;
-import java.io.*;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.text.MessageFormat;
-import java.util.*;
-import java.util.regex.Pattern;
-
-/**
- * Implementation for the jdeps tool for static class dependency analysis.
- */
-class JdepsTask {
-    static class BadArgs extends Exception {
-        static final long serialVersionUID = 8765093759964640721L;
-        BadArgs(String key, Object... args) {
-            super(JdepsTask.getMessage(key, args));
-            this.key = key;
-            this.args = args;
-        }
-
-        BadArgs showUsage(boolean b) {
-            showUsage = b;
-            return this;
-        }
-        final String key;
-        final Object[] args;
-        boolean showUsage;
-    }
-
-    static abstract class Option {
-        Option(boolean hasArg, String... aliases) {
-            this.hasArg = hasArg;
-            this.aliases = aliases;
-        }
-
-        boolean isHidden() {
-            return false;
-        }
-
-        boolean matches(String opt) {
-            for (String a : aliases) {
-                if (a.equals(opt))
-                    return true;
-                if (hasArg && opt.startsWith(a + "="))
-                    return true;
-            }
-            return false;
-        }
-
-        boolean ignoreRest() {
-            return false;
-        }
-
-        abstract void process(JdepsTask task, String opt, String arg) throws BadArgs;
-        final boolean hasArg;
-        final String[] aliases;
-    }
-
-    static abstract class HiddenOption extends Option {
-        HiddenOption(boolean hasArg, String... aliases) {
-            super(hasArg, aliases);
-        }
-
-        boolean isHidden() {
-            return true;
-        }
-    }
-
-    static Option[] recognizedOptions = {
-        new Option(false, "-h", "-?", "-help") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.help = true;
-            }
-        },
-        new Option(true, "-dotoutput") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                Path p = Paths.get(arg);
-                if (Files.exists(p) && (!Files.isDirectory(p) || !Files.isWritable(p))) {
-                    throw new BadArgs("err.invalid.path", arg);
-                }
-                task.options.dotOutputDir = arg;
-            }
-        },
-        new Option(false, "-s", "-summary") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.showSummary = true;
-                task.options.verbose = SUMMARY;
-            }
-        },
-        new Option(false, "-v", "-verbose",
-                          "-verbose:package",
-                          "-verbose:class") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                switch (opt) {
-                    case "-v":
-                    case "-verbose":
-                        task.options.verbose = VERBOSE;
-                        task.options.filterSameArchive = false;
-                        task.options.filterSamePackage = false;
-                        break;
-                    case "-verbose:package":
-                        task.options.verbose = PACKAGE;
-                        break;
-                    case "-verbose:class":
-                        task.options.verbose = CLASS;
-                        break;
-                    default:
-                        throw new BadArgs("err.invalid.arg.for.option", opt);
-                }
-            }
-        },
-        new Option(true, "-cp", "-classpath") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.classpath = arg;
-            }
-        },
-        new Option(true, "-p", "-package") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.packageNames.add(arg);
-            }
-        },
-        new Option(true, "-e", "-regex") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.regex = arg;
-            }
-        },
-
-        new Option(true, "-f", "-filter") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.filterRegex = arg;
-            }
-        },
-        new Option(false, "-filter:package",
-                          "-filter:archive",
-                          "-filter:none") {
-            void process(JdepsTask task, String opt, String arg) {
-                switch (opt) {
-                    case "-filter:package":
-                        task.options.filterSamePackage = true;
-                        task.options.filterSameArchive = false;
-                        break;
-                    case "-filter:archive":
-                        task.options.filterSameArchive = true;
-                        task.options.filterSamePackage = false;
-                        break;
-                    case "-filter:none":
-                        task.options.filterSameArchive = false;
-                        task.options.filterSamePackage = false;
-                        break;
-                }
-            }
-        },
-        new Option(true, "-include") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                task.options.includePattern = Pattern.compile(arg);
-            }
-        },
-        new Option(false, "-P", "-profile") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                task.options.showProfile = true;
-                task.options.showModule = false;
-            }
-        },
-        new Option(false, "-M", "-module") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                task.options.showModule = true;
-                task.options.showProfile = false;
-            }
-        },
-        new Option(false, "-apionly") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.apiOnly = true;
-            }
-        },
-        new Option(false, "-R", "-recursive") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.depth = 0;
-                // turn off filtering
-                task.options.filterSameArchive = false;
-                task.options.filterSamePackage = false;
-            }
-        },
-        new Option(false, "-jdkinternals") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.findJDKInternals = true;
-                task.options.verbose = CLASS;
-                if (task.options.includePattern == null) {
-                    task.options.includePattern = Pattern.compile(".*");
-                }
-            }
-        },
-            new HiddenOption(false, "-verify:access") {
-                void process(JdepsTask task, String opt, String arg) {
-                    task.options.verifyAccess = true;
-                    task.options.verbose = VERBOSE;
-                    task.options.filterSameArchive = false;
-                    task.options.filterSamePackage = false;
-                }
-            },
-            new HiddenOption(true, "-mp") {
-                void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                    task.options.mpath = Paths.get(arg);
-                    if (!Files.isDirectory(task.options.mpath)) {
-                        throw new BadArgs("err.invalid.path", arg);
-                    }
-                    if (task.options.includePattern == null) {
-                        task.options.includePattern = Pattern.compile(".*");
-                    }
-                }
-            },
-        new Option(false, "-version") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.version = true;
-            }
-        },
-        new HiddenOption(false, "-fullversion") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.fullVersion = true;
-            }
-        },
-        new HiddenOption(false, "-showlabel") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.showLabel = true;
-            }
-        },
-        new HiddenOption(false, "-q", "-quiet") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.nowarning = true;
-            }
-        },
-        new HiddenOption(true, "-depth") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                try {
-                    task.options.depth = Integer.parseInt(arg);
-                } catch (NumberFormatException e) {
-                    throw new BadArgs("err.invalid.arg.for.option", opt);
-                }
-            }
-        },
-    };
-
-    private static final String PROGNAME = "jdeps";
-    private final Options options = new Options();
-    private final List<String> classes = new ArrayList<>();
-
-    private PrintWriter log;
-    void setLog(PrintWriter out) {
-        log = out;
-    }
-
-    /**
-     * Result codes.
-     */
-    static final int EXIT_OK = 0, // Completed with no errors.
-                     EXIT_ERROR = 1, // Completed but reported errors.
-                     EXIT_CMDERR = 2, // Bad command-line arguments
-                     EXIT_SYSERR = 3, // System error or resource exhaustion.
-                     EXIT_ABNORMAL = 4;// terminated abnormally
-
-    int run(String[] args) {
-        if (log == null) {
-            log = new PrintWriter(System.out);
-        }
-        try {
-            handleOptions(args);
-            if (options.help) {
-                showHelp();
-            }
-            if (options.version || options.fullVersion) {
-                showVersion(options.fullVersion);
-            }
-            if (classes.isEmpty() && options.includePattern == null) {
-                if (options.help || options.version || options.fullVersion) {
-                    return EXIT_OK;
-                } else {
-                    showHelp();
-                    return EXIT_CMDERR;
-                }
-            }
-            if (options.regex != null && options.packageNames.size() > 0) {
-                showHelp();
-                return EXIT_CMDERR;
-            }
-            if ((options.findJDKInternals || options.verifyAccess) &&
-                   (options.regex != null || options.packageNames.size() > 0 || options.showSummary)) {
-                showHelp();
-                return EXIT_CMDERR;
-            }
-            if (options.showSummary && options.verbose != SUMMARY) {
-                showHelp();
-                return EXIT_CMDERR;
-            }
-
-            boolean ok = run();
-            return ok ? EXIT_OK : EXIT_ERROR;
-        } catch (BadArgs e) {
-            reportError(e.key, e.args);
-            if (e.showUsage) {
-                log.println(getMessage("main.usage.summary", PROGNAME));
-            }
-            return EXIT_CMDERR;
-        } catch (IOException e) {
-            return EXIT_ABNORMAL;
-        } finally {
-            log.flush();
-        }
-    }
-
-    private final List<Archive> sourceLocations = new ArrayList<>();
-    private final List<Archive> classpaths = new ArrayList<>();
-    private final List<Archive> initialArchives = new ArrayList<>();
-    private boolean run() throws IOException {
-        buildArchives();
-
-        if (options.verifyAccess) {
-            return verifyModuleAccess();
-        } else {
-            return analyzeDeps();
-        }
-    }
-
-    private boolean analyzeDeps() throws IOException {
-        Analyzer analyzer = new Analyzer(options.verbose, new Analyzer.Filter() {
-            @Override
-            public boolean accepts(Location origin, Archive originArchive,
-                                   Location target, Archive targetArchive)
-            {
-                if (options.findJDKInternals) {
-                    // accepts target that is JDK class but not exported
-                    return isJDKModule(targetArchive) &&
-                              !((Module) targetArchive).isExported(target.getClassName());
-                } else if (options.filterSameArchive) {
-                    // accepts origin and target that from different archive
-                    return originArchive != targetArchive;
-                }
-                return true;
-            }
-        });
-
-        // parse classfiles and find all dependencies
-        findDependencies(options.apiOnly);
-
-        // analyze the dependencies
-        analyzer.run(sourceLocations);
-
-        // output result
-        if (options.dotOutputDir != null) {
-            Path dir = Paths.get(options.dotOutputDir);
-            Files.createDirectories(dir);
-            generateDotFiles(dir, analyzer);
-        } else {
-            printRawOutput(log, analyzer);
-        }
-
-        if (options.findJDKInternals && !options.nowarning) {
-            showReplacements(analyzer);
-        }
-        return true;
-    }
-
-    private boolean verifyModuleAccess() throws IOException {
-        // two passes
-        // 1. check API dependences where the types of dependences must be re-exported
-        // 2. check all dependences where types must be accessible
-
-        // pass 1
-        findDependencies(true /* api only */);
-        Analyzer analyzer = Analyzer.getExportedAPIsAnalyzer();
-        boolean pass1 = analyzer.run(sourceLocations);
-        if (!pass1) {
-            System.out.println("ERROR: Failed API access verification");
-        }
-        // pass 2
-        findDependencies(false);
-        analyzer =  Analyzer.getModuleAccessAnalyzer();
-        boolean pass2 = analyzer.run(sourceLocations);
-        if (!pass2) {
-            System.out.println("ERROR: Failed module access verification");
-        }
-        if (pass1 & pass2) {
-            System.out.println("Access verification succeeded.");
-        }
-        return pass1 & pass2;
-    }
-
-    private void generateSummaryDotFile(Path dir, Analyzer analyzer) throws IOException {
-        // If verbose mode (-v or -verbose option),
-        // the summary.dot file shows package-level dependencies.
-        Analyzer.Type summaryType =
-            (options.verbose == PACKAGE || options.verbose == SUMMARY) ? SUMMARY : PACKAGE;
-        Path summary = dir.resolve("summary.dot");
-        try (PrintWriter sw = new PrintWriter(Files.newOutputStream(summary));
-             SummaryDotFile dotfile = new SummaryDotFile(sw, summaryType)) {
-            for (Archive archive : sourceLocations) {
-                if (!archive.isEmpty()) {
-                    if (options.verbose == PACKAGE || options.verbose == SUMMARY) {
-                        if (options.showLabel) {
-                            // build labels listing package-level dependencies
-                            analyzer.visitDependences(archive, dotfile.labelBuilder(), PACKAGE);
-                        }
-                    }
-                    analyzer.visitDependences(archive, dotfile, summaryType);
-                }
-            }
-        }
-    }
-
-    private void generateDotFiles(Path dir, Analyzer analyzer) throws IOException {
-        // output individual .dot file for each archive
-        if (options.verbose != SUMMARY) {
-            for (Archive archive : sourceLocations) {
-                if (analyzer.hasDependences(archive)) {
-                    Path dotfile = dir.resolve(archive.getName() + ".dot");
-                    try (PrintWriter pw = new PrintWriter(Files.newOutputStream(dotfile));
-                         DotFileFormatter formatter = new DotFileFormatter(pw, archive)) {
-                        analyzer.visitDependences(archive, formatter);
-                    }
-                }
-            }
-        }
-        // generate summary dot file
-        generateSummaryDotFile(dir, analyzer);
-    }
-
-    private void printRawOutput(PrintWriter writer, Analyzer analyzer) {
-        RawOutputFormatter depFormatter = new RawOutputFormatter(writer);
-        RawSummaryFormatter summaryFormatter = new RawSummaryFormatter(writer);
-        for (Archive archive : sourceLocations) {
-            if (!archive.isEmpty()) {
-                analyzer.visitDependences(archive, summaryFormatter, SUMMARY);
-                if (analyzer.hasDependences(archive) && options.verbose != SUMMARY) {
-                    analyzer.visitDependences(archive, depFormatter);
-                }
-            }
-        }
-    }
-
-    private boolean isValidClassName(String name) {
-        if (!Character.isJavaIdentifierStart(name.charAt(0))) {
-            return false;
-        }
-        for (int i=1; i < name.length(); i++) {
-            char c = name.charAt(i);
-            if (c != '.'  && !Character.isJavaIdentifierPart(c)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /*
-     * Dep Filter configured based on the input jdeps option
-     * 1. -p and -regex to match target dependencies
-     * 2. -filter:package to filter out same-package dependencies
-     *
-     * This filter is applied when jdeps parses the class files
-     * and filtered dependencies are not stored in the Analyzer.
-     *
-     * -filter:archive is applied later in the Analyzer as the
-     * containing archive of a target class may not be known until
-     * the entire archive
-     */
-    class DependencyFilter implements Dependency.Filter {
-        final Dependency.Filter filter;
-        final Pattern filterPattern;
-        DependencyFilter() {
-            if (options.regex != null) {
-                this.filter = Dependencies.getRegexFilter(Pattern.compile(options.regex));
-            } else if (options.packageNames.size() > 0) {
-                this.filter = Dependencies.getPackageFilter(options.packageNames, false);
-            } else {
-                this.filter = null;
-            }
-
-            this.filterPattern =
-                options.filterRegex != null ? Pattern.compile(options.filterRegex) : null;
-        }
-        @Override
-        public boolean accepts(Dependency d) {
-            if (d.getOrigin().equals(d.getTarget())) {
-                return false;
-            }
-            String pn = d.getTarget().getPackageName();
-            if (options.filterSamePackage && d.getOrigin().getPackageName().equals(pn)) {
-                return false;
-            }
-
-            if (filterPattern != null && filterPattern.matcher(pn).matches()) {
-                return false;
-            }
-            return filter != null ? filter.accepts(d) : true;
-        }
-    }
-
-    /**
-     * Tests if the given class matches the pattern given in the -include option
-     */
-    private boolean matches(String classname) {
-        if (options.includePattern != null) {
-            return options.includePattern.matcher(classname.replace('/', '.')).matches();
-        } else {
-            return true;
-        }
-    }
-
-    private void buildArchives() throws IOException {
-        for (String s : classes) {
-            Path p = Paths.get(s);
-            if (Files.exists(p)) {
-                initialArchives.add(Archive.getInstance(p));
-            }
-        }
-        sourceLocations.addAll(initialArchives);
-
-        classpaths.addAll(getClassPathArchives(options.classpath));
-        if (options.includePattern != null) {
-            initialArchives.addAll(classpaths);
-        }
-        classpaths.addAll(PlatformClassPath.getModules(options.mpath));
-        if (options.mpath != null) {
-            initialArchives.addAll(PlatformClassPath.getModules(options.mpath));
-        } else {
-            classpaths.addAll(PlatformClassPath.getJarFiles());
-        }
-        // add all classpath archives to the source locations for reporting
-        sourceLocations.addAll(classpaths);
-    }
-
-    private void findDependencies(boolean apiOnly) throws IOException {
-        Dependency.Finder finder =
-            apiOnly ? Dependencies.getAPIFinder(AccessFlags.ACC_PROTECTED)
-                    : Dependencies.getClassDependencyFinder();
-        Dependency.Filter filter = new DependencyFilter();
-
-        Deque<String> roots = new LinkedList<>();
-        for (String s : classes) {
-            Path p = Paths.get(s);
-            if (!Files.exists(p)) {
-                if (isValidClassName(s)) {
-                    roots.add(s);
-                } else {
-                    warning("warn.invalid.arg", s);
-                }
-            }
-        }
-
-        // Work queue of names of classfiles to be searched.
-        // Entries will be unique, and for classes that do not yet have
-        // dependencies in the results map.
-        Deque<String> deque = new LinkedList<>();
-        Set<String> doneClasses = new HashSet<>();
-
-        // get the immediate dependencies of the input files
-        for (Archive a : initialArchives) {
-            for (ClassFile cf : a.reader().getClassFiles()) {
-                String classFileName;
-                try {
-                    classFileName = cf.getName();
-                } catch (ConstantPoolException e) {
-                    throw new ClassFileError(e);
-                }
-
-                // tests if this class matches the -include or -apiOnly option if specified
-                if (!matches(classFileName) || (apiOnly && !cf.access_flags.is(AccessFlags.ACC_PUBLIC))) {
-                    continue;
-                }
-
-                if (!doneClasses.contains(classFileName)) {
-                    doneClasses.add(classFileName);
-                }
-
-                for (Dependency d : finder.findDependencies(cf)) {
-                    if (filter.accepts(d)) {
-                        String cn = d.getTarget().getName();
-                        if (!doneClasses.contains(cn) && !deque.contains(cn)) {
-                            deque.add(cn);
-                        }
-                        a.addClass(d.getOrigin(), d.getTarget());
-                    } else {
-                        // ensure that the parsed class is added the archive
-                        a.addClass(d.getOrigin());
-                    }
-                }
-                for (String name : a.reader().skippedEntries()) {
-                    warning("warn.skipped.entry", name, a.getPathName());
-                }
-            }
-        }
-
-        // add Archive for looking up classes from the classpath
-        // for transitive dependency analysis
-        Deque<String> unresolved = roots;
-        int depth = options.depth > 0 ? options.depth : Integer.MAX_VALUE;
-        do {
-            String name;
-            while ((name = unresolved.poll()) != null) {
-                if (doneClasses.contains(name)) {
-                    continue;
-                }
-                ClassFile cf = null;
-                for (Archive a : classpaths) {
-                    cf = a.reader().getClassFile(name);
-                    if (cf != null) {
-                        String classFileName;
-                        try {
-                            classFileName = cf.getName();
-                        } catch (ConstantPoolException e) {
-                            throw new ClassFileError(e);
-                        }
-                        if (!doneClasses.contains(classFileName)) {
-                            // if name is a fully-qualified class name specified
-                            // from command-line, this class might already be parsed
-                            doneClasses.add(classFileName);
-
-                            for (Dependency d : finder.findDependencies(cf)) {
-                                if (depth == 0) {
-                                    // ignore the dependency
-                                    a.addClass(d.getOrigin());
-                                    break;
-                                } else if (filter.accepts(d)) {
-                                    a.addClass(d.getOrigin(), d.getTarget());
-                                    String cn = d.getTarget().getName();
-                                    if (!doneClasses.contains(cn) && !deque.contains(cn)) {
-                                        deque.add(cn);
-                                    }
-                                } else {
-                                    // ensure that the parsed class is added the archive
-                                    a.addClass(d.getOrigin());
-                                }
-                            }
-                        }
-                        break;
-                    }
-                }
-                if (cf == null) {
-                    doneClasses.add(name);
-                }
-            }
-            unresolved = deque;
-            deque = new LinkedList<>();
-        } while (!unresolved.isEmpty() && depth-- > 0);
-    }
-
-    public void handleOptions(String[] args) throws BadArgs {
-        // process options
-        for (int i=0; i < args.length; i++) {
-            if (args[i].charAt(0) == '-') {
-                String name = args[i];
-                Option option = getOption(name);
-                String param = null;
-                if (option.hasArg) {
-                    if (name.startsWith("-") && name.indexOf('=') > 0) {
-                        param = name.substring(name.indexOf('=') + 1, name.length());
-                    } else if (i + 1 < args.length) {
-                        param = args[++i];
-                    }
-                    if (param == null || param.isEmpty() || param.charAt(0) == '-') {
-                        throw new BadArgs("err.missing.arg", name).showUsage(true);
-                    }
-                }
-                option.process(this, name, param);
-                if (option.ignoreRest()) {
-                    i = args.length;
-                }
-            } else {
-                // process rest of the input arguments
-                for (; i < args.length; i++) {
-                    String name = args[i];
-                    if (name.charAt(0) == '-') {
-                        throw new BadArgs("err.option.after.class", name).showUsage(true);
-                    }
-                    classes.add(name);
-                }
-            }
-        }
-    }
-
-    private Option getOption(String name) throws BadArgs {
-        for (Option o : recognizedOptions) {
-            if (o.matches(name)) {
-                return o;
-            }
-        }
-        throw new BadArgs("err.unknown.option", name).showUsage(true);
-    }
-
-    private void reportError(String key, Object... args) {
-        log.println(getMessage("error.prefix") + " " + getMessage(key, args));
-    }
-
-    private void warning(String key, Object... args) {
-        log.println(getMessage("warn.prefix") + " " + getMessage(key, args));
-    }
-
-    private void showHelp() {
-        log.println(getMessage("main.usage", PROGNAME));
-        for (Option o : recognizedOptions) {
-            String name = o.aliases[0].substring(1); // there must always be at least one name
-            name = name.charAt(0) == '-' ? name.substring(1) : name;
-            if (o.isHidden() || name.equals("h") || name.startsWith("filter:")) {
-                continue;
-            }
-            log.println(getMessage("main.opt." + name));
-        }
-    }
-
-    private void showVersion(boolean full) {
-        log.println(version(full ? "full" : "release"));
-    }
-
-    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);
-        } catch (MissingResourceException e) {
-            return getMessage("version.unknown", System.getProperty("java.version"));
-        }
-    }
-
-    static String getMessage(String key, Object... args) {
-        try {
-            return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
-        } catch (MissingResourceException e) {
-            throw new InternalError("Missing message: " + key);
-        }
-    }
-
-    private static class Options {
-        boolean help;
-        boolean version;
-        boolean fullVersion;
-        boolean showProfile;
-        boolean showModule;
-        boolean showSummary;
-        boolean apiOnly;
-        boolean showLabel;
-        boolean findJDKInternals;
-        boolean nowarning;
-        // default is to show package-level dependencies
-        // and filter references from same package
-        Analyzer.Type verbose = PACKAGE;
-        boolean filterSamePackage = true;
-        boolean filterSameArchive = false;
-        String filterRegex;
-        String dotOutputDir;
-        String classpath = "";
-        int depth = 1;
-        Set<String> packageNames = new HashSet<>();
-        String regex;             // apply to the dependences
-        Pattern includePattern;   // apply to classes
-        // module boundary access check
-        boolean verifyAccess;
-        Path mpath;
-    }
-    private static class ResourceBundleHelper {
-        static final ResourceBundle versionRB;
-        static final ResourceBundle bundle;
-        static final ResourceBundle jdkinternals;
-
-        static {
-            Locale locale = Locale.getDefault();
-            try {
-                bundle = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdeps", locale);
-            } catch (MissingResourceException e) {
-                throw new InternalError("Cannot find jdeps resource bundle for locale " + locale);
-            }
-            try {
-                versionRB = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.version");
-            } catch (MissingResourceException e) {
-                throw new InternalError("version.resource.missing");
-            }
-            try {
-                jdkinternals = ResourceBundle.getBundle("com.sun.tools.jdeps.resources.jdkinternals");
-            } catch (MissingResourceException e) {
-                throw new InternalError("Cannot find jdkinternals resource bundle");
-            }
-        }
-    }
-
-    /*
-     * Returns the list of Archive specified in cpaths and not included
-     * initialArchives
-     */
-    private List<Archive> getClassPathArchives(String cpaths)
-            throws IOException
-    {
-        List<Archive> result = new ArrayList<>();
-        if (cpaths.isEmpty()) {
-            return result;
-        }
-        List<Path> paths = new ArrayList<>();
-        for (String p : cpaths.split(File.pathSeparator)) {
-            if (p.length() > 0) {
-                // wildcard to parse all JAR files e.g. -classpath dir/*
-                int i = p.lastIndexOf(".*");
-                if (i > 0) {
-                    Path dir = Paths.get(p.substring(0, i));
-                    try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.jar")) {
-                        for (Path entry : stream) {
-                            paths.add(entry);
-                        }
-                    }
-                } else {
-                    paths.add(Paths.get(p));
-                }
-            }
-        }
-        for (Path path : paths) {
-            boolean found = initialArchives.stream()
-                                           .map(Archive::path)
-                                           .anyMatch(p -> isSameFile(path, p));
-            if (!found && Files.exists(path)) {
-                result.add(Archive.getInstance(path));
-            }
-        }
-        return result;
-    }
-
-    private boolean isSameFile(Path p1, Path p2) {
-        try {
-            return Files.isSameFile(p1, p2);
-        } catch (IOException e) {
-            throw new UncheckedIOException(e);
-        }
-    }
-
-    class RawOutputFormatter implements Analyzer.Visitor {
-        private final PrintWriter writer;
-        private String pkg = "";
-        RawOutputFormatter(PrintWriter writer) {
-            this.writer = writer;
-        }
-        @Override
-        public void visitDependence(String origin, Archive originArchive,
-                                    String target, Archive targetArchive) {
-            String tag = toTag(target, targetArchive);
-            if (options.verbose == VERBOSE) {
-                writer.format("   %-50s -> %-50s %s%n", origin, target, tag);
-            } else {
-                if (!origin.equals(pkg)) {
-                    pkg = origin;
-                    writer.format("   %s (%s)%n", origin, originArchive.getName());
-                }
-                writer.format("      -> %-50s %s%n", target, tag);
-            }
-        }
-    }
-
-    class RawSummaryFormatter implements Analyzer.Visitor {
-        private final PrintWriter writer;
-        RawSummaryFormatter(PrintWriter writer) {
-            this.writer = writer;
-        }
-        @Override
-        public void visitDependence(String origin, Archive originArchive,
-                                    String target, Archive targetArchive) {
-            String targetName =  targetArchive.getPathName();
-            if (options.showModule && isJDKModule(targetArchive)) {
-                targetName = ((Module)targetArchive).name();
-            }
-            writer.format("%s -> %s", originArchive.getName(), targetName);
-            if (options.showProfile && isJDKModule(targetArchive)) {
-                writer.format(" (%s)", target);
-            }
-            writer.format("%n");
-        }
-    }
-
-    class DotFileFormatter implements Analyzer.Visitor, AutoCloseable {
-        private final PrintWriter writer;
-        private final String name;
-        DotFileFormatter(PrintWriter writer, Archive archive) {
-            this.writer = writer;
-            this.name = archive.getName();
-            writer.format("digraph \"%s\" {%n", name);
-            writer.format("    // Path: %s%n", archive.getPathName());
-        }
-
-        @Override
-        public void close() {
-            writer.println("}");
-        }
-
-        @Override
-        public void visitDependence(String origin, Archive originArchive,
-                                    String target, Archive targetArchive) {
-            String tag = toTag(target, targetArchive);
-            writer.format("   %-50s -> \"%s\";%n",
-                          String.format("\"%s\"", origin),
-                          tag.isEmpty() ? target
-                                        : String.format("%s (%s)", target, tag));
-        }
-    }
-
-    class SummaryDotFile implements Analyzer.Visitor, AutoCloseable {
-        private final PrintWriter writer;
-        private final Analyzer.Type type;
-        private final Map<Archive, Map<Archive,StringBuilder>> edges = new HashMap<>();
-        SummaryDotFile(PrintWriter writer, Analyzer.Type type) {
-            this.writer = writer;
-            this.type = type;
-            writer.format("digraph \"summary\" {%n");
-        }
-
-        @Override
-        public void close() {
-            writer.println("}");
-        }
-
-        @Override
-        public void visitDependence(String origin, Archive originArchive,
-                                    String target, Archive targetArchive) {
-            String targetName = type == PACKAGE ? target : targetArchive.getName();
-            if (isJDKModule(targetArchive)) {
-                Module m = (Module)targetArchive;
-                String n = showProfileOrModule(m);
-                if (!n.isEmpty()) {
-                    targetName += " (" + n + ")";
-                }
-            } else if (type == PACKAGE) {
-                targetName += " (" + targetArchive.getName() + ")";
-            }
-            String label = getLabel(originArchive, targetArchive);
-            writer.format("  %-50s -> \"%s\"%s;%n",
-                          String.format("\"%s\"", origin), targetName, label);
-        }
-
-        String getLabel(Archive origin, Archive target) {
-            if (edges.isEmpty())
-                return "";
-
-            StringBuilder label = edges.get(origin).get(target);
-            return label == null ? "" : String.format(" [label=\"%s\",fontsize=9]", label.toString());
-        }
-
-        Analyzer.Visitor labelBuilder() {
-            // show the package-level dependencies as labels in the dot graph
-            return new Analyzer.Visitor() {
-                @Override
-                public void visitDependence(String origin, Archive originArchive, String target, Archive targetArchive) {
-                    edges.putIfAbsent(originArchive, new HashMap<>());
-                    edges.get(originArchive).putIfAbsent(targetArchive, new StringBuilder());
-                    StringBuilder sb = edges.get(originArchive).get(targetArchive);
-                    String tag = toTag(target, targetArchive);
-                    addLabel(sb, origin, target, tag);
-                }
-
-                void addLabel(StringBuilder label, String origin, String target, String tag) {
-                    label.append(origin).append(" -> ").append(target);
-                    if (!tag.isEmpty()) {
-                        label.append(" (" + tag + ")");
-                    }
-                    label.append("\\n");
-                }
-            };
-        }
-    }
-
-    /**
-     * Test if the given archive is part of the JDK
-     */
-    private boolean isJDKModule(Archive archive) {
-        return Module.class.isInstance(archive);
-    }
-
-    /**
-     * If the given archive is JDK archive, this method returns the profile name
-     * only if -profile option is specified; it accesses a private JDK API and
-     * the returned value will have "JDK internal API" prefix
-     *
-     * For non-JDK archives, this method returns the file name of the archive.
-     */
-    private String toTag(String name, Archive source) {
-        if (!isJDKModule(source)) {
-            return source.getName();
-        }
-
-        Module module = (Module)source;
-        boolean isExported = false;
-        if (options.verbose == CLASS || options.verbose == VERBOSE) {
-            isExported = module.isExported(name);
-        } else {
-            isExported = module.isExportedPackage(name);
-        }
-        if (isExported) {
-            // exported API
-            return showProfileOrModule(module);
-        } else {
-            return "JDK internal API (" + source.getName() + ")";
-        }
-    }
-
-    private String showProfileOrModule(Module m) {
-        String tag = "";
-        if (options.showProfile) {
-            Profile p = Profile.getProfile(m);
-            if (p != null) {
-                tag = p.profileName();
-            }
-        } else if (options.showModule) {
-            tag = m.name();
-        }
-        return tag;
-    }
-
-    private Profile getProfile(String name) {
-        String pn = name;
-        if (options.verbose == CLASS || options.verbose == VERBOSE) {
-            int i = name.lastIndexOf('.');
-            pn = i > 0 ? name.substring(0, i) : "";
-        }
-        return Profile.getProfile(pn);
-    }
-
-    /**
-     * Returns the recommended replacement API for the given classname;
-     * or return null if replacement API is not known.
-     */
-    private String replacementFor(String cn) {
-        String name = cn;
-        String value = null;
-        while (value == null && name != null) {
-            try {
-                value = ResourceBundleHelper.jdkinternals.getString(name);
-            } catch (MissingResourceException e) {
-                // go up one subpackage level
-                int i = name.lastIndexOf('.');
-                name = i > 0 ? name.substring(0, i) : null;
-            }
-        }
-        return value;
-    };
-
-    private void showReplacements(Analyzer analyzer) {
-        Map<String,String> jdkinternals = new TreeMap<>();
-        boolean useInternals = false;
-        for (Archive source : sourceLocations) {
-            useInternals = useInternals || analyzer.hasDependences(source);
-            for (String cn : analyzer.dependences(source)) {
-                String repl = replacementFor(cn);
-                if (repl != null) {
-                    jdkinternals.putIfAbsent(cn, repl);
-                }
-            }
-        }
-        if (useInternals) {
-            log.println();
-            warning("warn.replace.useJDKInternals", getMessage("jdeps.wiki.url"));
-        }
-        if (!jdkinternals.isEmpty()) {
-            log.println();
-            log.format("%-40s %s%n", "JDK Internal API", "Suggested Replacement");
-            log.format("%-40s %s%n", "----------------", "---------------------");
-            for (Map.Entry<String,String> e : jdkinternals.entrySet()) {
-                log.format("%-40s %s%n", e.getKey(), e.getValue());
-            }
-        }
-
-    }
-}