8165646: (jdeprscan) adjust tool output to improve clarity
authorsmarks
Tue, 01 Nov 2016 11:28:16 -0700
changeset 41863 98b049c8b848
parent 41862 471a0cb1b986
child 41864 f7dbab23003a
8165646: (jdeprscan) adjust tool output to improve clarity Reviewed-by: jjg, psandoz
langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java
langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java
langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md
langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties
langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java
langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java	Tue Nov 01 10:51:53 2016 -0400
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java	Tue Nov 01 11:28:16 2016 -0700
@@ -638,6 +638,8 @@
 
         // now the scanning phase
 
+        boolean scanStatus = true;
+
         switch (scanMode) {
             case LIST:
                 for (DeprData dd : deprList) {
@@ -661,24 +663,22 @@
                 Scan scan = new Scan(out, err, cp, db, verbose);
 
                 for (String a : args) {
-                    boolean success;
-
+                    boolean s;
                     if (a.endsWith(".jar")) {
-                        success = scan.scanJar(a);
+                        s = scan.scanJar(a);
+                    } else if (a.endsWith(".class")) {
+                        s = scan.processClassFile(a);
                     } else if (Files.isDirectory(Paths.get(a))) {
-                        success = scan.scanDir(a);
+                        s = scan.scanDir(a);
                     } else {
-                        success = scan.processClassName(a.replace('.', '/'));
+                        s = scan.processClassName(a.replace('.', '/'));
                     }
-
-                    if (!success) {
-                        return false;
-                    }
+                    scanStatus = scanStatus && s;
                 }
                 break;
         }
 
-        return true;
+        return scanStatus;
     }
 
     /**
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java	Tue Nov 01 10:51:53 2016 -0400
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java	Tue Nov 01 11:28:16 2016 -0700
@@ -34,6 +34,10 @@
  * Message handling class for localization.
  */
 public class Messages {
+    /** Indicates whether line separators in messages need replacement. */
+    static final boolean REPLACE_LINESEP = ! System.lineSeparator().equals("\n");
+
+    /** The resource bundle, must be non-null. */
     static final ResourceBundle bundle;
 
     static {
@@ -41,13 +45,25 @@
         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);
+            throw new InternalError("Cannot find jdeprscan resource bundle for locale " + locale, e);
         }
     }
 
+    /**
+     * Gets a message from the resource bundle. If necessary, translates "\n",
+     * the line break string used in the message file, to the system-specific
+     * line break string.
+     *
+     * @param key the message key
+     * @param args the message arguments
+     */
     public static String get(String key, Object... args) {
         try {
-            return MessageFormat.format(bundle.getString(key), args);
+            String msg = MessageFormat.format(bundle.getString(key), args);
+            if (REPLACE_LINESEP) {
+                msg = msg.replace("\n", System.lineSeparator());
+            }
+            return msg;
         } catch (MissingResourceException e) {
             throw new InternalError("Missing message: " + key, e);
         }
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md	Tue Nov 01 10:51:53 2016 -0400
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md	Tue Nov 01 11:28:16 2016 -0700
@@ -92,6 +92,9 @@
 that jar file and report information about how those classes use
 deprecated APIs.
 
+Given a class file, **jdeprscan** will scan that class and report
+its use of 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
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties	Tue Nov 01 10:51:53 2016 -0400
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties	Tue Nov 01 11:28:16 2016 -0700
@@ -14,9 +14,9 @@
 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\
+a JAR file, a class file, or a class name. The class name must be\n\
+specified using a fully qualified class name using the $ separator\n\
+character for nested classes, for example,\n\
 \n\
 \    java.lang.Thread$State\n\
 \n\
@@ -73,24 +73,26 @@
 \      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.dep.normal=
+scan.dep.removal=(forRemoval=true)
+
+scan.err.exception=error: unexpected exception {0}
+scan.err.noclass=error: cannot find class {0}
+scan.err.nofile=error: cannot find file {0}
+scan.err.nomethod=error: cannot resolve Methodref {0}.{1}:{2}
+
+scan.head.jar=Jar file {0}:
+scan.head.dir=Directory {0}:
 
-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}
+scan.out.extends={0} {1} extends deprecated class {2} {3}
+scan.out.implements={0} {1} implements deprecated interface {2} {3}
+scan.out.usesclass={0} {1} uses deprecated class {2} {3}
+scan.out.usesmethod={0} {1} uses deprecated method {2}::{3}{4} {5}
+scan.out.usesintfmethod={0} {1} uses deprecated method {2}::{3}{4} {5}
+scan.out.usesfield={0} {1} uses deprecated field {2}::{3} {4}
+scan.out.hasfield={0} {1} has field named {2} of deprecated type {3} {4}
+scan.out.methodparmtype={0} {1} has method named {2} having deprecated parameter type {3} {4}
+scan.out.methodrettype={0} {1} has method named {2} having deprecated return type {3} {4}
+scan.out.methodoverride={0} {1} overrides deprecated method {2}::{3}{4} {5}
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java	Tue Nov 01 10:51:53 2016 -0400
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java	Tue Nov 01 11:28:16 2016 -0700
@@ -28,6 +28,7 @@
 import java.io.IOException;
 import java.io.PrintStream;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayDeque;
