6558548: The compiler needs to be aligned with clarified specification of throws
authormcimadamore
Wed, 16 Mar 2011 11:12:26 +0000
changeset 8849 4189ac38ddc9
parent 8848 3f1b154379d6
child 8850 3c7365401a97
6558548: The compiler needs to be aligned with clarified specification of throws Summary: Javac should issue unconditional warnings when 'dead' catch clauses are detected Reviewed-by: jjg
langtools/src/share/classes/com/sun/tools/javac/code/Source.java
langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java
langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
langtools/test/tools/javac/6558548/T6558548.java
langtools/test/tools/javac/6558548/T6558548_6.out
langtools/test/tools/javac/6558548/T6558548_latest.out
langtools/test/tools/javac/diags/examples/UnreachableCatch.java
langtools/test/tools/javac/diags/examples/UnreachableCatch1.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java	Tue Mar 15 14:19:00 2011 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java	Wed Mar 16 11:12:26 2011 +0000
@@ -131,6 +131,12 @@
     public boolean allowMulticatch() {
         return compareTo(JDK1_7) >= 0;
     }
+    public boolean allowImprovedRethrowAnalysis() {
+        return compareTo(JDK1_7) >= 0;
+    }
+    public boolean allowImprovedCatchAnalysis() {
+        return compareTo(JDK1_7) >= 0;
+    }
     public boolean allowEnums() {
         return compareTo(JDK1_5) >= 0;
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Mar 15 14:19:00 2011 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Mar 16 11:12:26 2011 +0000
@@ -190,7 +190,8 @@
     private final Resolve rs;
     private Env<AttrContext> attrEnv;
     private       Lint lint;
-    private final boolean allowRethrowAnalysis;
+    private final boolean allowImprovedRethrowAnalysis;
+    private final boolean allowImprovedCatchAnalysis;
 
     public static Flow instance(Context context) {
         Flow instance = context.get(flowKey);
@@ -209,7 +210,8 @@
         lint = Lint.instance(context);
         rs = Resolve.instance(context);
         Source source = Source.instance(context);
-        allowRethrowAnalysis = source.allowMulticatch();
+        allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
+        allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
     }
 
     /** A flag that indicates whether the last statement could
@@ -1046,7 +1048,9 @@
             }
         }
         scanStat(tree.body);
-        List<Type> thrownInTry = thrown;
+        List<Type> thrownInTry = allowImprovedCatchAnalysis ?
+            chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
+            thrown;
         thrown = thrownPrev;
         caught = caughtPrev;
         boolean aliveEnd = alive;
@@ -1081,16 +1085,7 @@
                     ctypes = ctypes.append(exc);
                     if (types.isSameType(exc, syms.objectType))
                         continue;
-                    if (chk.subset(exc, caughtInTry)) {
-                        log.error(l.head.pos(),
-                                  "except.already.caught", exc);
-                    } else if (!chk.isUnchecked(l.head.pos(), exc) &&
-                               exc.tsym != syms.throwableType.tsym &&
-                               exc.tsym != syms.exceptionType.tsym &&
-                               !chk.intersects(exc, thrownInTry)) {
-                        log.error(l.head.pos(),
-                                  "except.never.thrown.in.try", exc);
-                    }
+                    checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
                     caughtInTry = chk.incl(exc, caughtInTry);
                 }
             }
@@ -1154,6 +1149,29 @@
         uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
     }
 
+    void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
+        if (chk.subset(exc, caughtInTry)) {
+            log.error(pos, "except.already.caught", exc);
+        } else if (!chk.isUnchecked(pos, exc) &&
+                exc.tsym != syms.throwableType.tsym &&
+                exc.tsym != syms.exceptionType.tsym &&
+                !chk.intersects(exc, thrownInTry)) {
+            log.error(pos, "except.never.thrown.in.try", exc);
+        } else if (allowImprovedCatchAnalysis) {
+            List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
+            // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
+            // unchecked exception, the result list would not be empty, as the augmented
+            // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
+            // exception, that would have been covered in the branch above
+            if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty()) {
+                String key = catchableThrownTypes.length() == 1 ?
+                        "unreachable.catch" :
+                        "unreachable.catch.1";
+                log.warning(pos, key, catchableThrownTypes);
+            }
+        }
+    }
+
     public void visitConditional(JCConditional tree) {
         scanCond(tree.cond);
         Bits initsBeforeElse = initsWhenFalse;
@@ -1238,7 +1256,7 @@
             sym.kind == VAR &&
             (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
             preciseRethrowTypes.get(sym) != null &&
-            allowRethrowAnalysis) {
+            allowImprovedRethrowAnalysis) {
             for (Type t : preciseRethrowTypes.get(sym)) {
                 markThrown(tree, t);
             }
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Mar 15 14:19:00 2011 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Mar 16 11:12:26 2011 +0000
@@ -1102,6 +1102,16 @@
     cast to {0} for a varargs call\n\
     cast to {1} for a non-varargs call and to suppress this warning
 
+# 0: list of type
+compiler.warn.unreachable.catch=\
+    unreachable catch clause\n\
+    thrown type {0} has already been caught
+
+# 0: list of type
+compiler.warn.unreachable.catch.1=\
+    unreachable catch clause\n\
+    thrown types {0} have already been caught
+
 # 0: symbol
 compiler.warn.long.SVUID=\
     serialVersionUID must be of type long in class {0}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6558548/T6558548.java	Wed Mar 16 11:12:26 2011 +0000
@@ -0,0 +1,300 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug     6558548
+ * @summary The compiler needs to be aligned with clarified specification of throws
+ * @compile/fail/ref=T6558548_latest.out -XDrawDiagnostics T6558548.java
+ * @compile/fail/ref=T6558548_6.out -source 6 -XDrawDiagnostics T6558548.java
+ */
+
+class T6558548 {
+
+    void nothing() {}
+    void checked() throws InterruptedException {}
+    void runtime() throws IllegalArgumentException {}
+
+    void m1() {
+        try {
+            throw new java.io.FileNotFoundException();
+        }
+        catch(java.io.FileNotFoundException exc) { }
+        catch(java.io.IOException exc) { } // 6: ok; latest: unreachable
+    }
+
+    void m1a() {
+        try {
+            throw new java.io.IOException();
+        }
+        catch(java.io.FileNotFoundException exc) { }
+        catch(java.io.IOException exc) { } //ok
+    }
+
+    void m2() {
+        try {
+            nothing();
+        }
+        catch(Exception exc) { } // ok
+    }
+
+    void m3() {
+        try {
+            checked();
+        }
+        catch(Exception exc) { } //ok
+    }
+
+    void m4() {
+        try {
+            runtime();
+        }
+        catch(Exception exc) { } //ok
+    }
+
+    void m5() {
+        try {
+            nothing();
+        }
+        catch(Throwable exc) { } //ok
+    }
+
+    void m6() {
+        try {
+            checked();
+        }
+        catch(Throwable exc) { } //ok
+    }
+
+    void m7() {
+        try {
+            runtime();
+        }
+        catch(Throwable exc) { } //ok
+    }
+
+    void m9() {
+        try {
+            checked();
+        }
+        catch(Error exc) { }
+        catch(Throwable exc) { } //ok
+    }
+
+    void m10() {
+        try {
+            runtime();
+        }
+        catch(Error exc) { }
+        catch(Throwable exc) { } //ok
+    }
+
+    void m11() {
+        try {
+            nothing();
+        }
+        catch(Error exc) { }
+        catch(Throwable exc) { } //ok
+    }
+
+    void m12() {
+        try {
+            checked();
+        }
+        catch(RuntimeException exc) { }
+        catch(Throwable exc) { } // ok
+    }
+
+    void m13() {
+        try {
+            runtime();
+        }
+        catch(RuntimeException exc) { }
+        catch(Throwable exc) { } // ok
+    }
+
+    void m14() {
+        try {
+            nothing();
+        }
+        catch(RuntimeException exc) { }
+        catch(Throwable exc) { } // ok
+    }
+
+    void m15() {
+        try {
+            checked();
+        }
+        catch(RuntimeException exc) { }
+        catch(Exception exc) { } //ok
+    }
+
+    void m16() {
+        try {
+            runtime();
+        }
+        catch(RuntimeException exc) { }
+        catch(Exception exc) { } //6: ok; latest: unreachable
+    }
+
+    void m17() {
+        try {
+            nothing();
+        }
+        catch(RuntimeException exc) { }
+        catch(Exception exc) { } //6: ok; latest: unreachable
+    }
+
+    void m18() {
+        try {
+            checked();
+        }
+        catch(RuntimeException exc) { }
+        catch(InterruptedException exc) { }
+        catch(Exception exc) { } //6: ok; latest: unreachable
+    }
+
+    void m19() {
+        try {
+            runtime();
+        }
+        catch(RuntimeException exc) { }
+        catch(InterruptedException exc) { } //never thrown in try
+        catch(Exception exc) { } //6: ok; latest: unreachable
+    }
+
+    void m20() {
+        try {
+            nothing();
+        }
+        catch(RuntimeException exc) { }
+        catch(InterruptedException exc) { } //never thrown in try
+        catch(Exception exc) { } //6: ok; latest: unreachable
+    }
+
+    void m21() {
+        try {
+            checked();
+        }
+        catch(RuntimeException exc) { }
+        catch(Exception exc) { } // ok
+    }
+
+    void m22() {
+        try {
+            runtime();
+        }
+        catch(RuntimeException exc) { }
+        catch(Exception exc) { } // 6: ok; latest: unreachable
+    }
+
+    void m23() {
+        try {
+            nothing();
+        }
+        catch(RuntimeException exc) { }
+        catch(Exception exc) { } // 6: ok; latest: unreachable
+    }
+
+    void m24() {
+        try {
+            checked();
+        }
+        catch(RuntimeException exc) { }
+        catch(Error exc) { }
+        catch(Throwable exc) { } //ok
+    }
+
+    void m25() {
+        try {
+            runtime();
+        }
+        catch(RuntimeException exc) { }
+        catch(Error exc) { }
+        catch(Throwable exc) { } //6: ok; latest: unreachable
+    }
+
+    void m26() {
+        try {
+            nothing();
+        }
+        catch(RuntimeException exc) { }
+        catch(Error exc) { }
+        catch(Throwable exc) { } //6: ok; latest: unreachable
+    }
+
+    void m27() {
+        try {
+            checked();
+        }
+        catch(RuntimeException exc) { }
+        catch(Error exc) { }
+        catch(InterruptedException exc) { }
+        catch(Throwable exc) { } //6: ok; latest: unreachable
+    }
+
+    void m28() {
+        try {
+            runtime();
+        }
+        catch(RuntimeException exc) { }
+        catch(Error exc) { }
+        catch(InterruptedException exc) { } //never thrown in try
+        catch(Throwable exc) { } //6: ok; latest: unreachable
+    }
+
+    void m29() {
+        try {
+            nothing();
+        }
+        catch(RuntimeException exc) { }
+        catch(Error exc) { }
+        catch(InterruptedException exc) { } //never thrown in try
+        catch(Throwable exc) { } //6: ok; latest: unreachable
+    }
+
+    void m30() {
+        try {
+            checked();
+        }
+        catch(RuntimeException exc) { }
+        catch(Error exc) { }
+        catch(Throwable exc) { } //ok
+    }
+
+    void m31() {
+        try {
+            runtime();
+        }
+        catch(RuntimeException exc) { }
+        catch(Error exc) { }
+        catch(Throwable exc) { } //6: ok; latest: unreachable
+    }
+
+    void m32() {
+        try {
+            nothing();
+        }
+        catch(RuntimeException exc) { }
+        catch(Error exc) { }
+        catch(Throwable exc) { } //6: ok; latest: unreachable
+    }
+
+    void m33() {
+        try {
+            checked();
+        }
+        catch(InterruptedException exc) { } //ok
+    }
+
+    void m34() {
+        try {
+            runtime();
+        }
+        catch(InterruptedException exc) { } //never thrown in try
+    }
+
+    void m35() {
+        try {
+            nothing();
+        }
+        catch(InterruptedException exc) { } //never thrown in try
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6558548/T6558548_6.out	Wed Mar 16 11:12:26 2011 +0000
@@ -0,0 +1,9 @@
+- compiler.warn.source.no.bootclasspath: 1.6
+T6558548.java:159:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+T6558548.java:168:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+T6558548.java:239:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+T6558548.java:249:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+T6558548.java:291:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+T6558548.java:298:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+6 errors
+1 warning
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6558548/T6558548_latest.out	Wed Mar 16 11:12:26 2011 +0000
@@ -0,0 +1,23 @@
+T6558548.java:20:9: compiler.warn.unreachable.catch: java.io.FileNotFoundException
+T6558548.java:134:9: compiler.warn.unreachable.catch: java.lang.RuntimeException
+T6558548.java:142:9: compiler.warn.unreachable.catch: java.lang.RuntimeException
+T6558548.java:151:9: compiler.warn.unreachable.catch.1: java.lang.InterruptedException,java.lang.RuntimeException
+T6558548.java:159:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+T6558548.java:160:9: compiler.warn.unreachable.catch: java.lang.RuntimeException
+T6558548.java:168:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+T6558548.java:169:9: compiler.warn.unreachable.catch: java.lang.RuntimeException
+T6558548.java:185:9: compiler.warn.unreachable.catch: java.lang.RuntimeException
+T6558548.java:193:9: compiler.warn.unreachable.catch: java.lang.RuntimeException
+T6558548.java:211:9: compiler.warn.unreachable.catch.1: java.lang.RuntimeException,java.lang.Error
+T6558548.java:220:9: compiler.warn.unreachable.catch.1: java.lang.RuntimeException,java.lang.Error
+T6558548.java:230:9: compiler.warn.unreachable.catch.1: java.lang.InterruptedException,java.lang.RuntimeException,java.lang.Error
+T6558548.java:239:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+T6558548.java:240:9: compiler.warn.unreachable.catch.1: java.lang.RuntimeException,java.lang.Error
+T6558548.java:249:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+T6558548.java:250:9: compiler.warn.unreachable.catch.1: java.lang.RuntimeException,java.lang.Error
+T6558548.java:268:9: compiler.warn.unreachable.catch.1: java.lang.RuntimeException,java.lang.Error
+T6558548.java:277:9: compiler.warn.unreachable.catch.1: java.lang.RuntimeException,java.lang.Error
+T6558548.java:291:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+T6558548.java:298:9: compiler.err.except.never.thrown.in.try: java.lang.InterruptedException
+6 errors
+15 warnings
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/UnreachableCatch.java	Wed Mar 16 11:12:26 2011 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+// key: compiler.warn.unreachable.catch
+
+class UnreachableCatch {
+
+    void test() {
+        try {
+            throw new java.io.FileNotFoundException();
+        }
+        catch(java.io.FileNotFoundException exc) { }
+        catch(java.io.IOException exc) { } //unreachable
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/UnreachableCatch1.java	Wed Mar 16 11:12:26 2011 +0000
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+// key: compiler.warn.unreachable.catch.1
+
+class UnreachableCatch1 {
+
+    void test() {
+        try {
+            throw new IllegalArgumentException();
+        }
+        catch(Error err) { }
+        catch(RuntimeException rex) { }
+        catch(Throwable t) { } //unreachable
+    }
+}