eclipse-jdt / eclipse-jdt/eclipse.jdt.core
JDT APT `Elements#overrides` provides incorrect response for generic methods in multi level nesting
- Dominant language
- Java
- Stars
- 237
- Forks
- 195
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 47
Description
We've had a reported bug for MapStruct related to some handling of generics during our annotation processing (https://github.com/mapstruct/mapstruct/issues/3458). We've managed to create a small reproducer which only affects the Eclipse JDT compiler, but not Javac.
The model for testing looks like:
```java
package targets.model.pc.OverridingGeneric;
public class OverridingGeneric {
static abstract class Generic {
abstract T map(S source);
}
static class Identity extends Generic {
I map(I source) {
return source;
}
}
static class Impl extends Identity {
}
}
```
The processor that can be used to reproduce this looks like:
```java
@SupportedAnnotationTypes("*")
public class CustomOverridesProcessor extends AbstractProcessor {
@Override
public boolean process(Set annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
return true;
}
examineOverridesGeneric();
return true;
}
private boolean examineOverridesGeneric() {
Elements elementUtils = processingEnv.getElementUtils();
// Impl extends (Identity extends Generic).
TypeElement typeImpl = elementUtils.getTypeElement("targets.model.pc.OverridingGeneric.Impl");
TypeElement typeIdentity = elementUtils.getTypeElement("targets.model.pc.OverridingGeneric.Identity");
TypeElement typeGeneric = elementUtils.getTypeElement("targets.model.pc.OverridingGeneric.Generic");
if (typeImpl == null || typeIdentity == null || typeGeneric == null) {
reportError("Unable to find types in targets.model.pc.OverridingGeneric");
return false;
}
ExecutableElement methodGenericMap = null;
ExecutableElement methodIdentityMap = null;
for (ExecutableElement method : ElementFilter.methodsIn(typeGeneric.getEnclosedElements())) {
String name = method.getSimpleName().toString();
if ("map".equals(name)) {
methodGenericMap = method;
}
}
for (ExecutableElement method : ElementFilter.methodsIn(typeIdentity.getEnclosedElements())) {
String name = method.getSimpleName().toString();
if ("map".equals(name)) {
methodIdentityMap = method;
}
}
if (methodGenericMap == null || methodIdentityMap == null) {
reportError("examineOverridesGeneric: could not find some methods");
return false;
}
// Should override:
if (!elementUtils.overrides(methodIdentityMap, methodGenericMap, typeIdentity)) {
reportError("examineOverridesGeneric: Identity.map(I) should override Generic.map(S) in the context of Identity");
return false;
}
if (!elementUtils.overrides(methodIdentityMap, methodGenericMap, typeImpl)) {
reportError("examineOverridesGeneric: Identity.map(I) should override Generic.map(S) in the context of Impl");
return false;
}
// Should not override:
if (elementUtils.overrides(methodIdentityMap, methodIdentityMap, typeIdentity)) {
reportError("examineOverridesGeneric: Identity.map(I) should not override itself in the context of Identity");
return false;
}
if (elementUtils.overrides(methodIdentityMap, methodIdentityMap, typeImpl)) {
reportError("examineOverridesGeneric: Identity.map(I) should not override itself in the context of Impl");
return false;
}
return false;
}
protected void reportError(String message) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message);
}
}
```
If I remove the generics then everything works as expected. With javac both with and without generics it works correctly.
I tried to add this to your [`ElementsUtilProc`](https://github.com/eclipse-jdt/eclipse.jdt.core/blob/master/org.eclipse.jdt.compiler.apt.tests/processors/org/eclipse/jdt/compiler/apt/tests/processors/elementutils/ElementUtilsProc.java) and the add the `OverridingGeneric` model to your test resources https://github.com/eclipse-jdt/eclipse.jdt.core/tree/master/org.eclipse.jdt.compiler.apt.tests/resources/targets/model/pc, but as I'm not using Eclipse I couldn't really test it properly.
Contributor guide
Assessment
This issue has not been assessed yet.