Community
Participate
Working Groups
I20050923-1000 We have an issue with raw references to a non-generic inner type of a generic type. public class NodeList<E> { public class Cursor { } private Cursor raw; // wrong non-generic type binding (bug 110806: declaring class is generic) private NodeList.Cursor rawQualified; // raw type binding (an issue for bug 110594) private NodeList<E>.Cursor parameterized; // non-generic type binding, only declaring class is generic (bug 80472) private NodeList<String>.Cursor parameterizedString; // non-generic type binding, only declaring class is parameterized } Currently, the javadoc of ITypeBinding#getTypeDeclaration() says that for raw and parameterized types, it "[..] returns the binding for the corresponding generic type. For other type bindings, this returns the same binding." The type of "NodeList.Cursor rawQualified;" is a raw type, whose getTypeDeclaration() is a non-generic type. This contradicts the javadoc and confuses clients who assume they always get a generic type from a raw type (e.g. our bug 110594). I see that "NodeList.Cursor rawQualified;" is in a way "raw", and that it must be a different binding than the declaration of Cursor. IMO, the declaration of Cursor should be a generic binding (without type parameters, since these are only declared by the enclosing type NodeList). The alternative would be to make NodeList.Cursor in "NodeList.Cursor rawQualified;" a non-generic type. But then we would have to update the spec of getTypeDeclaration() to also explain that it does not necessarily return the same type for non-generic types.
State in I20051116-1332 + jdt.core from HEAD (bug 80472 fixed): public class NodeList<E> { public class Cursor { } private Cursor simple; private NodeList<E>.Cursor parameterized; private NodeList<String>.Cursor parameterizedString; // type is non-generic, declaring class is parameterized // type declaration of type is non-generic, declaring class is generic private NodeList.Cursor rawQualified; // type is raw, declaring class is raw // type is declaration of type is non-generic, declaring class is generic } 2 issues remaining: (A) The first group violates the contract of ITypeBinding#getTypeDeclaration(), which states that for non-generic types, the same binding is returned => I don't see a solution other than updating the spec to tell that a different non-generic binding will be returned when one of the declaring types/methods was parameterized. (B) The 'NodeList.Cursor rawQualified' case also violates the contract for ITypeBinding#getTypeDeclaration(), since it doesn't return a generic type for the raw target. => Here, the kind of the type binding should be changed to a non-generic type, whose declaring class is a raw type. Like in (A), the type declaration should be a different non-generic type, whose declaring class is a generic type. The type declarations for all kinds of type references to Cursor are currently correct and identical to the binding we get from the declaration.
Olivier - pls align the spec with the implementation along the lines described by Markus.
Would this be fine? /** * Returns the binding for the type declaration corresponding to this type * binding. * <p>For parameterized types ({@link #isParameterizedType()}), * this method returns the binding for the corresponding generic type.</p> * <p>For raw types ({@link #isRawType()}), the type declaration is a different * non-generic type, whose declaring class is a generic type.</p> * <p>A different non-generic binding will be returned when one of the declaring * types/methods was parameterized.</p> * <p>For other type bindings, this returns the same binding.</p> * * @return the type binding * @since 3.1 */
JLS3 4.8 specifies that a member type reference is raw if its declaring type is raw (regardless of the member type's parameterization). This supports the current implementation and speaks against the change I proposed in (B), so a javadoc update should be enough. The proposal in comment 3 does not tell about the case where a raw type is not a member type. I'd propose this change: /** * Returns the binding for the type declaration corresponding to this type * binding. * <p>For parameterized types ({@link #isParameterizedType()}) * and most raw types ({@link #isRawType()}), this method returns the binding * for the corresponding generic type.</p> * <p>For raw member types ({@link #isRawType()}, {@link #isMember()}) * of a raw declaring class, the type declaration is a generic or a non-generic * type.</p> * <p>A different non-generic binding will be returned when one of the declaring * types/methods was parameterized.</p> * <p>For other type bindings, this returns the same binding.</p> * * @return the type binding * @since 3.1 */ public ITypeBinding getTypeDeclaration();
Fixed and released in HEAD. Thanks Markus.
Verified for 3.2 RC1 using build I20060413-0010