changeset 4230:871b60b0c091

8145464: implement deprecation static analysis tool Reviewed-by: psandoz, darcy
author smarks
date Thu, 25 Aug 2016 17:58:39 -0700
parents e20e3cb61cf8
children 3aacdb2da217
files make/CompileInterim.gmk src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/CSV.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/CSVParseException.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/DeprDB.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/DeprData.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/LoadProc.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Pretty.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/TraverseProc.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/internals.md src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/CPEntries.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/CPSelector.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/ClassFinder.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/MethodSig.java src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleAnnotation.java test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleClass.java test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleElements.java test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleEnum.java test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleInterface.java test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleSubclass.java test/tools/jdeprscan/cases/jdk/deprcases/types/DeprecatedAnnotation.java test/tools/jdeprscan/cases/jdk/deprcases/types/DeprecatedClass.java test/tools/jdeprscan/cases/jdk/deprcases/types/DeprecatedEnum.java test/tools/jdeprscan/cases/jdk/deprcases/types/DeprecatedException.java test/tools/jdeprscan/cases/jdk/deprcases/types/DeprecatedInterface.java test/tools/jdeprscan/tests/jdk/jdeprscan/TestCSV.java test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoad.java test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoadExpected.csv test/tools/jdeprscan/tests/jdk/jdeprscan/TestMethodSig.java test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java test/tools/jdeprscan/tests/jdk/jdeprscan/TestScanExpected.txt test/tools/jdeprscan/usage/jdk/deprusage/UseAnnotation.java test/tools/jdeprscan/usage/jdk/deprusage/UseClass.java test/tools/jdeprscan/usage/jdk/deprusage/UseEnum.java test/tools/jdeprscan/usage/jdk/deprusage/UseEnumMembers.java test/tools/jdeprscan/usage/jdk/deprusage/UseException.java test/tools/jdeprscan/usage/jdk/deprusage/UseField.java test/tools/jdeprscan/usage/jdk/deprusage/UseInterface.java test/tools/jdeprscan/usage/jdk/deprusage/UseMethod.java
diffstat 43 files changed, 5006 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/make/CompileInterim.gmk	Thu Aug 25 22:35:51 2016 +0000
+++ b/make/CompileInterim.gmk	Thu Aug 25 17:58:39 2016 -0700
@@ -32,7 +32,7 @@
 include SetupJavaCompilers.gmk
 
 ################################################################################
-# Setup the rules to build interim langtools, which is compiled by the boot 
+# Setup the rules to build interim langtools, which is compiled by the boot
 # javac and can be run on the boot jdk. This will be used to compile
 # the rest of the product. Each module is compiled separately to allow a modular
 # boot jdk to override system classes using -Xoverride:.
@@ -45,7 +45,8 @@
       DISABLE_SJAVAC := true, \
       SRC := $(LANGTOOLS_TOPDIR)/src/$(strip $1)/share/classes \
           $$(wildcard $(SUPPORT_OUTPUTDIR)/gensrc/$(strip $1)), \
-      EXCLUDES := sun com/sun/tools/jdeps com/sun/tools/javap, \
+      EXCLUDES := sun com/sun/tools/jdeps com/sun/tools/javap \
+          com/sun/tools/jdeprscan, \
       EXCLUDE_FILES := module-info.java, \
       COPY := .gif .png .xml .css .js javax.tools.JavaCompilerTool, \
       BIN := $(BUILDTOOLS_OUTPUTDIR)/override_modules/$(strip $1), \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/CSV.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,147 @@