@@ -62,7 +63,7 @@
     final boolean verbose;
 
     final ClassFinder finder;
-    boolean error = false;
+    boolean errorOccurred = false;
 
     public Scan(PrintStream out,
                 PrintStream err,
@@ -124,71 +125,72 @@
         }
     }
 
-    void printType(String key, ClassFile cf, String cname, boolean forRemoval)
+    String dep(boolean forRemoval) {
+        return Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal");
+    }
+
+    void printType(String key, ClassFile cf, String cname, boolean r)
             throws ConstantPoolException {
-        String dep = Messages.get(forRemoval ? "scan.dep.removal" : "scan.dep.normal");
-        out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, dep));
+        out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, dep(r)));
     }
 
     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));
+                     boolean r) throws ConstantPoolException {
+        out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, mname, rtype, dep(r)));
     }
 
     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));
+                     boolean r) throws ConstantPoolException {
+        out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, fname, dep(r)));
     }
 
     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));
+                     boolean r) throws ConstantPoolException {
+        out.println(Messages.get(key, typeKind(cf), cf.getName(), cname, fname, type, dep(r)));
     }
 
-    void printHasField(ClassFile cf, String fname, String type, boolean forRemoval)
+    void printHasField(ClassFile cf, String fname, String type, boolean r)
             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));
+        out.println(Messages.get("scan.out.hasfield", typeKind(cf), cf.getName(), fname, type, dep(r)));
     }
 
-    void printHasMethodParmType(ClassFile cf, String mname, String parmType, boolean forRemoval)
+    void printHasMethodParmType(ClassFile cf, String mname, String parmType, boolean r)
             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));
+        out.println(Messages.get("scan.out.methodparmtype", typeKind(cf), cf.getName(), mname, parmType, dep(r)));
     }
 
-    void printHasMethodRetType(ClassFile cf, String mname, String retType, boolean forRemoval)
+    void printHasMethodRetType(ClassFile cf, String mname, String retType, boolean r)
             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));
+        out.println(Messages.get("scan.out.methodrettype", typeKind(cf), cf.getName(), mname, retType, dep(r)));
     }
 
-    void printHasOverriddenMethod(ClassFile cf, String overridden, String mname, String desc, boolean forRemoval)
+    void printHasOverriddenMethod(ClassFile cf, String overridden, String mname, String desc, boolean r)
             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));
+                                 mname, desc, dep(r)));
+    }
+
+    void errorException(Exception ex) {
+        errorOccurred = true;
+        err.println(Messages.get("scan.err.exception", ex.toString()));
+        if (verbose) {
+            ex.printStackTrace(err);
+        }
     }
 
