8145464: implement deprecation static analysis tool
Reviewed-by: psandoz, darcy
This commit is contained in:
parent
e1d3c14945
commit
1673e17518
@ -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), \
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
@ -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}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 "";
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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() { }
|
||||
}
|
@ -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() { }
|
||||
}
|
@ -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;
|
||||
}
|
@ -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";
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 {
|
||||
}
|
144
langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestCSV.java
Normal file
144
langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestCSV.java
Normal 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");
|
||||
}
|
||||
}
|
120
langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoad.java
Normal file
120
langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestLoad.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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.
|
@ -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)");
|
||||
}
|
||||
}
|
110
langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java
Normal file
110
langtools/test/tools/jdeprscan/tests/jdk/jdeprscan/TestScan.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
107
langtools/test/tools/jdeprscan/usage/jdk/deprusage/UseClass.java
Normal file
107
langtools/test/tools/jdeprscan/usage/jdk/deprusage/UseClass.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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) { }
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
||||
}
|
||||
}
|
@ -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() { }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user