+/*
+ * 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.  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.jdeprscan;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Utility class for manipulating comma-separated-value (CSV) data.
+ */
+public class CSV {
+    static String quote(String input) {
+        String result;
+        boolean needQuote = input.contains(",");
+
+        if (input.contains("\"")) {
+            needQuote = true;
+            result = input.replace("\"", "\"\"");
+        } else {
+            result = input;
+        }
+
+        if (needQuote) {
+            return "\"" + result + "\"";
+        } else {
+            return result;
+        }
+    }
+
+    /**
+     * Writes the objects' string representations to the output as a line of CSV.
+     * The objects are converted to String, quoted if necessary, joined with commas,
+     * and are written to the output followed by the line separator string.
+     *
+     * @param out the output destination
+     * @param objs the objects to write
+     */
+    public static void write(PrintStream out, Object... objs) {
+        out.println(Arrays.stream(objs)
+                          .map(Object::toString)
+                          .map(CSV::quote)
+                          .collect(Collectors.joining(",")));
+    }
+
+    /**
+     * The CSV parser state.
+     */
+    enum State {
+        START_FIELD, // the start of a field
+        IN_FIELD,    // within an unquoted field
+        IN_QFIELD,   // within a quoted field
+        END_QFIELD   // after the end of a quoted field
+    }
+
+    /**
+     * Splits an input line into a list of strings, handling quoting.
+     *
+     * @param input the input line
+     * @return the resulting list of strings
+     */
+    public static List<String> split(String input) {
+        List<String> result = new ArrayList<>();
+        StringBuilder cur = new StringBuilder();
+        State state = State.START_FIELD;
+
+        for (int i = 0; i < input.length(); i++) {
+            char ch = input.charAt(i);
+            switch (ch) {
+                case ',':
+                    switch (state) {
+                        case IN_QFIELD:
+                            cur.append(',');
+                            break;
+                        default:
+                            result.add(cur.toString());
+                            cur.setLength(0);
+                            state = State.START_FIELD;
+                            break;
+                    }
+                    break;
+                case '"':
+                    switch (state) {
+                        case START_FIELD:
+                            state = State.IN_QFIELD;
+                            break;
+                        case IN_QFIELD:
+                            state = State.END_QFIELD;
+                            break;
+                        case IN_FIELD:
+                            throw new CSVParseException("unexpected quote", input, i);
+                        case END_QFIELD:
+                            cur.append('"');
+                            state = State.IN_QFIELD;
+                            break;
+                    }
+                    break;
+                default:
+                    switch (state) {
+                        case START_FIELD:
+                            state = State.IN_FIELD;
+                            break;
+                        case IN_FIELD:
+                        case IN_QFIELD:
+                            break;
+                        case END_QFIELD:
+                            throw new CSVParseException("extra character after quoted string",
+                                                        input, i);
+                    }
+                    cur.append(ch);
+                    break;
+            }
+        }
+
+        if (state == State.IN_QFIELD) {
+            throw new CSVParseException("unclosed quote", input, input.length());
+        }
+
+        result.add(cur.toString());
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/CSVParseException.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,55 @@
+/*
+ * 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.  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.jdeprscan;
+
+/**
+ * Exception representing an error encountered during CSV parsing.
+ */
+public class CSVParseException extends IllegalArgumentException {
+    private static final long serialVersionUID = 6822670269555409371L;
+    final String input;
+    final int index;
+
+    public CSVParseException(String msg, String input, int index) {
+        super(msg);
+        this.input = input;
+        this.index = index;
+    }
+
+    public String getInput() { return input; }
+
+    public int getIndex() { return index; }
+
+    /**
+     * Returns a string describing the parse error.
+     *
+     * @return a string describing the parse error
+     */
+    @Override
+    public String getMessage() {
+        return super.getMessage() + " at index " + index + ": " + input;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/DeprDB.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,178 @@
+/*
+ * 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.  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.jdeprscan;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javax.lang.model.element.ElementKind;
+
+/**
+ * A database of deprecations (APIs declared to be deprecated),
+ * loaded from a JDK or from a class library.
+ */
+public class DeprDB {
+    /**
+     * Deprecated types.
+     * A map from deprecated type names to DeprData values.
+     * Types include classes, interfaces, enums, and annotation types.
+     */
+    final Map<String, DeprData> types = new HashMap<>();
+
+    /**
+     * Deprecated methods. Key is type name, value is map from method
+     * signatures in the form "methodname(parms)ret" to DeprData value.
+     */
+    final Map<String, Map<String, DeprData>> methods = new HashMap<>();
+
+    /**
+     * Deprecated fields. Key is type name, value is map from field name
+     * to forRemoval value.
+     */
+    final Map<String, Map<String, DeprData>> fields = new HashMap<>();
+
+    /**
+     * Set of valid ElementKind strings.
+     */
+    static final Set<String> validElementKinds =
+        Set.of(Arrays.stream(ElementKind.values())
+                     .map(ElementKind::toString)
+                     .toArray(String[]::new));
+
+
+    private DeprDB() { }
+
+    public static List<DeprData> loadFromFile(String filename) throws IOException {
+        List<DeprData> list = new ArrayList<>();
+
+        exit:
+        try (final BufferedReader br = Files.newBufferedReader(Paths.get(filename))) {
+            String line = br.readLine();
+            if (line == null || !line.equals("#jdepr1")) {
+                System.out.printf("ERROR: invalid first line %s%n", line);
+                break exit;
+            }
+            while ((line = br.readLine()) != null) {
+                if (line.startsWith("#")) {
+                    continue;
+                }
+                List<String> tokens = CSV.split(line);
+                if (tokens.size() != 5) {
+                    System.out.printf("ERROR: %s%n", line);
+                    continue;
+                }
+                // kind,typeName,descOrName,since,forRemoval
+                String kindStr = tokens.get(0);
+                String type = tokens.get(1);
+                String detail = tokens.get(2);
+                String since = tokens.get(3);
+                boolean forRemoval = Boolean.parseBoolean(tokens.get(4));
+                ElementKind kind;
+
+                if (validElementKinds.contains(kindStr)) {
+                    kind = ElementKind.valueOf(kindStr);
+                } else {
+                    System.out.printf("ERROR: invalid element kind %s%n", kindStr);
+                    continue;
+                }
+
+                DeprData data = new DeprData(kind, /*TypeElement*/null, type, detail, since, forRemoval);
+                list.add(data);
+            }
+        }
+        return list;
+    }
+
+    public static DeprDB loadFromList(List<DeprData> deprList) {
+        DeprDB db = new DeprDB();
+
+        for (DeprData dd : deprList) {
+            switch (dd.kind) {
+                case CLASS:
+                case INTERFACE:
+                case ENUM:
+                case ANNOTATION_TYPE:
+                    db.types.put(dd.typeName, dd);
+                    break;
+                case METHOD:
+                case CONSTRUCTOR:
+                    db.methods.computeIfAbsent(dd.typeName, k -> new HashMap<>())
+                              .put(dd.nameSig, dd);
+                    break;
+                case ENUM_CONSTANT:
+                case FIELD:
+                    db.fields.computeIfAbsent(dd.typeName, k -> new HashMap<>())
+                             .put(dd.nameSig, dd);
+                    break;
+            }
+        }
+
+        return db;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        Formatter f = new Formatter(sb, Locale.US);
+        f.format("=== Types ===%n");
+        f.format("%s%n", types.toString());
+        f.format("=== Methods ===%n");
+        f.format("%s%n", methods.toString());
+        f.format("=== Fields ===%n");
+        f.format("%s%n", fields.toString());
+        return sb.toString();
+    }
+
+    public DeprData getTypeDeprecated(String typeName) {
+        return types.get(typeName);
+    }
+
+    public DeprData getMethodDeprecated(String typeName, String methodName, String type) {
+        Map<String, DeprData> m = methods.get(typeName);
+        if (m == null) {
+            return null;
+        }
+        return m.get(methodName + type);
+    }
+
+    public DeprData getFieldDeprecated(String typeName, String fieldName) {
+        Map<String, DeprData> f = fields.get(typeName);
+        if (f == null) {
+            return null;
+        }
+        return f.get(fieldName);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/DeprData.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,62 @@
+/*
+ * 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.  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.jdeprscan;
+
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * A simple data class that contains language model data (TypeElement, etc.)
+ * about a deprecated API.
+ */
+public class DeprData {
+    final ElementKind kind;
+    final TypeElement type; // null if data loaded from file
+    final String typeName;
+    final String nameSig;
+    final String since;
+    final boolean forRemoval;
+
+    public DeprData(ElementKind kind, TypeElement type, String typeName, String nameSig,
+                    String since, boolean forRemoval) {
+        this.kind = kind;
+        this.type = type;
+        this.typeName = typeName;
+        this.nameSig = nameSig;
+        this.since = since;
+        this.forRemoval = forRemoval;
+    }
+
+    public boolean isForRemoval() {
+        return forRemoval;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("DeprData(%s,%s,%s,%s,%s,%s)",
+                             kind, type, typeName, nameSig, since, forRemoval);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/LoadProc.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,206 @@
+/*
+ * 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.  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.jdeprscan;
+
+import java.lang.annotation.IncompleteAnnotationException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+
+import javax.tools.Diagnostic;
+
+import static javax.lang.model.SourceVersion.RELEASE_9;
+
+/**
+ * Annotation processor for the Deprecation Scanner tool.
+ * Examines APIs for deprecated elements and records information
+ *
+ */
+@SupportedAnnotationTypes("java.lang.Deprecated")
+@SupportedSourceVersion(RELEASE_9)
+public class LoadProc extends AbstractProcessor {
+    Elements elements;
+    Messager messager;
+    final List<DeprData> deprList = new ArrayList<>();
+
+    public LoadProc() {
+    }
+
+    @Override
+    public void init(ProcessingEnvironment pe) {
+        super.init(pe);
+        elements = pe.getElementUtils();
+        messager = pe.getMessager();
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return false;
+        }
+
+        // Assume annotations contains only @Deprecated.
+        // Note: no way to get deprecated packages, since
+        // @Deprecated is ignored in package-info.java files.
+
+        Set<? extends Element> set = roundEnv.getElementsAnnotatedWith(Deprecated.class);
+        for (Element e : set) {
+            ElementKind kind = e.getKind();
+            Deprecated depr = e.getAnnotation(Deprecated.class);
+            switch (kind) {
+                case CLASS:
+                case INTERFACE:
+                case ENUM:
+                case ANNOTATION_TYPE:
+                    addType(kind, (TypeElement)e, depr);
+                    break;
+                case CONSTRUCTOR:
+                case ENUM_CONSTANT:
+                case FIELD:
+                case METHOD:
+                    Element encl = e.getEnclosingElement();
+                    ElementKind enclKind = encl.getKind();
+                    switch (enclKind) {
+                        case CLASS:
+                        case INTERFACE:
+                        case ENUM:
+                        case ANNOTATION_TYPE:
+                            String detail = getDetail(e);
+                            addMember(kind, (TypeElement)encl, detail, depr);
+                            break;
+                        default:
+                            messager.printMessage(Diagnostic.Kind.WARNING,
+                                "element " + e +
+                                " within unknown enclosing element " + encl +
+                                " of kind " + enclKind, e);
+                            break;
+                    }
+                    break;
+                default:
+                    messager.printMessage(Diagnostic.Kind.WARNING,
+                        "unknown element " + e +
+                        " of kind " + kind +
+                        " within " + e.getEnclosingElement(), e);
+                    break;
+            }
+        }
+        return true;
+    }
+
+    public List<DeprData> getDeprecations() {
+        return deprList;
+    }
+
+    String getDetail(Element e) {
+        if (e.getKind().isField()) {
+            return e.getSimpleName().toString();
+        } else {
+            // method or constructor
+            ExecutableElement ee = (ExecutableElement) e;
+            String ret;
+            ret = desc(ee.getReturnType());
+            List<? extends TypeMirror> parameterTypes = ((ExecutableType)ee.asType()).getParameterTypes();
+            String parms = parameterTypes.stream()
+                                .map(this::desc)
+                                .collect(Collectors.joining());
+            return ee.getSimpleName().toString() + "(" + parms + ")" + ret;
+        }
+    }
+
+    String desc(TypeMirror tm) {
+        switch (tm.getKind()) {
+            case BOOLEAN:
+                return "Z";
+            case BYTE:
+                return "B";
+            case SHORT:
+                return "S";
+            case CHAR:
+                return "C";
+            case INT:
+                return "I";
+            case LONG:
+                return "J";
+            case FLOAT:
+                return "F";
+            case DOUBLE:
+                return "D";
+            case VOID:
+                return "V";
+            case DECLARED:
+                String s =
+                    ((TypeElement)((DeclaredType)tm).asElement()).getQualifiedName().toString();
+                s = s.replace('.', '/');
+                return "L" + s + ";";
+            case ARRAY:
+                return "[" + desc(((ArrayType)tm).getComponentType());
+            default:
+                return tm.getKind().toString();
+        }
+    }
+
+    void addType(ElementKind kind, TypeElement type, Deprecated dep) {
+        addData(kind, type, "", dep);
+    }
+
+    void addMember(ElementKind kind, TypeElement type, String nameSig, Deprecated dep) {
+        addData(kind, type, nameSig, dep);
+    }
+
+    void addData(ElementKind kind, TypeElement type, String nameSig, Deprecated dep) {
+        String typeName = elements.getBinaryName(type).toString().replace('.', '/');
+
+        String since = "";
+        try {
+            since = dep.since();
+        } catch (IncompleteAnnotationException ignore) { }
+
+        boolean forRemoval = false;
+        try {
+            forRemoval = dep.forRemoval();
+        } catch (IncompleteAnnotationException ignore) { }
+
+        deprList.add(new DeprData(kind, type, typeName, nameSig, since, forRemoval));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,717 @@
+/*
+ * 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.  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.jdeprscan;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.Queue;
+import java.util.stream.Stream;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+import com.sun.tools.javac.file.JavacFileManager;
+
+import com.sun.tools.jdeprscan.scan.Scan;
+
+import static java.util.stream.Collectors.*;
+
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Deprecation Scanner tool. Loads API deprecation information from the
+ * JDK image, or optionally, from a jar file or class hierarchy. Then scans
+ * a class library for usages of those APIs.
+ *
+ * TODO:
+ *  - audit error handling throughout, but mainly in scan package
+ *  - handling of covariant overrides
+ *  - handling of override of method found in multiple superinterfaces
+ *  - convert type/method/field output to Java source like syntax, e.g.
+ *      instead of java/lang/Runtime.runFinalizersOnExit(Z)V
+ *      print void java.lang.Runtime.runFinalizersOnExit(boolean)
+ *  - more example output in man page
+ *  - more rigorous GNU style option parsing; use joptsimple?
+ *
+ * FUTURES:
+ *  - add module support: -addmods, -modulepath, module arg
+ *  - load deprecation declarations from a designated class library instead
+ *    of the JDK
+ *  - load deprecation declarations from a module
+ *  - scan a module (but a modular jar can be treated just a like an ordinary jar)
+ *  - multi-version jar
+ */
+public class Main implements DiagnosticListener<JavaFileObject> {
+    public static Main instance;
+
+    final PrintStream out;
+    final PrintStream err;
+    final List<File> bootClassPath = new ArrayList<>();
+    final List<File> classPath = new ArrayList<>();
+    final List<File> systemModules = new ArrayList<>();
+    final List<String> options = new ArrayList<>();
+    final List<String> comments = new ArrayList<>();
+
+    // Valid releases need to match what the compiler supports.
+    // Keep these updated manually until there's a compiler API
+    // that allows querying of supported releases.
+    final Set<String> releasesWithoutForRemoval = Set.of("6", "7", "8");
+    final Set<String> releasesWithForRemoval = Set.of("9");
+
+    final Set<String> validReleases;
+    {
+        Set<String> temp = new HashSet<>(releasesWithoutForRemoval);
+        temp.addAll(releasesWithForRemoval);
+        validReleases = Set.of(temp.toArray(new String[0]));
+    }
+
+    boolean verbose = false;
+    boolean forRemoval = false;
+
+    final JavaCompiler compiler;
+    final StandardJavaFileManager fm;
+
+    List<DeprData> deprList; // non-null after successful load phase
+
+    /**
+     * Processes a collection of class names. Names should fully qualified
+     * names in the form "pkg.pkg.pkg.classname".
+     *
+     * @param classNames collection of fully qualified classnames to process
+     * @return true for success, false for failure
+     * @throws IOException if an I/O error occurs
+     */
+    boolean doClassNames(Collection<String> classNames) throws IOException {
+        if (verbose) {
+            out.println("List of classes to process:");
+            classNames.forEach(out::println);
+            out.println("End of class list.");
+        }
+
+        // TODO: not sure this is necessary...
+        if (fm instanceof JavacFileManager) {
+            ((JavacFileManager)fm).setSymbolFileEnabled(false);
+        }
+
+        fm.setLocation(StandardLocation.CLASS_PATH, classPath);
+        if (!bootClassPath.isEmpty()) {
+            fm.setLocation(StandardLocation.PLATFORM_CLASS_PATH, bootClassPath);
+        }
+
+        if (!systemModules.isEmpty()) {
+            fm.setLocation(StandardLocation.SYSTEM_MODULES, systemModules);
+        }
+
+        LoadProc proc = new LoadProc();
+        JavaCompiler.CompilationTask task =
+            compiler.getTask(null, fm, this, options, classNames, null);
+        task.setProcessors(List.of(proc));
+        boolean r = task.call();
+        if (r) {
+            if (forRemoval) {
+                deprList = proc.getDeprecations().stream()
+                               .filter(DeprData::isForRemoval)
+                               .collect(toList());
+            } else {
+                deprList = proc.getDeprecations();
+            }
+        }
+        return r;
+    }
+
+    /**
+     * Processes a stream of filenames (strings). The strings are in the
+     * form pkg/pkg/pkg/classname.class relative to the root of a package
+     * hierarchy.
+     *
+     * @param filenames a Stream of filenames to process
+     * @return true for success, false for failure
+     * @throws IOException if an I/O error occurs
+     */
+    boolean doFileNames(Stream<String> filenames) throws IOException {
+        return doClassNames(
+            filenames.filter(name -> name.endsWith(".class"))
+                     .filter(name -> !name.endsWith("package-info.class"))
+                     .filter(name -> !name.endsWith("module-info.class"))
+                     .map(s -> s.replaceAll("\\.class$", ""))
+                     .map(s -> s.replace('/', '.'))
+                     .collect(toList()));
+    }
+
+    /**
+     * Replaces all but the first occurrence of '/' with '.'. Assumes
+     * that the name is in the format module/pkg/pkg/classname.class.
+     * That is, the name should contain at least one '/' character
+     * separating the module name from the package-class name.
+     *
+     * @param filename the input filename
+     * @return the modular classname
+     */
+    String convertModularFileName(String filename) {
+        int slash = filename.indexOf('/');
+        return filename.substring(0, slash)
+               + "/"
+               + filename.substring(slash+1).replace('/', '.');
+    }
+
+    /**
+     * Processes a stream of filenames (strings) including a module prefix.
+     * The strings are in the form module/pkg/pkg/pkg/classname.class relative
+     * to the root of a directory containing modules. The strings are processed
+     * into module-qualified class names of the form
+     * "module/pkg.pkg.pkg.classname".
+     *
+     * @param filenames a Stream of filenames to process
+     * @return true for success, false for failure
+     * @throws IOException if an I/O error occurs
+     */
+    boolean doModularFileNames(Stream<String> filenames) throws IOException {
+        return doClassNames(
+            filenames.filter(name -> name.endsWith(".class"))
+                     .filter(name -> !name.endsWith("package-info.class"))
+                     .filter(name -> !name.endsWith("module-info.class"))
+                     .map(s -> s.replaceAll("\\.class$", ""))
+                     .map(this::convertModularFileName)
+                     .collect(toList()));
+    }
+
+    /**
+     * Processes named class files in the given directory. The directory
+     * should be the root of a package hierarchy. If classNames is
+     * empty, walks the directory hierarchy to find all classes.
+     *
+     * @param dirname the name of the directory to process
+     * @param classNames the names of classes to process
+     * @return true for success, false for failure
+     * @throws IOException if an I/O error occurs
+     */
+    boolean processDirectory(String dirname, Collection<String> classNames) throws IOException {
+        if (!Files.isDirectory(Paths.get(dirname))) {
+            err.printf("%s: not a directory%n", dirname);
+            return false;
+        }
+
+        classPath.add(0, new File(dirname));
+
+        if (classNames.isEmpty()) {
+            Path base = Paths.get(dirname);
+            int baseCount = base.getNameCount();
+            try (Stream<Path> paths = Files.walk(base)) {
+                Stream<String> files =
+                    paths.filter(p -> p.getNameCount() > baseCount)
+                         .map(p -> p.subpath(baseCount, p.getNameCount()))
+                         .map(Path::toString);
+                return doFileNames(files);
+            }
+        } else {
+            return doClassNames(classNames);
+        }
+    }
+
+    /**
+     * Processes all class files in the given jar file.
+     *
+     * @param jarname the name of the jar file to process
+     * @return true for success, false for failure
+     * @throws IOException if an I/O error occurs
+     */
+    boolean doJarFile(String jarname) throws IOException {
+        try (JarFile jf = new JarFile(jarname)) {
+            Stream<String> files =
+                jf.stream()
+                  .map(JarEntry::getName);
+            return doFileNames(files);
+        }
+    }
+
+    /**
+     * Processes named class files from the given jar file,
+     * or all classes if classNames is empty.
+     *
+     * @param jarname the name of the jar file to process
+     * @param classNames the names of classes to process
+     * @return true for success, false for failure
+     * @throws IOException if an I/O error occurs
+     */
+    boolean processJarFile(String jarname, Collection<String> classNames) throws IOException {
+        classPath.add(0, new File(jarname));
+
+        if (classNames.isEmpty()) {
+            return doJarFile(jarname);
+        } else {
+            return doClassNames(classNames);
+        }
+    }
+
+    /**
+     * Processes named class files from rt.jar of a JDK version 7 or 8.
+     * If classNames is empty, processes all classes.
+     *
+     * @param jdkHome the path to the "home" of the JDK to process
+     * @param classNames the names of classes to process
+     * @return true for success, false for failure
+     * @throws IOException if an I/O error occurs
+     */
+    boolean processOldJdk(String jdkHome, Collection<String> classNames) throws IOException {
+        String RTJAR = jdkHome + "/jre/lib/rt.jar";
+        String CSJAR = jdkHome + "/jre/lib/charsets.jar";
+
+        bootClassPath.add(0, new File(RTJAR));
+        bootClassPath.add(1, new File(CSJAR));
+        options.add("-source");
+        options.add("8");
+
+        if (classNames.isEmpty()) {
+            return doJarFile(RTJAR);
+        } else {
+            return doClassNames(classNames);
+        }
+    }
+
+    /**
+     * Processes listed classes given a JDK 9 home.
+     */
+    boolean processJdk9(String jdkHome, Collection<String> classes) throws IOException {
+        systemModules.add(new File(jdkHome));
+        return doClassNames(classes);
+    }
+
+    /**
+     * Processes the class files from the currently running JDK,
+     * using the jrt: filesystem.
+     *
+     * @return true for success, false for failure
+     * @throws IOException if an I/O error occurs
+     */
+    boolean processSelf(Collection<String> classes) throws IOException {
+        options.add("-addmods");
+        options.add("java.se.ee,jdk.xml.bind"); // TODO why jdk.xml.bind?
+
+        if (classes.isEmpty()) {
+            Path modules = FileSystems.getFileSystem(URI.create("jrt:/"))
+                                      .getPath("/modules");
+
+            // names are /modules/<modulename>/pkg/.../Classname.class
+            try (Stream<Path> paths = Files.walk(modules)) {
+                Stream<String> files =
+                    paths.filter(p -> p.getNameCount() > 2)
+                         .map(p -> p.subpath(1, p.getNameCount()))
+                         .map(Path::toString);
+                return doModularFileNames(files);
+            }
+        } else {
+            return doClassNames(classes);
+        }
+    }
+
+    /**
+     * Process classes from a particular JDK release, using only information
+     * in this JDK.
+     *
+     * @param release "6", "7", "8", or "9"
+     * @param classes collection of classes to process, may be empty
+     * @return success value
+     */
+    boolean processRelease(String release, Collection<String> classes) throws IOException {
+        options.addAll(List.of("-release", release));
+
+        if (release.equals("9")) {
+            List<String> rootMods = List.of("java.se", "java.se.ee");
+            TraverseProc proc = new TraverseProc(rootMods);
+            JavaCompiler.CompilationTask task =
+                compiler.getTask(null, fm, this,
+                                 // options
+                                 List.of("-addmods", String.join(",", rootMods)),
+                                 // classes
+                                 List.of("java.lang.Object"),
+                                 null);
+            task.setProcessors(List.of(proc));
+            if (!task.call()) {
+                return false;
+            }
+            Map<PackageElement, List<TypeElement>> types = proc.getPublicTypes();
+            options.add("-addmods");
+            options.add(String.join(",", rootMods));
+            return doClassNames(
+                types.values().stream()
+                     .flatMap(List::stream)
+                     .map(TypeElement::toString)
+                     .collect(toList()));
+        } else {
+            // TODO: kind of a hack...
+            // Create a throwaway compilation task with options "-release N"
+            // which has the side effect of setting the file manager's
+            // PLATFORM_CLASS_PATH to the right value.
+            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+            StandardJavaFileManager fm =
+                compiler.getStandardFileManager(this, null, StandardCharsets.UTF_8);
+            JavaCompiler.CompilationTask task =
+                compiler.getTask(null, fm, this, List.of("-release", release), null, null);
+            List<Path> paths = new ArrayList<>();
+            for (Path p : fm.getLocationAsPaths(StandardLocation.PLATFORM_CLASS_PATH)) {
+                try (Stream<Path> str = Files.walk(p)) {
+                    str.forEachOrdered(paths::add);
+                }
+            }
+
+            options.add("-Xlint:-options");
+
+            return doClassNames(
+                paths.stream()
+                     .filter(path -> path.toString().endsWith(".sig"))
+                     .map(path -> path.subpath(1, path.getNameCount()))
+                     .map(Path::toString)
+                     .map(s -> s.replaceAll("\\.sig$", ""))
+                     .map(s -> s.replace('/', '.'))
+                     .collect(toList()));
+        }
+    }
+
+    /**
+     * Prints a usage message to the err stream.
+     */
+    void usage() {
+
+    }
+
+    /**
+     * An enum denoting the mode in which the tool is running.
+     * Different modes correspond to the different process* methods.
+     * The exception is UNKNOWN, which indicates that a mode wasn't
+     * specified on the command line, which is an error.
+     */
+    static enum LoadMode {
+        CLASSES, DIR, JAR, OLD_JDK, JDK9, SELF, RELEASE, LOAD_CSV
+    }
+
+    static enum ScanMode {
+        ARGS, LIST, PRINT_CSV
+    }
+
+    /**
+     * A checked exception that's thrown if a command-line syntax error
+     * is detected.
+     */
+    static class UsageException extends Exception {
+        private static final long serialVersionUID = 3611828659572908743L;
+    }
+
+    /**
+     * Convenience method to throw UsageException if a condition is false.
+     *
+     * @param cond the condition that's required to be true
+     * @throws UsageException
+     */
+    void require(boolean cond) throws UsageException {
+        if (!cond) {
+            throw new UsageException();
+        }
+    }
+
+    /**
+     * Constructs an instance of the finder tool.
+     *
+     * @param out the stream to which the tool's output is sent
+     * @param err the stream to which error messages are sent
+     */
+    Main(PrintStream out, PrintStream err) {
+        this.out = out;
+        this.err = err;
+        compiler = ToolProvider.getSystemJavaCompiler();
+        fm = compiler.getStandardFileManager(this, null, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Prints the diagnostic to the err stream.
+     *
+     * Specified by the DiagnosticListener interface.
+     *
+     * @param diagnostic the tool diagnostic to print
+     */
+    @Override
+    public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+        err.println(diagnostic);
+    }
+
+    /**
+     * Parses arguments and performs the requested processing.
+     *
+     * @param argArray command-line arguments
+     * @return true on success, false on error
+     */
+    boolean run(String... argArray) {
+        Queue<String> args = new ArrayDeque<>(Arrays.asList(argArray));
+        LoadMode loadMode = LoadMode.RELEASE;
+        ScanMode scanMode = ScanMode.ARGS;
+        String dir = null;
+        String jar = null;
+        String jdkHome = null;
+        String release = "9";
+        List<String> loadClasses = new ArrayList<>();
+        String csvFile = null;
+
+        try {
+            while (!args.isEmpty()) {
+                String a = args.element();
+                if (a.startsWith("-")) {
+                    args.remove();
+                    switch (a) {
+                        case "--class-path":
+                        case "-cp":
+                            classPath.clear();
+                            Arrays.stream(args.remove().split(File.pathSeparator))
+                                  .map(File::new)
+                                  .forEachOrdered(classPath::add);
+                            break;
+                        case "--for-removal":
+                            forRemoval = true;
+                            break;
+                        case "--full-version":
+                            out.println(System.getProperty("java.vm.version"));
+                            return false;
+                        case "--help":
+                        case "-h":
+                            out.println(Messages.get("main.usage"));
+                            out.println();
+                            out.println(Messages.get("main.help"));
+                            return false;
+                        case "-l":
+                        case "--list":
+                            require(scanMode == ScanMode.ARGS);
+                            scanMode = ScanMode.LIST;
+                            break;
+                        case "--release":
+                            loadMode = LoadMode.RELEASE;
+                            release = args.remove();
+                            if (!validReleases.contains(release)) {
+                                throw new UsageException();
+                            }
+                            break;
+                        case "-v":
+                        case "--verbose":
+                            verbose = true;
+                            break;
+                        case "--version":
+                            out.println(System.getProperty("java.version"));
+                            return false;
+                        case "--Xcompiler-arg":
+                            options.add(args.remove());
+                            break;
+                        case "--Xcsv-comment":
+                            comments.add(args.remove());
+                            break;
+                        case "--Xhelp":
+                            out.println(Messages.get("main.xhelp"));
+                            return false;
+                        case "--Xload-class":
+                            loadMode = LoadMode.CLASSES;
+                            loadClasses.add(args.remove());
+                            break;
+                        case "--Xload-csv":
+                            loadMode = LoadMode.LOAD_CSV;
+                            csvFile = args.remove();
+                            break;
+                        case "--Xload-dir":
+                            loadMode = LoadMode.DIR;
+                            dir = args.remove();
+                            break;
+                        case "--Xload-jar":
+                            loadMode = LoadMode.JAR;
+                            jar = args.remove();
+                            break;
+                        case "--Xload-jdk9":
+                            loadMode = LoadMode.JDK9;
+                            jdkHome = args.remove();
+                            break;
+                        case "--Xload-old-jdk":
+                            loadMode = LoadMode.OLD_JDK;
+                            jdkHome = args.remove();
+                            break;
+                        case "--Xload-self":
+                            loadMode = LoadMode.SELF;
+                            break;
+                        case "--Xprint-csv":
+                            require(scanMode == ScanMode.ARGS);
+                            scanMode = ScanMode.PRINT_CSV;
+                            break;
+                        default:
+                            throw new UsageException();
+                    }
+                } else {
+                    break;
+                }
+            }
+
+            if ((scanMode == ScanMode.ARGS) == args.isEmpty()) {
+                throw new UsageException();
+            }
+
+            if (    forRemoval && loadMode == LoadMode.RELEASE &&
+                    releasesWithoutForRemoval.contains(release)) {
+                throw new UsageException();
+            }
+
+            boolean success = false;
+
+            switch (loadMode) {
+                case CLASSES:
+                    success = doClassNames(loadClasses);
+                    break;
+                case DIR:
+                    success = processDirectory(dir, loadClasses);
+                    break;
+                case JAR:
+                    success = processJarFile(jar, loadClasses);
+                    break;
+                case JDK9:
+                    require(!args.isEmpty());
+                    success = processJdk9(jdkHome, loadClasses);
+                    break;
+                case LOAD_CSV:
+                    deprList = DeprDB.loadFromFile(csvFile);
+                    success = true;
+                    break;
+                case OLD_JDK:
+                    success = processOldJdk(jdkHome, loadClasses);
+                    break;
+                case RELEASE:
+                    success = processRelease(release, loadClasses);
+                    break;
+                case SELF:
+                    success = processSelf(loadClasses);
+                    break;
+                default:
+                    throw new UsageException();
+            }
+
+            if (!success) {
+                return false;
+            }
+        } catch (NoSuchElementException | UsageException ex) {
+            err.println(Messages.get("main.usage"));
+            return false;
+        } catch (IOException ioe) {
+            if (verbose) {
+                ioe.printStackTrace(err);
+            } else {
+                err.println(ioe);
+            }
+            return false;
+        }
+
+        // now the scanning phase
+
+        switch (scanMode) {
+            case LIST:
+                for (DeprData dd : deprList) {
+                    if (!forRemoval || dd.isForRemoval()) {
+                        out.println(Pretty.print(dd));
+                    }
+                }
+                break;
+            case PRINT_CSV:
+                out.println("#jdepr1");
+                comments.forEach(s -> out.println("# " + s));
+                for (DeprData dd : deprList) {
+                    CSV.write(out, dd.kind, dd.typeName, dd.nameSig, dd.since, dd.forRemoval);
+                }
+                break;
+            case ARGS:
+                DeprDB db = DeprDB.loadFromList(deprList);
+                List<String> cp = classPath.stream()
+                                           .map(File::toString)
+                                           .collect(toList());
+                Scan scan = new Scan(out, err, cp, db, verbose);
+
+                for (String a : args) {
+                    boolean success;
+
+                    if (a.endsWith(".jar")) {
+                        success = scan.scanJar(a);
+                    } else if (Files.isDirectory(Paths.get(a))) {
+                        success = scan.scanDir(a);
+                    } else {
+                        success = scan.processClassName(a.replace('.', '/'));
+                    }
+
+                    if (!success) {
+                        return false;
+                    }
+                }
+                break;
+        }
+
+        return true;
+    }
+
+    /**
+     * Programmatic main entry point: initializes the tool instance to
+     * use stdout and stderr; runs the tool, passing command-line args;
+     * returns an exit status.
+     *
+     * @return true on success, false otherwise
+     */
+    public static boolean call(PrintStream out, PrintStream err, String... args) {
+        try {
+            instance = new Main(out, err);
+            return instance.run(args);
+        } finally {
+            instance = null;
+        }
+    }
+
+    /**
+     * Calls the main entry point and exits the JVM with an exit
+     * status determined by the return status.
+     */
+    public static void main(String[] args) {
+        System.exit(call(System.out, System.err, args) ? 0 : 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,55 @@
+/*
+ * 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.  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.jdeprscan;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Message handling class for localization.
+ */
+public class Messages {
+    static final ResourceBundle bundle;
+
+    static {
+        Locale locale = Locale.getDefault();
+        try {
+            bundle = ResourceBundle.getBundle("com.sun.tools.jdeprscan.resources.jdeprscan", locale);
+        } catch (MissingResourceException e) {
+            throw new InternalError("Cannot find jdeps resource bundle for locale " + locale, e);
+        }
+    }
+
+    public static String get(String key, Object... args) {
+        try {
+            return MessageFormat.format(bundle.getString(key), args);
+        } catch (MissingResourceException e) {
+            throw new InternalError("Missing message: " + key, e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Pretty.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,274 @@
+/*
+ * 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.  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.jdeprscan;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Utility class for pretty-printing various bits of API syntax.
+ */
+public class Pretty {
+    /**
+     * Converts deprecation information into an {@code @Deprecated} annotation.
+     * The output is minimized: an empty since string is omitted, a forRemoval
+     * value of false is omitted; and if both are omitted, the trailing parentheses
+     * are also omitted.
+     *
+     * @param since the since value
+     * @param forRemoval the forRemoval value
+     * @return string containing an annotation
+     */
+    static String depr(String since, boolean forRemoval) {
+        String d = "@Deprecated";
+
+        if (since.isEmpty() && !forRemoval) {
+            return d;
+        }
+
+        StringBuilder sb = new StringBuilder(d).append('(');
+
+        if (!since.isEmpty()) {
+            sb.append("since=\"")
+              .append(since.replace("\"", "\\\""))
+              .append('"');
+        }
+
+        if (forRemoval) {
+            if (!since.isEmpty()) {
+                sb.append(", ");
+            }
+            sb.append("forRemoval=true");
+        }
+
+        sb.append(')');
+
+        return sb.toString();
+    }
+
+    /**
+     * Converts a slash-$ style name into a dot-separated name.
+     *
+     * @param n the input name
+     * @return the result name
+     */
+    static String unslashify(String n) {
+        return n.replace("/", ".")
+                .replace("$", ".");
+    }
+
+    /**
+     * Converts a type descriptor to a readable string.
+     *
+     * @param desc the input descriptor
+     * @return the result string
+     */
+    static String desc(String desc) {
+        return desc(desc, new int[] { 0 });
+    }
+
+    /**
+     * Converts one type descriptor to a readable string, starting
+     * from position {@code pos_inout[0]}, and updating it to the
+     * location following the descriptor just parsed. A type descriptor
+     * mostly corresponds to a FieldType in JVMS 4.3.2. It can be one of a
+     * BaseType (a single character denoting a primitive, plus void),
+     * an object type ("Lname;"), or an array type (one more more '[' followed
+     * by a base or object type).
+     *
+     * @param desc a string possibly containing several descriptors
+     * @param pos_inout on input, the start position; on return, the position
+     *                  following the just-parsed descriptor
+     * @return the result string
+     */
+    static String desc(String desc, int[] pos_inout) {
+        int dims = 0;
+        int pos = pos_inout[0];
+        final int len = desc.length();
+
+        while (pos < len && desc.charAt(pos) == '[') {
+            pos++;
+            dims++;
+        }
+
+        String name;
+
+        if (pos >= len) {
+            return null;
+        }
+
+        char c = desc.charAt(pos++);
+        switch (c) {
+            case 'Z':
+                name = "boolean";
+                break;
+            case 'B':
+                name = "byte";
+                break;
+            case 'S':
+                name = "short";
+                break;
+            case 'C':
+                name = "char";
+                break;
+            case 'I':
+                name = "int";
+                break;
+            case 'J':
+                name = "long";
+                break;
+            case 'F':
+                name = "float";
+                break;
+            case 'D':
+                name = "double";
+                break;
+            case 'V':
+                name = "void";
+                break;
+            case 'L':
+                int semi = desc.indexOf(';', pos);
+                if (semi == -1) {
+                    return null;
+                }
+                name = unslashify(desc.substring(pos, semi));
+                pos = semi + 1;
+                break;
+            default:
+                return null;
+        }
+
+        StringBuilder sb = new StringBuilder(name);
+        for (int i = 0; i < dims; i++) {
+            sb.append("[]");
+        }
+        pos_inout[0] = pos;
+        return sb.toString();
+    }
+
+    /**
+     * Converts a series of type descriptors into a comma-separated,
+     * readable string. This is used for the parameter types of a
+     * method descriptor.
+     *
+     * @param types the parameter types
+     * @return the readable string
+     */
+    static String parms(String types) {
+        int[] pos = new int[] { 0 };
+        StringBuilder sb = new StringBuilder();
+
+        boolean first = true;
+
+        String t;
+
+        while ((t = desc(types, pos)) != null) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(',');
+            }
+            sb.append(t);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Pattern for matching a method descriptor. Match results can
+     * be retrieved from named capture groups as follows: "name(params)return".
+     */
+    static final Pattern DESC_PAT = Pattern.compile("(?<name>.*)\\((?<args>.*)\\)(?<return>.*)");
+
+    /**
+     * Pretty-prints the data contained in the given DeprData object.
+     *
+     * @param dd the deprecation data object
+     * @return the formatted string
+     */
+    public static String print(DeprData dd) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(depr(dd.since, dd.forRemoval))
+          .append(' ');
+
+        switch (dd.kind) {
+            case ANNOTATION_TYPE:
+                sb.append("@interface ");
+                sb.append(unslashify(dd.typeName));
+                break;
+            case CLASS:
+                sb.append("class ");
+                sb.append(unslashify(dd.typeName));
+                break;
+            case ENUM:
+                sb.append("enum ");
+                sb.append(unslashify(dd.typeName));
+                break;
+            case INTERFACE:
+                sb.append("interface ");
+                sb.append(unslashify(dd.typeName));
+                break;
+
+            case ENUM_CONSTANT:
+            case FIELD:
+                sb.append(unslashify(dd.typeName))
+                  .append('.')
+                  .append(dd.nameSig);
+                break;
+            case CONSTRUCTOR:
+                Matcher cons = DESC_PAT.matcher(dd.nameSig);
+                sb.append(unslashify(dd.typeName));
+                if (cons.matches()) {
+                    sb.append('(')
+                      .append(parms(cons.group("args")))
+                      .append(')');
+                } else {
+                    sb.append('.')
+                      .append(dd.nameSig);
+                }
+                break;
+            case METHOD:
+                Matcher meth = DESC_PAT.matcher(dd.nameSig);
+                if (meth.matches()) {
+                    sb.append(desc(meth.group("return")))
+                      .append(' ')
+                      .append(unslashify(dd.typeName))
+                      .append('.')
+                      .append(meth.group("name"))
+                      .append('(')
+                      .append(parms(meth.group("args")))
+                      .append(')');
+                } else {
+                    sb.append(unslashify(dd.typeName))
+                      .append('.')
+                      .append(dd.nameSig);
+                }
+                break;
+        }
+
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/TraverseProc.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,172 @@
+/*
+ * 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.  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.jdeprscan;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+
+import static javax.lang.model.SourceVersion.RELEASE_9;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.tools.Diagnostic;
+
+@SupportedSourceVersion(RELEASE_9)
+@SupportedAnnotationTypes("*")
+public class TraverseProc extends AbstractProcessor {
+    Elements elements;
+    Messager messager;
+    final List<String> moduleRoots;
+    Map<PackageElement, List<TypeElement>> publicTypes;
+
+    TraverseProc(List<String> roots) {
+        moduleRoots = roots;
+    }
+
+    @Override
+    public void init(ProcessingEnvironment pe) {
+        super.init(pe);
+        elements = pe.getElementUtils();
+        messager = pe.getMessager();
+    }
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+            return false;
+        }
+
+        Set<ModuleElement> modules = new HashSet<>();
+        for (String mname : moduleRoots) {
+            ModuleElement me = elements.getModuleElement(mname);
+            if (me == null) {
+                messager.printMessage(Diagnostic.Kind.ERROR,
+                                      String.format("module %s not found%n", mname));
+            } else {
+                modules.addAll(findModules(me));
+            }
+        }
+
+        Set<PackageElement> packages = findPackages(modules);
+
+        publicTypes = findPublicTypes(packages);
+
+        return true;
+    }
+
+    void printPublicTypes() {
+        printPublicTypes(publicTypes);
+    }
+
+    public Map<PackageElement, List<TypeElement>> getPublicTypes() {
+        return publicTypes;
+    }
+
+    void printPublicTypes(Map<PackageElement, List<TypeElement>> types) {
+        System.out.println("All public types:");
+        types.entrySet().stream()
+             .sorted(Comparator.comparing(e -> e.getKey().toString()))
+             .forEach(e -> {
+                 System.out.println("  " + e.getKey());
+                 e.getValue().stream()
+                         .sorted(Comparator.comparing(TypeElement::toString))
+                         .forEach(t -> System.out.println("    " + t));
+             });
+        System.out.println();
+        System.out.flush();
+    }
+
+    Set<ModuleElement> findModules(ModuleElement root) {
+        return findModules0(root, new HashSet<>(), 0);
+    }
+
+    Set<ModuleElement> findModules0(ModuleElement m, Set<ModuleElement> set, int nesting) {
+        set.add(m);
+        for (ModuleElement.Directive dir : m.getDirectives()) {
+            if (dir.getKind() == ModuleElement.DirectiveKind.REQUIRES) {
+                ModuleElement.RequiresDirective req = (ModuleElement.RequiresDirective)dir;
+                findModules0(req.getDependency(), set, nesting + 1);
+            }
+        }
+        return set;
+    }
+
+    Set<PackageElement> findPackages(Collection<ModuleElement> mods) {
+        Set<PackageElement> set = new HashSet<>();
+        for (ModuleElement m : mods) {
+            for (ModuleElement.Directive dir : m.getDirectives()) {
+                if (dir.getKind() == ModuleElement.DirectiveKind.EXPORTS) {
+                    ModuleElement.ExportsDirective exp = (ModuleElement.ExportsDirective)dir;
+                    if (exp.getTargetModules() == null) {
+                        set.add(exp.getPackage());
+                    }
+                }
+            }
+        }
+        return set;
+    }
+
+    Map<PackageElement, List<TypeElement>> findPublicTypes(Collection<PackageElement> pkgs) {
+        Map<PackageElement, List<TypeElement>> map = new HashMap<>();
+        for (PackageElement pkg : pkgs) {
+            List<TypeElement> enclosed = new ArrayList<>();
+            for (Element e : pkg.getEnclosedElements()) {
+                addPublicTypes(enclosed, e);
+            }
+            map.put(pkg, enclosed);
+        }
+        return map;
+    }
+
+    void addPublicTypes(List<TypeElement> list, Element e) {
+        ElementKind kind = e.getKind();
+        if ((kind.isClass() || kind.isInterface())
+                && e.getModifiers().contains(Modifier.PUBLIC)) {
+            list.add((TypeElement)e);
+            for (Element enc : e.getEnclosedElements()) {
+                addPublicTypes(list, enc);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/internals.md	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,215 @@
+<!--
+
+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.  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.
+
+-->
+
+
+JDeprScan Internals
+-----
+
+**EXPERIMENTAL OPTIONS**
+
+    --Xload-class CLASSNAME
+
+        Loads deprecation data from the class named CLASSNAME instead of from
+        the JDK image.
+
+    --Xload-csv CVSFILE
+
+        Loads deprecation data from file CSVFILE.
+
+    --Xload-dir DIR
+
+        Loads deprecation data from the class hierarchy rooted
+        at the directory named DIR.
+
+    --Xload-jar JARFILE
+
+        Loads deprecation data from the classes contained in the
+        jar file named JARFILE.
+
+    --Xload-jdk9 JAVA_HOME
+
+        Loads deprecation data from a modular JDK whose home
+        directory is at JAVA_HOME. This essentially adds the given
+        path to the system-modules location.
+
+    --Xload-old-jdk JAVA_HOME
+
+        Loads deprecation data from an old (non-modular) JDK whose
+        home directory is at JAVA_HOME. This essentially scans the
+        rt.jar file from that JDK.
+
+    --Xload-self
+
+        Loads deprecation data from the running JDK image by
+        traversing the entire jrt: filesystem. This differs from
+        -release 9, which traverses modules, packages, and classes by
+        starting from a set of root modules and using javax.lang.model
+        mechanisms (as opposed to filesystem mechanisms) for
+        traversing contained elements recursively.
+
+    --Xcompiler-arg ARG
+
+        Adds ARG to the list of arguments passed to the compiler.
+
+    --Xcsv-comment COMMENT
+
+        Adds a comment line containing COMMENT to the top of the CSV
+        that is emitted.  Valid only when --Xprint-csv is
+        specified. More than one --Xcsv-comment option is permitted,
+        which will cause a corresponding number of comment lines to be
+        emitted to the CSV file.
+
+    --Xprint-csv
+
+        Prints out the loaded deprecation information in CSV format
+        to standard output. In this mode, no scanning is done, so
+        there must not be any additional directory, jar, or classname
+        arguments.
+
+**CSV FILE SYNTAX**
+
+The `-Xprint-csv` option causes **jdeprscan** to emit the loaded
+deprecation data in CSV (comma-separated value) format.  The general
+syntax of CSV is documented in [RFC 4180][RFC] with supplemental
+information in a [Wikipedia article][wiki].
+
+The file is encoded in UTF-8.
+
+The file consists of a series of lines. Any of the standard line
+separators CR (U+000D), LF (U+000A), or a CR immediately followed by
+LF, are supported. Newlines are only supported between records and
+are not supported within field values.
+
+Comment lines start with a `#` (U+0023) character in the first
+column. The entire line is ignored up until the next line separator
+sequence.
+
+Each line is divided into fields separated by the comma `,` (U+002C)
+character.  Horizontal whitespace is not treated specially; that is,
+it is considered part of a field's value. An empty line is considered
+to have one field which is the empty string.
+
+A field value that contains a comma or a quote quotation mark `"`
+(U+0022) must be surrounded by quotation marks. The surrounding
+quotation marks are not considered part of the field value. Any
+quotation marks that are part of a field value must be repeated in
+addition to being surrounded by quotation marks.
+
+It is a syntax error if a quotation mark appears within an unquoted field;
+if a quoted field isn't immediately followed by a comma or line
+separator; or if a quoted field is left unclosed at the end of the line.
+
+For example, a record with the following four fields:
+
+1. abcd
+2. ef,gh
+3. ij"kl
+4. mnop
+
+would be encoded as follows:
+
+        abcd,"ef,gh","ij""kl",mnop
+
+**CSV FILE DATA**
+
+The first line of output must be the following:
+
+        #jdepr1
+
+This is strictly a comment line, but it serves as a file
+identifier. The "1" indicates version 1 of this file.
+
+Zero or more comment lines follow, containing text that is specified
+by the `-Xcsv-comment` options.
+
+Subsequent non-comment lines must have the following five fields:
+
+        kind,typeName,descOrName,since,forRemoval
+
+Fields are defined as follows:
+
+ * _kind_ - one of CONSTRUCTOR, FIELD, METHOD, ENUM\_CONSTANT,
+   CLASS, INTERFACE, ENUM, or ANNOTATION\_TYPE. These correspond to
+   enumeration constants from the `javax.lang.model.element.ElementKind`
+   enum.
+
+ * _typeName_ - the fully qualified name of the type (if *kind* is
+   CLASS, INTERFACE, ENUM, or ANNOTATION\_TYPE) or of the enclosing
+   type (if _kind_ is CONSTRUCTOR, FIELD, METHOD, or
+   ENUM\_CONSTANT). This value is a _binary name_ [JLS 13.1][jls131]
+   using a slash character `/` (U+002F) to separate package and
+   top-level name components, and a dollar sign `$` (U+0024) to
+   separate nested name components. For example, the `Thread.State`
+   enum that appears in Java SE would have the following typeName:
+
+            java/lang/Thread$State
+
+ * _descOrName_ - if _kind_ is METHOD or CONSTRUCTOR, this is the method's
+   or constructor's descriptor [JVMS 4.3.3][jvms433]; if _kind_ is FIELD or
+   ENUM\_CONSTANT, this is its name; otherwise this field is empty.
+   A method's descriptor includes its name, parameter types, and return
+   type. For example, the method
+
+           public void String.getBytes(int srcBegin,
+                                       int srcEnd,
+                                       byte[] dst,
+                                       int dstBegin)
+
+   has the descriptor
+
+           getBytes(II[BI)V
+
+ * _since_ - the value of the `since` element of the `@Deprecated`
+   annotation, or empty if this element is not present.
+
+ * _forRemoval_ - the value of the `forRemoval` element of the
+   `@Deprecated` annotation, a boolean, either "true" or "false".
+
+Note that the _since_ field can have arbitrary text (excluding
+line separators) and is thus subject to quoting.
+
+**EXAMPLE OUTPUT**
+
+Given the following method declaration and annotation from the
+`java.lang.Runtime` class,
+
+            @Deprecated(since="1.2",
+                        forRemoval=true)
+            public static void runFinalizersOnExit(boolean value)
+
+the following line will be emitted from **jdeprscan -Xprint-csv**:
+
+            METHOD,java/lang/Runtime,runFinalizersOnExit(Z)V,1.2,true
+
+
+[RFC]: https://www.ietf.org/rfc/rfc4180.txt
+
+[wiki]: https://en.wikipedia.org/wiki/Comma-separated_values
+
+[jls131]: http://docs.oracle.com/javase/specs/jls/se8/html/jls-13.html#jls-13.1
+
+[jvms433]: http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.3.3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,180 @@
+<!--
+
+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.  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.
+
+-->
+
+
+JDeprScan Tool Command Reference
+-----
+
+**NAME**
+
+        jdeprscan - Java deprecation scanner
+
+**SYNOPSIS**
+
+        jdeprscan [options] {dir | jar | class} ...
+
+**OPTIONS**
+
+        -cp PATH
+        --class-path PATH
+
+            Sets the classpath to PATH.
+
+        --for-removal
+
+            Limit reporting to deprecations whose forRemoval element
+            is true.
+
+        --full-version
+
+            Prints the full version string of the tool and exits.
+
+        -h
+        --help
+
+            Prints a help message and exits.
+
+        -l
+        --list
+
+            Prints out the set of deprecated APIs.
+
+        --release 6|7|8|9
+
+            Specifies the Java SE release that is the source of
+            the list of deprecated APIs. If no --release option is
+            provided, the latest release is used.
+
+        -v
+        --verbose
+
+            Enables additional output.
+
+        --version
+
+            Prints the version string of the tool and exits.
+
+**DESCRIPTION**
+
+**jdeprscan** scans a class library for uses of deprecated APIs.
+**jdeprscan** processes one or more arguments, which can be any
+combination of a directory, a jar file, or a class name.
+
+A directory argument must specify a path to a directory hierarchy that
+reflects the Java package hierarchy of the classes it contains.
+**jdeprscan** will scan each class found in the directory hierarchy
+and report information about how those classes use deprecated APIs.
+
+Given a jar file, **jdeprscan** will scan the classes found within
+that jar file and report information about how those classes use
+deprecated APIs.
+
+Given a class name, **jdeprscan** will search for that class on the
+classpath, scan that class, and report information about how that
+class uses deprecated APIs. The class name must use the fully
+qualified binary name of the class, as described in the
+[Java Language Specification, section 13.1][jls131]. This form uses
+the '$' character instead of '.' as the separator for nested class names.
+For example, the `Thread.State` enum would be specified using the string
+
+        java.lang.Thread$State
+
+The `--class-path` and `-cp` options specify the classpath used for
+class searching. The classpath is used for classes named on the
+command line, as well as for dependencies of the classes in jar file
+or directory hierarchy to be scanned.
+
+The `--for-removal` option limits output to uses of deprecated APIs
+whose `@Deprecated` annotation includes the `forRemoval` element with
+the value `true`. Note: the `forRemoval` attribute of the
+`@Deprecated` annotation did not exist prior to Java SE 9, so this
+option cannot be used with a release value of 6, 7, or 8.
+
+The `--release` option specifies the Java SE specification version
+that determines the set of deprecated APIs for which scanning is
+done. This is useful if a deprecation report is desired that lists
+uses of deprecated APIs as of a particular release in the past. If no
+`--release` option is given, the latest release is used.
+
+The `--list` and `-l` options will list the known set of deprecated
+APIs instead of doing any scanning. Since no scanning is done,
+no directory, jar, or class arguments should be provided. The set
+of deprecated APIs listed is affected by the `--release` and the
+`--for-removal` options.
+
+
+**EXAMPLE OUTPUT**
+
+The output is a report that lists program elements that use deprecated
+APIs. Output is subject to change.
+
+Consider the following declarations from Java SE 9:
+
+        // java.lang.Boolean
+
+        @Deprecated(since="9")
+        public Boolean(boolean value)
+
+        // java.lang.Runtime
+
+        @Deprecated(since="1.2", forRemoval=true)
+        public static void runFinalizersOnExit(boolean value)
+
+Running **jdeprscan** over a class that calls these methods will result
+in output something like the following:
+
+        class Example uses method java/lang/Boolean.<init>(Z)V deprecated
+        class Example uses method java/lang/Runtime.runFinalizersOnExit(Z)V deprecated for removal
+
+Running **jdeprscan** with the `--list` option will result in output
+including something like the following:
+
+        ...
+        @Deprecated(since="9") java.lang.Boolean(boolean)
+        @Deprecated(since="1.2", forRemoval=true) void java.lang.Runtime.runFinalizersOnExit(boolean)
+        ...
+
+**NOTES**
+
+The **jdeprscan** tool operates by opening Java class files and
+reading their structures directly, particularly the constant
+pool. Because of this, **jdeprscan** can tell _that_ a deprecated API
+is used, but it often cannot tell _where_ in the class that API is
+used.
+
+The **jdeprscan** tool doesn't follow the same set of rules for
+emitting warnings as specified for Java compilers in [JLS section
+9.6.4.6][jls9646]. In particular, **jdeprscan** does not respond to
+the `@SuppressWarnings` annotation, as that is significant only in
+source code, not in class files. In addition, **jdeprscan** emits
+warnings even if the usage is within the API element that is
+deprecated and when the use and declaration are within the same
+outermost class.
+
+[jls9646]: http://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.6.4.6
+
+[jls131]: http://docs.oracle.com/javase/specs/jls/se8/html/jls-13.html#jls-13.1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,96 @@
+main.usage=\
+Usage: jdeprscan [options] '{dir|jar|class}' ...\n\
+\n\
+options:\n\
+\  -cp  --class-path PATH\n\
+\       --for-removal\n\
+\       --full-version\n\
+\  -h   --help\n\
+\  -l   --list\n\
+\       --release 6|7|8|9\n\
+\  -v   --verbose\n\
+\       --version
+
+main.help=\
+Scans each argument for usages of deprecated APIs. An argument\n\
+may be a directory specifying the root of a package hierarchy,\n\
+a JAR file, or a class name. The class name must be specified\n\
+using a fully qualified class name using the $ separator character\n\
+for nested classes, for example,\n\
+\n\
+\    java.lang.Thread$State\n\
+\n\
+The --class-path (-cp) option provides a search path for resolution\n\
+of dependent classes.\n\
+\n\
+The --for-removal option limits scanning or listing to APIs that are\n\
+deprecated for removal. Cannot be used with a release value of 6, 7, or 8.\n\
+\n\
+The --full-version option prints out the full version string of the tool.\n\
+\n\
+The --help option prints out a full help message.\n\
+\n\
+The --list (-l) option prints out the set of deprecated APIs. No scanning is done,\n\
+so no directory, jar, or class arguments should be provided.\n\
+\n\
+The --release option specifies the Java SE release that provides the set\n\
+of deprecated APIs for scanning.\n\
+\n\
+The --verbose (-v) option enables additional message output during processing.\n\
+\n\
+The --version option prints out the abbreviated version string of the tool.
+
+main.xhelp=\
+Unsupported options:\n\
+\n\
+\  --Xload-class CLASS\n\
+\      Loads deprecation information from the named class.\n\
+\  --Xload-csv CSVFILE\n\
+\      Loads deprecation information from the named CSV file.\n\
+\  --Xload-dir DIR\n\
+\      Loads deprecation information from the class hierarchy\n\
+\      at the named directory.\n\
+\  --Xload-jar JARFILE\n\
+\      Loads deprecation information from the named JAR file.\n\
+\  --Xload-jdk9 JAVA_HOME\n\
+\      Loads deprecation information from the JDK located at\n\
+\      JAVA_HOME, which must be a modular JDK.\n\
+\  --Xload-old-jdk JAVA_HOME\n\
+\      Loads deprecation information from the JDK located at\n\
+\      JAVA_HOME, which must not be a modular JDK. Instead, the\n\
+\      named JDK must be a "classic" JDK with an rt.jar file.\n\
+\  --Xload-self\n\
+\      Loads deprecation information by traversing the jrt:\n\
+\      filesystem of the running JDK image.\n\
+\  --Xcompiler-arg ARG\n\
+\      Adds ARG to the list of compiler arguments.\n\
+\  --Xcsv-comment COMMENT\n\
+\      Adds COMMENT as a comment line to the output CSV file.\n\
+\      Only effective if -Xprint-csv is also supplied.\n\
+\  --Xhelp\n\
+\      Prints this message.\n\
+\  --Xprint-csv\n\
+\      Prints a CSV file containing the loaded deprecation information\n\
+\      instead of scanning any classes or JAR files.
+
+error.prefix=Error:
+
+scan.process.class=Processing class {0}...
+
+scan.dep.normal=deprecated
+scan.dep.removal=deprecated FOR REMOVAL
+
+scan.out.extends={0} {1} extends class {2} {3}
+scan.out.implements={0} {1} implements interface {2} {3}
+scan.out.usestype={0} {1} uses type {2} {3}
+scan.out.usesmethodintype={0} {1} uses method in type {2} {3}
+scan.out.usesmethod={0} {1} uses method {2} {3} {4} {5}
+scan.out.usesintfmethodintype={0} {1} uses interface method in type {2} {3}
+scan.out.usesintfmethod={0} {1} uses interface method {2} {3} {4} {5}
+scan.out.usesfieldintype={0} {1} uses field in type {2} {3}
+scan.out.usesfield={0} {1} uses field {2} {3} {4}
+scan.out.usesfieldoftype={0} {1} uses field of type {2} {3} {4} {5}
+scan.out.hasfield={0} {1} has field {2} of type {3} {4}
+scan.out.methodparmtype={0} {1} method {2} has parameter type {3} {4}
+scan.out.methodrettype={0} {1} method {2} has return type {3} {4}
+scan.out.methodoverride={0} {1} overrides method {2} {3} {4} {5}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/CPEntries.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,76 @@
+/*
+ * 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.  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.jdeprscan.scan;
+
+import java.util.ArrayList;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Locale;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPool;
+
+import static com.sun.tools.classfile.ConstantPool.CPInfo;
+
+/**
+ * A container for selected constant pool entries. There are currently
+ * lists that contain the following types of CP entries:
+ *
+ *  - CONSTANT_Class_info
+ *  - CONSTANT_Fieldref_info
+ *  - CONSTANT_Methodref_info
+ *  - CONSTANT_InterfaceMethodref_info
+ */
+class CPEntries {
+    final List<ConstantPool.CONSTANT_Class_info> classes = new ArrayList<>();
+    final List<ConstantPool.CONSTANT_Fieldref_info> fieldRefs = new ArrayList<>();
+    final List<ConstantPool.CONSTANT_Methodref_info> methodRefs = new ArrayList<>();
+    final List<ConstantPool.CONSTANT_InterfaceMethodref_info> intfMethodRefs = new ArrayList<>();
+
+    public static CPEntries loadFrom(ClassFile cf) {
+        CPEntries entries = new CPEntries();
+        for (CPInfo cpi : cf.constant_pool.entries()) {
+            cpi.accept(new CPSelector(), entries);
+        }
+        return entries;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        Formatter f = new Formatter(sb, Locale.getDefault());
+        f.format("Classes:%n");
+        f.format("%s%n", classes);
+        f.format("FieldRefs:%n");
+        f.format("%s%n", fieldRefs);
+        f.format("MethodRefs:%n");
+        f.format("%s%n", methodRefs);
+        f.format("InterfaceMethodRefs:%n");
+        f.format("%s%n", intfMethodRefs);
+        f.flush();
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/CPSelector.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,108 @@
+/*
+ * 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.  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.jdeprscan.scan;
+
+import com.sun.tools.classfile.ConstantPool;
+
+/**
+ * A visitor that selects constant pool entries by type and adds
+ * them to the given CPEntries object.
+ */
+class CPSelector implements ConstantPool.Visitor<Void,CPEntries> {
+    @Override
+    public Void visitClass(ConstantPool.CONSTANT_Class_info info, CPEntries p) {
+        p.classes.add(info);
+        return null;
+    }
+
+    @Override
+    public Void visitDouble(ConstantPool.CONSTANT_Double_info info, CPEntries p) {
+        return null;
+    }
+
+    @Override
+    public Void visitFieldref(ConstantPool.CONSTANT_Fieldref_info info, CPEntries p) {
+        p.fieldRefs.add(info);
+        return null;
+    }
+
+    @Override
+    public Void visitFloat(ConstantPool.CONSTANT_Float_info info, CPEntries p) {
+        return null;
+    }
+
+    @Override
+    public Void visitInteger(ConstantPool.CONSTANT_Integer_info info, CPEntries p) {
+        return null;
+    }
+
+    @Override
+    public Void visitInterfaceMethodref(ConstantPool.CONSTANT_InterfaceMethodref_info info, CPEntries p) {
+        p.intfMethodRefs.add(info);
+        return null;
+    }
+
+    @Override
+    public Void visitInvokeDynamic(ConstantPool.CONSTANT_InvokeDynamic_info info, CPEntries p) {
+        return null;
+    }
+
+    @Override
+    public Void visitLong(ConstantPool.CONSTANT_Long_info info, CPEntries p) {
+        return null;
+    }
+
+    @Override
+    public Void visitNameAndType(ConstantPool.CONSTANT_NameAndType_info info, CPEntries p) {
+        return null;
+    }
+
+    @Override
+    public Void visitMethodref(ConstantPool.CONSTANT_Methodref_info info, CPEntries p) {
+        p.methodRefs.add(info);
+        return null;
+    }
+
+    @Override
+    public Void visitMethodHandle(ConstantPool.CONSTANT_MethodHandle_info info, CPEntries p) {
+        return null;
+    }
+
+    @Override
+    public Void visitMethodType(ConstantPool.CONSTANT_MethodType_info info, CPEntries p) {
+        return null;
+    }
+
+    @Override
+    public Void visitString(ConstantPool.CONSTANT_String_info info, CPEntries p) {
+        return null;
+    }
+
+    @Override
+    public Void visitUtf8(ConstantPool.CONSTANT_Utf8_info info, CPEntries p) {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/ClassFinder.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,211 @@
+/*
+ * 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.  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.jdeprscan.scan;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPoolException;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Stream;
+
+/**
+ * A simple search path for classes.
+ */
+public class ClassFinder {
+    final List<PathEntry> list = new ArrayList<>();
+    final boolean verbose;
+
+    public ClassFinder(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    /**
+     * Adds a directory to this finder's search path, ignoring errors.
+     *
+     * @param dirName the directory to add
+     */
+    public void addDir(String dirName) {
+        Path dir = Paths.get(dirName);
+
+        if (Files.isDirectory(dir)) {
+            list.add(new DirPathEntry(dir));
+        }
+    }
+
+    /**
+     * Adds a jar file to this finder's search path, ignoring errors.
+     *
+     * @param jarName the jar file name to add
+     */
+    public void addJar(String jarName) {
+        try {
+            list.add(new JarPathEntry(new JarFile(jarName)));
+        } catch (IOException ignore) { }
+    }
+
+    /**
+     * Adds the JRT filesystem to this finder's search path.
+     */
+    public void addJrt() {
+        list.add(new JrtPathEntry());
+    }
+
+    /**
+     * Searches the class path for a class with the given name,
+     * returning a ClassFile for it. Returns null if not found.
+     *
+     * @param className the class to search for
+     * @return a ClassFile instance, or null if not found
+     */
+    public ClassFile find(String className) {
+        for (PathEntry pe : list) {
+            ClassFile cf = pe.find(className);
+            if (cf != null) {
+                return cf;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * An entry in this finder's class path.
+     */
+    interface PathEntry {
+        /**
+         * Returns a ClassFile instance corresponding to this name,
+         * or null if it's not present in this entry.
+         *
+         * @param className the class to search for
+         * @return a ClassFile instance, or null if not found
+         */
+        ClassFile find(String className);
+    }
+
+    /**
+     * An entry that represents a jar file.
+     */
+    class JarPathEntry implements PathEntry {
+        final JarFile jarFile;
+
+        JarPathEntry(JarFile jf) {
+            jarFile = jf;
+        }
+
+        @Override
+        public ClassFile find(String className) {
+            JarEntry entry = jarFile.getJarEntry(className + ".class");
+            if (entry == null) {
+                return null;
+            }
+            try {
+                return ClassFile.read(jarFile.getInputStream(entry));
+            } catch (IOException | ConstantPoolException ex) {
+                if (verbose) {
+                    ex.printStackTrace();
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
+     * An entry that represents a directory containing a class hierarchy.
+     */
+    class DirPathEntry implements PathEntry {
+        final Path dir;
+
+        DirPathEntry(Path dir) {
+            this.dir = dir;
+        }
+
+        @Override
+        public ClassFile find(String className) {
+            Path classFileName = dir.resolve(className + ".class");
+            try {
+                return ClassFile.read(classFileName);
+            } catch (NoSuchFileException nsfe) {
+                // not found, return silently
+            } catch (IOException | ConstantPoolException ex) {
+                if (verbose) {
+                    ex.printStackTrace();
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
+     * An entry that represents the JRT filesystem in the running image.
+     *
+     * JRT filesystem structure is:
+     *     /packages/<dotted-pkgname>/<modlink>
+     * where modlink is a symbolic link to /modules/<modname> which is
+     * the top of the usual package-class hierarchy
+     */
+    class JrtPathEntry implements PathEntry {
+        final FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
+
+        @Override
+        public ClassFile find(String className) {
+            int end = className.lastIndexOf('/');
+            if (end < 0) {
+                return null;
+            }
+            String pkg = "/packages/" + className.substring(0, end)
+                                                 .replace('/', '.');
+            try (Stream<Path> mods = Files.list(fs.getPath(pkg))) {
+                Optional<Path> opath =
+                    mods.map(path -> path.resolve(className + ".class"))
+                        .filter(Files::exists)
+                        .findFirst();
+                if (opath.isPresent()) {
+                    return ClassFile.read(opath.get());
+                } else {
+                    return null;
+                }
+            } catch (NoSuchFileException nsfe) {
+                // not found, return silently
+            } catch (IOException | ConstantPoolException ex) {
+                if (verbose) {
+                    ex.printStackTrace();
+                }
+            }
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/MethodSig.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,167 @@
+/*
+ * 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.  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.jdeprscan.scan;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents a method's signature, that is, its parameter types
+ * and its return type.
+ */
+public class MethodSig {
+    final List<String> parameters;
+    final String returnType;
+
+    /**
+     * Parses the method descriptor and returns a MethodSig instance.
+     *
+     * @param desc the descriptor to parse
+     * @return the new MethodSig instance
+     */
+    public static MethodSig fromDesc(String desc) {
+        return parse(desc, 0, desc.length());
+    }
+
+    /**
+     * Returns this method's return type.
+     *
+     * @return the return type
+     */
+    public String getReturnType() {
+        return returnType;
+    }
+
+    /**
+     * Returns a list of parameters of this method.
+     *
+     * @return the parameter list
+     */
+    public List<String> getParameters() {
+        return parameters;
+    }
+
+    /**
+     * Returns a string describing this method.
+     *
+     * @return the string description
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("parameters");
+        if (parameters.isEmpty()) {
+            sb.append(" none");
+        } else {
+            int i = 0;
+            for (String p : parameters) {
+                sb.append(String.format(" %d=%s", i++, p));
+            }
+        }
+        sb.append(String.format(" return %s", returnType));
+        return sb.toString();
+    }
+
+    private MethodSig(List<String> parameters, String returnType) {
+        this.parameters = Collections.unmodifiableList(parameters);
+        this.returnType = returnType;
+    }
+
+    private static IllegalArgumentException ex(String desc, int pos) {
+        return new IllegalArgumentException(String.format(
+            "illegal descriptor \"%s\" at position %d", desc, pos));
+    }
+
+    private static MethodSig parse(String desc, int start, int end)
+            throws IllegalArgumentException {
+        int p = start;
+        int dims = 0;
+        boolean inReturnType = false;
+        String returnType = null;
+        List<String> parameters = new ArrayList<>();
+
+        while (p < end) {
+            String type;
+            char ch;
+            switch (ch = desc.charAt(p)) {
+                case '(':
+                    p++;
+                    continue;
+
+                case ')':
+                    p++;
+                    inReturnType = true;
+                    continue;
+
+                case '[':
+                    p++;
+                    dims++;
+                    continue;
+
+                case 'B': // byte
+                case 'C': // char
+                case 'D': // double
+                case 'F': // float
+                case 'I': // int
+                case 'J': // long
+                case 'S': // short
+                case 'Z': // boolean
+                case 'V': // void
+                    type = Character.toString(ch);
+                    p++;
+                    break;
+
+                case 'L':
+                    int sep = desc.indexOf(';', p);
+                    if (sep == -1 || sep >= end)
+                        throw ex(desc, p);
+                    type = desc.substring(p, ++sep);
+                    p = sep;
+                    break;
+
+                default:
+                    throw ex(desc, p);
+            }
+
+            StringBuilder sb = new StringBuilder();
+            for ( ; dims > 0; dims-- )
+                sb.append("[");
+            sb.append(type);
+            if (inReturnType) {
+                returnType = sb.toString();
+            } else {
+                parameters.add(sb.toString());
+            }
+        }
+
+        if (returnType == null) {
+            throw ex(desc, end);
+        }
+
+        return new MethodSig(parameters, returnType);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,614 @@
+/*
+ * 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.  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.jdeprscan.scan;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import com.sun.tools.classfile.*;
+import com.sun.tools.jdeprscan.DeprData;
+import com.sun.tools.jdeprscan.DeprDB;
+import com.sun.tools.jdeprscan.Messages;
+
+import static com.sun.tools.classfile.AccessFlags.*;
+import static com.sun.tools.classfile.ConstantPool.*;
+
+/**
+ * An object that represents the scanning phase of deprecation usage checking.
+ * Given a deprecation database, scans the targeted directory hierarchy, jar
+ * file, or individual class for uses of deprecated APIs.
+ */
+public class Scan {
+    final PrintStream out;
+    final PrintStream err;
+    final List<String> classPath;
+    final DeprDB db;
+    final boolean verbose;
+
+    final ClassFinder finder;
+    boolean error = false;
+
+    public Scan(PrintStream out,
+                PrintStream err,
+                List<String> classPath,
+                DeprDB db,
+                boolean verbose) {
+        this.out = out;
+        this.err = err;
+        this.classPath = classPath;
+        this.db = db;
+        this.verbose = verbose;
+
+        ClassFinder f = new ClassFinder(verbose);
+
+        // TODO: this isn't quite right. If we've specified a release other than the current
+        // one, we should instead add a reference to the symbol file for that release instead
+        // of the current image. The problems are a) it's unclear how to get from a release
+        // to paths that reference the symbol files, as this might be internal to the file
+        // manager; and b) the symbol file includes .sig files, not class files, which ClassFile
+        // might not be able to handle.
+        f.addJrt();
+
+        for (String name : classPath) {
+            if (name.endsWith(".jar")) {
+                f.addJar(name);
+            } else {
+                f.addDir(name);
+            }
+        }
+
+        finder = f;
+    }
+
+    Pattern typePattern = Pattern.compile("\\[*L(.*);");
+
+    // "flattens" an array type name to its component type
+    // and a reference type "Lpkg/pkg/pkg/name;" to its base name
+    // "pkg/pkg/pkg/name".
+    // TODO: deal with primitive types
+    String flatten(String typeName) {
+        Matcher matcher = typePattern.matcher(typeName);
+        if (matcher.matches()) {
+            return matcher.group(1);
+        } else {
+            return typeName;
+        }
+    }
+
+    String typeKind(ClassFile cf) {
+        AccessFlags flags = cf.access_flags;
+        if (flags.is(ACC_ENUM)) {
+            return "enum";
+        } else if (flags.is(ACC_ANNOTATION)) {
+            return "@interface";
+        } else if (flags.is(ACC_INTERFACE)) {
+            return "interface";
+        } else {
+            return "class";
+        }
+    }
+
+    void printType(String key, ClassFile cf, String cname, boolean forRemoval)
+            throws ConstantPoolException {
+        String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal");
+        out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, dep));
+    }
+
+    void printMethod(String key, ClassFile cf, String cname, String mname, String rtype,
+                     boolean forRemoval) throws ConstantPoolException {
+        String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal");
+        out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, mname, rtype, dep));
+    }
+
+    void printField(String key, ClassFile cf, String cname, String fname,
+                     boolean forRemoval) throws ConstantPoolException {
+        String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal");
+        out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, fname, dep));
+    }
+
+    void printFieldType(String key, ClassFile cf, String cname, String fname, String type,
+                     boolean forRemoval) throws ConstantPoolException {
+        String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal");
+        out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, fname, type, dep));
+    }
+
+    void printHasField(ClassFile cf, String fname, String type, boolean forRemoval)
+            throws ConstantPoolException {
+        String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal");
+        out.println(Messages.get("scan.out.hasfield", typeKind(cf), cf.getName(), fname, type, dep));
+    }
+
+    void printHasMethodParmType(ClassFile cf, String mname, String parmType, boolean forRemoval)
+            throws ConstantPoolException {
+        String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal");
+        out.println(Messages.get("scan.out.methodparmtype", typeKind(cf), cf.getName(), mname, parmType, dep));
+    }
+
+    void printHasMethodRetType(ClassFile cf, String mname, String retType, boolean forRemoval)
+            throws ConstantPoolException {
+        String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal");
+        out.println(Messages.get("scan.out.methodrettype", typeKind(cf), cf.getName(), mname, retType, dep));
+    }
+
+    void printHasOverriddenMethod(ClassFile cf, String overridden, String mname, String desc, boolean forRemoval)
+            throws ConstantPoolException {
+        String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal");
+        out.println(Messages.get("scan.out.methodoverride", typeKind(cf), cf.getName(), overridden,
+                                 mname, desc, dep));
+    }
+
+    // format should not have a newline
+    void err(String format, Object... args) {
+        error = true;
+        err.print("error: ");
+        err.printf(format, args);
+        err.println();
+    }
+
+    void printException(Exception ex) {
+        err.print(Messages.get("error.prefix"));
+        err.print(" ");
+        if (verbose) {
+            ex.printStackTrace(err);
+        } else {
+            err.print(ex);
+        }
+    }
+
+    /**
+     * Checks whether a member (method or field) is present in a class.
+     * The checkMethod parameter determines whether this checks for a method
+     * or for a field.
+     *
+     * @param targetClass the ClassFile of the class to search
+     * @param targetName the method or field's name
+     * @param targetDesc the methods descriptor (ignored if checkMethod is false)
+     * @param checkMethod true if checking for method, false if checking for field
+     * @return boolean indicating whether the member is present
+     * @throws ConstantPoolException if a constant pool entry cannot be found
+     */
+    boolean isMemberPresent(ClassFile targetClass,
+                            String targetName,
+                            String targetDesc,
+                            boolean checkMethod)
+            throws ConstantPoolException {
+        if (checkMethod) {
+            for (Method m : targetClass.methods) {
+                String mname = m.getName(targetClass.constant_pool);
+                String mdesc = targetClass.constant_pool.getUTF8Value(m.descriptor.index);
+                if (targetName.equals(mname) && targetDesc.equals(mdesc)) {
+                    return true;
+                }
+            }
+        } else {
+            for (Field f : targetClass.fields) {
+                String fname = f.getName(targetClass.constant_pool);
+                if (targetName.equals(fname)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Adds all interfaces from this class to the deque of interfaces.
+     *
+     * @param intfs the deque of interfaces
+     * @param cf the ClassFile of this class
+     * @throws ConstantPoolException if a constant pool entry cannot be found
+     */
+    void addInterfaces(Deque<String> intfs, ClassFile cf)
+            throws ConstantPoolException {
+        int count = cf.interfaces.length;
+        for (int i = 0; i < count; i++) {
+            intfs.addLast(cf.getInterfaceName(i));
+        }
+    }
+
+    /**
+     * Resolves a member by searching this class and all its superclasses and
+     * implemented interfaces.
+     *
+     * TODO: handles a few too many cases; needs cleanup.
+     *
+     * TODO: refine error handling
+     *
+     * @param cf the ClassFile of this class
+     * @param startClassName the name of the class at which to start searching
+     * @param findName the member name to search for
+     * @param findDesc the method descriptor to search for (ignored for fields)
+     * @param resolveMethod true if resolving a method, false if resolving a field
+     * @param checkStartClass true if the start class should be searched, false if
+     *                        it should be skipped
+     * @return the name of the class where the member resolved, or null
+     * @throws ConstantPoolException if a constant pool entry cannot be found
+     */
+    String resolveMember(
+            ClassFile cf, String startClassName, String findName, String findDesc,
+            boolean resolveMethod, boolean checkStartClass)
+            throws ConstantPoolException {
+        ClassFile startClass;
+
+        if (cf.getName().equals(startClassName)) {
+            startClass = cf;
+        } else {
+            startClass = finder.find(startClassName);
+            if (startClass == null) {
+                err("can't find class %s", startClassName);
+                return startClassName;
+            }
+        }
+
+        // follow super_class until it's 0, meaning we've reached Object
+        // accumulate interfaces of superclasses as we go along
+
+        ClassFile curClass = startClass;
+        Deque<String> intfs = new ArrayDeque<>();
+        while (true) {
+            if ((checkStartClass || curClass != startClass) &&
+                    isMemberPresent(curClass, findName, findDesc, resolveMethod)) {
+                break;
+            }
+
+            if (curClass.super_class == 0) { // reached Object
+                curClass = null;
+                break;
+            }
+
+            String superName = curClass.getSuperclassName();
+            curClass = finder.find(superName);
+            if (curClass == null) {
+                err("can't find class %s", superName);
+                break;
+            }
+            addInterfaces(intfs, curClass);
+        }
+
+        // search interfaces: add all interfaces and superinterfaces to queue
+        // search until it's empty
+
+        if (curClass == null) {
+            addInterfaces(intfs, startClass);
+            while (intfs.size() > 0) {
+                String intf = intfs.removeFirst();
+                curClass = finder.find(intf);
+                if (curClass == null) {
+                    err("can't find interface %s", intf);
+                    break;
+                }
+
+                if (isMemberPresent(curClass, findName, findDesc, resolveMethod)) {
+                    break;
+                }
+
+                addInterfaces(intfs, curClass);
+            }
+        }
+
+        if (curClass == null) {
+            if (checkStartClass) {
+                err("can't resolve methodref %s %s %s",
+                    startClassName, findName, findDesc);
+                return startClassName;
+            } else {
+                // TODO: refactor this
+                // checkStartClass == false means we're checking for overrides
+                // so not being able to resolve a method simply means there's
+                // no overriding, which isn't an error
+                return null;
+            }
+        } else {
+            String foundClassName = curClass.getName();
+            return foundClassName;
+        }
+    }
+
+    /**
+     * Checks the superclass of this class.
+     *
+     * @param cf the ClassFile of this class
+     * @throws ConstantPoolException if a constant pool entry cannot be found
+     */
+    void checkSuper(ClassFile cf) throws ConstantPoolException {
+        String sname = cf.getSuperclassName();
+        DeprData dd = db.getTypeDeprecated(sname);
+        if (dd != null) {
+            printType("scan.out.extends", cf, sname, dd.isForRemoval());
+        }
+    }
+
+    /**
+     * Checks the interfaces of this class.
+     *
+     * @param cf the ClassFile of this class
+     * @throws ConstantPoolException if a constant pool entry cannot be found
+     */
+    void checkInterfaces(ClassFile cf) throws ConstantPoolException {
+        int ni = cf.interfaces.length;
+        for (int i = 0; i < ni; i++) {
+            String iname = cf.getInterfaceName(i);
+            DeprData dd = db.getTypeDeprecated(iname);
+            if (dd != null) {
+                printType("scan.out.implements", cf, iname, dd.isForRemoval());
+            }
+        }
+    }
+
+    /**
+     * Checks types referred to from the constant pool.
+     *
+     * @param cf the ClassFile of this class
+     * @param entries constant pool entries collected from this class
+     * @throws ConstantPoolException if a constant pool entry cannot be found
+     */
+    void checkTypes(ClassFile cf, CPEntries entries) throws ConstantPoolException {
+        for (ConstantPool.CONSTANT_Class_info ci : entries.classes) {
+            String typeName = ci.getName();
+            DeprData dd = db.getTypeDeprecated(flatten(typeName));
+            if (dd != null) {
+                printType("scan.out.usestype", cf, typeName, dd.isForRemoval());
+            }
+        }
+    }
+
+    /**
+     * Checks methods referred to from the constant pool.
+     *
+     * @param cf the ClassFile of this class
+     * @param nti the NameAndType_info from a MethodRef or InterfaceMethodRef entry
+     * @param clname the class name
+     * @param typeKey key for the type message
+     * @param methKey key for the method message
+     * @throws ConstantPoolException if a constant pool entry cannot be found
+     */
+    void checkMethodRef(ClassFile cf,
+                        CONSTANT_NameAndType_info nti,
+                        String clname,
+                        String typeKey,
+                        String methKey) throws ConstantPoolException {
+        DeprData dd = db.getTypeDeprecated(flatten(clname));
+        if (dd != null) {
+            printType(typeKey, cf, clname, dd.isForRemoval());
+        }
+
+        String name = nti.getName();
+        String type = nti.getType();
+        clname = resolveMember(cf, flatten(clname), name, type, true, true);
+        dd = db.getMethodDeprecated(clname, name, type);
+        if (dd != null) {
+            printMethod(methKey, cf, clname, name, type, dd.isForRemoval());
+        }
+    }
+
+    /**
+     * Checks fields referred to from the constant pool.
+     *
+     * @param cf the ClassFile of this class
+     * @throws ConstantPoolException if a constant pool entry cannot be found
+     */
+    void checkFieldRef(ClassFile cf,
+                       ConstantPool.CONSTANT_Fieldref_info fri) throws ConstantPoolException {
+        CONSTANT_NameAndType_info nti = fri.getNameAndTypeInfo();
+        String clname = fri.getClassName();
+        String name = nti.getName();
+        String type = nti.getType();
+        DeprData dd = db.getTypeDeprecated(clname);
+
+        if (dd != null) {
+            printType("scan.out.usesfieldintype", cf, clname, dd.isForRemoval());
+        }
+
+        clname = resolveMember(cf, flatten(clname), name, type, false, true);
+        dd = db.getFieldDeprecated(clname, name);
+        if (dd != null) {
+            printField("scan.out.usesfield", cf, clname, name, dd.isForRemoval());
+        }
+
+        dd = db.getTypeDeprecated(flatten(type));
+        if (dd != null) {
+            printFieldType("scan.out.usesfieldoftype", cf, clname, name, type, dd.isForRemoval());
+        }
+    }
+
+    /**
+     * Checks the fields declared in this class.
+     *
+     * @param cf the ClassFile of this class
+     * @throws ConstantPoolException if a constant pool entry cannot be found
+     */
+    void checkFields(ClassFile cf) throws ConstantPoolException {
+        for (Field f : cf.fields) {
+            String type = cf.constant_pool.getUTF8Value(f.descriptor.index);
+            DeprData dd = db.getTypeDeprecated(flatten(type));
+            if (dd != null) {
+                printHasField(cf, f.getName(cf.constant_pool), type, dd.isForRemoval());
+            }
+        }
+    }
+
+    /**
+     * Checks the methods declared in this class.
+     *
+     * @param cf the ClassFile object of this class
+     * @throws ConstantPoolException if a constant pool entry cannot be found
+     */
+    void checkMethods(ClassFile cf) throws ConstantPoolException {
+        for (Method m : cf.methods) {
+            String mname = m.getName(cf.constant_pool);
+            String desc = cf.constant_pool.getUTF8Value(m.descriptor.index);
+            MethodSig sig = MethodSig.fromDesc(desc);
+            DeprData dd;
+
+            for (String parm : sig.getParameters()) {
+                dd = db.getTypeDeprecated(flatten(parm));
+                if (dd != null) {
+                    printHasMethodParmType(cf, mname, parm, dd.isForRemoval());
+                }
+            }
+
+            String ret = sig.getReturnType();
+            dd = db.getTypeDeprecated(flatten(ret));
+            if (dd != null) {
+                printHasMethodRetType(cf, mname, ret, dd.isForRemoval());
+            }
+
+            // check overrides
+            String overridden = resolveMember(cf, cf.getName(), mname, desc, true, false);
+            if (overridden != null) {
+                dd = db.getMethodDeprecated(overridden, mname, desc);
+                if (dd != null) {
+                    printHasOverriddenMethod(cf, overridden, mname, desc, dd.isForRemoval());
+                }
+            }
+        }
+    }
+
+    /**
+     * Processes a single class file.
+     *
+     * @param cf the ClassFile of the class
+     * @throws ConstantPoolException if a constant pool entry cannot be found
+     */
+    void processClass(ClassFile cf) throws ConstantPoolException {
+        if (verbose) {
+            out.println(Messages.get("scan.process.class", cf.getName()));
+        }
+
+        CPEntries entries = CPEntries.loadFrom(cf);
+
+        checkSuper(cf);
+        checkInterfaces(cf);
+        checkTypes(cf, entries);
+
+        for (ConstantPool.CONSTANT_Methodref_info mri : entries.methodRefs) {
+            CONSTANT_NameAndType_info nti = mri.getNameAndTypeInfo();
+            String clname = mri.getClassName();
+            checkMethodRef(cf, nti, clname, "scan.out.usesmethodintype", "scan.out.usesmethod");
+        }
+
+        for (ConstantPool.CONSTANT_InterfaceMethodref_info imri : entries.intfMethodRefs) {
+            CONSTANT_NameAndType_info nti = imri.getNameAndTypeInfo();
+            String clname = imri.getClassName();
+            checkMethodRef(cf, nti, clname, "scan.out.usesintfmethodintype", "scan.out.usesintfmethod");
+        }
+
+        for (ConstantPool.CONSTANT_Fieldref_info fri : entries.fieldRefs) {
+            checkFieldRef(cf, fri);
+        }
+
+        checkFields(cf);
+        checkMethods(cf);
+    }
+
+    /**
+     * Scans a jar file for uses of deprecated APIs.
+     *
+     * @param jarname the jar file to process
+     * @return true on success, false on failure
+     */
+    public boolean scanJar(String jarname) {
+        try (JarFile jf = new JarFile(jarname)) {
+            finder.addJar(jarname);
+            Enumeration<JarEntry> entries = jf.entries();
+            while (entries.hasMoreElements()) {
+                JarEntry entry = entries.nextElement();
+                String name = entry.getName();
+                if (name.endsWith(".class")
+                        && !name.endsWith("package-info.class")
+                        && !name.endsWith("module-info.class")) {
+                    processClass(ClassFile.read(jf.getInputStream(entry)));
+                }
+            }
+            return true;
+        } catch (IOException | ConstantPoolException ex) {
+            printException(ex);
+            return false;
+        }
+    }
+
+    /**
+     * Scans class files in the named directory hierarchy for uses of deprecated APIs.
+     *
+     * @param dirname the directory hierarchy to process
+     * @return true on success, false on failure
+     */
+    public boolean scanDir(String dirname) {
+        Path base = Paths.get(dirname);
+        int baseCount = base.getNameCount();
+        finder.addDir(dirname);
+        try (Stream<Path> paths = Files.walk(Paths.get(dirname))) {
+            List<Path> classes =
+                paths.filter(p -> p.getNameCount() > baseCount)
+                     .filter(path -> path.toString().endsWith(".class"))
+                     .filter(path -> !path.toString().endsWith("package-info.class"))
+                     .filter(path -> !path.toString().endsWith("module-info.class"))
+                     .collect(Collectors.toList());
+            for (Path p : classes) {
+                processClass(ClassFile.read(p));
+            }
+            return true;
+        } catch (IOException | ConstantPoolException ex) {
+            printException(ex);
+            return false;
+        }
+    }
+
+    /**
+     * Scans the named class for uses of deprecated APIs.
+     *
+     * @param className the class to scan
+     * @return true on success, false on failure
+     */
+    public boolean processClassName(String className) {
+        try {
+            ClassFile cf = finder.find(className);
+            if (cf == null) {
+                err("can't find class %s", className);
+                return false;
+            } else {
+                processClass(cf);
+                return true;
+            }
+        } catch (ConstantPoolException ex) {
+            printException(ex);
+            return false;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleAnnotation.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,34 @@
+/*
+ * 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 jdk.deprcases.members;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+
+@Retention(value=RetentionPolicy.RUNTIME)
+@Target({TYPE, METHOD, FIELD})
+public @interface ExampleAnnotation {
+    String file();
+    @Deprecated String name() default "";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleClass.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,49 @@
+/*
+ * 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 jdk.deprcases.members;
+
+public class ExampleClass {
+    public ExampleClass() { }
+
+    @Deprecated
+    public ExampleClass(boolean deprecatedConstructor) { }
+
+    @Deprecated
+    public void method1() { }
+
+    @Deprecated
+    public void method2() { }
+
+    @Deprecated
+    public int field1 = 0;
+
+    @Deprecated
+    public int field2 = 0;
+
+    @Deprecated
+    public static void staticmethod1() { }
+
+    @Deprecated
+    public static int staticfield3 = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleElements.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,44 @@
+/*
+ * 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 jdk.deprcases.members;
+
+public class ExampleElements {
+    @Deprecated
+    Object emptyFalse;
+
+    @Deprecated(since="xyzzy")
+    Object sinceFalse;
+
+    @Deprecated(forRemoval=true)
+    Object emptyTrue;
+
+    @Deprecated(since="plugh", forRemoval=true)
+    Object sinceTrue;
+
+    @Deprecated(since="123,456")
+    Object sinceWithComma;
+
+    @Deprecated(since="7.9 \"pre-beta\" snapshot")
+    Object sinceWithQuote;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleEnum.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,42 @@
+/*
+ * 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 jdk.deprcases.members;
+
+public enum ExampleEnum {
+    ONE,
+    TWO {
+        @Override
+        public void deprMethod1() { }
+        @Override @Deprecated
+        public void deprMethod2() { }
+    },
+    @Deprecated THREE,
+    FOUR,
+    @Deprecated FIVE;
+
+    @Deprecated
+    public void deprMethod1() { }
+
+    public void deprMethod2() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleInterface.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,44 @@
+/*
+ * 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 jdk.deprcases.members;
+
+public interface ExampleInterface {
+    @Deprecated
+    static final int DEP_FIELD1 = 1;
+
+    @Deprecated
+    static final int DEP_FIELD2 = 2;
+
+    @Deprecated
+    void interfaceMethod1();
+
+    @Deprecated
+    void interfaceMethod2();
+
+    @Deprecated
+    default void defaultMethod() { }
+
+    @Deprecated
+    static void staticmethod2() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/cases/jdk/deprcases/members/ExampleSubclass.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,39 @@
+/*
+ * 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 jdk.deprcases.members;
+
+public abstract class ExampleSubclass extends ExampleClass implements ExampleInterface {
+    @Override
+    public void method1() { }
+
+    // hides ExampleClass.field1
+    public Object field1 = null;
+
+    @Override
+    public void interfaceMethod2() {
+    }
+
+    // hides ExampleInterface.DEP_FIELD1
+    public Object DEP_FIELD1 = null;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/cases/jdk/deprcases/types/DeprecatedAnnotation.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,35 @@
+/*
+ * 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 jdk.deprcases.types;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+
+@Retention(value=RetentionPolicy.RUNTIME)
+@Target({TYPE, METHOD, FIELD})
+@Deprecated
+public @interface DeprecatedAnnotation {
+    String file() default "x";
+    String value() default "y";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/cases/jdk/deprcases/types/DeprecatedClass.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * 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 jdk.deprcases.types;
+
+@Deprecated
+public class DeprecatedClass {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/cases/jdk/deprcases/types/DeprecatedEnum.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,31 @@
+/*
+ * 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 jdk.deprcases.types;
+
+@Deprecated
+public enum DeprecatedEnum {
+    FIRST,
+    SECOND,
+    THIRD
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/cases/jdk/deprcases/types/DeprecatedException.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,29 @@
+/*
+ * 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 jdk.deprcases.types;
+
+@Deprecated
+public class DeprecatedException extends RuntimeException {
+    private static final long serialVersionUID = 0L;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/cases/jdk/deprcases/types/DeprecatedInterface.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * 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 jdk.deprcases.types;
+
+@Deprecated
+public interface DeprecatedInterface {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/tests/jdk/jdeprscan/TestCSV.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary Basic tests CSV printing and parsing
+ * @modules jdk.jdeps/com.sun.tools.jdeprscan
+ * @build TestCSV
+ * @run testng jdk.jdeprscan.TestCSV
+ */
+
+package jdk.jdeprscan;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+
+import java.util.List;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import com.sun.tools.jdeprscan.CSV;
+import com.sun.tools.jdeprscan.CSVParseException;
+
+@Test
+public class TestCSV {
+    static String NL = System.lineSeparator();
+    ByteArrayOutputStream baos;
+    PrintStream out;
+
+    @BeforeMethod
+    public void setup() throws UnsupportedEncodingException {
+        baos = new ByteArrayOutputStream();
+        out = new PrintStream(baos, true, "UTF-8");
+    }
+
+    String result() {
+        out.flush();
+        return new String(baos.toByteArray(), java.nio.charset.StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Asserts string equality after checking for and removing a trailing line separator.
+     *
+     * @param expected expected result
+     */
+    void checkString(String expected) {
+        String actual = result();
+        assertTrue(actual.endsWith(NL));
+        assertEquals(actual.substring(0, actual.length() - NL.length()), expected);
+    }
+
+    @DataProvider(name = "csvdata")
+    public Object[][] getCSVData() {
+        return new Object[][] {
+            { "",               List.of("") },
+            { "a",              List.of("a") },
+            { "a,b",            List.of("a", "b") },
+            { "a,b,c",          List.of("a", "b", "c") },
+            { ",a,b",           List.of("", "a", "b") },
+            { "a,b,",           List.of("a", "b", "") },
+            { ",a,b,",          List.of("", "a", "b", "") },
+            { ",a,,b,",         List.of("", "a", "", "b", "") },
+            { ",",              List.of("", "") },
+            { ",,",             List.of("", "", "") },
+            { ",,,",            List.of("", "", "", "") },
+            { " a , b ",        List.of(" a ", " b ") },
+            { "a,\",\",b",      List.of("a", ",", "b") },
+            { "a,\"b\"\"c\",d", List.of("a", "b\"c", "d") },
+            { "a,\"b,c\",d",    List.of("a", "b,c", "d") },
+
+            // from https://en.wikipedia.org/wiki/Comma-separated_values
+            // slightly modified to enable round-tripping
+
+            { "Year,Make,Model,Description,Price",
+                List.of("Year", "Make", "Model", "Description", "Price") },
+            { "1997,Ford,E350,\"ac, abs, moon\",3000.00",
+                List.of("1997", "Ford", "E350", "ac, abs, moon", "3000.00") },
+            { "1999,Chevy,\"Venture \"\"Extended Edition\"\"\",,4900.00",
+                List.of("1999", "Chevy", "Venture \"Extended Edition\"", "", "4900.00") },
+            { "1999,Chevy,\"Venture \"\"Extended Edition, Very Large\"\"\",,5000.00",
+                List.of("1999", "Chevy", "Venture \"Extended Edition, Very Large\"", "", "5000.00") },
+            { "1996,Jeep,Grand Cherokee,\"MUST SELL!\nair, moon roof, loaded\",4799.00",
+                List.of("1996", "Jeep", "Grand Cherokee", "MUST SELL!\nair, moon roof, loaded", "4799.00") }
+        };
+    }
+
+    @Test(dataProvider = "csvdata")
+    public void roundTrip(String input, List<String> parsed) {
+        List<String> actual = CSV.split(input);
+        assertEquals(actual, parsed);
+        CSV.write(out, actual.toArray());
+        checkString(input);
+    }
+
+    // won't round-trip
+    public void testExtraQuote() {
+        assertEquals(CSV.split("a,\"b\",c"), List.of("a", "b", "c"));
+    }
+
+    // won't round-trip
+    public void testEmptyQuote() {
+        assertEquals(CSV.split("a,\"\",b"), List.of("a", "", "b"));
+    }
+
+    @Test(expectedExceptions=CSVParseException.class)
+    public void errorUnexpectedQuote() {
+        CSV.split("ab\"cd");
+    }
+
+    @Test(expectedExceptions=CSVParseException.class)
+    public void errorCharacterAfterQuote() {
+        CSV.split("a,\"b\"c,d");
+    }
+
+    @Test(expectedExceptions=CSVParseException.class)
+    public void errorUnclosedQuote() {
+        CSV.split("a,\"b");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoad.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary Test of jdeprscan tool loading and printing to aCSV file.
+ * @modules jdk.jdeps/com.sun.tools.jdeprscan
+ * @library ../../../cases
+ * @build jdk.deprcases.members.* jdk.deprcases.types.*
+ * @build jdk.jdeprscan.TestLoad
+ * @run testng jdk.jdeprscan.TestLoad
+ */
+
+package jdk.jdeprscan;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.sun.tools.jdeprscan.Main;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertEquals;
+
+
+public class TestLoad {
+    static final String UTF8 = "UTF-8";
+    static final String EXPECTED = "TestLoadExpected.csv";
+
+    @Test
+    public void test1() throws IOException, UnsupportedEncodingException {
+        String testclasses = System.getProperty("test.classes");
+        String deprcases = testclasses + "/../../../cases";
+        boolean rval;
+
+        System.out.println("test.src = " + System.getProperty("test.src"));
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        ByteArrayOutputStream berr = new ByteArrayOutputStream();
+
+        try (PrintStream prout = new PrintStream(bout, true, UTF8);
+             PrintStream prerr = new PrintStream(berr, true, UTF8)) {
+            System.out.println("Calling JDeprScan --Xprint-csv --Xload-dir " + deprcases);
+            rval = Main.call(prout, prerr, "--Xprint-csv", "--Xload-dir", deprcases);
+            System.out.println("JDeprScan returns " + rval);
+        }
+
+        System.out.println("----- stdout");
+        new ByteArrayInputStream(bout.toByteArray()).transferTo(System.out);
+        System.out.println("----- end stdout");
+        System.out.println("----- stderr");
+        new ByteArrayInputStream(berr.toByteArray()).transferTo(System.out);
+        System.out.println("----- end stderr");
+
+        List<String> actualList;
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(bout.toByteArray());
+             InputStreamReader isr = new InputStreamReader(bais);
+             BufferedReader br = new BufferedReader(isr)) {
+            actualList = br.lines().collect(Collectors.toList());
+        }
+
+        Path expfile = Paths.get(System.getProperty("test.src"), EXPECTED);
+        List<String> expectedList = Files.readAllLines(expfile);
+
+        Set<String> actual = new HashSet<>(actualList.subList(1, actualList.size()));
+        Set<String> expected = new HashSet<>(expectedList.subList(1, expectedList.size()));
+
+        Set<String> diff1 = new HashSet<>(actual);
+        diff1.removeAll(expected);
+        Set<String> diff2 = new HashSet<>(expected);
+        diff2.removeAll(actual);
+        if (diff1.size() > 0) {
+            System.out.println("Extra lines in output:");
+            diff1.forEach(System.out::println);
+        }
+
+        if (diff2.size() > 0) {
+            System.out.println("Lines missing from output:");
+            diff2.forEach(System.out::println);
+        }
+
+        assertTrue(rval);
+        assertEquals(berr.toByteArray().length, 0);
+        assertEquals(actual.size(), actualList.size() - 1);
+        assertEquals(diff1.size(), 0);
+        assertEquals(diff2.size(), 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoadExpected.csv	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,30 @@
+#jdepr 1
+METHOD,jdk/deprcases/members/ExampleAnnotation,name()Ljava/lang/String;,,false
+FIELD,jdk/deprcases/members/ExampleClass,field1,,false
+FIELD,jdk/deprcases/members/ExampleClass,field2,,false
+FIELD,jdk/deprcases/members/ExampleClass,staticfield3,,false
+CONSTRUCTOR,jdk/deprcases/members/ExampleClass,<init>(Z)V,,false
+METHOD,jdk/deprcases/members/ExampleClass,method1()V,,false
+METHOD,jdk/deprcases/members/ExampleClass,method2()V,,false
+METHOD,jdk/deprcases/members/ExampleClass,staticmethod1()V,,false
+METHOD,jdk/deprcases/members/ExampleEnum$1,deprMethod2()V,,false
+ENUM_CONSTANT,jdk/deprcases/members/ExampleEnum,THREE,,false
+ENUM_CONSTANT,jdk/deprcases/members/ExampleEnum,FIVE,,false
+METHOD,jdk/deprcases/members/ExampleEnum,deprMethod1()V,,false
+FIELD,jdk/deprcases/members/ExampleInterface,DEP_FIELD1,,false
+FIELD,jdk/deprcases/members/ExampleInterface,DEP_FIELD2,,false
+METHOD,jdk/deprcases/members/ExampleInterface,interfaceMethod1()V,,false
+METHOD,jdk/deprcases/members/ExampleInterface,interfaceMethod2()V,,false
+METHOD,jdk/deprcases/members/ExampleInterface,defaultMethod()V,,false
+METHOD,jdk/deprcases/members/ExampleInterface,staticmethod2()V,,false
+ANNOTATION_TYPE,jdk/deprcases/types/DeprecatedAnnotation,,,false
+CLASS,jdk/deprcases/types/DeprecatedClass,,,false
+ENUM,jdk/deprcases/types/DeprecatedEnum,,,false
+CLASS,jdk/deprcases/types/DeprecatedException,,,false
+INTERFACE,jdk/deprcases/types/DeprecatedInterface,,,false
+FIELD,jdk/deprcases/members/ExampleElements,emptyFalse,,false
+FIELD,jdk/deprcases/members/ExampleElements,sinceFalse,xyzzy,false
+FIELD,jdk/deprcases/members/ExampleElements,emptyTrue,,true
+FIELD,jdk/deprcases/members/ExampleElements,sinceTrue,plugh,true
+FIELD,jdk/deprcases/members/ExampleElements,sinceWithComma,"123,456",false
+FIELD,jdk/deprcases/members/ExampleElements,sinceWithQuote,"7.9 ""pre-beta"" snapshot",false
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/tests/jdk/jdeprscan/TestMethodSig.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary Simple tests for method signature parsing
+ * @modules jdk.jdeps/com.sun.tools.jdeprscan.scan
+ * @build TestMethodSig
+ * @run testng jdk.jdeprscan.TestMethodSig
+ */
+
+package jdk.jdeprscan;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+import static com.sun.tools.jdeprscan.scan.MethodSig.fromDesc;
+
+public class TestMethodSig {
+    @Test
+    public void testSimple() {
+        assertEquals(fromDesc("(Ljava/rmi/RMISecurityManager;)Ljava/lang/Object;").toString(),
+                     "parameters 0=Ljava/rmi/RMISecurityManager; return Ljava/lang/Object;");
+    }
+
+    @Test
+    public void testMultParamVoidReturn() {
+        assertEquals(fromDesc("([[IZLjava/lang/String;B[J)V").toString(),
+                     "parameters 0=[[I 1=Z 2=Ljava/lang/String; 3=B 4=[J return V");
+    }
+
+    @Test
+    public void testNoParams() {
+        assertEquals(fromDesc("()J").toString(),
+                     "parameters none return J");
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testMissingReturnType() {
+        fromDesc("(ISJZ)");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary Basic test of jdeprscan's scanning phase.
+ * @modules jdk.jdeps/com.sun.tools.jdeprscan
+ * @library ../../../cases
+ * @library ../../../usage
+ * @build jdk.deprcases.members.* jdk.deprcases.types.*
+ * @build jdk.deprusage.*
+ * @build jdk.jdeprscan.TestScan
+ * @run testng jdk.jdeprscan.TestScan
+ */
+
+package jdk.jdeprscan;
+
+import com.sun.tools.jdeprscan.Main;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.testng.Assert;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+
+
+public class TestScan {
+    Set<String> loadExpected() throws IOException {
+        Path expFile = Paths.get(System.getProperty("test.src"), "TestScanExpected.txt");
+        return new HashSet<>(Files.readAllLines(expFile, StandardCharsets.UTF_8));
+    }
+
+    @Test
+    public void testScanAgainstReferenceFile() throws IOException {
+        String testclasses = System.getProperty("test.classes");
+        String deprcases = testclasses + "/../../../cases";
+        String deprusage = testclasses + "/../../../usage";
+
+        Set<String> expected = loadExpected();
+        System.out.println("expected = " + expected);
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (PrintStream out = new PrintStream(baos, false, "UTF-8")) {
+            boolean r = Main.call(out, System.err,
+                "-cp", deprcases, "--Xload-dir", deprcases, deprusage);
+            assertTrue(r);
+        }
+        byte[] bytes = baos.toByteArray();
+
+        System.out.println("--- output ---");
+        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+        bais.transferTo(System.out);
+        System.out.println("--- end output ---");
+
+        Set<String> actual =
+            new BufferedReader(
+                new InputStreamReader(
+                    new ByteArrayInputStream(bytes), StandardCharsets.UTF_8))
+                        .lines()
+                        .map(line -> line.split(" +"))
+                        .map(array -> array[1])
+                        .collect(Collectors.toSet());
+        System.out.println("actual = " + actual);
+
+        Set<String> diff1 = new HashSet<>(expected);
+        diff1.removeAll(actual);
+        Set<String> diff2 = new HashSet<>(actual);
+        diff2.removeAll(expected);
+
+        if (diff1.size() > 0 || diff2.size() > 0) {
+            System.out.println("missing items: " + diff1);
+            System.out.println("extra items: " + diff2);
+        }
+
+        Assert.assertEquals(diff1.size(), 0);
+        Assert.assertEquals(diff2.size(), 0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScanExpected.txt	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,47 @@
+jdk/jdeprusage/UseClass$ArrayCreation
+jdk/jdeprusage/UseClass$ArrayFieldUsage
+jdk/jdeprusage/UseClass$ArrayMethodCall
+jdk/jdeprusage/UseClass$Cast
+jdk/jdeprusage/UseClass$ClassLiteral
+jdk/jdeprusage/UseClass$Construct
+jdk/jdeprusage/UseClass$Extends
+jdk/jdeprusage/UseClass$FieldType
+jdk/jdeprusage/UseClass$InstanceOf
+jdk/jdeprusage/UseClass$MethodParameter
+jdk/jdeprusage/UseClass$MethodReturn
+jdk/jdeprusage/UseEnum$ClassObject
+jdk/jdeprusage/UseEnum$EnumConstant
+jdk/jdeprusage/UseEnum$FieldType
+jdk/jdeprusage/UseEnum$MethodParameter
+jdk/jdeprusage/UseEnum$ReturnValue
+jdk/jdeprusage/UseEnum$ValueOfMethod
+jdk/jdeprusage/UseEnum$ValuesMethod
+jdk/jdeprusage/UseEnumMembers$1
+jdk/jdeprusage/UseEnumMembers$MethodInEnum1
+jdk/jdeprusage/UseEnumMembers$MethodOnConstant1
+jdk/jdeprusage/UseEnumMembers$ReturnValue
+jdk/jdeprusage/UseException$Catch
+jdk/jdeprusage/UseException$Throws
+jdk/jdeprusage/UseField$Direct
+jdk/jdeprusage/UseField$FromSubclass
+jdk/jdeprusage/UseField$Inherited
+jdk/jdeprusage/UseField$StaticField
+jdk/jdeprusage/UseField$SuperFromSubclass
+jdk/jdeprusage/UseInterface$ClassImplements
+jdk/jdeprusage/UseInterface$InterfaceExtends
+jdk/jdeprusage/UseMethod$ClassStatic
+jdk/jdeprusage/UseMethod$Constructor
+jdk/jdeprusage/UseMethod$ConstructorFromSubclass
+jdk/jdeprusage/UseMethod$Direct
+jdk/jdeprusage/UseMethod$Inherited
+jdk/jdeprusage/UseMethod$InheritedDefault
+jdk/jdeprusage/UseMethod$InheritedFromSubclass
+jdk/jdeprusage/UseMethod$InheritedInterface
+jdk/jdeprusage/UseMethod$InheritedInterfaceDefault
+jdk/jdeprusage/UseMethod$InterfaceDefault
+jdk/jdeprusage/UseMethod$InterfaceDirect
+jdk/jdeprusage/UseMethod$InterfaceStatic
+jdk/jdeprusage/UseMethod$OverrideClassMethod
+jdk/jdeprusage/UseMethod$OverrideDefaultMethod
+jdk/jdeprusage/UseMethod$OverrideInterfaceMethod
+jdk/jdeprusage/UseMethod$SuperFromSubclass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/usage/jdk/deprusage/UseAnnotation.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,41 @@
+/*
+ * 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 jdk.jdeprusage;
+
+import jdk.deprcases.types.DeprecatedAnnotation;
+
+public class UseAnnotation {
+    @DeprecatedAnnotation
+    static class AnnotatedClass { }
+
+    static class AnnotatedMethod {
+        @DeprecatedAnnotation
+        void foo() { }
+    }
+
+    static class AnnotatedField {
+        @DeprecatedAnnotation
+        int foo = 1;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/usage/jdk/deprusage/UseClass.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,107 @@
+/*
+ * 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 jdk.jdeprusage;
+
+import jdk.deprcases.types.DeprecatedClass;
+
+public class UseClass {
+    static class Extends extends DeprecatedClass {
+    }
+
+    static class ClassLiteral {
+        Class<?> clazz = DeprecatedClass.class;
+    }
+
+    static class FieldType {
+        DeprecatedClass obj = null;
+    }
+
+    static class MethodParameter {
+        void foo(DeprecatedClass x) { }
+    }
+
+    static class MethodReturn {
+        DeprecatedClass foo() { return null; }
+    }
+
+    static class ArrayCreation {
+        Object foo() {
+            return new DeprecatedClass[1];
+        }
+    }
+
+    static class ArrayFieldUsage {
+        int foo(Object o) {
+            return ((DeprecatedClass[])o).length;
+        }
+    }
+
+    static class ArrayMethodCall {
+        Object foo(Object o) {
+            return ((DeprecatedClass[])o).clone();
+        }
+    }
+
+    static class InstanceOf {
+        boolean foo(Object o) {
+            return o instanceof DeprecatedClass;
+        }
+    }
+
+    static class Cast {
+        Object foo(Object o) {
+            return (DeprecatedClass)o;
+        }
+    }
+
+    static class Generic<T> {
+        static <U> void g() { }
+    }
+
+    static class ClassTypeArg extends Generic<DeprecatedClass> { }
+
+    static class MethodTypeArg {
+        void foo() {
+            Generic.<DeprecatedClass>g();
+        }
+    }
+
+    static class ConstructorTypeArg {
+        Object foo() {
+            return new Generic<DeprecatedClass>();
+        }
+    }
+
+    static class Construct {
+        Object foo() {
+            return new DeprecatedClass();
+        }
+    }
+
+    static class Local {
+        void foo() {
+            DeprecatedClass obj = null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/usage/jdk/deprusage/UseEnum.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,62 @@
+/*
+ * 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 jdk.jdeprusage;
+
+import jdk.deprcases.types.DeprecatedEnum;
+
+public class UseEnum {
+    static class ReturnValue {
+        static DeprecatedEnum returnValue() { return null; }
+    }
+
+    static class MethodParameter {
+        static void methodParameterType(DeprecatedEnum e) { }
+    }
+
+    static class FieldType {
+        static DeprecatedEnum field;
+    }
+
+    static class EnumConstant {
+        static Object field2 = DeprecatedEnum.FIRST;
+    }
+
+    static class ValuesMethod {
+        static Object[] valuesMethod() {
+            return DeprecatedEnum.values();
+        }
+    }
+
+    static class ValueOfMethod {
+        static Object valueOfMethod(String s) {
+            return DeprecatedEnum.valueOf(s);
+        }
+    }
+
+    static class ClassObject {
+        static Object classObject() {
+            return DeprecatedEnum.class;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/usage/jdk/deprusage/UseEnumMembers.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,74 @@
+/*
+ * 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 jdk.jdeprusage;
+
+import jdk.deprcases.members.ExampleEnum;
+
+public class UseEnumMembers {
+    static class ReturnValue {
+        static ExampleEnum returnValue() {
+            return ExampleEnum.FIVE;
+        }
+    }
+
+    static class UseInSwitch {
+        // enum switch generates inner class UseEnumMembers$UseInSwitch$1
+        static void useInSwitch(ExampleEnum e) {
+            switch (e) {
+                case ONE:
+                case TWO:
+                case FOUR:
+                    // no deprecation
+                    break;
+                case THREE:
+                    // deprecated
+                    break;
+            }
+        }
+    }
+
+    static class MethodInEnum1 {
+        static void methodInEnum1(ExampleEnum e) {
+            e.deprMethod1();
+        }
+    }
+
+    static class MethodOnConstant1 {
+        static void methodOnConstant1() {
+            // surprising that there is a warning here;
+            // the method deprMethod1 is overridden in TWO
+            ExampleEnum.TWO.deprMethod1();
+        }
+    }
+
+    static void methodInEnum2(ExampleEnum e) {
+        e.deprMethod2();
+    }
+
+    static void methodOnConstant2() {
+        // surprising there is no warning here;
+        // the method is deprecated in TWO
+        ExampleEnum.TWO.deprMethod2();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/usage/jdk/deprusage/UseException.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,40 @@
+/*
+ * 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 jdk.jdeprusage;
+
+import jdk.deprcases.types.DeprecatedException;
+
+public class UseException {
+    static class Throws {
+        static void foo() throws DeprecatedException { }
+    }
+
+    static class Catch {
+        void foo() {
+            try {
+                Throws.foo();
+            } catch (DeprecatedException de) { }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/usage/jdk/deprusage/UseField.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,72 @@
+/*
+ * 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 jdk.jdeprusage;
+
+import jdk.deprcases.members.ExampleClass;
+import jdk.deprcases.members.ExampleInterface;
+import jdk.deprcases.members.ExampleSubclass;
+
+public class UseField {
+    static class Direct {
+        int f(ExampleClass ec) {
+            return ec.field1;
+        }
+    }
+
+    static class Inherited {
+        int f(ExampleSubclass esc) {
+            return esc.field2;
+        }
+    }
+
+    static class InterfaceInherited {
+        int f(ExampleSubclass esc) {
+            return esc.DEP_FIELD2;
+        }
+    }
+
+    static class InterfaceDirect {
+        int f(ExampleInterface ei) {
+            return ei.DEP_FIELD1;
+        }
+    }
+
+    static class FromSubclass extends ExampleClass {
+        int f() {
+            return field1;
+        }
+    }
+
+    static class SuperFromSubclass extends ExampleClass {
+        int f() {
+            return super.field1;
+        }
+    }
+
+    static class StaticField {
+        int f() {
+            return ExampleClass.staticfield3;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/usage/jdk/deprusage/UseInterface.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,36 @@
+/*
+ * 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 jdk.jdeprusage;
+
+import jdk.deprcases.types.DeprecatedInterface;
+
+public class UseInterface {
+    static class ClassImplements implements DeprecatedInterface {
+
+    }
+
+    interface InterfaceExtends extends DeprecatedInterface {
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jdeprscan/usage/jdk/deprusage/UseMethod.java	Thu Aug 25 17:58:39 2016 -0700
@@ -0,0 +1,123 @@
+/*
+ * 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 jdk.jdeprusage;
+
+import jdk.deprcases.members.ExampleClass;
+import jdk.deprcases.members.ExampleInterface;
+import jdk.deprcases.members.ExampleSubclass;
+
+public class UseMethod {
+    static class Direct {
+        void m(ExampleClass ec) {
+            ec.method1();
+        }
+    }
+
+    static class Inherited {
+        void m(ExampleSubclass esc) {
+            esc.method2();
+        }
+    }
+
+    static class InheritedDefault {
+        void m(ExampleSubclass esc) {
+            esc.defaultMethod();
+        }
+    }
+
+    static class InterfaceDirect {
+        void m(ExampleInterface ei) {
+            ei.interfaceMethod1();
+        }
+    }
+
+    static class InterfaceDefault {
+        void m(ExampleInterface ei) {
+            ei.defaultMethod();
+        }
+    }
+
+    static class ClassStatic {
+        void m() {
+            ExampleClass.staticmethod1();
+        }
+    }
+
+    static class InterfaceStatic {
+        void m() {
+            ExampleInterface.staticmethod2();
+        }
+    }
+
+    static class SuperFromSubclass extends ExampleClass {
+        void m() {
+            super.method1();
+        }
+    }
+
+    static class InheritedFromSubclass extends ExampleClass {
+        void m() {
+            method1();
+        }
+    }
+
+    static class Constructor {
+        Object m() {
+            return new ExampleClass(true);
+        }
+    }
+
+    static class ConstructorFromSubclass extends ExampleClass {
+        public ConstructorFromSubclass() {
+            super(true);
+        }
+    }
+
+    abstract static class InheritedInterfaceDefault extends ExampleSubclass {
+        void m() {
+            defaultMethod();
+        }
+    }
+
+    abstract static class InheritedInterface extends ExampleSubclass {
+        void m() {
+            interfaceMethod1();
+        }
+    }
+
+    static class OverrideClassMethod extends ExampleClass {
+        @Override
+        public void method1() { }
+    }
+
+    abstract static class OverrideInterfaceMethod implements ExampleInterface {
+        @Override
+        public void interfaceMethod1() { }
+    }
+
+    abstract static class OverrideDefaultMethod implements ExampleInterface {
+        @Override
+        public void defaultMethod() { }
+    }
+}