# HG changeset patch # User smarks # Date 1478024896 25200 # Node ID 98b049c8b848fc36f294fa85564ef297b4c53ff7 # Parent 471a0cb1b986e3be055ab684d63f1aff039bc6cc 8165646: (jdeprscan) adjust tool output to improve clarity Reviewed-by: jjg, psandoz diff -r 471a0cb1b986 -r 98b049c8b848 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.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; } /** diff -r 471a0cb1b986 -r 98b049c8b848 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Messages.java --- 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); } diff -r 471a0cb1b986 -r 98b049c8b848 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md --- 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 diff -r 471a0cb1b986 -r 98b049c8b848 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/resources/jdeprscan.properties --- 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} diff -r 471a0cb1b986 -r 98b049c8b848 langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/scan/Scan.java --- 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 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; + } } diff -r 471a0cb1b986 -r 98b049c8b848 langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java --- 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());