You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Java] Question on Overrides of Generic Methods #3490
/** class representing java.util.Collection.toArray(T[]) */classCollectionToArrayextendsMethod{CollectionToArray(){this.getDeclaringType().hasQualifiedName("java.util","Collection")andthis.hasName("toArray")andthis.getNumberOfParameters()=1}}/** class representing calls to java.util.Collection.toArray(T[]) */classCollectionToArrayCallextendsMethodAccess{CollectionToArrayCall(){exists(CollectionToArraym|this.getMethod().getSourceDeclaration().overrides*(m))}/** the call's actual return type, as determined from its argument */ArraygetActualReturnType(){result=this.getArgument(0).getType()}}
Notice the use of getSourceDeclaration and overrides in the constructor of CollectionToArrayCall: we want to find calls to Collection.toArray and to any method that overrides it, as well as any parameterized instances of these methods. In our example above, for instance, the call l.toArray resolves to method toArray in the raw class ArrayList.
Question:
Why does the query, that requires the method to be declared in a specific type, not work?
If I understand the documentation correctly, this should work.
Am I misunderstanding what " and to any method that overrides it" means?
Thank you for finding this bug in the tutorial. We'll get that fixed. The TLDR of this is that you can use either .overridesOrInstantiates*(m) or .getASourceOverriddenMethod*() = m in place of .overrides*(m) for this to work properly.
The longer explanation of what goes wrong is this:
Consider a class MyListCollection<E> implements Collection<List<E>>. In this class the method MyListCollection<E>::toArray overrides Collection<List<E>>::toArray, which is is an instantiation of Collection<T>::toArray (modelled here as the QL class CollectionToArray), so if we only look for straight overrides we won't reach CollectionToArray. This example highlights the issue, but the same thing happens for all other subtypes of Collection. Take for instance List<E> extends Collection<E>; again List<E>::toArray overrides Collection<E>::toArray, which isn't the same method as Collection<T>::toArray since one type variable is the one from the definition of List and the other is the one from the definition of Collection. I've used the names E and T here to highlight the difference, but they could equally well both be named T without changing the issue. With all this in mind we could also use yet another (slightly more verbose fix):
CollectionToArrayCall() {
exists(CollectionToArray m, Method overridden |
this.getMethod().getSourceDeclaration().overrides*(overridden) and
overridden.getSourceDeclaration() = m
)
}
Activity
aschackmull commentedon May 22, 2020
Thank you for finding this bug in the tutorial. We'll get that fixed. The TLDR of this is that you can use either
.overridesOrInstantiates*(m)or.getASourceOverriddenMethod*() = min place of.overrides*(m)for this to work properly.The longer explanation of what goes wrong is this:
Consider a class
MyListCollection<E> implements Collection<List<E>>. In this class the methodMyListCollection<E>::toArrayoverridesCollection<List<E>>::toArray, which is is an instantiation ofCollection<T>::toArray(modelled here as the QL classCollectionToArray), so if we only look for straight overrides we won't reachCollectionToArray. This example highlights the issue, but the same thing happens for all other subtypes ofCollection. Take for instanceList<E> extends Collection<E>; againList<E>::toArrayoverridesCollection<E>::toArray, which isn't the same method asCollection<T>::toArraysince one type variable is the one from the definition ofListand the other is the one from the definition ofCollection. I've used the namesEandThere to highlight the difference, but they could equally well both be namedTwithout changing the issue. With all this in mind we could also use yet another (slightly more verbose fix):