eclipse-jdt / eclipse-jdt/eclipse.jdt.core

JDT APT `Elements#overrides` provides incorrect response for generic methods in multi level nesting

Open
#2,403 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.