-    // format should not have a newline
-    void err(String format, Object... args) {
-        error = true;
-        err.print("error: ");
-        err.printf(format, args);
-        err.println();
+    void errorNoClass(String className) {
+        errorOccurred = true;
+        err.println(Messages.get("scan.err.noclass", className));
     }
 
-    void printException(Exception ex) {
-        err.print(Messages.get("error.prefix"));
-        err.print(" ");
-        if (verbose) {
-            ex.printStackTrace(err);
-        } else {
-            err.print(ex);
-        }
+    void errorNoFile(String fileName) {
+        errorOccurred = true;
+        err.println(Messages.get("scan.err.nofile", fileName));
+    }
+
+    void errorNoMethod(String className, String methodName, String desc) {
+        errorOccurred = true;
+        err.println(Messages.get("scan.err.nomethod", className, methodName, desc));
     }
 
     /**
@@ -271,7 +273,7 @@
         } else {
             startClass = finder.find(startClassName);
             if (startClass == null) {
-                err("can't find class %s", startClassName);
+                errorNoClass(startClassName);
                 return startClassName;
             }
         }
@@ -295,7 +297,7 @@
             String superName = curClass.getSuperclassName();
             curClass = finder.find(superName);
             if (curClass == null) {
-                err("can't find class %s", superName);
+                errorNoClass(superName);
                 break;
             }
             addInterfaces(intfs, curClass);
@@ -310,7 +312,7 @@
                 String intf = intfs.removeFirst();
                 curClass = finder.find(intf);
                 if (curClass == null) {
-                    err("can't find interface %s", intf);
+                    errorNoClass(intf);
                     break;
                 }
 
@@ -324,8 +326,7 @@
 
         if (curClass == null) {
             if (checkStartClass) {
-                err("can't resolve methodref %s %s %s",
-                    startClassName, findName, findDesc);
+                errorNoMethod(startClassName, findName, findDesc);
                 return startClassName;
             } else {
                 // TODO: refactor this
@@ -372,18 +373,18 @@
     }
 
     /**
-     * Checks types referred to from the constant pool.
+     * Checks Class_info entries in 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 {
+    void checkClasses(ClassFile cf, CPEntries entries) throws ConstantPoolException {
         for (ConstantPool.CONSTANT_Class_info ci : entries.classes) {
-            String typeName = ci.getName();
-            DeprData dd = db.getTypeDeprecated(flatten(typeName));
+            String className = ci.getName();
+            DeprData dd = db.getTypeDeprecated(flatten(className));
             if (dd != null) {
-                printType("scan.out.usestype", cf, typeName, dd.isForRemoval());
+                printType("scan.out.usesclass", cf, className, dd.isForRemoval());
             }
         }
     }
@@ -394,26 +395,19 @@
      * @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
+     * @param msgKey message key for localization
      * @throws ConstantPoolException if a constant pool entry cannot be found
      */
     void checkMethodRef(ClassFile cf,
+                        String clname,
                         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 msgKey) throws ConstantPoolException {
         String name = nti.getName();
         String type = nti.getType();
         clname = resolveMember(cf, flatten(clname), name, type, true, true);
-        dd = db.getMethodDeprecated(clname, name, type);
+        DeprData dd = db.getMethodDeprecated(clname, name, type);
         if (dd != null) {
-            printMethod(methKey, cf, clname, name, type, dd.isForRemoval());
+            printMethod(msgKey, cf, clname, name, type, dd.isForRemoval());
         }
     }
 
@@ -425,26 +419,16 @@
      */
     void checkFieldRef(ClassFile cf,
                        ConstantPool.CONSTANT_Fieldref_info fri) throws ConstantPoolException {
+        String clname = fri.getClassName();
         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);
+        DeprData 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());
-        }
     }
 
     /**
@@ -515,18 +499,18 @@
 
         checkSuper(cf);
         checkInterfaces(cf);
-        checkTypes(cf, entries);
+        checkClasses(cf, entries);
 
         for (ConstantPool.CONSTANT_Methodref_info mri : entries.methodRefs) {
+            String clname = mri.getClassName();
             CONSTANT_NameAndType_info nti = mri.getNameAndTypeInfo();
-            String clname = mri.getClassName();
-            checkMethodRef(cf, nti, clname, "scan.out.usesmethodintype", "scan.out.usesmethod");
+            checkMethodRef(cf, clname, nti, "scan.out.usesmethod");
         }
 
         for (ConstantPool.CONSTANT_InterfaceMethodref_info imri : entries.intfMethodRefs) {
+            String clname = imri.getClassName();
             CONSTANT_NameAndType_info nti = imri.getNameAndTypeInfo();
-            String clname = imri.getClassName();
-            checkMethodRef(cf, nti, clname, "scan.out.usesintfmethodintype", "scan.out.usesintfmethod");
+            checkMethodRef(cf, clname, nti, "scan.out.usesintfmethod");
         }
 
         for (ConstantPool.CONSTANT_Fieldref_info fri : entries.fieldRefs) {
@@ -545,6 +529,7 @@
      */
     public boolean scanJar(String jarname) {
         try (JarFile jf = new JarFile(jarname)) {
+            out.println(Messages.get("scan.head.jar", jarname));
             finder.addJar(jarname);
             Enumeration<JarEntry> entries = jf.entries();
             while (entries.hasMoreElements()) {
@@ -557,10 +542,12 @@
                 }
             }
             return true;
+        } catch (NoSuchFileException nsfe) {
+            errorNoFile(jarname);
         } catch (IOException | ConstantPoolException ex) {
-            printException(ex);
-            return false;
+            errorException(ex);
         }
