Bug 73676 - [dom] Need API on bindings for overriding and assignment rules
Summary: [dom] Need API on bindings for overriding and assignment rules
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.0   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.1 M6   Edit
Assignee: Jerome Lanneluc CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 69021 (view as bug list)
Depends on:
Blocks: 71631
  Show dependency tree
 
Reported: 2004-09-10 11:25 EDT by Dirk Baeumer CLA
Modified: 2005-03-31 04:31 EST (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dirk Baeumer CLA 2004-09-10 11:25:54 EDT
With generics and covariance these rules got complex. Method on bindings like

- IMethodBinding.override(IMethodBinding ....)
- ITypeBinding.isConform(ITypeBinding...)

would help.
Comment 1 Dirk Baeumer CLA 2004-09-10 11:30:11 EDT
Need API to answer questions like method overloads another method as well.
Comment 2 Philipe Mulet CLA 2004-11-09 12:33:12 EST
Should "only" be surfacing compiler services thru DOM bindings.
Comment 3 Dirk Baeumer CLA 2004-11-10 11:53:19 EST
Questions were need answers for

ITypeBinding#isSubType(ITypeBinding) considers wild cards e.g List<String> is a
sub type of List<? extends Object>

ITypeBinding#canCast(ITypeBinding)
ITypeBinding#canAssign(ITypeBinding) considers auto boxing, conversion rules, ....

IMethodBinding#override(IMethodBinding)
IMethodBining#overloads(IMethodBinding)
Comment 4 Dirk Baeumer CLA 2004-11-18 13:12:21 EST
*** Bug 69021 has been marked as a duplicate of this bug. ***
Comment 5 Dirk Baeumer CLA 2004-11-18 13:15:06 EST
We also need API to determine if a type is a subtype of another type (see bug
69021). Something like ITypeBinding#isSubType(ITypeBinding).

Discussed with Philippe but still not 100% clear if we need both isSubType and
canAssign or is there is API for auto boxing and basic type conversion.
Comment 6 Jerome Lanneluc CLA 2004-11-25 10:12:34 EST
I don't think that IMethodBinding#overloads(IMethodBinding) makes sense.
According to the JLS2, 8.4.7, a method is overloaded in the context of a class.

So I propose to have instead:
ITypeBinding#isMethodOverloaded(IMethodBinding, IMethodBinding). 
This would return whether the 2 methods have the same selector and that each of
their declaring classes is a supertype of (or equal to) the receiver.
Comment 7 Jerome Lanneluc CLA 2004-11-26 04:23:36 EST
Added the following APIs:
ITypeBinding#isAssignmentCompatible(ITypeBinding)
ITypeBinding#isCastCompatible(ITypeBinding)
ITypeBinding#isSubTypeCompatible(ITypeBinding)
IMethodBinding#overrides(IMethodBinding)

Tests are in CompatibilityRulesTests.
Comment 8 Jerome Lanneluc CLA 2004-11-26 04:24:44 EST
Dirk, Markus, please let me know if you agree with comment 6, or if you don't
need any API for overloading.
Comment 9 Markus Keller CLA 2004-11-30 11:21:20 EST
Hi Jerome

We're still struggling with nontrivial cases like the one below, where we
honestly don't really know ourselves what results we expect of 'overrides' and
'overloads' queries.

I'm not sure which API is the right one, but I feel like 'overrides' and
'overloads' should be symmetric (either both are on ITypeBinding, or none).

interface I1<T> { void m(T t); }
interface I2<E> { void m(E e); }
interface IIntNum extends I1<Integer>, I2<Number> { }
interface IIntInt extends I1<Integer>, I2<Integer> { }

class A implements IIntNum {
	public void m(Integer i) {	}
	public void m(Number n) { }
}

class B implements IIntInt {
	public void m(Integer i) {}
}

Questions we have to answer are e.g.
- Does I1#m(T) override I2#m(E)? And in the context of IIntNum or IIntInt?
- What if IIntNum, IIntInt, A, B exist / don't exist in the system?

I will start writing test cases for these problems and see how far I get with
implementing a generics-aware RippleMethodFinder. Please allow use some days to
sort this out - we'll get back to you as soon as we have clear requirements.
Comment 10 Jerome Lanneluc CLA 2004-11-30 11:37:29 EST
I don't think 'overrides' and 'overloads' are symetrical. 'overloading' is
finding if a method name is visible more than once in the context of given type.
'overriding' is finding if a method (name + signature + return type) in a given
type is hidding  another method in another type.

Also note that for methods that are abtract (as in an interface), the method
that hides the abstract method is said to 'implement' it (even if it is also
abstract).
Comment 11 Markus Keller CLA 2004-12-03 05:37:40 EST
> "implement ... "
This should be described in the Javadoc. The overrides query should return true
if the first method overrides OR implements the other.

Both 'overrides' and 'overloads' are queries to determine the relationship
between two methods. Methods with the same name and parameters count are one of:

(a) unrelated: There's no common super- or subtype of the methods' declaring
types. A call one of the methods can never be redirected the other method by
changing the types of the invocation's arguments.

(b) overriding: The methods are related (i.e. they are not (a)), and their
erasures have the same signature.

(c) overloading: The methods are related but don't override (i.e. not (a) and
not (b)).

Let's look at this example (types A and B are unrelated:
interface I1 { void f(A a); }
interface I2 { void f(A a); void f(B b); }
interface I12 extends I1, I2 {  }

