8145464: implement deprecation static analysis tool

Reviewed-by: psandoz, darcy
This commit is contained in:
Stuart Marks 2016-08-25 17:58:39 -07:00
parent e1d3c14945
commit 1673e17518
43 changed files with 5006 additions and 2 deletions

View File

@ -32,7 +32,7 @@ include JavaCompilation.gmk
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 @@ define SetupInterimModule
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), \

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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 "";
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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() { }
}

View File

@ -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() { }
}

View File

@ -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;
}

View File

@ -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";
}

View File

@ -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 {
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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 {
}

View File

@ -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");
}
}

View File

@ -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);
}
}

View File

@ -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
Can't render this file because it has a wrong number of fields in line 2.

View File

@ -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)");
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}

View File

@ -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) { }
}
}
}

View File

@ -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;
}
}
}

View File

@ -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 {
}
}

View File

@ -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() { }
}
}