+        return false;
     }
 
     /**
@@ -580,12 +567,15 @@
                      .filter(path -> !path.toString().endsWith("package-info.class"))
                      .filter(path -> !path.toString().endsWith("module-info.class"))
                      .collect(Collectors.toList());
+
+            out.println(Messages.get("scan.head.dir", dirname));
+
             for (Path p : classes) {
                 processClass(ClassFile.read(p));
             }
             return true;
         } catch (IOException | ConstantPoolException ex) {
-            printException(ex);
+            errorException(ex);
             return false;
         }
     }
@@ -600,15 +590,35 @@
         try {
             ClassFile cf = finder.find(className);
             if (cf == null) {
-                err("can't find class %s", className);
+                errorNoClass(className);
                 return false;
             } else {
                 processClass(cf);
                 return true;
             }
         } catch (ConstantPoolException ex) {
-            printException(ex);
+            errorException(ex);
             return false;
         }
     }
+
+    /**
+     * Scans the named class file for uses of deprecated APIs.
+     *
+     * @param fileName the class file to scan
+     * @return true on success, false on failure
+     */
+    public boolean processClassFile(String fileName) {
+        Path path = Paths.get(fileName);
+        try {
+            ClassFile cf = ClassFile.read(path);
+            processClass(cf);
+            return true;
+        } catch (NoSuchFileException nsfe) {
+            errorNoFile(fileName);
+        } catch (IOException | ConstantPoolException ex) {
+            errorException(ex);
+        }
+        return false;
+    }
 }
--- a/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java	Tue Nov 01 10:51:53 2016 -0400
+++ b/langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java	Tue Nov 01 11:28:16 2016 -0700
@@ -89,6 +89,7 @@
                 new InputStreamReader(
                     new ByteArrayInputStream(bytes), StandardCharsets.UTF_8))
                         .lines()
+                        .filter(line -> !line.endsWith(":"))
                         .map(line -> line.split(" +"))
                         .map(array -> array[1])
                         .collect(Collectors.toSet());