7027157: Project Coin: javac warnings for AutoCloseable.close throwing InterruptedException

Tue, 29 Mar 2011 16:41:18 +0100

author
mcimadamore
date
Tue, 29 Mar 2011 16:41:18 +0100
changeset 951
de1c65ecfec2
parent 950
f5b5112ee1cc
child 952
02ba4ff98742

7027157: Project Coin: javac warnings for AutoCloseable.close throwing InterruptedException
Summary: javac should warn about use/declaration of AutoCloseable subclasses that can throw InterruptedException
Reviewed-by: jjg

src/share/classes/com/sun/tools/javac/code/Symtab.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Attr.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/resources/compiler.properties file | annotate | diff | comparison | revisions
test/tools/javac/TryWithResources/InterruptedExceptionTest.java file | annotate | diff | comparison | revisions
test/tools/javac/diags/examples/TryResourceThrowsInterruptedExc.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/code/Symtab.java	Tue Mar 29 16:40:51 2011 +0100
     1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java	Tue Mar 29 16:41:18 2011 +0100
     1.3 @@ -131,6 +131,7 @@
     1.4      public final Type polymorphicSignatureType;
     1.5      public final Type throwableType;
     1.6      public final Type errorType;
     1.7 +    public final Type interruptedExceptionType;
     1.8      public final Type illegalArgumentExceptionType;
     1.9      public final Type exceptionType;
    1.10      public final Type runtimeExceptionType;
    1.11 @@ -441,6 +442,7 @@
    1.12          polymorphicSignatureType = enterClass("java.lang.invoke.MethodHandle$PolymorphicSignature");
    1.13          errorType = enterClass("java.lang.Error");
    1.14          illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException");
    1.15 +        interruptedExceptionType = enterClass("java.lang.InterruptedException");
    1.16          exceptionType = enterClass("java.lang.Exception");
    1.17          runtimeExceptionType = enterClass("java.lang.RuntimeException");
    1.18          classNotFoundExceptionType = enterClass("java.lang.ClassNotFoundException");
    1.19 @@ -480,6 +482,7 @@
    1.20                               autoCloseableType.tsym);
    1.21          trustMeType = enterClass("java.lang.SafeVarargs");
    1.22  
    1.23 +        synthesizeEmptyInterfaceIfMissing(autoCloseableType);
    1.24          synthesizeEmptyInterfaceIfMissing(cloneableType);
    1.25          synthesizeEmptyInterfaceIfMissing(serializableType);
    1.26          synthesizeEmptyInterfaceIfMissing(transientPolymorphicSignatureType); // transient - 292
     2.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Mar 29 16:40:51 2011 +0100
     2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Mar 29 16:41:18 2011 +0100
     2.3 @@ -1089,6 +1089,10 @@
     2.4              if (resource.getTag() == JCTree.VARDEF) {
     2.5                  attribStat(resource, tryEnv);
     2.6                  chk.checkType(resource, resource.type, syms.autoCloseableType, "try.not.applicable.to.type");
     2.7 +
     2.8 +                //check that resource type cannot throw InterruptedException
     2.9 +                checkAutoCloseable(resource.pos(), localEnv, resource.type);
    2.10 +
    2.11                  VarSymbol var = (VarSymbol)TreeInfo.symbolFor(resource);
    2.12                  var.setData(ElementKind.RESOURCE_VARIABLE);
    2.13              } else {
    2.14 @@ -1127,6 +1131,35 @@
    2.15          result = null;
    2.16      }
    2.17  
    2.18 +    void checkAutoCloseable(DiagnosticPosition pos, Env<AttrContext> env, Type resource) {
    2.19 +        if (!resource.isErroneous() &&
    2.20 +                types.asSuper(resource, syms.autoCloseableType.tsym) != null) {
    2.21 +            Symbol close = syms.noSymbol;
    2.22 +            boolean prevDeferDiags = log.deferDiagnostics;
    2.23 +            Queue<JCDiagnostic> prevDeferredDiags = log.deferredDiagnostics;
    2.24 +            try {
    2.25 +                log.deferDiagnostics = true;
    2.26 +                log.deferredDiagnostics = ListBuffer.lb();
    2.27 +                close = rs.resolveQualifiedMethod(pos,
    2.28 +                        env,
    2.29 +                        resource,
    2.30 +                        names.close,
    2.31 +                        List.<Type>nil(),
    2.32 +                        List.<Type>nil());
    2.33 +            }
    2.34 +            finally {
    2.35 +                log.deferDiagnostics = prevDeferDiags;
    2.36 +                log.deferredDiagnostics = prevDeferredDiags;
    2.37 +            }
    2.38 +            if (close.kind == MTH &&
    2.39 +                    close.overrides(syms.autoCloseableClose, resource.tsym, types, true) &&
    2.40 +                    chk.isHandled(syms.interruptedExceptionType, types.memberType(resource, close).getThrownTypes()) &&
    2.41 +                    env.info.lint.isEnabled(LintCategory.TRY)) {
    2.42 +                log.warning(LintCategory.TRY, pos, "try.resource.throws.interrupted.exc", resource);
    2.43 +            }
    2.44 +        }
    2.45 +    }
    2.46 +
    2.47      public void visitConditional(JCConditional tree) {
    2.48          attribExpr(tree.cond, env, syms.booleanType);
    2.49          attribExpr(tree.truepart, env);
    2.50 @@ -3169,6 +3202,9 @@
    2.51          // method conform to the method they implement.
    2.52          chk.checkImplementations(tree);
    2.53  
    2.54 +        //check that a resource implementing AutoCloseable cannot throw InterruptedException
    2.55 +        checkAutoCloseable(tree.pos(), env, c.type);
    2.56 +
    2.57          for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
    2.58              // Attribute declaration
    2.59              attribStat(l.head, env);
     3.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Mar 29 16:40:51 2011 +0100
     3.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Mar 29 16:41:18 2011 +0100
     3.3 @@ -1244,6 +1244,10 @@
     3.4  compiler.warn.try.resource.not.referenced=\
     3.5      auto-closeable resource {0} is never referenced in body of corresponding try statement
     3.6  
     3.7 +# 0: type
     3.8 +compiler.warn.try.resource.throws.interrupted.exc=\
     3.9 +    auto-closeable resource {0} has a member method close() that could throw InterruptedException
    3.10 +
    3.11  compiler.warn.unchecked.assign=\
    3.12      unchecked assignment: {0} to {1}
    3.13  
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/tools/javac/TryWithResources/InterruptedExceptionTest.java	Tue Mar 29 16:41:18 2011 +0100
     4.3 @@ -0,0 +1,234 @@
     4.4 +/*
     4.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
     4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.7 + *
     4.8 + * This code is free software; you can redistribute it and/or modify it
     4.9 + * under the terms of the GNU General Public License version 2 only, as
    4.10 + * published by the Free Software Foundation.
    4.11 + *
    4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    4.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    4.15 + * version 2 for more details (a copy is included in the LICENSE file that
    4.16 + * accompanied this code).
    4.17 + *
    4.18 + * You should have received a copy of the GNU General Public License version
    4.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    4.21 + *
    4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    4.23 + * or visit www.oracle.com if you need additional information or have any
    4.24 + * questions.
    4.25 + */
    4.26 +
    4.27 +/*
    4.28 + * @test
    4.29 + * @bug 7027157
    4.30 + * @summary Project Coin: javac warnings for AutoCloseable.close throwing InterruptedException
    4.31 + */
    4.32 +
    4.33 +import com.sun.source.util.JavacTask;
    4.34 +import java.net.URI;
    4.35 +import java.util.Arrays;
    4.36 +import javax.tools.Diagnostic;
    4.37 +import javax.tools.JavaCompiler;
    4.38 +import javax.tools.JavaFileObject;
    4.39 +import javax.tools.SimpleJavaFileObject;
    4.40 +import javax.tools.StandardJavaFileManager;
    4.41 +import javax.tools.ToolProvider;
    4.42 +
    4.43 +public class InterruptedExceptionTest {
    4.44 +
    4.45 +    enum XlintOption {
    4.46 +        NONE("none"),
    4.47 +        TRY("try");
    4.48 +
    4.49 +        String opt;
    4.50 +
    4.51 +        XlintOption(String opt) {
    4.52 +            this.opt = opt;
    4.53 +        }
    4.54 +
    4.55 +        String getXlintOption() {
    4.56 +            return "-Xlint:" + opt;
    4.57 +        }
    4.58 +    }
    4.59 +
    4.60 +    enum SuppressLevel {
    4.61 +        NONE,
    4.62 +        SUPPRESS;
    4.63 +
    4.64 +        String getSuppressAnno() {
    4.65 +            return this == SUPPRESS ?
    4.66 +                "@SuppressWarnings(\"try\")" :
    4.67 +                "";
    4.68 +        }
    4.69 +    }
    4.70 +
    4.71 +    enum ClassKind {
    4.72 +        ABSTRACT_CLASS("abstract class", "implements", false),
    4.73 +        CLASS("class", "implements", true),
    4.74 +        INTERFACE("interface", "extends", false);
    4.75 +
    4.76 +        String kindName;
    4.77 +        String extendsClause;
    4.78 +        boolean hasBody;
    4.79 +
    4.80 +        private ClassKind(String kindName, String extendsClause, boolean hasBody) {
    4.81 +            this.kindName = kindName;
    4.82 +            this.extendsClause = extendsClause;
    4.83 +            this.hasBody = hasBody;
    4.84 +        }
    4.85 +
    4.86 +        String getBody() {
    4.87 +            return hasBody ? "{}" : ";";
    4.88 +        }
    4.89 +    }
    4.90 +
    4.91 +    enum ExceptionKind {
    4.92 +        NONE("", false),
    4.93 +        EXCEPTION("Exception", true),
    4.94 +        INTERRUPTED_EXCEPTION("InterruptedException", true),
    4.95 +        ILLEGAL_ARGUMENT_EXCEPTION("IllegalArgumentException", false),
    4.96 +        X("X", false);
    4.97 +
    4.98 +        String exName;
    4.99 +        boolean shouldWarn;
   4.100 +
   4.101 +        private ExceptionKind(String exName, boolean shouldWarn) {
   4.102 +            this.exName = exName;
   4.103 +            this.shouldWarn = shouldWarn;
   4.104 +        }
   4.105 +
   4.106 +        String getThrowsClause() {
   4.107 +            return this == NONE ? "" : "throws " + exName;
   4.108 +        }
   4.109 +
   4.110 +        String getTypeArguments(ExceptionKind decl) {
   4.111 +            return (decl != X || this == NONE) ? "" : "<" + exName + ">";
   4.112 +        }
   4.113 +
   4.114 +        String getTypeParameter() {
   4.115 +            return this == X ? "<X extends Exception>" : "";
   4.116 +        }
   4.117 +    }
   4.118 +
   4.119 +    public static void main(String... args) throws Exception {
   4.120 +
   4.121 +        //create default shared JavaCompiler - reused across multiple compilations
   4.122 +        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
   4.123 +        StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
   4.124 +
   4.125 +        for (XlintOption xlint : XlintOption.values()) {
   4.126 +            for (SuppressLevel suppress_decl : SuppressLevel.values()) {
   4.127 +                for (SuppressLevel suppress_use : SuppressLevel.values()) {
   4.128 +                    for (ClassKind ck : ClassKind.values()) {
   4.129 +                        for (ExceptionKind ek_decl : ExceptionKind.values()) {
   4.130 +                            for (ExceptionKind ek_use : ExceptionKind.values()) {
   4.131 +                                new InterruptedExceptionTest(xlint, suppress_decl,
   4.132 +                                        suppress_use, ck, ek_decl, ek_use).run(comp, fm);
   4.133 +                            }
   4.134 +                        }
   4.135 +                    }
   4.136 +                }
   4.137 +            }
   4.138 +        }
   4.139 +    }
   4.140 +
   4.141 +    XlintOption xlint;
   4.142 +    SuppressLevel suppress_decl;
   4.143 +    SuppressLevel suppress_use;
   4.144 +    ClassKind ck;
   4.145 +    ExceptionKind ek_decl;
   4.146 +    ExceptionKind ek_use;
   4.147 +    JavaSource source;
   4.148 +    DiagnosticChecker diagChecker;
   4.149 +
   4.150 +    InterruptedExceptionTest(XlintOption xlint, SuppressLevel suppress_decl, SuppressLevel suppress_use,
   4.151 +            ClassKind ck, ExceptionKind ek_decl, ExceptionKind ek_use) {
   4.152 +        this.xlint = xlint;
   4.153 +        this.suppress_decl = suppress_decl;
   4.154 +        this.suppress_use = suppress_use;
   4.155 +        this.ck = ck;
   4.156 +        this.ek_decl = ek_decl;
   4.157 +        this.ek_use = ek_use;
   4.158 +        this.source = new JavaSource();
   4.159 +        this.diagChecker = new DiagnosticChecker();
   4.160 +    }
   4.161 +
   4.162 +    class JavaSource extends SimpleJavaFileObject {
   4.163 +
   4.164 +        String template = "#S1 #CK Resource#G #EC AutoCloseable {\n" +
   4.165 +                              "public void close() #TK #BK\n" +
   4.166 +                          "}\n" +
   4.167 +                          "class Test {\n" +
   4.168 +                              "#S2 <X> void test() {\n" +
   4.169 +                                 "try (Resource#PK r = null) { }\n" +
   4.170 +                              "}\n" +
   4.171 +                          "}\n";
   4.172 +
   4.173 +        String source;
   4.174 +
   4.175 +        public JavaSource() {
   4.176 +            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
   4.177 +            source = template.replace("#S1", suppress_decl.getSuppressAnno())
   4.178 +                    .replace("#S2", suppress_use.getSuppressAnno())
   4.179 +                    .replace("#CK", ck.kindName)
   4.180 +                    .replace("#EC", ck.extendsClause)
   4.181 +                    .replace("#G", ek_decl.getTypeParameter())
   4.182 +                    .replace("#TK", ek_decl.getThrowsClause())
   4.183 +                    .replace("#BK", ck.getBody())
   4.184 +                    .replace("#PK", ek_use.getTypeArguments(ek_decl));
   4.185 +        }
   4.186 +
   4.187 +        @Override
   4.188 +        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   4.189 +            return source;
   4.190 +        }
   4.191 +    }
   4.192 +
   4.193 +    void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
   4.194 +        JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
   4.195 +                Arrays.asList(xlint.getXlintOption()), null, Arrays.asList(source));
   4.196 +        ct.analyze();
   4.197 +        check();
   4.198 +    }
   4.199 +
   4.200 +    void check() {
   4.201 +
   4.202 +        boolean shouldWarnDecl = ek_decl.shouldWarn &&
   4.203 +                xlint == XlintOption.TRY &&
   4.204 +                suppress_decl != SuppressLevel.SUPPRESS;
   4.205 +
   4.206 +        boolean shouldWarnUse = (ek_decl.shouldWarn ||
   4.207 +                ((ek_use.shouldWarn || ek_use == ExceptionKind.NONE) && ek_decl == ExceptionKind.X)) &&
   4.208 +                xlint == XlintOption.TRY &&
   4.209 +                suppress_use != SuppressLevel.SUPPRESS;
   4.210 +
   4.211 +        int foundWarnings = 0;
   4.212 +
   4.213 +        if (shouldWarnDecl) foundWarnings++;
   4.214 +        if (shouldWarnUse) foundWarnings++;
   4.215 +
   4.216 +        if (foundWarnings != diagChecker.tryWarnFound) {
   4.217 +            throw new Error("invalid diagnostics for source:\n" +
   4.218 +                source.getCharContent(true) +
   4.219 +                "\nOptions: " + xlint.getXlintOption() +
   4.220 +                "\nFound warnings: " + diagChecker.tryWarnFound +
   4.221 +                "\nExpected decl warning: " + shouldWarnDecl +
   4.222 +                "\nExpected use warning: " + shouldWarnUse);
   4.223 +        }
   4.224 +    }
   4.225 +
   4.226 +    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
   4.227 +
   4.228 +        int tryWarnFound;
   4.229 +
   4.230 +        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   4.231 +            if (diagnostic.getKind() == Diagnostic.Kind.WARNING &&
   4.232 +                    diagnostic.getCode().contains("try.resource.throws.interrupted.exc")) {
   4.233 +                tryWarnFound++;
   4.234 +            }
   4.235 +        }
   4.236 +    }
   4.237 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/tools/javac/diags/examples/TryResourceThrowsInterruptedExc.java	Tue Mar 29 16:41:18 2011 +0100
     5.3 @@ -0,0 +1,29 @@
     5.4 +/*
     5.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.
    5.11 + *
    5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.15 + * version 2 for more details (a copy is included in the LICENSE file that
    5.16 + * accompanied this code).
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License version
    5.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.21 + *
    5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.23 + * or visit www.oracle.com if you need additional information or have any
    5.24 + * questions.
    5.25 + */
    5.26 +
    5.27 +// key: compiler.warn.try.resource.throws.interrupted.exc
    5.28 +// options: -Xlint:try
    5.29 +
    5.30 +class TryResourceThrowsInterruptedException implements AutoCloseable {
    5.31 +    public void close() throws InterruptedException {}
    5.32 +}

mercurial