Warn5.java revision 794
0N/A/*
2362N/A * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation.
0N/A *
2362N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
0N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
0N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
2362N/A */
2362N/A
0N/A/**
0N/A * @test
0N/A * @bug 6993978
0N/A * @summary Project Coin: Annotation to reduce varargs warnings
0N/A * @author mcimadamore
0N/A * @run main Warn5
0N/A */
0N/Aimport com.sun.source.util.JavacTask;
0N/Aimport java.net.URI;
0N/Aimport java.util.ArrayList;
0N/Aimport java.util.Arrays;
0N/Aimport javax.tools.Diagnostic;
0N/Aimport javax.tools.JavaCompiler;
0N/Aimport javax.tools.JavaFileObject;
0N/Aimport javax.tools.SimpleJavaFileObject;
0N/Aimport javax.tools.ToolProvider;
0N/A
0N/Apublic class Warn5 {
0N/A
0N/A enum XlintOption {
0N/A NONE("none"),
0N/A ALL("all");
0N/A
0N/A String opt;
0N/A
0N/A XlintOption(String opt) {
0N/A this.opt = opt;
0N/A }
0N/A
0N/A String getXlintOption() {
0N/A return "-Xlint:" + opt;
0N/A }
0N/A }
0N/A
0N/A enum TrustMe {
0N/A DONT_TRUST(""),
0N/A TRUST("@java.lang.SafeVarargs");
0N/A
0N/A String anno;
0N/A
0N/A TrustMe(String anno) {
0N/A this.anno = anno;
0N/A }
0N/A }
0N/A
0N/A enum SuppressLevel {
0N/A NONE,
0N/A VARARGS;
0N/A
0N/A String getSuppressAnno() {
0N/A return this == VARARGS ?
0N/A "@SuppressWarnings(\"varargs\")" :
0N/A "";
0N/A }
0N/A }
0N/A
0N/A enum ModifierKind {
0N/A NONE(""),
0N/A FINAL("final"),
0N/A STATIC("static");
0N/A
0N/A String mod;
0N/A
0N/A ModifierKind(String mod) {
0N/A this.mod = mod;
0N/A }
0N/A }
0N/A
0N/A enum MethodKind {
0N/A METHOD("void m"),
0N/A CONSTRUCTOR("Test");
0N/A
0N/A
0N/A String name;
0N/A
0N/A MethodKind(String name) {
0N/A this.name = name;
0N/A }
0N/A }
0N/A
0N/A enum SourceLevel {
0N/A JDK_6("6"),
0N/A JDK_7("7");
0N/A
0N/A String sourceKey;
0N/A
0N/A SourceLevel(String sourceKey) {
0N/A this.sourceKey = sourceKey;
0N/A }
0N/A }
0N/A
0N/A enum SignatureKind {
0N/A VARARGS_X("#K <X>#N(X... x)", false, true),
0N/A VARARGS_STRING("#K #N(String... x)", true, true),
0N/A ARRAY_X("#K <X>#N(X[] x)", false, false),
0N/A ARRAY_STRING("#K #N(String[] x)", true, false);
0N/A
0N/A String stub;
0N/A boolean isReifiableArg;
0N/A boolean isVarargs;
0N/A
0N/A SignatureKind(String stub, boolean isReifiableArg, boolean isVarargs) {
0N/A this.stub = stub;
0N/A this.isReifiableArg = isReifiableArg;
0N/A this.isVarargs = isVarargs;
0N/A }
0N/A
0N/A String getSignature(ModifierKind modKind, MethodKind methKind) {
0N/A return methKind != MethodKind.CONSTRUCTOR ?
0N/A stub.replace("#K", modKind.mod).replace("#N", methKind.name) :
0N/A stub.replace("#K", "").replace("#N", methKind.name);
0N/A }
0N/A }
0N/A
0N/A enum BodyKind {
0N/A ASSIGN("Object o = x;", true),
0N/A CAST("Object o = (Object)x;", true),
0N/A METH("test(x);", true),
0N/A PRINT("System.out.println(x.toString());", false),
0N/A ARRAY_ASSIGN("Object[] o = x;", true),
0N/A ARRAY_CAST("Object[] o = (Object[])x;", true),
0N/A ARRAY_METH("testArr(x);", true);
0N/A
String body;
boolean hasAliasing;
BodyKind(String body, boolean hasAliasing) {
this.body = body;
this.hasAliasing = hasAliasing;
}
}
static 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(TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind,
MethodKind methKind, SignatureKind meth, BodyKind body) {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
source = template.replace("#T", trustMe.anno).
replace("#S", suppressLevel.getSuppressAnno()).
replace("#M", meth.getSignature(modKind, methKind)).
replace("#B", body.body);
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return source;
}
}
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()) {
test(sourceLevel,
xlint,
trustMe,
suppressLevel,
modKind,
methKind,
sig,
body);
}
}
}
}
}
}
}
}
}
static void test(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel,
ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) throws Exception {
final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
JavaSource source = new JavaSource(trustMe, suppressLevel, modKind, methKind, sig, body);
DiagnosticChecker dc = new DiagnosticChecker();
JavacTask ct = (JavacTask)tool.getTask(null, null, dc,
Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source));
ct.analyze();
check(sourceLevel, dc, source, xlint, trustMe,
suppressLevel, modKind, methKind, sig, body);
}
static void check(SourceLevel sourceLevel, DiagnosticChecker dc, JavaSource source,
XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind,
MethodKind methKind, SignatureKind meth, BodyKind body) {
boolean hasPotentiallyUnsafeBody = sourceLevel == SourceLevel.JDK_7 &&
trustMe == TrustMe.TRUST &&
suppressLevel != SuppressLevel.VARARGS &&
xlint != XlintOption.NONE &&
meth.isVarargs && !meth.isReifiableArg && body.hasAliasing &&
(methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE));
boolean hasPotentiallyPollutingDecl = sourceLevel == SourceLevel.JDK_7 &&
trustMe == TrustMe.DONT_TRUST &&
meth.isVarargs &&
!meth.isReifiableArg &&
xlint == XlintOption.ALL;
boolean hasMalformedAnnoInDecl = sourceLevel == SourceLevel.JDK_7 &&
trustMe == TrustMe.TRUST &&
(!meth.isVarargs ||
(modKind == ModifierKind.NONE && methKind == MethodKind.METHOD));
boolean hasRedundantAnnoInDecl = sourceLevel == SourceLevel.JDK_7 &&
trustMe == TrustMe.TRUST &&
xlint != XlintOption.NONE &&
suppressLevel != SuppressLevel.VARARGS &&
(modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) &&
meth.isVarargs &&
meth.isReifiableArg;
if (hasPotentiallyUnsafeBody != dc.hasPotentiallyUnsafeBody ||
hasPotentiallyPollutingDecl != dc.hasPotentiallyPollutingDecl ||
hasMalformedAnnoInDecl != dc.hasMalformedAnnoInDecl ||
hasRedundantAnnoInDecl != dc.hasRedundantAnnoInDecl) {
throw new Error("invalid diagnostics for source:\n" +
source.getCharContent(true) +
"\nOptions: " + xlint.getXlintOption() +
"\nExpected potentially unsafe body warning: " + hasPotentiallyUnsafeBody +
"\nExpected potentially polluting decl warning: " + hasPotentiallyPollutingDecl +
"\nExpected malformed anno error: " + hasMalformedAnnoInDecl +
"\nExpected redundant anno warning: " + hasRedundantAnnoInDecl +
"\nFound potentially unsafe body warning: " + dc.hasPotentiallyUnsafeBody +
"\nFound potentially polluting decl warning: " + dc.hasPotentiallyPollutingDecl +
"\nFound malformed anno error: " + dc.hasMalformedAnnoInDecl +
"\nFound redundant anno warning: " + dc.hasRedundantAnnoInDecl);
}
}
static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
boolean hasPotentiallyUnsafeBody = false;
boolean hasPotentiallyPollutingDecl = false;
boolean hasMalformedAnnoInDecl = false;
boolean hasRedundantAnnoInDecl = false;
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
if (diagnostic.getKind() == Diagnostic.Kind.WARNING) {
if (diagnostic.getCode().contains("unsafe.use.varargs.param")) {
hasPotentiallyUnsafeBody = true;
} else if (diagnostic.getCode().contains("redundant.trustme")) {
hasRedundantAnnoInDecl = true;
}
} else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING &&
diagnostic.getCode().contains("varargs.non.reifiable.type")) {
hasPotentiallyPollutingDecl = true;
} else if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
diagnostic.getCode().contains("invalid.trustme")) {
hasMalformedAnnoInDecl = true;
}
}
}
}