Bug 100233 - [1.5] Incorrect overriding marker for bad overriding with generics
Summary: [1.5] Incorrect overriding marker for bad overriding with generics
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.1   Edit
Hardware: PC Windows 2000
: P3 normal (vote)
Target Milestone: 3.1.1   Edit
Assignee: Markus Keller CLA Friend
QA Contact:
URL:
Whiteboard:
Keywords:
: 97027 (view as bug list)
Depends on:
Blocks:
 
Reported: 2005-06-15 12:44 EDT by Osvaldo Pinali Doederlein CLA Friend
Modified: 2005-09-02 09:38 EDT (History)
5 users (show)

See Also:


Attachments
Proposed path (738 bytes, patch)
2005-06-23 05:47 EDT, Dirk Baeumer CLA Friend
no flags Details | Diff
Better patch (18.86 KB, patch)
2005-08-04 10:05 EDT, Markus Keller CLA Friend
no flags Details | Diff
Patch 3 (20.99 KB, patch)
2005-08-17 06:50 EDT, Markus Keller CLA Friend
no flags Details | Diff
Tests for Patch 3 (34.17 KB, patch)
2005-08-17 06:51 EDT, Markus Keller CLA Friend
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Osvaldo Pinali Doederlein CLA Friend 2005-06-15 12:44:24 EDT
Hi.  The following code contains a bug in inheritance of generic methods:

abstract class A<T> {
  void g1 (T t) {
    System.out.println("g1 base: " + t);
  }
  void g2 (T t) {
    System.out.println("g2 base: " + t);
  }
}

public class B extends A<java.util.List<Number>> {
  void g1 (java.util.List<?> t) {
    System.out.println("g1 derived: " + t);
  }
  void g2 (java.util.List<Number> t) {
    System.out.println("g2 derived: " + t);
  }
  public static void main (String[] args) {
    B b = new B();
    b.g1(new java.util.ArrayList<Number>());
    b.g2(new java.util.ArrayList<Number>());
  }
}

Notice that B.g1() does not override A.g1() because it declares a type parameter
incompatible with the bound T->List<Number> established by class B.

The JDT compiler is working correctly; output is:

g1 base: []
g2 derived: []

and in the bytecode, B has a stub for erasure delegation g2(Object)->g2(List)
but not for g1(Object)->g1(List).

The problem is in the editor.  There is a marker saying that B.g1() overrides
A.g1(); it's wrong as there is no overriding in this case, only overloading.
I performed some experiments with variations of this example, and it seems that
the source editor ignores completely the parameters' generic types to infer
inheritance, even though it considers generic type info from class hierarchy:
if I declare B.g2(String), the overriding marker disappears because String is
not compatible with B's T->List<Number>.

If I tag B's methods with the annotation @Override, the behavior is correct.
The annotation is OK for g2(), but at g1() the compiler flags an error:
"The method g1(List<?>) of type B must override a superclass method".
This shows that the compiler and the editor's code responsible for marker
generation are not using the same strategy to validate method overriding.

This wrong marker is an usability problem, but a relatively severe one because
it induces the programmer to error.  I just had this kind of error in my app
and it was difficult to analyse because I failed to inherit a method, so the
wrong method was being invoked, but inspection of the source didn't reveal the
problem because I blindly trusted the overriding marker -- shame on me for not
using the @Override tag, I know -- so I only caught this bug after laborious
step-by-step debugging.
Comment 1 Kent Johnson CLA Friend 2005-06-15 13:06:50 EDT
Another case related to bug 97027
Comment 2 Dirk Baeumer CLA Friend 2005-06-23 05:46:47 EDT
Markus, as discussed the problem is with taking the erasure of the left hand
side in equals.

Although the fix is trivial it is risky since the method is called in various
other situations as well and we have to understand how these clients use the method.

