Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8337795

Type annotation attached to incorrect type during class reading

XMLWordPrintable

    • b11

        [As seen in https://github.com/uber/NullAway/issues/1011 ]

        After the fix for JDK-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 for JDK-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>)

              cushon Liam Miller-Cushon
              cushon Liam Miller-Cushon
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

                Created:
                Updated:
                Resolved: