/*
* Copyright (c) 2011, 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
* @bug 7027157
* @summary Project Coin: javac warnings for AutoCloseable.close throwing InterruptedException
*/
import com.sun.source.util.JavacTask;
import java.net.URI;
import java.util.Arrays;
import javax.tools.Diagnostic;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class InterruptedExceptionTest {
enum XlintOption {
NONE("none"),
TRY("try");
String opt;
XlintOption(String opt) {
this.opt = opt;
}
String getXlintOption() {
return "-Xlint:" + opt;
}
}
enum SuppressLevel {
NONE,
SUPPRESS;
String getSuppressAnno() {
return this == SUPPRESS ?
"@SuppressWarnings(\"try\")" :
"";
}
}
enum ClassKind {
ABSTRACT_CLASS("abstract class", "implements", false),
CLASS("class", "implements", true),
INTERFACE("interface", "extends", false);
String kindName;
String extendsClause;
boolean hasBody;
private ClassKind(String kindName, String extendsClause, boolean hasBody) {
this.kindName = kindName;
this.extendsClause = extendsClause;
this.hasBody = hasBody;
}
String getBody() {
return hasBody ? "{}" : ";";
}
}
enum ExceptionKind {
NONE("", false),
EXCEPTION("Exception", true),
INTERRUPTED_EXCEPTION("InterruptedException", true),
ILLEGAL_ARGUMENT_EXCEPTION("IllegalArgumentException", false),
X("X", false);
String exName;
boolean shouldWarn;
private ExceptionKind(String exName, boolean shouldWarn) {
this.exName = exName;
this.shouldWarn = shouldWarn;
}
String getThrowsClause() {
return this == NONE ? "" : "throws " + exName;
}
String getTypeArguments(ExceptionKind decl) {
return (decl != X || this == NONE) ? "" : "<" + exName + ">";
}
String getTypeParameter() {
return this == X ? "<X extends Exception>" : "";
}
}
public static void main(String... args) throws Exception {
//create default shared JavaCompiler - reused across multiple compilations
JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
for (XlintOption xlint : XlintOption.values()) {
for (SuppressLevel suppress_decl : SuppressLevel.values()) {
for (SuppressLevel suppress_use : SuppressLevel.values()) {
for (ClassKind ck : ClassKind.values()) {
for (ExceptionKind ek_decl : ExceptionKind.values()) {
for (ExceptionKind ek_use : ExceptionKind.values()) {
new InterruptedExceptionTest(xlint, suppress_decl,
suppress_use, ck, ek_decl, ek_use).run(comp, fm);
}
}
}
}
}
}
}
XlintOption xlint;
SuppressLevel suppress_decl;
SuppressLevel suppress_use;
ClassKind ck;
ExceptionKind ek_decl;
ExceptionKind ek_use;
JavaSource source;
DiagnosticChecker diagChecker;
InterruptedExceptionTest(XlintOption xlint, SuppressLevel suppress_decl, SuppressLevel suppress_use,
ClassKind ck, ExceptionKind ek_decl, ExceptionKind ek_use) {
this.xlint = xlint;
this.suppress_decl = suppress_decl;
this.suppress_use = suppress_use;
this.ck = ck;
this.ek_decl = ek_decl;
this.ek_use = ek_use;
this.source = new JavaSource();
this.diagChecker = new DiagnosticChecker();
}
class JavaSource extends SimpleJavaFileObject {
String template = "#S1 #CK Resource#G #EC AutoCloseable {\n" +
"public void close() #TK #BK\n" +
"}\n" +
"class Test {\n" +
"#S2 <X> void test() {\n" +
"try (Resource#PK r = null) { }\n" +
"}\n" +
"}\n";
String source;
public JavaSource() {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
source = template.replace("#S1", suppress_decl.getSuppressAnno())
.replace("#S2", suppress_use.getSuppressAnno())
.replace("#CK", ck.kindName)
.replace("#EC", ck.extendsClause)
.replace("#G", ek_decl.getTypeParameter())
.replace("#TK", ek_decl.getThrowsClause())
.replace("#BK", ck.getBody())
.replace("#PK", ek_use.getTypeArguments(ek_decl));
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return source;
}
}
void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
Arrays.asList(xlint.getXlintOption()), null, Arrays.asList(source));
ct.analyze();
check();
}
void check() {
boolean shouldWarnDecl = ek_decl.shouldWarn &&
xlint == XlintOption.TRY &&
suppress_decl != SuppressLevel.SUPPRESS;
boolean shouldWarnUse = (ek_decl.shouldWarn ||
((ek_use.shouldWarn || ek_use == ExceptionKind.NONE) && ek_decl == ExceptionKind.X)) &&
xlint == XlintOption.TRY &&
suppress_use != SuppressLevel.SUPPRESS;
int foundWarnings = 0;
if (shouldWarnDecl) foundWarnings++;
if (shouldWarnUse) foundWarnings++;
if (foundWarnings != diagChecker.tryWarnFound) {
throw new Error("invalid diagnostics for source:\n" +
source.getCharContent(true) +
"\nOptions: " + xlint.getXlintOption() +
"\nFound warnings: " + diagChecker.tryWarnFound +
"\nExpected decl warning: " + shouldWarnDecl +
"\nExpected use warning: " + shouldWarnUse);
}
}
static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
int tryWarnFound;
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
if (diagnostic.getKind() == Diagnostic.Kind.WARNING &&
diagnostic.getCode().contains("try.resource.throws.interrupted.exc")) {
tryWarnFound++;
}
}
}
}