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

Type annotation attached to incorrect type during class reading

    XMLWordPrintable

Details

    • b11

    Description

      [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>)

      Attachments

        Issue Links

          Activity

            People

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

              Dates

                Created:
                Updated:
                Resolved: