8006225: tools/jdeps/Basic.java failes with AssertionError
authormchung
Thu, 14 Feb 2013 09:43:00 -0800
changeset 16290 b0b4f52de7ea
parent 16289 8bf9d5ba7dc6
child 16291 d4249734ecd8
child 16292 3be2cdacb3b3
8006225: tools/jdeps/Basic.java failes with AssertionError Reviewed-by: alanb
langtools/src/share/classes/com/sun/tools/jdeps/Analyzer.java
langtools/src/share/classes/com/sun/tools/jdeps/Archive.java
langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java
langtools/test/tools/jdeps/Basic.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/Analyzer.java	Thu Feb 14 09:43:00 2013 -0800
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2013, 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.Dependency.Location;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * Dependency Analyzer.
+ */
+public class Analyzer {
+    /**
+     * Type of the dependency analysis.  Appropriate level of data
+     * will be stored.
+     */
+    public enum Type {
+        SUMMARY,
+        PACKAGE,
+        CLASS,
+        VERBOSE
+    };
+
+    private final Type type;
+    private final List<ArchiveDeps> results = new ArrayList<ArchiveDeps>();
+    private final Map<String, Archive> map = new HashMap<String, Archive>();
+    private final Archive NOT_FOUND
+        = new Archive(JdepsTask.getMessage("artifact.not.found"));
+
+    /**
+     * Constructs an Analyzer instance.
+     *
+     * @param type Type of the dependency analysis
+     */
+    public Analyzer(Type type) {
+        this.type = type;
+    }
+
+    /**
+     * Performs the dependency analysis on the given archives.
+     */
+    public void run(List<Archive> archives) {
+        for (Archive archive : archives) {
+            ArchiveDeps deps;
+            if (type == Type.CLASS || type == Type.VERBOSE) {
+                deps = new ClassVisitor(archive);
+            } else {
+                deps = new PackageVisitor(archive);
+            }
+            archive.visit(deps);
+            results.add(deps);
+        }
+
+        // set the required dependencies
+        for (ArchiveDeps result: results) {
+            for (Set<String> set : result.deps.values()) {
+                for (String target : set) {
+                    Archive source = getArchive(target);
+                    if (result.archive != source) {
+                        if (!result.requiredArchives.contains(source)) {
+                            result.requiredArchives.add(source);
+                        }
+                        // either a profile name or the archive name
+                        String tname = getProfile(target);
+                        if (tname.isEmpty()){
+                            tname = source.toString();
+                        }
+                        if (!result.targetNames.contains(tname)) {
+                            result.targetNames.add(tname);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public interface Visitor {
+        /**
+         * Visits a recorded dependency from origin to target which can be
+         * a fully-qualified classname, a package name, a profile or
+         * archive name depending on the Analyzer's type.
+         */
+        void visit(String origin, String target);
+        /**
+         * Visits the source archive to its destination archive of
+         * a recorded dependency.
+         */
+        void visit(Archive source, Archive dest);
+    }
+
+    public void visitSummary(Visitor v) {
+        for (ArchiveDeps r : results) {
+            for (Archive a : r.requiredArchives) {
+                v.visit(r.archive, a);
+            }
+            for (String name : r.targetNames) {
+                v.visit(r.archive.getFileName(), name);
+            }
+        }
+    }
+
+    public void visit(Visitor v) {
+        for (ArchiveDeps r: results) {
+            for (Archive a : r.requiredArchives) {
+                v.visit(r.archive, a);
+            }
+            for (String origin : r.deps.keySet()) {
+                for (String target : r.deps.get(origin)) {
+                    // filter intra-dependency unless in verbose mode
+                    if (type == Type.VERBOSE || getArchive(origin) != getArchive(target)) {
+                        v.visit(origin, target);
+                    }
+                }
+            }
+        }
+    }
+
+    public Archive getArchive(String name) {
+        return map.containsKey(name) ? map.get(name) : NOT_FOUND;
+    }
+
+    public String getArchiveName(String name) {
+        return getArchive(name).getFileName();
+    }
+
+    public String getProfile(String name) {
+        String pn = type == Type.CLASS ? packageOf(name) : name;
+        Archive source = map.get(name);
+        if (source != null && PlatformClassPath.contains(source)) {
+            String profile = PlatformClassPath.getProfileName(pn);
+            if (profile.isEmpty()) {
+                return "JDK internal API (" + source.getFileName() + ")";
+            }
+            return profile;
+        }
+        return "";
+    }
+
+    private abstract class ArchiveDeps implements Archive.Visitor {
+        final Archive archive;
+        final Set<Archive> requiredArchives;
+        final SortedSet<String> targetNames;
+        final SortedMap<String, SortedSet<String>> deps;
+
+        ArchiveDeps(Archive archive) {
+            this.archive = archive;
+            this.requiredArchives = new HashSet<Archive>();
+            this.targetNames = new TreeSet<String>();
+            this.deps = new TreeMap<String, SortedSet<String>>();
+        }
+
+        void add(String loc) {
+            Archive a = map.get(loc);
+            if (a == null) {
+                map.put(loc, archive);
+            } else if (a != archive) {
+                // duplicated class warning?
+            }
+        }
+
+        void add(String origin, String target) {
+            SortedSet<String> set = deps.get(origin);
+            if (set == null) {
+                set = new TreeSet<String>();
+                deps.put(origin, set);
+            }
+            if (!set.contains(target)) {
+                set.add(target);
+            }
+        }
+
+        public abstract void visit(Location o, Location t);
+    }
+
+    private class ClassVisitor extends ArchiveDeps {
+        ClassVisitor(Archive archive) {
+            super(archive);
+        }
+        public void visit(Location l) {
+            add(l.getClassName());
+        }
+        public void visit(Location o, Location t) {
+            add(o.getClassName(), t.getClassName());
+        }
+    }
+
+    private class PackageVisitor extends ArchiveDeps {
+        PackageVisitor(Archive archive) {
+            super(archive);
+        }
+        public void visit(Location o, Location t) {
+            add(packageOf(o), packageOf(t));
+        }
+
+        public void visit(Location l) {
+            add(packageOf(l));
+        }
+
+        private String packageOf(Location loc) {
+            String pkg = loc.getPackageName();
+            return pkg.isEmpty() ? "<unnamed>" : pkg;
+        }
+    }
+
+    private static String packageOf(String cn) {
+        int i = cn.lastIndexOf('.');
+        return (i > 0) ? cn.substring(0, i) : "<unnamed>";
+    }
+}
--- a/langtools/src/share/classes/com/sun/tools/jdeps/Archive.java	Wed Feb 13 23:05:17 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/Archive.java	Thu Feb 14 09:43:00 2013 -0800
@@ -24,43 +24,32 @@
  */
 package com.sun.tools.jdeps;
 
-import com.sun.tools.classfile.Dependency;
 import com.sun.tools.classfile.Dependency.Location;
 import java.io.File;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.SortedMap;
-import java.util.SortedSet;
-import java.util.TreeMap;
-import java.util.TreeSet;
 
 /**
  * Represents the source of the class files.
  */
 public class Archive {
-    private static Map<String,Archive> archiveForClass = new HashMap<String,Archive>();
-    public static Archive find(Location loc) {
-        return archiveForClass.get(loc.getName());
-    }
-
     private final File file;
     private final String filename;
-    private final DependencyRecorder recorder;
     private final ClassFileReader reader;
+    private final Map<Location, Set<Location>> deps
+        = new HashMap<Location, Set<Location>>();
+
     public Archive(String name) {
         this.file = null;
         this.filename = name;
-        this.recorder = new DependencyRecorder();
         this.reader = null;
     }
 
     public Archive(File f, ClassFileReader reader) {
         this.file = f;
         this.filename = f.getName();
-        this.recorder = new DependencyRecorder();
         this.reader = reader;
     }
 
@@ -72,102 +61,37 @@
         return filename;
     }
 
-    public void addClass(String classFileName) {
-        Archive a = archiveForClass.get(classFileName);
-        assert(a == null || a == this); // ## issue warning?
-        if (!archiveForClass.containsKey(classFileName)) {
-            archiveForClass.put(classFileName, this);
+    public void addClass(Location origin) {
+        Set<Location> set = deps.get(origin);
+        if (set == null) {
+            set = new HashSet<Location>();
+            deps.put(origin, set);
         }
     }
-
-    public void addDependency(Dependency d) {
-        recorder.addDependency(d);
+    public void addClass(Location origin, Location target) {
+        Set<Location> set = deps.get(origin);
+        if (set == null) {
+            set = new HashSet<Location>();
+            deps.put(origin, set);
+        }
+        set.add(target);
     }
 
-    /**
-     * Returns a sorted map of a class to its dependencies.
-     */
-    public SortedMap<Location, SortedSet<Location>> getDependencies() {
-        DependencyRecorder.Filter filter = new DependencyRecorder.Filter() {
-            public boolean accept(Location origin, Location target) {
-                 return (archiveForClass.get(origin.getName()) !=
-                            archiveForClass.get(target.getName()));
-        }};
-
-        SortedMap<Location, SortedSet<Location>> result =
-            new TreeMap<Location, SortedSet<Location>>(locationComparator);
-        for (Map.Entry<Location, Set<Location>> e : recorder.dependencies().entrySet()) {
-            Location o = e.getKey();
-            for (Location t : e.getValue()) {
-                if (filter.accept(o, t)) {
-                    SortedSet<Location> odeps = result.get(o);
-                    if (odeps == null) {
-                        odeps = new TreeSet<Location>(locationComparator);
-                        result.put(o, odeps);
-                    }
-                    odeps.add(t);
-                }
+    public void visit(Visitor v) {
+        for (Map.Entry<Location,Set<Location>> e: deps.entrySet()) {
+            v.visit(e.getKey());
+            for (Location target : e.getValue()) {
+                v.visit(e.getKey(), target);
             }
         }
-        return result;
-    }
-
-    /**
-     * Returns the set of archives this archive requires.
-     */
-    public Set<Archive> getRequiredArchives() {
-        SortedSet<Archive> deps = new TreeSet<Archive>(new Comparator<Archive>() {
-            public int compare(Archive a1, Archive a2) {
-                return a1.toString().compareTo(a2.toString());
-            }
-        });
-
-        for (Map.Entry<Location, Set<Location>> e : recorder.dependencies().entrySet()) {
-            Location o = e.getKey();
-            Archive origin = Archive.find(o);
-            for (Location t : e.getValue()) {
-                Archive target = Archive.find(t);
-                assert(origin != null && target != null);
-                if (origin != target) {
-                    if (!deps.contains(target)) {
-                        deps.add(target);
-                    }
-                }
-            }
-        }
-        return deps;
     }
 
     public String toString() {
         return file != null ? file.getPath() : filename;
     }
 
-    private static class DependencyRecorder {
-        static interface Filter {
-            boolean accept(Location origin, Location target);
-        }
-
-        public void addDependency(Dependency d) {
-            Set<Location> odeps = map.get(d.getOrigin());
-            if (odeps == null) {
-                odeps = new HashSet<Location>();
-                map.put(d.getOrigin(), odeps);
-            }
-            odeps.add(d.getTarget());
-        }
-
-        public Map<Location, Set<Location>> dependencies() {
-            return map;
-        }
-
-        private final Map<Location, Set<Location>> map =
-            new HashMap<Location, Set<Location>>();
+    interface Visitor {
+        void visit(Location loc);
+        void visit(Location origin, Location target);
     }
-
-    private static Comparator<Location> locationComparator =
-        new Comparator<Location>() {
-            public int compare(Location o1, Location o2) {
-                return o1.toString().compareTo(o2.toString());
-            }
-        };
 }
--- a/langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java	Wed Feb 13 23:05:17 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/jdeps/JdepsTask.java	Thu Feb 14 09:43:00 2013 -0800
@@ -29,7 +29,6 @@
 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 java.io.*;
 import java.text.MessageFormat;
 import java.util.*;
@@ -42,7 +41,7 @@
     class BadArgs extends Exception {
         static final long serialVersionUID = 8765093759964640721L;
         BadArgs(String key, Object... args) {
-            super(JdepsTask.this.getMessage(key, args));
+            super(JdepsTask.getMessage(key, args));
             this.key = key;
             this.args = args;
         }
@@ -105,25 +104,22 @@
         new Option(false, "-s", "--summary") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.showSummary = true;
-                task.options.verbose = Options.Verbose.SUMMARY;
+                task.options.verbose = Analyzer.Type.SUMMARY;
             }
         },
         new Option(false, "-v", "--verbose") {
             void process(JdepsTask task, String opt, String arg) {
-                task.options.verbose = Options.Verbose.VERBOSE;
+                task.options.verbose = Analyzer.Type.VERBOSE;
             }
         },
         new Option(true, "-V", "--verbose-level") {
             void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                switch (arg) {
-                    case "package":
-                        task.options.verbose = Options.Verbose.PACKAGE;
-                        break;
-                    case "class":
-                        task.options.verbose = Options.Verbose.CLASS;
-                        break;
-                    default:
-                        throw task.new BadArgs("err.invalid.arg.for.option", opt);
+                if ("package".equals(arg)) {
+                    task.options.verbose = Analyzer.Type.PACKAGE;
+                } else if ("class".equals(arg)) {
+                    task.options.verbose = Analyzer.Type.CLASS;
+                } else {
+                    throw task.new BadArgs("err.invalid.arg.for.option", opt);
                 }
             }
         },
@@ -171,7 +167,6 @@
                 task.options.fullVersion = true;
             }
         },
-
     };
 
     private static final String PROGNAME = "jdeps";
@@ -216,7 +211,7 @@
                 showHelp();
                 return EXIT_CMDERR;
             }
-            if (options.showSummary && options.verbose != Options.Verbose.SUMMARY) {
+            if (options.showSummary && options.verbose != Analyzer.Type.SUMMARY) {
                 showHelp();
                 return EXIT_CMDERR;
             }
@@ -236,26 +231,14 @@
     }
 
     private final List<Archive> sourceLocations = new ArrayList<Archive>();
-    private final Archive NOT_FOUND = new Archive(getMessage("artifact.not.found"));
     private boolean run() throws IOException {
         findDependencies();
-        switch (options.verbose) {
-            case VERBOSE:
-            case CLASS:
-                printClassDeps(log);
-                break;
-            case PACKAGE:
-                printPackageDeps(log);
-                break;
-            case SUMMARY:
-                for (Archive origin : sourceLocations) {
-                    for (Archive target : origin.getRequiredArchives()) {
-                        log.format("%-30s -> %s%n", origin, target);
-                    }
-                }
-                break;
-            default:
-                throw new InternalError("Should not reach here");
+        Analyzer analyzer = new Analyzer(options.verbose);
+        analyzer.run(sourceLocations);
+        if (options.verbose == Analyzer.Type.SUMMARY) {
+            printSummary(log, analyzer);
+        } else {
+            printDependencies(log, analyzer);
         }
         return true;
     }
@@ -331,7 +314,7 @@
                 } catch (ConstantPoolException e) {
                     throw new ClassFileError(e);
                 }
-                a.addClass(classFileName);
+
                 if (!doneClasses.contains(classFileName)) {
                     doneClasses.add(classFileName);
                 }
@@ -341,7 +324,7 @@
                         if (!doneClasses.contains(cn) && !deque.contains(cn)) {
                             deque.add(cn);
                         }
-                        a.addDependency(d);
+                        a.addClass(d.getOrigin(), d.getTarget());
                     }
                 }
             }
@@ -367,19 +350,20 @@
                         } catch (ConstantPoolException e) {
                             throw new ClassFileError(e);
                         }
-                        a.addClass(classFileName);
                         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);
-                            if (depth > 0) {
-                                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.addDependency(d);
+                            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);
                                     }
                                 }
                             }
