Community
Participate
Working Groups
With generics and covariance these rules got complex. Method on bindings like - IMethodBinding.override(IMethodBinding ....) - ITypeBinding.isConform(ITypeBinding...) would help.
Need API to answer questions like method overloads another method as well.
Should "only" be surfacing compiler services thru DOM bindings.
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)
*** Bug 69021 has been marked as a duplicate of this bug. ***
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.
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.
Added the following APIs: ITypeBinding#isAssignmentCompatible(ITypeBinding) ITypeBinding#isCastCompatible(ITypeBinding) ITypeBinding#isSubTypeCompatible(ITypeBinding) IMethodBinding#overrides(IMethodBinding) Tests are in CompatibilityRulesTests.
Dirk, Markus, please let me know if you agree with comment 6, or if you don't need any API for overloading.
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.
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).
> "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);
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.
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.
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).
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) ?
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
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.
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.
Added IMethodBinding#isSubsignature(IMethodBinding). Added tests CompatibilityRulesTests#test025() to test028()
Verified in I20050330-0500