Community
Participate
Working Groups
The following produces error in Eclipse, but no error happens from Oracle/Sun java compiler or from other IDEs: interface A{ void authenticateUser(String username, String password) throws javax.naming.NameNotFoundException, javax.naming.NamingException; } interface B extends A{ void authenticateUser(String username, String password) throws javax.naming.NamingException; } B b = new B() { @Override public void authenticateUser(String username, String password) {} }; try { b.authenticateUser("", ""); } catch (NameNotFoundException e) { } catch(javax.naming.InterruptedNamingException e){ //Eclipse ERROR: Unreachable catch block for InterruptedNamingException. //This exception is never thrown from the try statement body } No problem when going through the base interface. I have 3rd party lib that has this hierarchy and throws specifications (which I've simplified above). Not something I can change. But also there is no error from standard Java compiler or other IDEs.
Please provide a complete test case that reproduces this issue. This will help identifying what could be wrong. Thanks.
Reducing severity. Might reassess once a test case is provided.
I can reproduce (in 4.2.0) given the example from comment 0. The method in B declares to throw NamingException, which is a common supertype of NameNotFoundException, InterruptedNamingException and others. It seems that ECJ erroneously believes that catching NameNotFoundException already covers InterruptedNameingException, too, which is not true. The bug does not occur when B is a class and no anonymous class is involved. The bug also disappears when removing the redundant NameNotFoundException in the throws list in A. Also: the redundant declaration must be in A, not in B to trigger the bug. Another symptom of the bug is that a real error is not reported: NamingException itself is not handled.
I provided the complete case. It simply needs to be copy/pasted into java source file in eclipse. Why else is needed? There is no 3rd party source. It's just simple standard java.
(In reply to comment #4) > I provided the complete case. It simply needs to be copy/pasted into java > source file in eclipse. Why else is needed? There is no 3rd party source. > It's just simple standard java. Don't worry: (In reply to comment #3) > I can reproduce (in 4.2.0) given the example from comment 0.
I have a patch under test, which fixes the problem based on the following understanding: The root of the problem is the redundant throws clause in A (avoiding this redundancy also avoids the problem, i.e., a workaround exists). If method lookup passes through Scope.mostSpecificMethodBinding() and if shouldIntersectExceptions is set to true, a flat list of exceptions is filtered as to eliminate more general exceptions in favour of more specific ones. This elimination is only correct for exceptions from different interfaces, like: (A, B independent, E1 subtype of E): A#foo throws E B#foo throws E1 I extends A, B -> I#foo can only throw E1 But concluding from (A1 subtype of A) A#foo throws E, E1 A1#foo throws E C implements A1 that C#foo can only throw E1 is wrong. My patch addresses this by splitting the filtering of exceptions inside Scope.mostSpecificMethodBinding(): (1) exceptions thrown from the same method are first filtered to favour more general exceptions (so we don't lose any exceptions that can possibly be thrown) (2) only after that first step for filtering, eliminate by favouring more specific exceptions over more general ones.
Created attachment 221112 [details] patch under test This patch fixes the problem and passes tests.compiler.regression. More testing still to be done.
Tests & fix have been released for 4.3 M2 via commit bfb7aec1d503f7f6d62839e0fbbc7dbce023c93b. I briefly considered caching the result from exception filtering, because this function has O(n^2) effort, but experiments with compiling the jdt.ui plugin showed a total of only 18 executions of this method (not counting very early exits), all of which had n==2, so there wasn't really much time spent in this method, not enough to justify the memory for caching.
(In reply to comment #4) > I provided the complete case. It simply needs to be copy/pasted into java > source file in eclipse. Why else is needed? There is no 3rd party source. > It's just simple standard java. Nope, comment#0 case needs slight fixing: Here is a proper case: //------ import javax.naming.NameNotFoundException; import javax.naming.NamingException; interface A { void authenticateUser(String username, String password) throws javax.naming.NameNotFoundException, javax.naming.NamingException; } interface B extends A{ void authenticateUser(String username, String password) throws javax.naming.NamingException; } class C { public static void main(String[] args) { B b = new B() { public void authenticateUser(String username, String password) {} }; try { b.authenticateUser("", ""); } catch (NameNotFoundException e) { } catch(javax.naming.InterruptedNamingException e){ } catch (NamingException e) { e.printStackTrace(); } } }
Verified for 4.3 M2 using Build id: I20120917-0800