@@ -388,7 +372,7 @@
                     }
                 }
                 if (cf == null) {
-                    NOT_FOUND.addClass(name);
+                    doneClasses.add(name);
                 }
             }
             unresolved = deque;
@@ -396,96 +380,44 @@
         } while (!unresolved.isEmpty() && depth-- > 0);
     }
 
-    private void printPackageDeps(PrintWriter out) {
-        for (Archive source : sourceLocations) {
-            SortedMap<Location, SortedSet<Location>> deps = source.getDependencies();
-            if (deps.isEmpty())
-                continue;
-
-            for (Archive target : source.getRequiredArchives()) {
-                out.format("%s -> %s%n", source, target);
-            }
-
-            Map<String, Archive> pkgs = new TreeMap<String, Archive>();
-            SortedMap<String, Archive> targets = new TreeMap<String, Archive>();
-            String pkg = "";
-            for (Map.Entry<Location, SortedSet<Location>> e : deps.entrySet()) {
-                String cn = e.getKey().getClassName();
-                String p = packageOf(e.getKey());
-                Archive origin = Archive.find(e.getKey());
-                assert origin != null;
-                if (!pkgs.containsKey(p)) {
-                    pkgs.put(p, origin);
-                } else if (pkgs.get(p) != origin) {
-                    warning("warn.split.package", p, origin, pkgs.get(p));
-                }
-
-                if (!p.equals(pkg)) {
-                    printTargets(out, targets);
-                    pkg = p;
-                    targets.clear();
-                    out.format("   %s (%s)%n", p, origin.getFileName());
-                }
-
-                for (Location t : e.getValue()) {
-                    p = packageOf(t);
-                    Archive target = Archive.find(t);
-                    if (!targets.containsKey(p)) {
-                        targets.put(p, target);
-                    }
+    private void printSummary(final PrintWriter out, final Analyzer analyzer) {
+        Analyzer.Visitor visitor = new Analyzer.Visitor() {
+            public void visit(String origin, String profile) {
+                if (options.showProfile) {
+                    out.format("%-30s -> %s%n", origin, profile);
                 }
             }
-            printTargets(out, targets);
-            out.println();
-        }
+            public void visit(Archive origin, Archive target) {
+                if (!options.showProfile) {
+                    out.format("%-30s -> %s%n", origin, target);
+                }
+            }
+        };
+        analyzer.visitSummary(visitor);
     }
 
-    private void printTargets(PrintWriter out, Map<String, Archive> targets) {
-        for (Map.Entry<String, Archive> t : targets.entrySet()) {
-            String pn = t.getKey();
-            out.format("      -> %-40s %s%n", pn, getPackageInfo(pn, t.getValue()));
-        }
-    }
-
-    private String getPackageInfo(String pn, Archive source) {
-        if (PlatformClassPath.contains(source)) {
-            String name = PlatformClassPath.getProfileName(pn);
-            if (name.isEmpty()) {
-                return "JDK internal API (" + source.getFileName() + ")";
+    private void printDependencies(final PrintWriter out, final Analyzer analyzer) {
+        Analyzer.Visitor visitor = new Analyzer.Visitor() {
+            private String pkg = "";
+            public void visit(String origin, String target) {
+                if (!origin.equals(pkg)) {
+                    pkg = origin;
+                    out.format("   %s (%s)%n", origin, analyzer.getArchiveName(origin));
+                }
+                Archive source = analyzer.getArchive(target);
+                String profile = options.showProfile ? analyzer.getProfile(target) : "";
+                out.format("      -> %-50s %s%n", target,
+                           PlatformClassPath.contains(source)
+                               ? profile
+                               : analyzer.getArchiveName(target));
             }
-            return options.showProfile ? name : "";
-        }
-        return source.getFileName();
-    }
-
-    private static String packageOf(Location loc) {
-        String pkg = loc.getPackageName();
-        return pkg.isEmpty() ? "<unnamed>" : pkg;
+            public void visit(Archive origin, Archive target) {
+                out.format("%s -> %s%n", origin, target);
+            }
+        };
+        analyzer.visit(visitor);
     }
 
-    private void printClassDeps(PrintWriter out) {
-        for (Archive source : sourceLocations) {
-            SortedMap<Location, SortedSet<Location>> deps = source.getDependencies();
-            if (deps.isEmpty())
-                continue;
-
-            for (Archive target : source.getRequiredArchives()) {
-                out.format("%s -> %s%n", source, target);
-            }
-            out.format("%s%n", source);
-            for (Map.Entry<Location, SortedSet<Location>> e : deps.entrySet()) {
-                String cn = e.getKey().getClassName();
-                Archive origin = Archive.find(e.getKey());
-                out.format("   %s (%s)%n", cn, origin.getFileName());
-                for (Location t : e.getValue()) {
-                    cn = t.getClassName();
-                    Archive target = Archive.find(t);
-                    out.format("      -> %-60s %s%n", cn, getPackageInfo(t.getPackageName(), target));
-                }
-            }
-            out.println();
-        }
-    }
     public void handleOptions(String[] args) throws BadArgs {
         // process options
         for (int i=0; i < args.length; i++) {
@@ -570,7 +502,7 @@
         }
     }
 
-    public String getMessage(String key, Object... args) {
+    static String getMessage(String key, Object... args) {
         try {
             return MessageFormat.format(ResourceBundleHelper.bundle.getString(key), args);
         } catch (MissingResourceException e) {
@@ -579,13 +511,6 @@
     }
 
     private static class Options {
-        enum Verbose {
-            CLASS,
-            PACKAGE,
-            SUMMARY,
-            VERBOSE
-        };
-
         boolean help;
         boolean version;
         boolean fullVersion;
@@ -596,7 +521,7 @@
         String regex;
         String classpath = "";
         int depth = 1;
-        Verbose verbose = Verbose.PACKAGE;
+        Analyzer.Type verbose = Analyzer.Type.PACKAGE;
         Set<String> packageNames = new HashSet<String>();
     }
 
--- a/langtools/test/tools/jdeps/Basic.java	Wed Feb 13 23:05:17 2013 -0800
+++ b/langtools/test/tools/jdeps/Basic.java	Thu Feb 14 09:43:00 2013 -0800
@@ -68,11 +68,15 @@
         test(new File(testDir, "Test.class"),
              new String[] {"java.lang"},
              new String[] {"-V", "package", "-e", "java\\.lang\\..*"});
-        // test -classpath and -all options
+        // test -classpath and wildcard options
         test(null,
              new String[] {"com.sun.tools.jdeps", "java.lang", "java.util",
-                           "java.util.regex", "java.io", "p"},
+                           "java.util.regex", "java.io"},
              new String[] {"--classpath", testDir.getPath(), "*"});
+        // -v shows intra-dependency
+        test(new File(testDir, "Test.class"),
+             new String[] {"java.lang.Object", "p.Foo"},
+             new String[] {"-v", "--classpath", testDir.getPath(), "Test.class"});
         return errors;
     }