type annotations inside javac

Werner Dietl wdietl at gmail.com
Wed Jan 30 18:40:19 PST 2013

Jon, all,

I've used your very useful DPrinter over the last few days to debug
these problems.
My current understanding is the following.

Let us take a look at this very simple code:

import java.lang.annotation.*;
import java.util.*;

class Test {
    @TA Test[] f;
    Test @TA[] g;

@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@interface TA {}


DPrinter trees -showTreeSymbols -showTreeTypes  -after ANALYZE

in particular gives:

    1: VARDEF type:(@TA :: Test)[] sym:f
      name: f
      mods: MODIFIERS
        annotations: [1]
          0: ANNOTATION type:TA
            annotationType: IDENT type:TA
              name: TA
            args: [0]
        flags: []
      vartype: TYPEARRAY type:Test[]
        elemtype: IDENT type:Test
          name: Test
      init: #null

    2: VARDEF type:(@TA :: Test[]) sym:g
      name: g
      mods: MODIFIERS
        annotations: [0]
        flags: []
      vartype: ANNOTATED_TYPE type:(@TA :: Test[])
        annotations: [1]
          0: TYPE_ANNOTATION type:TA
            annotationType: IDENT type:TA
              name: TA
            args: [0]
        underlyingType: TYPEARRAY type:Test[]
          elemtype: IDENT type:Test
            name: Test
      init: #null

The difference between the type annotations in field f and g are that
for f the type annotation appears in a syntactic location where also a
declaration annotation can appear.
We cannot build an JCAnnotatedType/AnnotatedTypeTree for f, because we
cannot decide at parse time whether an annotation is a type or
declaration annotation.
Therefore, the AST contains the type annotation together with the
other annotations in the modifiers.
Later, in com.sun.tools.javac.code.TypeAnnotations.TypeAnnotationPositions.separateAnnotationsKinds,
we go through all annotations and separate type and declaration
However, notice how separateAnnotationsKinds only sets sym.type with
the newly determined type - it does not modify the variable type. We
clearly see this mismatch in the output for field f.

On the other hand, there are some locations where already the parser
knows that we are dealing with a type annotation - in particular the
annotation on an array dimension, as for field g.
In this case, we generate an JCAnnotatedType/AnnotatedTypeTree and
will convert it into an AnnotatedType.
This conversion happens whenever MemberEnter or Attr asks for
attributing a type, which is much earlier than when we call
I think this is the reason why for field g we see the annotated type
in both the tree and the type.

I think it would be good to perform separateAnnotationsKinds earlier,
but I don't know what the best spot for this would be.
By performing the separation earlier, I hope that the AnnotatedType
gets propagated to more places and giving us a consistent view of the
types - regardless of whether the AST contained an AnnotatedTypeTree.

This would also make the output of the LintCast test consistent:
When the type came from an AnnotatedTypeTree, the annotation is shown
in the error message; if the annotation appeared in a declaration
location it is not shown in the error message, because
separateAnnotationsKinds has not been called yet when this semantic
check is performed.

Jon, your examples were troubled by primitive types not being copied
correctly. I've pushed a fix for this earlier tonight. I hadn't
correctly written a visitType method - which apparently is also used
for primitives. Please re-run your experiment and let me know whether
you agree with my descriptions above.

For DPrinter, it would be helpful if the usage instructions gave
information on what the first parameter (mode) can be (trees, symbols,
...) I needed to look through the source to figure this out.

Please let me know if you think my understanding of how this works is
not correct and what you think the best way to fix this is.

cu, WMD.

On Wed, Jan 30, 2013 at 5:39 PM, Jonathan Gibbons
<jonathan.gibbons at oracle.com> wrote:
> I've been investigating why javadoc is not generating type annotations in
> its output, and as part of that, I've been investigating types within javac,
> with an eye to viewing which should be annotated types.  I think this will
> also be of interest as we work on supporting javax.lang.model for type
> annotations.
> I've attached a patch (which I hope stays attached) for a demo and potential
> proto-test for looking at  these types.
> The test code is the following simple program, in which DAnno is a
> delcartion annotation, and TAnno is a type annotation.
> public class Test {
>     @DAnno @TAnno int mAnnotatedReturn() { return 0; }
>     void mAnnotatedIntParam(@DAnno @TAnno int a) { }
>     void mAnnotatedIntArrayParam(@DAnno int @TAnno [] a) { }
>     void mAnnotatedThrows() throws @TAnno Exception { }
> }
> I've then created and run an annotation processor over the code, to look at
> the internal types at the time of annotation processing -- which is of
> interest to javax.lang.model users, and is effectively the same time that
> javadoc needs the info.
> For the declarations within the test classes, I print out the symbol, and
> the types of the various parts within the symbol, where I expect to see some
> representation of an annotated type.  The output is generated with the new
> DPrinter utility API, and is also attached.
> Here's the summary:
> -- mAnnotatedReturn: type annotations are within the symbol, but the return
> type is not annotated.
> -- mAnnotatedIntParam: type annotations are within the symbol but the
> parameter type is not annotated. The same TypeCompund seems to end up on
> both the VarSymbol for the paramater and the MethodSymbol.  The decl
> annotation just ends up on the declaration, which is more what I would
> expect.
> -- mAnnotatedIntArrayParam: type annotation seems very confused on this one,
> showing up in 3 places.  The debug output is not (yet) detailed enough to
> identify which of these are ==.
> The type of the param looks correct on this one.
> -- mAnnotatedThrows: this actually looks as I would expect, although the
> debug output is a little confusing w.r.t. the display of an annotated type,
> since AnnotatedType shows the tag of the underlying type.
> -- Jon


More information about the type-annotations-dev mailing list