-
Bug
-
Resolution: Fixed
-
P3
-
22, 23
-
b11
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8341114 | 23.0.2 | Liam Miller-Cushon | P3 | Resolved | Fixed | b01 |
[As seen in https://github.com/uber/NullAway/issues/1011 ]
After the fix forJDK-8225377, type annotations are sometimes incorrectly attached to the wrong contained type if the same type appears multiple times. For example given `Function<B, @N B>` below, the annotation is attached to the first occurrence of `B`, resulting in `Function<@N B, B>`.
The fix forJDK-8225377 relies on the identity of `Type` instances to find the position of types with type annotations, and then to rewrite them: https://github.com/openjdk/jdk/blob/8bd3cd51562ff9e76fa0e3d49d38e6e19210f878/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java#L2464-L2470
This was done to share logic for rewriting types with TypeAnnotationTypeMapping, but relies on the incorrect assumption that the contained types will have unique identities.
Demo:
=== ./B.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.function.Function;
public class B {
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface N {}
void g(Function<B, @N B> f) {}
}
=== ./P.java
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
@SupportedAnnotationTypes("*")
public class P extends AbstractProcessor {
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
boolean first = true;
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!first) {
return false;
}
first = false;
for (var m :
ElementFilter.methodsIn(
processingEnv.getElementUtils().getTypeElement("B").getEnclosedElements())) {
System.err.println(m);
}
return false;
}
}
$ javac -fullversion
javac full version "23-ea+35-2364"
$ javac P.java
Compiling B.java from source shows the annotation in the correct location on the second type argument:
$ javac -processor P B.java
g(java.util.function.Function<B,@B.N B>)
After reading B.class the annotation is incorrectly placed on the first type argument:
$ javac -processor P B
g(java.util.function.Function<@B.N B,B>)
After the fix for
The fix for
This was done to share logic for rewriting types with TypeAnnotationTypeMapping, but relies on the incorrect assumption that the contained types will have unique identities.
Demo:
=== ./B.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.function.Function;
public class B {
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface N {}
void g(Function<B, @N B> f) {}
}
=== ./P.java
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
@SupportedAnnotationTypes("*")
public class P extends AbstractProcessor {
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
boolean first = true;
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!first) {
return false;
}
first = false;
for (var m :
ElementFilter.methodsIn(
processingEnv.getElementUtils().getTypeElement("B").getEnclosedElements())) {
System.err.println(m);
}
return false;
}
}
$ javac -fullversion
javac full version "23-ea+35-2364"
$ javac P.java
Compiling B.java from source shows the annotation in the correct location on the second type argument:
$ javac -processor P B.java
g(java.util.function.Function<B,@B.N B>)
After reading B.class the annotation is incorrectly placed on the first type argument:
$ javac -processor P B
g(java.util.function.Function<@B.N B,B>)
- backported by
-
JDK-8341114 Type annotation attached to incorrect type during class reading
- Resolved
- links to
-
Commit(master) openjdk/jdk23u/a55e4763
-
Commit(master) openjdk/jdk/8d083147
-
Review(master) openjdk/jdk23u/67
-
Review(master) openjdk/jdk/20460