2010-12-13 23:11:00 +00:00
|
|
|
/*
|
2011-04-07 03:33:44 +00:00
|
|
|
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
2010-12-13 23:11:00 +00:00
|
|
|
* 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
|
2011-10-17 11:54:33 +00:00
|
|
|
* @bug 6993978 7097436
|
2010-12-13 23:11:00 +00:00
|
|
|
* @summary Project Coin: Annotation to reduce varargs warnings
|
|
|
|
* @author mcimadamore
|
|
|
|
* @run main Warn5
|
|
|
|
*/
|
|
|
|
import com.sun.source.util.JavacTask;
|
2011-02-24 16:40:49 +00:00
|
|
|
import com.sun.tools.javac.api.JavacTool;
|
2010-12-13 23:11:00 +00:00
|
|
|
import java.net.URI;
|
|
|
|
import java.util.Arrays;
|
2011-10-17 11:54:33 +00:00
|
|
|
import java.util.EnumSet;
|
2010-12-13 23:11:00 +00:00
|
|
|
import javax.tools.Diagnostic;
|
|
|
|
import javax.tools.JavaCompiler;
|
|
|
|
import javax.tools.JavaFileObject;
|
|
|
|
import javax.tools.SimpleJavaFileObject;
|
2011-02-24 16:40:49 +00:00
|
|
|
import javax.tools.StandardJavaFileManager;
|
2010-12-13 23:11:00 +00:00
|
|
|
import javax.tools.ToolProvider;
|
|
|
|
|
|
|
|
public class Warn5 {
|
|
|
|
|
|
|
|
enum XlintOption {
|
|
|
|
NONE("none"),
|
|
|
|
ALL("all");
|
|
|
|
|
|
|
|
String opt;
|
|
|
|
|
|
|
|
XlintOption(String opt) {
|
|
|
|
this.opt = opt;
|
|
|
|
}
|
|
|
|
|
|
|
|
String getXlintOption() {
|
|
|
|
return "-Xlint:" + opt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum TrustMe {
|
|
|
|
DONT_TRUST(""),
|
|
|
|
TRUST("@java.lang.SafeVarargs");
|
|
|
|
|
|
|
|
String anno;
|
|
|
|
|
|
|
|
TrustMe(String anno) {
|
|
|
|
this.anno = anno;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum SuppressLevel {
|
|
|
|
NONE,
|
|
|
|
VARARGS;
|
|
|
|
|
|
|
|
String getSuppressAnno() {
|
|
|
|
return this == VARARGS ?
|
|
|
|
"@SuppressWarnings(\"varargs\")" :
|
|
|
|
"";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum ModifierKind {
|
|
|
|
NONE(""),
|
|
|
|
FINAL("final"),
|
|
|
|
STATIC("static");
|
|
|
|
|
|
|
|
String mod;
|
|
|
|
|
|
|
|
ModifierKind(String mod) {
|
|
|
|
this.mod = mod;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum MethodKind {
|
|
|
|
METHOD("void m"),
|
|
|
|
CONSTRUCTOR("Test");
|
|
|
|
|
|
|
|
String name;
|
|
|
|
|
|
|
|
MethodKind(String name) {
|
|
|
|
this.name = name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum SourceLevel {
|
|
|
|
JDK_6("6"),
|
|
|
|
JDK_7("7");
|
|
|
|
|
|
|
|
String sourceKey;
|
|
|
|
|
|
|
|
SourceLevel(String sourceKey) {
|
|
|
|
this.sourceKey = sourceKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum SignatureKind {
|
|
|
|
VARARGS_X("#K <X>#N(X... x)", false, true),
|
|
|
|
VARARGS_STRING("#K #N(String... x)", true, true),
|
|
|
|
ARRAY_X("#K <X>#N(X[] x)", false, false),
|
|
|
|
ARRAY_STRING("#K #N(String[] x)", true, false);
|
|
|
|
|
|
|
|
String stub;
|
|
|
|
boolean isReifiableArg;
|
|
|
|
boolean isVarargs;
|
|
|
|
|
|
|
|
SignatureKind(String stub, boolean isReifiableArg, boolean isVarargs) {
|
|
|
|
this.stub = stub;
|
|
|
|
this.isReifiableArg = isReifiableArg;
|
|
|
|
this.isVarargs = isVarargs;
|
|
|
|
}
|
|
|
|
|
|
|
|
String getSignature(ModifierKind modKind, MethodKind methKind) {
|
|
|
|
return methKind != MethodKind.CONSTRUCTOR ?
|
|
|
|
stub.replace("#K", modKind.mod).replace("#N", methKind.name) :
|
|
|
|
stub.replace("#K", "").replace("#N", methKind.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum BodyKind {
|
|
|
|
ASSIGN("Object o = x;", true),
|
|
|
|
CAST("Object o = (Object)x;", true),
|
|
|
|
METH("test(x);", true),
|
|
|
|
PRINT("System.out.println(x.toString());", false),
|
|
|
|
ARRAY_ASSIGN("Object[] o = x;", true),
|
|
|
|
ARRAY_CAST("Object[] o = (Object[])x;", true),
|
|
|
|
ARRAY_METH("testArr(x);", true);
|
|
|
|
|
|
|
|
String body;
|
|
|
|
boolean hasAliasing;
|
|
|
|
|
|
|
|
BodyKind(String body, boolean hasAliasing) {
|
|
|
|
this.body = body;
|
|
|
|
this.hasAliasing = hasAliasing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
enum WarningKind {
|
|
|
|
UNSAFE_BODY,
|
|
|
|
UNSAFE_DECL,
|
|
|
|
MALFORMED_SAFEVARARGS,
|
|
|
|
REDUNDANT_SAFEVARARGS;
|
2010-12-13 23:11:00 +00:00
|
|
|
}
|
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
// Create a single file manager and reuse it for each compile to save time.
|
|
|
|
static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
|
|
|
|
|
2010-12-13 23:11:00 +00:00
|
|
|
public static void main(String... args) throws Exception {
|
|
|
|
for (SourceLevel sourceLevel : SourceLevel.values()) {
|
|
|
|
for (XlintOption xlint : XlintOption.values()) {
|
|
|
|
for (TrustMe trustMe : TrustMe.values()) {
|
|
|
|
for (SuppressLevel suppressLevel : SuppressLevel.values()) {
|
|
|
|
for (ModifierKind modKind : ModifierKind.values()) {
|
|
|
|
for (MethodKind methKind : MethodKind.values()) {
|
|
|
|
for (SignatureKind sig : SignatureKind.values()) {
|
|
|
|
for (BodyKind body : BodyKind.values()) {
|
2011-10-17 11:54:33 +00:00
|
|
|
new Warn5(sourceLevel,
|
2010-12-13 23:11:00 +00:00
|
|
|
xlint,
|
|
|
|
trustMe,
|
|
|
|
suppressLevel,
|
|
|
|
modKind,
|
|
|
|
methKind,
|
|
|
|
sig,
|
2011-10-17 11:54:33 +00:00
|
|
|
body).test();
|
2010-12-13 23:11:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
final SourceLevel sourceLevel;
|
|
|
|
final XlintOption xlint;
|
|
|
|
final TrustMe trustMe;
|
|
|
|
final SuppressLevel suppressLevel;
|
|
|
|
final ModifierKind modKind;
|
|
|
|
final MethodKind methKind;
|
|
|
|
final SignatureKind sig;
|
|
|
|
final BodyKind body;
|
|
|
|
final JavaSource source;
|
|
|
|
final DiagnosticChecker dc;
|
|
|
|
|
|
|
|
public Warn5(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) {
|
|
|
|
this.sourceLevel = sourceLevel;
|
|
|
|
this.xlint = xlint;
|
|
|
|
this.trustMe = trustMe;
|
|
|
|
this.suppressLevel = suppressLevel;
|
|
|
|
this.modKind = modKind;
|
|
|
|
this.methKind = methKind;
|
|
|
|
this.sig = sig;
|
|
|
|
this.body = body;
|
|
|
|
this.source = new JavaSource();
|
|
|
|
this.dc = new DiagnosticChecker();
|
|
|
|
}
|
2011-02-24 16:40:49 +00:00
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
void test() throws Exception {
|
2010-12-13 23:11:00 +00:00
|
|
|
final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
|
2011-02-24 16:40:49 +00:00
|
|
|
JavacTask ct = (JavacTask)tool.getTask(null, fm, dc,
|
2010-12-13 23:11:00 +00:00
|
|
|
Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source));
|
|
|
|
ct.analyze();
|
2011-10-17 11:54:33 +00:00
|
|
|
check();
|
2010-12-13 23:11:00 +00:00
|
|
|
}
|
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
void check() {
|
2010-12-13 23:11:00 +00:00
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
EnumSet<WarningKind> expectedWarnings = EnumSet.noneOf(WarningKind.class);
|
|
|
|
|
|
|
|
if (sourceLevel == SourceLevel.JDK_7 &&
|
2010-12-13 23:11:00 +00:00
|
|
|
trustMe == TrustMe.TRUST &&
|
|
|
|
suppressLevel != SuppressLevel.VARARGS &&
|
|
|
|
xlint != XlintOption.NONE &&
|
2011-10-17 11:54:33 +00:00
|
|
|
sig.isVarargs && !sig.isReifiableArg && body.hasAliasing &&
|
|
|
|
(methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE))) {
|
|
|
|
expectedWarnings.add(WarningKind.UNSAFE_BODY);
|
|
|
|
}
|
2010-12-13 23:11:00 +00:00
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
if (sourceLevel == SourceLevel.JDK_7 &&
|
2010-12-13 23:11:00 +00:00
|
|
|
trustMe == TrustMe.DONT_TRUST &&
|
2011-10-17 11:54:33 +00:00
|
|
|
sig.isVarargs &&
|
|
|
|
!sig.isReifiableArg &&
|
|
|
|
xlint == XlintOption.ALL) {
|
|
|
|
expectedWarnings.add(WarningKind.UNSAFE_DECL);
|
|
|
|
}
|
2010-12-13 23:11:00 +00:00
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
if (sourceLevel == SourceLevel.JDK_7 &&
|
2010-12-13 23:11:00 +00:00
|
|
|
trustMe == TrustMe.TRUST &&
|
2011-10-17 11:54:33 +00:00
|
|
|
(!sig.isVarargs ||
|
|
|
|
(modKind == ModifierKind.NONE && methKind == MethodKind.METHOD))) {
|
|
|
|
expectedWarnings.add(WarningKind.MALFORMED_SAFEVARARGS);
|
|
|
|
}
|
2010-12-13 23:11:00 +00:00
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
if (sourceLevel == SourceLevel.JDK_7 &&
|
2010-12-13 23:11:00 +00:00
|
|
|
trustMe == TrustMe.TRUST &&
|
|
|
|
xlint != XlintOption.NONE &&
|
|
|
|
suppressLevel != SuppressLevel.VARARGS &&
|
|
|
|
(modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) &&
|
2011-10-17 11:54:33 +00:00
|
|
|
sig.isVarargs &&
|
|
|
|
sig.isReifiableArg) {
|
|
|
|
expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS);
|
|
|
|
}
|
2010-12-13 23:11:00 +00:00
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
if (!expectedWarnings.containsAll(dc.warnings) ||
|
|
|
|
!dc.warnings.containsAll(expectedWarnings)) {
|
2010-12-13 23:11:00 +00:00
|
|
|
throw new Error("invalid diagnostics for source:\n" +
|
|
|
|
source.getCharContent(true) +
|
|
|
|
"\nOptions: " + xlint.getXlintOption() +
|
2011-10-17 11:54:33 +00:00
|
|
|
"\nExpected warnings: " + expectedWarnings +
|
|
|
|
"\nFound warnings: " + dc.warnings);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class JavaSource extends SimpleJavaFileObject {
|
|
|
|
|
|
|
|
String template = "import com.sun.tools.javac.api.*;\n" +
|
|
|
|
"import java.util.List;\n" +
|
|
|
|
"class Test {\n" +
|
|
|
|
" static void test(Object o) {}\n" +
|
|
|
|
" static void testArr(Object[] o) {}\n" +
|
|
|
|
" #T \n #S #M { #B }\n" +
|
|
|
|
"}\n";
|
|
|
|
|
|
|
|
String source;
|
|
|
|
|
|
|
|
public JavaSource() {
|
|
|
|
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
|
|
|
|
source = template.replace("#T", trustMe.anno).
|
|
|
|
replace("#S", suppressLevel.getSuppressAnno()).
|
|
|
|
replace("#M", sig.getSignature(modKind, methKind)).
|
|
|
|
replace("#B", body.body);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
|
|
|
|
return source;
|
2010-12-13 23:11:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
|
2010-12-13 23:11:00 +00:00
|
|
|
|
2011-10-17 11:54:33 +00:00
|
|
|
EnumSet<WarningKind> warnings = EnumSet.noneOf(WarningKind.class);
|
2010-12-13 23:11:00 +00:00
|
|
|
|
|
|
|
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
|
|
|
if (diagnostic.getKind() == Diagnostic.Kind.WARNING) {
|
|
|
|
if (diagnostic.getCode().contains("unsafe.use.varargs.param")) {
|
2011-10-17 11:54:33 +00:00
|
|
|
setWarning(WarningKind.UNSAFE_BODY);
|
2010-12-13 23:11:00 +00:00
|
|
|
} else if (diagnostic.getCode().contains("redundant.trustme")) {
|
2011-10-17 11:54:33 +00:00
|
|
|
setWarning(WarningKind.REDUNDANT_SAFEVARARGS);
|
2010-12-13 23:11:00 +00:00
|
|
|
}
|
|
|
|
} else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING &&
|
|
|
|
diagnostic.getCode().contains("varargs.non.reifiable.type")) {
|
2011-10-17 11:54:33 +00:00
|
|
|
setWarning(WarningKind.UNSAFE_DECL);
|
2010-12-13 23:11:00 +00:00
|
|
|
} else if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
|
|
|
|
diagnostic.getCode().contains("invalid.trustme")) {
|
2011-10-17 11:54:33 +00:00
|
|
|
setWarning(WarningKind.MALFORMED_SAFEVARARGS);
|
2010-12-13 23:11:00 +00:00
|
|
|
}
|
|
|
|
}
|
2011-10-17 11:54:33 +00:00
|
|
|
|
|
|
|
void setWarning(WarningKind wk) {
|
|
|
|
if (!warnings.add(wk)) {
|
|
|
|
throw new AssertionError("Duplicate warning of kind " + wk + " in source:\n" + source);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean hasWarning(WarningKind wk) {
|
|
|
|
return warnings.contains(wk);
|
|
|
|
}
|
2010-12-13 23:11:00 +00:00
|
|
|
}
|
|
|
|
}
|