I1#f(A) is unrelated to all other methods.
I2#f(A) overloads I2#f(B) and vice versa.
I12#f(A) overrides I1#f(A) and I2#f(A), and overloads I2#f(B) and I12#f(B).
I12#f(B) overloads I1#f(A), and I2#f(A), and I12#f(A).

Since we currently don't have method bindings for I12#f(A) and I12#f(B), both
'overrides' and 'overloads' queries must be a function of three arguments:
IMethodBinding method1, IMethodBinding method2, ITypeBinding resolutionContext.

Since the queries' intent is to answer questions about methods, I think they
should be placed on IMethodBinding, and not ITypeBinding. Concluding, what I
suggest is this API on IMethodBinding:

    /**
     * ...
     * @param resolutionContext the resolution context, or <code>null</code> to
     *   the resolve in the context of the receiver's declaring type
     * @return <code>true</code> if this method overrides the given method,
     *   in the context of the given type and <code>false</code> otherwise
     */
    boolean overrides(IMethodBinding method, ITypeBinding resolutionContext);
    
	/** ... analogously ... */ 
    boolean overloads(IMethodBinding method, ITypeBinding resolutionContext);
Comment 12 Jerome Lanneluc CLA 2004-12-08 10:25:06 EST
If I understand correctly, you want to be able to determine if a method (that
doesn't exist yet) will override/overload another existing method.

Unfortunately the compiler's bindings must correspond to existing methods. So we
cannot use the compiler internal to implement what you're requesting. 

This means that we won't do any better than you, i.e. we will check if the
resolutionContext type is a subtype of the targeted method's type, then we will
check if the selector are the same, and (for the override case), we will check
if the signatures are the same.
Comment 13 Markus Keller CLA 2004-12-13 06:32:46 EST
No, we want to be able to determine whether a method overrides another method
according to the JLS. In the example from comment 11, I12#f(A) does exist (see
JLS2, 8.4.6 (Inheritance, Overriding, and Hiding): "A class inherits from its
direct superclass and direct superinterfaces all the non-private methods ...").
The source just doesn't redeclare the method, and the jdt.dom has no binding for
it (but bug 79798 suggests that such a binding would be beneficial ;-).

So, what would you suggest us to do if we need to find out whether and how the
methods from comment 11 are related?

Since we already know the relation of the types in the type hierarchy, it would
be sufficient for our use case, if we could just ask a method binding whether
its signature is a subsignature of another method binding. According to JLS3,
8.4.8.1 (Inheritance, Overriding, and Hiding > Overriding), a method m1
overrides a method m2 if "[..]2. The signature of m1 is a subsignature (ยง8.4.2)
of the signature of m2.[..]".

Therefore, a query IMethodBinding#isSubsignatureOf(IMethodBinding) would be an
alternative to the overrides/overloads queries.
Comment 14 Philipe Mulet CLA 2005-01-03 15:40:27 EST
I like the last take on subsignature. 

One thing though about I12#f(A): this method doesn't exist. Inherited methods
are not represented by bindings in subclass, as these only represent (locally)
declared methods. One has to walk the type hierarchy to find inherited methods
(and yes there could be a helper playing the accessibility/visibility rules).

Comment 15 Jerome Lanneluc CLA 2005-01-05 05:35:25 EST
Markus, given Philippe's comment #14 (especially "Inherited methods
are not represented by bindings in subclass"), should we still go in this
direction and add IMethodBinding#isSubSignature(IMethodBinding) ?
Comment 16 Martin Aeschlimann CLA 2005-01-05 05:54:31 EST
Philippe says: One has to walk the hierarchy and find inherited methods. To do
that, a method 'IMethodBinding#isSubSignature(..)' is important to be able to
filter overridden methods
class A extends B {
  foo();
}
class B() {
  foo();
}
-> Type Z extends A inherits method A.foo (but not B.foo)

I think IMethodBinding#isSubSignature(..) is a good idea as we would use that to
find a method in the hierarchy. As arguments it would be best to not have a
IMethodBinding but all you need to find a matching method (name, type binding...).

'overrides()' and 'overloads()' seems to be much more sophisticated, also
testing visibility and accessibility. It's better to have that also separate ->
isVisible, isAccessible
Comment 17 Jerome Lanneluc CLA 2005-01-06 11:36:20 EST
I'm confused. How can we have IMethodBinding#isSubSignature(...) in the case of
"I12#f(A) overrides I1#f(A) and I2#f(A)" ? What is the receiceiver ? It cannot
be I12#f(A) since it doesn't exist.
Comment 18 Dirk Baeumer CLA 2005-01-06 12:19:32 EST
The sub siugnature question doesn't take the type hierarchy into consideration.
So we would ask I1#f(A).isSubSignature(I2#f(A)). To decide if a method overrides
another method or are related by marriage of convenience the client as to take
the hierarchy into consideration.

In your case we (JDT/UI) have to check that I1 and I2 are super types of I12 to
conclude that there is a relation ship between them. Analogous to check whether
a method overrides another method. 
Comment 19 Jerome Lanneluc CLA 2005-02-24 07:22:50 EST
Added IMethodBinding#isSubsignature(IMethodBinding).
Added tests CompatibilityRulesTests#test025() to test028()
Comment 20 David Audel CLA 2005-03-31 04:31:29 EST
Verified in I20050330-0500