We should investigate for 3.1.1
Comment 3 Dirk Baeumer CLA Friend 2005-06-23 05:47:22 EDT
Created attachment 23829 [details]
Proposed path
Comment 4 Markus Keller CLA Friend 2005-06-23 06:11:42 EDT
If we decide to keep our implementation of the override checking code, then we
should also rename isEqualMethod(..) to isSubsignature(..) and check all clients
and both implementations whether they are only used for override checking and
only in the right direction. Furthermore, bug 97027 should also be fixed then
(we currently don't compare method type parameters).

The alternative would be to switch to IMethodBinding#overrides(..) in cases
where we have bindings. Clients that have less strict requirements such as quick
fix (doesn't want to check return types) should then still use the old code,
unless IMethodBinding#overrides(..) gets loosened to not checking return types.
Comment 5 Markus Keller CLA Friend 2005-08-04 10:05:05 EDT
Created attachment 25674 [details]
Better patch
Comment 6 Markus Keller CLA Friend 2005-08-04 10:10:48 EDT
The patch from comment 5 also fixes the override indicator bug 97027. I updated
all clients of
isEqualMethod(IMethodBinding method, String methodName, ITypeBinding[]
parameters) to isSubsignature(IMethodBinding, IMethodBinding) where I think it
is safe.
Comment 7 Markus Keller CLA Friend 2005-08-04 10:50:07 EDT
Released the patch to HEAD.
Comment 8 Dirk Baeumer CLA Friend 2005-08-08 06:21:36 EDT
Although this is not a one line fix, I opt to put it into 3.1.1 if we see that
it works fine in the 3.2 branch.

Markus, here are some comments/questions regarding the fix:

Class Bindings:

- isSubSignature: to avoid some false positives shouldn't we only take the
  erasure of the m1Parameters when the parameter itself contains a type
  variable. Otherwise I think it isn't needed.

- areSubTypeCompatible: please check the method with Tobias and look if 
  we can remove it in favour of isSubSignature. The current implementation
  of areSubTypeCompatible doesn't look quite right either ;-)

Class StubUtility2

- findOverridingMethod: checking both isSubSignature and areSubTypeCompatible
  looks strange to me. Please check with Tobias.

Martin, Tobias can you please have a look at the patch as well and cast your votes.
Comment 9 Tobias Widmer CLA Friend 2005-08-08 09:59:53 EDT
Regarding StubUtility2#findOverridingMethod:

The conditional expression in this method can be replaced by 
Bindings#isSubSignature only, because the method Bindings#areOverriddenMethods 
effectively should implement the same behavior as Bindings#isSubSignature. The 
implementation suggested by the patch works, but does or'ed checks for the 
same thing. Method invocations to Bindings#areOverriddenMethods should 
therefore be replaced by isSubSignature

Regarding Bindings#areSubTypeCompatible

The method occurrence in areOverriddenMethods can be eliminated (see above).
The occurrence in isSignatureEquivalentConstructor actually corresponds to a 
call to isSubSignature, but without checking for the method name.

With the current API of isSubSignature, this is not possible. IMO we should be 
more flexible and offer an API where the components of a signature (name, 
parameters, exception, etc.) can be passed in separately.

+1 for 3.1.1
Comment 10 Martin Aeschlimann CLA Friend 2005-08-09 03:26:26 EDT
*** Bug 97027 has been marked as a duplicate of this bug. ***
Comment 11 Martin Aeschlimann CLA Friend 2005-08-09 03:45:26 EDT
patch looks ok to me.
Comment 12 Markus Keller CLA Friend 2005-08-17 06:50:17 EDT
Created attachment 26185 [details]
Patch 3

This (last) patch only takes the erasure where the parameters contain type
variables (Dirk's comment 8) and fixes several other issues found while writing
test cases.

The only changes w.r.t. "Better Patch" are in Bindings#isSubsignature(..) and
three new private methods.
Comment 13 Markus Keller CLA Friend 2005-08-17 06:51:39 EDT
Created attachment 26186 [details]
Tests for Patch 3
Comment 14 Dirk Baeumer CLA Friend 2005-08-17 13:20:33 EDT
Improved patch looks OK to me.
Comment 15 Martin Aeschlimann CLA Friend 2005-08-19 09:57:21 EDT
patch is OK. We now also have much more test cases -> ok to release.
Comment 16 Markus Keller CLA Friend 2005-08-19 11:40:50 EDT
Released to 3.1.1 (and HEAD).
Comment 17 Tom Hofmann CLA Friend 2005-09-02 08:40:19 EDT
verifying...
Comment 18 Tom Hofmann CLA Friend 2005-09-02 09:38:43 EDT
verified scenarios in comment 0 and bug 97027 work correctly.