diff -r 9bc1baa22a83 -r 46ac954e4a84 langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java --- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Tue May 14 13:55:35 2013 -0700 +++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Tue May 14 15:04:06 2013 -0700 @@ -49,12 +49,16 @@ import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntryKind; import com.sun.tools.javac.code.TypeTag; import com.sun.tools.javac.code.Symbol.VarSymbol; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.comp.Annotate.Annotator; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCLambda; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCNewClass; import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.TreeScanner; @@ -81,17 +85,18 @@ * determine the correct positions for type annotations. * This version only visits types in signatures and should be * called from MemberEnter. - * The method returns the Annotator object that should be added - * to the correct Annotate queue for later processing. + * The method takes the Annotate object as parameter and + * adds an Annotator to the correct Annotate queue for + * later processing. */ - public static Annotator organizeTypeAnnotationsSignatures(final Symtab syms, final Names names, - final Log log, final JCClassDecl tree) { - return new Annotator() { + public static void organizeTypeAnnotationsSignatures(final Symtab syms, final Names names, + final Log log, final JCClassDecl tree, Annotate annotate) { + annotate.afterRepeated( new Annotator() { @Override public void enterAnnotation() { new TypeAnnotationPositions(syms, names, log, true).scan(tree); } - }; + } ); } /** @@ -102,9 +107,103 @@ new TypeAnnotationPositions(syms, names, log, false).scan(tree); } - private static class TypeAnnotationPositions extends TreeScanner { + public enum AnnotationType { DECLARATION, TYPE, BOTH }; - private enum AnnotationType { DECLARATION, TYPE, BOTH }; + /** + * Determine whether an annotation is a declaration annotation, + * a type annotation, or both. + */ + public static AnnotationType annotationType(Symtab syms, Names names, + Attribute.Compound a, Symbol s) { + Attribute.Compound atTarget = + a.type.tsym.attribute(syms.annotationTargetType.tsym); + if (atTarget == null) { + return inferTargetMetaInfo(a, s); + } + Attribute atValue = atTarget.member(names.value); + if (!(atValue instanceof Attribute.Array)) { + Assert.error("annotationType(): bad @Target argument " + atValue + + " (" + atValue.getClass() + ")"); + return AnnotationType.DECLARATION; // error recovery + } + Attribute.Array arr = (Attribute.Array) atValue; + boolean isDecl = false, isType = false; + for (Attribute app : arr.values) { + if (!(app instanceof Attribute.Enum)) { + Assert.error("annotationType(): unrecognized Attribute kind " + app + + " (" + app.getClass() + ")"); + isDecl = true; + continue; + } + Attribute.Enum e = (Attribute.Enum) app; + if (e.value.name == names.TYPE) { + if (s.kind == Kinds.TYP) + isDecl = true; + } else if (e.value.name == names.FIELD) { + if (s.kind == Kinds.VAR && + s.owner.kind != Kinds.MTH) + isDecl = true; + } else if (e.value.name == names.METHOD) { + if (s.kind == Kinds.MTH && + !s.isConstructor()) + isDecl = true; + } else if (e.value.name == names.PARAMETER) { + if (s.kind == Kinds.VAR && + s.owner.kind == Kinds.MTH && + (s.flags() & Flags.PARAMETER) != 0) + isDecl = true; + } else if (e.value.name == names.CONSTRUCTOR) { + if (s.kind == Kinds.MTH && + s.isConstructor()) + isDecl = true; + } else if (e.value.name == names.LOCAL_VARIABLE) { + if (s.kind == Kinds.VAR && + s.owner.kind == Kinds.MTH && + (s.flags() & Flags.PARAMETER) == 0) + isDecl = true; + } else if (e.value.name == names.ANNOTATION_TYPE) { + if (s.kind == Kinds.TYP && + (s.flags() & Flags.ANNOTATION) != 0) + isDecl = true; + } else if (e.value.name == names.PACKAGE) { + if (s.kind == Kinds.PCK) + isDecl = true; + } else if (e.value.name == names.TYPE_USE) { + if (s.kind == Kinds.TYP || + s.kind == Kinds.VAR || + (s.kind == Kinds.MTH && !s.isConstructor() && + !s.type.getReturnType().hasTag(TypeTag.VOID)) || + (s.kind == Kinds.MTH && s.isConstructor())) + isType = true; + } else if (e.value.name == names.TYPE_PARAMETER) { + /* Irrelevant in this case */ + // TYPE_PARAMETER doesn't aid in distinguishing between + // Type annotations and declaration annotations on an + // Element + } else { + Assert.error("annotationType(): unrecognized Attribute name " + e.value.name + + " (" + e.value.name.getClass() + ")"); + isDecl = true; + } + } + if (isDecl && isType) { + return AnnotationType.BOTH; + } else if (isType) { + return AnnotationType.TYPE; + } else { + return AnnotationType.DECLARATION; + } + } + + /** Infer the target annotation kind, if none is give. + * We only infer declaration annotations. + */ + private static AnnotationType inferTargetMetaInfo(Attribute.Compound a, Symbol s) { + return AnnotationType.DECLARATION; + } + + + private static class TypeAnnotationPositions extends TreeScanner { private final Symtab syms; private final Names names; @@ -154,7 +253,7 @@ ListBuffer typeAnnos = new ListBuffer(); for (Attribute.Compound a : annotations) { - switch (annotationType(a, sym)) { + switch (annotationType(syms, names, a, sym)) { case DECLARATION: declAnnos.append(a); break; @@ -175,6 +274,10 @@ sym.annotations.reset(); sym.annotations.setDeclarationAttributes(declAnnos.toList()); + if (typeAnnos.isEmpty()) { + return; + } + List typeAnnotations = typeAnnos.toList(); if (type == null) { @@ -190,16 +293,33 @@ if (sym.getKind() == ElementKind.METHOD) { sym.type.asMethodType().restype = type; + } else if (sym.getKind() == ElementKind.PARAMETER) { + sym.type = type; + if (sym.getQualifiedName().equals(names._this)) { + sym.owner.type.asMethodType().recvtype = type; + // note that the typeAnnotations will also be added to the owner below. + } else { + MethodType methType = sym.owner.type.asMethodType(); + List params = ((MethodSymbol)sym.owner).params; + List oldArgs = methType.argtypes; + ListBuffer newArgs = new ListBuffer(); + while (params.nonEmpty()) { + if (params.head == sym) { + newArgs.add(type); + } else { + newArgs.add(oldArgs.head); + } + oldArgs = oldArgs.tail; + params = params.tail; + } + methType.argtypes = newArgs.toList(); + } } else { sym.type = type; } sym.annotations.appendUniqueTypes(typeAnnotations); - if (sym.getKind() == ElementKind.PARAMETER && - sym.getQualifiedName().equals(names._this)) { - sym.owner.type.asMethodType().recvtype = type; - // note that the typeAnnotations will also be added to the owner below. - } + if (sym.getKind() == ElementKind.PARAMETER || sym.getKind() == ElementKind.LOCAL_VARIABLE || sym.getKind() == ElementKind.RESOURCE_VARIABLE || @@ -276,10 +396,21 @@ TypeAnnotationPosition p = a.position; p.location = p.location.prependList(depth.toList()); } + typetree.type = toreturn; return toreturn; } else if (type.hasTag(TypeTag.TYPEVAR)) { // Nothing to do for type variables. return type; + } else if (type.getKind() == TypeKind.UNION) { + // There is a TypeKind, but no TypeTag. + JCTypeUnion tutree = (JCTypeUnion) typetree; + JCExpression fst = tutree.alternatives.get(0); + Type res = typeWithAnnotations(fst, fst.type, annotations, log); + fst.type = res; + // TODO: do we want to set res as first element in uct.alternatives? + // UnionClassType uct = (com.sun.tools.javac.code.Type.UnionClassType)type; + // Return the un-annotated union-type. + return type; } else { Type enclTy = type; Element enclEl = type.asElement(); @@ -357,6 +488,7 @@ } Type ret = typeWithAnnotations(type, enclTy, annotations); + typetree.type = ret; return ret; } } @@ -480,94 +612,6 @@ return new Attribute.TypeCompound(a, p); } - private AnnotationType annotationType(Attribute.Compound a, Symbol s) { - Attribute.Compound atTarget = - a.type.tsym.attribute(syms.annotationTargetType.tsym); - if (atTarget == null) { - return inferTargetMetaInfo(a, s); - } - Attribute atValue = atTarget.member(names.value); - if (!(atValue instanceof Attribute.Array)) { - Assert.error("annotationType(): bad @Target argument " + atValue + - " (" + atValue.getClass() + ")"); - return AnnotationType.DECLARATION; // error recovery - } - Attribute.Array arr = (Attribute.Array) atValue; - boolean isDecl = false, isType = false; - for (Attribute app : arr.values) { - if (!(app instanceof Attribute.Enum)) { - Assert.error("annotationType(): unrecognized Attribute kind " + app + - " (" + app.getClass() + ")"); - isDecl = true; - continue; - } - Attribute.Enum e = (Attribute.Enum) app; - if (e.value.name == names.TYPE) { - if (s.kind == Kinds.TYP) - isDecl = true; - } else if (e.value.name == names.FIELD) { - if (s.kind == Kinds.VAR && - s.owner.kind != Kinds.MTH) - isDecl = true; - } else if (e.value.name == names.METHOD) { - if (s.kind == Kinds.MTH && - !s.isConstructor()) - isDecl = true; - } else if (e.value.name == names.PARAMETER) { - if (s.kind == Kinds.VAR && - s.owner.kind == Kinds.MTH && - (s.flags() & Flags.PARAMETER) != 0) - isDecl = true; - } else if (e.value.name == names.CONSTRUCTOR) { - if (s.kind == Kinds.MTH && - s.isConstructor()) - isDecl = true; - } else if (e.value.name == names.LOCAL_VARIABLE) { - if (s.kind == Kinds.VAR && - s.owner.kind == Kinds.MTH && - (s.flags() & Flags.PARAMETER) == 0) - isDecl = true; - } else if (e.value.name == names.ANNOTATION_TYPE) { - if (s.kind == Kinds.TYP && - (s.flags() & Flags.ANNOTATION) != 0) - isDecl = true; - } else if (e.value.name == names.PACKAGE) { - if (s.kind == Kinds.PCK) - isDecl = true; - } else if (e.value.name == names.TYPE_USE) { - if (s.kind == Kinds.TYP || - s.kind == Kinds.VAR || - (s.kind == Kinds.MTH && !s.isConstructor() && - !s.type.getReturnType().hasTag(TypeTag.VOID)) || - (s.kind == Kinds.MTH && s.isConstructor())) - isType = true; - } else if (e.value.name == names.TYPE_PARAMETER) { - /* Irrelevant in this case */ - // TYPE_PARAMETER doesn't aid in distinguishing between - // Type annotations and declaration annotations on an - // Element - } else { - Assert.error("annotationType(): unrecognized Attribute name " + e.value.name + - " (" + e.value.name.getClass() + ")"); - isDecl = true; - } - } - if (isDecl && isType) { - return AnnotationType.BOTH; - } else if (isType) { - return AnnotationType.TYPE; - } else { - return AnnotationType.DECLARATION; - } - } - - /** Infer the target annotation kind, if none is give. - * We only infer declaration annotations. - */ - private static AnnotationType inferTargetMetaInfo(Attribute.Compound a, Symbol s) { - return AnnotationType.DECLARATION; - } - /* This is the beginning of the second part of organizing * type annotations: determine the type annotation positions. @@ -585,7 +629,13 @@ switch (frame.getKind()) { case TYPE_CAST: + JCTypeCast frameTC = (JCTypeCast) frame; p.type = TargetType.CAST; + if (frameTC.clazz.hasTag(Tag.TYPEINTERSECTION)) { + // This case was already handled by INTERSECTION_TYPE + } else { + p.type_index = 0; + } p.pos = frame.pos; return; @@ -595,8 +645,22 @@ return; case NEW_CLASS: - JCNewClass frameNewClass = (JCNewClass)frame; - if (frameNewClass.typeargs.contains(tree)) { + JCNewClass frameNewClass = (JCNewClass) frame; + if (frameNewClass.def != null) { + // Special handling for anonymous class instantiations + JCClassDecl frameClassDecl = frameNewClass.def; + if (frameClassDecl.extending == tree) { + p.type = TargetType.CLASS_EXTENDS; + p.type_index = -1; + } else if (frameClassDecl.implementing.contains(tree)) { + p.type = TargetType.CLASS_EXTENDS; + p.type_index = frameClassDecl.implementing.indexOf(tree); + } else { + // In contrast to CLASS below, typarams cannot occur here. + Assert.error("Could not determine position of tree " + tree + + " within frame " + frame); + } + } else if (frameNewClass.typeargs.contains(tree)) { p.type = TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT; p.type_index = frameNewClass.typeargs.indexOf(tree); } else { @@ -649,6 +713,8 @@ } case PARAMETERIZED_TYPE: { + List newPath = path.tail; + if (((JCTypeApply)frame).clazz == tree) { // generic: RAW; noop } else if (((JCTypeApply)frame).arguments.contains(tree)) { @@ -656,13 +722,21 @@ int arg = taframe.arguments.indexOf(tree); p.location = p.location.prepend(new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg)); - locateNestedTypes(taframe.type, p); + Type typeToUse; + if (newPath.tail != null && newPath.tail.head.hasTag(Tag.NEWCLASS)) { + // If we are within an anonymous class instantiation, use its type, + // because it contains a correctly nested type. + typeToUse = newPath.tail.head.type; + } else { + typeToUse = taframe.type; + } + + locateNestedTypes(typeToUse, p); } else { Assert.error("Could not determine type argument position of tree " + tree + " within frame " + frame); } - List newPath = path.tail; resolveFrame(newPath.head, newPath.tail.head, newPath, p); return; } @@ -780,6 +854,9 @@ default: Assert.error("Found unexpected type annotation for variable: " + v + " with kind: " + v.getKind()); } + if (v.getKind() != ElementKind.FIELD) { + v.owner.annotations.appendUniqueTypes(v.getRawTypeAttributes()); + } return; case ANNOTATED_TYPE: { @@ -789,6 +866,11 @@ // not care about inner types. JCAnnotatedType atypetree = (JCAnnotatedType) frame; final Type utype = atypetree.underlyingType.type; + if (utype == null) { + // This might happen during DeferredAttr; + // we will be back later. + return; + } Symbol tsym = utype.tsym; if (tsym.getKind().equals(ElementKind.TYPE_PARAMETER) || utype.getKind().equals(TypeKind.WILDCARD) || @@ -806,8 +888,6 @@ } case UNION_TYPE: { - // TODO: can we store any information here to help in - // determining the final position? List newPath = path.tail; resolveFrame(newPath.head, newPath.tail.head, newPath, p); return; @@ -873,11 +953,20 @@ private static int methodParamIndex(List path, JCTree param) { List curr = path; - while (curr.head.getTag() != Tag.METHODDEF) { + while (curr.head.getTag() != Tag.METHODDEF && + curr.head.getTag() != Tag.LAMBDA) { curr = curr.tail; } - JCMethodDecl method = (JCMethodDecl)curr.head; - return method.params.indexOf(param); + if (curr.head.getTag() == Tag.METHODDEF) { + JCMethodDecl method = (JCMethodDecl)curr.head; + return method.params.indexOf(param); + } else if (curr.head.getTag() == Tag.LAMBDA) { + JCLambda lambda = (JCLambda)curr.head; + return lambda.params.indexOf(param); + } else { + Assert.error("methodParamIndex expected to find method or lambda for param: " + param); + return -1; + } } // Each class (including enclosed inner classes) is visited separately. @@ -889,6 +978,7 @@ if (isInClass) return; isInClass = true; + if (sigOnly) { scan(tree.mods); scan(tree.typarams); @@ -910,7 +1000,9 @@ return; } if (sigOnly) { - { + if (!tree.mods.annotations.isEmpty()) { + // Nothing to do for separateAnnotationsKinds if + // there are no annotations of either kind. TypeAnnotationPosition pos = new TypeAnnotationPosition(); pos.type = TargetType.METHOD_RETURN; if (tree.sym.isConstructor()) { @@ -923,7 +1015,10 @@ tree.sym, pos); } } - if (tree.recvparam != null && tree.recvparam.sym != null) { + if (tree.recvparam != null && tree.recvparam.sym != null && + !tree.recvparam.mods.annotations.isEmpty()) { + // Nothing to do for separateAnnotationsKinds if + // there are no annotations of either kind. // TODO: make sure there are no declaration annotations. TypeAnnotationPosition pos = new TypeAnnotationPosition(); pos.type = TargetType.METHOD_RECEIVER; @@ -933,11 +1028,15 @@ } int i = 0; for (JCVariableDecl param : tree.params) { - TypeAnnotationPosition pos = new TypeAnnotationPosition(); - pos.type = TargetType.METHOD_FORMAL_PARAMETER; - pos.parameter_index = i; - pos.pos = param.vartype.pos; - separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos); + if (!param.mods.annotations.isEmpty()) { + // Nothing to do for separateAnnotationsKinds if + // there are no annotations of either kind. + TypeAnnotationPosition pos = new TypeAnnotationPosition(); + pos.type = TargetType.METHOD_FORMAL_PARAMETER; + pos.parameter_index = i; + pos.pos = param.vartype.pos; + separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos); + } ++i; } } @@ -958,16 +1057,53 @@ pop(); } + /* Store a reference to the current lambda expression, to + * be used by all type annotations within this expression. + */ + private JCLambda currentLambda = null; + + public void visitLambda(JCLambda tree) { + JCLambda prevLambda = currentLambda; + try { + currentLambda = tree; + + int i = 0; + for (JCVariableDecl param : tree.params) { + if (!param.mods.annotations.isEmpty()) { + // Nothing to do for separateAnnotationsKinds if + // there are no annotations of either kind. + TypeAnnotationPosition pos = new TypeAnnotationPosition(); + pos.type = TargetType.METHOD_FORMAL_PARAMETER; + pos.parameter_index = i; + pos.pos = param.vartype.pos; + pos.onLambda = tree; + separateAnnotationsKinds(param.vartype, param.sym.type, param.sym, pos); + } + ++i; + } + + push(tree); + scan(tree.body); + scan(tree.params); + pop(); + } finally { + currentLambda = prevLambda; + } + } + /** * Resolve declaration vs. type annotations in variable declarations and * then determine the positions. */ @Override public void visitVarDef(final JCVariableDecl tree) { - if (tree.sym == null) { + if (tree.mods.annotations.isEmpty()) { + // Nothing to do for separateAnnotationsKinds if + // there are no annotations of either kind. + } else if (tree.sym == null) { // Something is wrong already. Quietly ignore. } else if (tree.sym.getKind() == ElementKind.PARAMETER) { - // Parameters are handled in visitMethodDef above. + // Parameters are handled in visitMethodDef or visitLambda. } else if (tree.sym.getKind() == ElementKind.FIELD) { if (sigOnly) { TypeAnnotationPosition pos = new TypeAnnotationPosition(); @@ -979,16 +1115,19 @@ TypeAnnotationPosition pos = new TypeAnnotationPosition(); pos.type = TargetType.LOCAL_VARIABLE; pos.pos = tree.pos; + pos.onLambda = currentLambda; separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); } else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { TypeAnnotationPosition pos = new TypeAnnotationPosition(); pos.type = TargetType.EXCEPTION_PARAMETER; pos.pos = tree.pos; + pos.onLambda = currentLambda; separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); } else if (tree.sym.getKind() == ElementKind.RESOURCE_VARIABLE) { TypeAnnotationPosition pos = new TypeAnnotationPosition(); pos.type = TargetType.RESOURCE_VARIABLE; pos.pos = tree.pos; + pos.onLambda = currentLambda; separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); } else if (tree.sym.getKind() == ElementKind.ENUM_CONSTANT) { // No type annotations can occur here. @@ -1031,6 +1170,40 @@ } @Override + public void visitNewClass(JCNewClass tree) { + if (tree.def != null && + !tree.def.mods.annotations.isEmpty()) { + JCClassDecl classdecl = tree.def; + TypeAnnotationPosition pos = new TypeAnnotationPosition(); + pos.type = TargetType.CLASS_EXTENDS; + pos.pos = tree.pos; + if (classdecl.extending == tree.clazz) { + pos.type_index = -1; + } else if (classdecl.implementing.contains(tree.clazz)) { + pos.type_index = classdecl.implementing.indexOf(tree.clazz); + } else { + // In contrast to CLASS elsewhere, typarams cannot occur here. + Assert.error("Could not determine position of tree " + tree); + } + Type before = classdecl.sym.type; + separateAnnotationsKinds(classdecl, tree.clazz.type, classdecl.sym, pos); + + // classdecl.sym.type now contains an annotated type, which + // is not what we want there. + // TODO: should we put this type somewhere in the superclass/interface? + classdecl.sym.type = before; + } + + scan(tree.encl); + scan(tree.typeargs); + scan(tree.clazz); + scan(tree.args); + + // The class body will already be scanned. + // scan(tree.def); + } + + @Override public void visitNewArray(JCNewArray tree) { findPosition(tree, tree, tree.annotations); int dimAnnosCount = tree.dimAnnotations.size(); @@ -1040,6 +1213,7 @@ for (int i = 0; i < dimAnnosCount; ++i) { TypeAnnotationPosition p = new TypeAnnotationPosition(); p.pos = tree.pos; + p.onLambda = currentLambda; p.type = TargetType.NEW; if (i != 0) { depth = depth.append(TypePathEntry.ARRAY); @@ -1053,18 +1227,23 @@ // int i = dimAnnosCount == 0 ? 0 : dimAnnosCount - 1; // TODO: is depth.size == i here? JCExpression elemType = tree.elemtype; + depth = depth.append(TypePathEntry.ARRAY); while (elemType != null) { if (elemType.hasTag(JCTree.Tag.ANNOTATED_TYPE)) { JCAnnotatedType at = (JCAnnotatedType)elemType; TypeAnnotationPosition p = new TypeAnnotationPosition(); p.type = TargetType.NEW; p.pos = tree.pos; - p.location = p.location.appendList(depth.toList()); + p.onLambda = currentLambda; + locateNestedTypes(elemType.type, p); + p.location = p.location.prependList(depth.toList()); setTypeAnnotationPos(at.annotations, p); elemType = at.underlyingType; } else if (elemType.hasTag(JCTree.Tag.TYPEARRAY)) { depth = depth.append(TypePathEntry.ARRAY); elemType = ((JCArrayTypeTree)elemType).elemtype; + } else if (elemType.hasTag(JCTree.Tag.SELECT)) { + elemType = ((JCFieldAccess)elemType).selected; } else { break; } @@ -1076,10 +1255,11 @@ if (!annotations.isEmpty()) { /* System.out.println("Finding pos for: " + annotations); - System.out.println(" tree: " + tree); - System.out.println(" frame: " + frame); + System.out.println(" tree: " + tree + " kind: " + tree.getKind()); + System.out.println(" frame: " + frame + " kind: " + frame.getKind()); */ TypeAnnotationPosition p = new TypeAnnotationPosition(); + p.onLambda = currentLambda; resolveFrame(tree, frame, frames.toList(), p); setTypeAnnotationPos(annotations, p); } @@ -1088,8 +1268,17 @@ private static void setTypeAnnotationPos(List annotations, TypeAnnotationPosition position) { for (JCAnnotation anno : annotations) { - ((Attribute.TypeCompound) anno.attribute).position = position; + // attribute might be null during DeferredAttr; + // we will be back later. + if (anno.attribute != null) { + ((Attribute.TypeCompound) anno.attribute).position = position; + } } } + + @Override + public String toString() { + return super.toString() + ": sigOnly: " + sigOnly; + } } }