--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Jun 26 12:22:40 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Fri Jun 26 18:51:39 2009 -0700
@@ -75,6 +75,42 @@
/** The name table. */
private Names names;
+ // Because of javac's limited lookahead, some contexts are ambiguous in
+ // the presence of type annotations even though they are not ambiguous
+ // in the absence of type annotations. Consider this code:
+ // void m(String [] m) { }
+ // void m(String ... m) { }
+ // After parsing "String", javac calls bracketsOpt which immediately
+ // returns if the next character is not '['. Similarly, javac can see
+ // if the next token is ... and in that case parse an ellipsis. But in
+ // the presence of type annotations:
+ // void m(String @A [] m) { }
+ // void m(String @A ... m) { }
+ // no finite lookahead is enough to determine whether to read array
+ // levels or an ellipsis. Furthermore, if you call bracketsOpt, then
+ // bracketsOpt first reads all the leading annotations and only then
+ // discovers that it needs to fail. bracketsOpt needs a way to push
+ // back the extra annotations that it read. (But, bracketsOpt should
+ // not *always* be allowed to push back extra annotations that it finds
+ // -- in most contexts, any such extra annotation is an error.
+ // Another similar case occurs with arrays and receiver annotations:
+ // String b() @Array [] @Receiver { }
+ // String b() @Receiver { }
+ //
+ // The following two variables permit type annotations that have
+ // already been read to be stored for later use. Alternate
+ // implementations are possible but would cause much larger changes to
+ // the parser.
+ /** Type annotations that have already been read but have not yet been used. **/
+ private List<JCTypeAnnotation> typeAnnotationsPushedBack = null;
+ /**
+ * If the parser notices extra annotations, then it either immediately
+ * issues an error (if this variable is false) or places the extra
+ * annotations in variable typeAnnotationsPushedBack (if this variable
+ * is true).
+ */
+ private boolean permitTypeAnnotationsPushBack = false;
+
/** Construct a parser from a given scanner, tree factory and log.
*/
protected JavacParser(ParserFactory fac,
@@ -95,13 +131,19 @@
this.allowForeach = source.allowForeach();
this.allowStaticImport = source.allowStaticImport();
this.allowAnnotations = source.allowAnnotations();
+ this.allowTypeAnnotations = source.allowTypeAnnotations();
this.keepDocComments = keepDocComments;
if (keepDocComments)
docComments = new HashMap<JCTree,String>();
this.keepLineMap = keepLineMap;
this.errorTree = F.Erroneous();
+ this.debugJSR308 = fac.options.get("TA:parser") != null;
}
+ /** Switch: debug output for type-annotations operations
+ */
+ boolean debugJSR308;
+
/** Switch: Should generics be recognized?
*/
boolean allowGenerics;
@@ -130,6 +172,10 @@
*/
boolean allowAnnotations;
+ /** Switch: should we recognize type annotations?
+ */
+ boolean allowTypeAnnotations;
+
/** Switch: should we keep docComments?
*/
boolean keepDocComments;
@@ -558,7 +604,33 @@
return term(EXPR);
}
+ /**
+ * parses (optional) type annotations followed by a type. If the
+ * annotations are present before the type and are not consumed during array
+ * parsing, this method returns a {@link JCAnnotatedType} consisting of
+ * these annotations and the underlying type. Otherwise, it returns the
+ * underlying type.
+ *
+ * <p>
+ *
+ * Note that this method sets {@code mode} to {@code TYPE} first, before
+ * parsing annotations.
+ */
public JCExpression parseType() {
+ List<JCTypeAnnotation> annotations = typeAnnotationsOpt();
+ return parseType(annotations);
+ }
+
+ public JCExpression parseType(List<JCTypeAnnotation> annotations) {
+ JCExpression result = unannotatedType();
+
+ if (!annotations.isEmpty())
+ result = F.AnnotatedType(annotations, result);
+
+ return result;
+ }
+
+ public JCExpression unannotatedType() {
return term(TYPE);
}
@@ -792,8 +864,8 @@
* | [TypeArguments] THIS [Arguments]
* | [TypeArguments] SUPER SuperSuffix
* | NEW [TypeArguments] Creator
- * | Ident { "." Ident }
- * [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
+ * | [Annotations] Ident { "." Ident }
+ * [ [Annotations] "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
* | Arguments
* | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator )
* ]
@@ -942,23 +1014,62 @@
typeArgs = null;
} else return illegal();
break;
+ case MONKEYS_AT:
+
+ // only annotated targetting class literals or cast types are valid
+ List<JCTypeAnnotation> typeAnnos = typeAnnotationsOpt();
+ if (typeAnnos.isEmpty()) {
+ // else there would be no '@'
+ throw new AssertionError("type annos is empty");
+ }
+
+ JCExpression expr = term3();
+
+ // Type annotations: If term3 just parsed a non-type, expect a
+ // class literal (and issue a syntax error if there is no class
+ // literal). Otherwise, create a JCAnnotatedType.
+ if ((mode & TYPE) == 0) {
+ if (expr.getTag() != JCTree.SELECT)
+ return illegal(typeAnnos.head.pos);
+ JCFieldAccess sel = (JCFieldAccess)expr;
+ if (sel.name != names._class)
+ return illegal();
+ else {
+ sel.selected = F.AnnotatedType(typeAnnos, sel.selected);
+ t = expr;
+ }
+ } else {
+ // type annotation targeting a cast
+ t = toP(F.at(S.pos()).AnnotatedType(typeAnnos, expr));
+ }
+ break;
case IDENTIFIER: case ASSERT: case ENUM:
if (typeArgs != null) return illegal();
t = toP(F.at(S.pos()).Ident(ident()));
loop: while (true) {
pos = S.pos();
+ final List<JCTypeAnnotation> annos = typeAnnotationsOpt();
+
+ // need to report an error later if LBRACKET is for array
+ // index access rather than array creation level
+ if (!annos.isEmpty() && S.token() != LBRACKET && S.token() != ELLIPSIS)
+ return illegal(annos.head.pos);
switch (S.token()) {
case LBRACKET:
S.nextToken();
+
if (S.token() == RBRACKET) {
+
S.nextToken();
- t = bracketsOpt(t);
+
+ t = bracketsOpt(t, annos);
t = toP(F.at(pos).TypeArray(t));
t = bracketsSuffix(t);
} else {
if ((mode & EXPR) != 0) {
mode = EXPR;
JCExpression t1 = term();
+ if (!annos.isEmpty()) t = illegal(annos.head.pos);
t = to(F.at(pos).Indexed(t, t1));
}
accept(RBRACKET);
@@ -1011,6 +1122,10 @@
// typeArgs saved for next loop iteration.
t = toP(F.at(pos).Select(t, ident()));
break;
+ case ELLIPSIS:
+ assert this.permitTypeAnnotationsPushBack;
+ typeAnnotationsPushedBack = annos;
+ break loop;
default:
break loop;
}
@@ -1049,14 +1164,18 @@
if (typeArgs != null) illegal();
while (true) {
int pos1 = S.pos();
+
+ final List<JCTypeAnnotation> annos = typeAnnotationsOpt();
+
if (S.token() == LBRACKET) {
S.nextToken();
+
if ((mode & TYPE) != 0) {
int oldmode = mode;
mode = TYPE;
if (S.token() == RBRACKET) {
S.nextToken();
- t = bracketsOpt(t);
+ t = bracketsOpt(t, annos);
t = toP(F.at(pos1).TypeArray(t));
return t;
}
@@ -1091,6 +1210,13 @@
typeArgs = null;
}
} else {
+ if (!annos.isEmpty()) {
+ illegal(0);
+ if (permitTypeAnnotationsPushBack)
+ typeAnnotationsPushedBack = annos;
+ else
+ return illegal(annos.head.pos);
+ }
break;
}
}
@@ -1100,6 +1226,7 @@
S.token() == PLUSPLUS ? JCTree.POSTINC : JCTree.POSTDEC, t));
S.nextToken();
}
+
return toP(t);
}
@@ -1232,22 +1359,24 @@
}
/** TypeArgument = Type
- * | "?"
- * | "?" EXTENDS Type {"&" Type}
- * | "?" SUPER Type
+ * | [Annotations] "?"
+ * | [Annotations] "?" EXTENDS Type {"&" Type}
+ * | [Annotations] "?" SUPER Type
*/
JCExpression typeArgument() {
- if (S.token() != QUES) return parseType();
+ List<JCTypeAnnotation> annotations = typeAnnotationsOpt();
+ if (S.token() != QUES) return parseType(annotations);
int pos = S.pos();
S.nextToken();
+ JCExpression result;
if (S.token() == EXTENDS) {
TypeBoundKind t = to(F.at(S.pos()).TypeBoundKind(BoundKind.EXTENDS));
S.nextToken();
- return F.at(pos).Wildcard(t, parseType());
+ result = F.at(pos).Wildcard(t, parseType());
} else if (S.token() == SUPER) {
TypeBoundKind t = to(F.at(S.pos()).TypeBoundKind(BoundKind.SUPER));
S.nextToken();
- return F.at(pos).Wildcard(t, parseType());
+ result = F.at(pos).Wildcard(t, parseType());
} else if (S.token() == IDENTIFIER) {
//error recovery
reportSyntaxError(S.prevEndPos(), "expected3",
@@ -1255,11 +1384,14 @@
TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND);
JCExpression wc = toP(F.at(pos).Wildcard(t, null));
JCIdent id = toP(F.at(S.pos()).Ident(ident()));
- return F.at(pos).Erroneous(List.<JCTree>of(wc, id));
+ result = F.at(pos).Erroneous(List.<JCTree>of(wc, id));
} else {
TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND);
- return toP(F.at(pos).Wildcard(t, null));
+ result = toP(F.at(pos).Wildcard(t, null));
}
+ if (!annotations.isEmpty())
+ result = toP(F.at(annotations.head.pos).AnnotatedType(annotations,result));
+ return result;
}
JCTypeApply typeArguments(JCExpression t) {
@@ -1268,21 +1400,47 @@
return toP(F.at(pos).TypeApply(t, args));
}
- /** BracketsOpt = {"[" "]"}
+ /**
+ * BracketsOpt = { [Annotations] "[" "]" }
+ *
+ * <p>
+ *
+ * <code>annotations</code> is the list of annotations targeting
+ * the expression <code>t</code>.
*/
- private JCExpression bracketsOpt(JCExpression t) {
+ private JCExpression bracketsOpt(JCExpression t,
+ List<JCTypeAnnotation> annotations) {
+ List<JCTypeAnnotation> nextLevelAnnotations = typeAnnotationsOpt();
+
if (S.token() == LBRACKET) {
int pos = S.pos();
S.nextToken();
- t = bracketsOptCont(t, pos);
- F.at(pos);
+
+ JCExpression orig = t;
+ t = bracketsOptCont(t, pos, nextLevelAnnotations);
+ } else if (!nextLevelAnnotations.isEmpty()) {
+ if (permitTypeAnnotationsPushBack) {
+ this.typeAnnotationsPushedBack = nextLevelAnnotations;
+ } else
+ return illegal(nextLevelAnnotations.head.pos);
}
+
+ int apos = S.pos();
+ if (!annotations.isEmpty())
+ t = F.at(apos).AnnotatedType(annotations, t);
return t;
}
- private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos) {
+ /** BracketsOpt = {"[" TypeAnnotations "]"}
+ */
+ private JCExpression bracketsOpt(JCExpression t) {
+ return bracketsOpt(t, List.<JCTypeAnnotation>nil());
+ }
+
+ private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos,
+ List<JCTypeAnnotation> annotations) {
accept(RBRACKET);
- t = bracketsOpt(t);
+ t = bracketsOpt(t, annotations);
return toP(F.at(pos).TypeArray(t));
}
@@ -1316,18 +1474,29 @@
return t;
}
- /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
+ /** Creator = [Annotations] Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
*/
JCExpression creator(int newpos, List<JCExpression> typeArgs) {
+
+ List<JCTypeAnnotation> newAnnotations = typeAnnotationsOpt();
+
switch (S.token()) {
case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
case DOUBLE: case BOOLEAN:
- if (typeArgs == null)
- return arrayCreatorRest(newpos, basicType());
+ if (typeArgs == null) {
+ if (newAnnotations.isEmpty())
+ return arrayCreatorRest(newpos, basicType());
+ else
+ return arrayCreatorRest(newpos, F.AnnotatedType(newAnnotations, basicType()));
+ }
break;
default:
}
JCExpression t = qualident();
+ // handle type annotations for non primitive arrays
+ if (!newAnnotations.isEmpty())
+ t = F.AnnotatedType(newAnnotations, t);
+
int oldmode = mode;
mode = TYPE;
if (S.token() == LT) {
@@ -1344,7 +1513,7 @@
}
}
mode = oldmode;
- if (S.token() == LBRACKET) {
+ if (S.token() == LBRACKET || S.token() == MONKEYS_AT) {
JCExpression e = arrayCreatorRest(newpos, t);
if (typeArgs != null) {
int pos = newpos;
@@ -1360,7 +1529,12 @@
}
return e;
} else if (S.token() == LPAREN) {
- return classCreatorRest(newpos, null, typeArgs, t);
+ JCNewClass newClass = classCreatorRest(newpos, null, typeArgs, t);
+ if (newClass.def != null) {
+ assert newClass.def.mods.annotations.isEmpty();
+ newClass.def.mods.annotations = List.convert(JCAnnotation.class, newAnnotations);
+ }
+ return newClass;
} else {
reportSyntaxError(S.pos(), "expected2",
LPAREN, LBRACKET);
@@ -1380,40 +1554,73 @@
return classCreatorRest(newpos, encl, typeArgs, t);
}
- /** ArrayCreatorRest = "[" ( "]" BracketsOpt ArrayInitializer
- * | Expression "]" {"[" Expression "]"} BracketsOpt )
+ /** ArrayCreatorRest = [Annotations] "[" ( "]" BracketsOpt ArrayInitializer
+ * | Expression "]" {[Annotations] "[" Expression "]"} BracketsOpt )
*/
JCExpression arrayCreatorRest(int newpos, JCExpression elemtype) {
+
+ List<JCTypeAnnotation> topAnnos = List.nil();
+ if (elemtype.getTag() == JCTree.ANNOTATED_TYPE) {
+ JCAnnotatedType atype = (JCAnnotatedType) elemtype;
+ topAnnos = atype.annotations;
+ elemtype = atype.underlyingType;
+ }
+
+ List<JCTypeAnnotation> annos = typeAnnotationsOpt();
+
accept(LBRACKET);
+
if (S.token() == RBRACKET) {
accept(RBRACKET);
- elemtype = bracketsOpt(elemtype);
+
+ elemtype = bracketsOpt(elemtype, annos);
+
if (S.token() == LBRACE) {
- return arrayInitializer(newpos, elemtype);
+ JCNewArray na = (JCNewArray)arrayInitializer(newpos, elemtype);
+
+ na.annotations = topAnnos;
+
+ return na;
} else {
return syntaxError(S.pos(), "array.dimension.missing");
}
} else {
ListBuffer<JCExpression> dims = new ListBuffer<JCExpression>();
+
+ // maintain array dimension type annotations
+ ListBuffer<List<JCTypeAnnotation>> dimAnnotations = ListBuffer.lb();
+ dimAnnotations.append(annos);
+
dims.append(parseExpression());
accept(RBRACKET);
- while (S.token() == LBRACKET) {
+ while (S.token() == LBRACKET
+ || (S.token() == MONKEYS_AT)) {
+ List<JCTypeAnnotation> maybeDimAnnos = typeAnnotationsOpt();
int pos = S.pos();
S.nextToken();
if (S.token() == RBRACKET) {
- elemtype = bracketsOptCont(elemtype, pos);
+ elemtype = bracketsOptCont(elemtype, pos, maybeDimAnnos);
} else {
- dims.append(parseExpression());
- accept(RBRACKET);
+ if (S.token() == RBRACKET) { // no dimension
+ elemtype = bracketsOptCont(elemtype, pos, maybeDimAnnos);
+ } else {
+ dimAnnotations.append(maybeDimAnnos);
+ dims.append(parseExpression());
+ accept(RBRACKET);
+ }
}
}
- return toP(F.at(newpos).NewArray(elemtype, dims.toList(), null));
+
+ JCNewArray na = toP(F.at(newpos).NewArray(elemtype, dims.toList(), null));
+ na.annotations = topAnnos;
+ na.dimAnnotations = dimAnnotations.toList();
+ return na;
}
}
/** ClassCreatorRest = Arguments [ClassBody]
*/
- JCExpression classCreatorRest(int newpos,
+ JCNewClass classCreatorRest(int newpos,
JCExpression encl,
List<JCExpression> typeArgs,
JCExpression t)
@@ -1860,17 +2067,32 @@
new ListBuffer<JCExpressionStatement>()).toList();
}
+ enum AnnotationKind { DEFAULT_ANNO, TYPE_ANNO };
+
/** AnnotationsOpt = { '@' Annotation }
*/
- List<JCAnnotation> annotationsOpt() {
+ List<JCAnnotation> annotationsOpt(AnnotationKind kind) {
if (S.token() != MONKEYS_AT) return List.nil(); // optimization
ListBuffer<JCAnnotation> buf = new ListBuffer<JCAnnotation>();
+ int prevmode = mode;
while (S.token() == MONKEYS_AT) {
int pos = S.pos();
S.nextToken();
- buf.append(annotation(pos));
+ buf.append(annotation(pos, kind));
}
- return buf.toList();
+ lastmode = mode;
+ mode = prevmode;
+ List<JCAnnotation> annotations = buf.toList();
+
+ if (debugJSR308 && kind == AnnotationKind.TYPE_ANNO)
+ System.out.println("TA: parsing " + annotations
+ + " in " + log.currentSourceFile());
+ return annotations;
+ }
+
+ List<JCTypeAnnotation> typeAnnotationsOpt() {
+ List<JCAnnotation> annotations = annotationsOpt(AnnotationKind.TYPE_ANNO);
+ return List.convert(JCTypeAnnotation.class, annotations);
}
/** ModifiersOpt = { Modifier }
@@ -1915,7 +2137,7 @@
if (flag == Flags.ANNOTATION) {
checkAnnotations();
if (S.token() != INTERFACE) {
- JCAnnotation ann = annotation(lastPos);
+ JCAnnotation ann = annotation(lastPos, AnnotationKind.DEFAULT_ANNO);
// if first modifier is an annotation, set pos to annotation's.
if (flags == 0 && annotations.isEmpty())
pos = ann.pos;
@@ -1946,12 +2168,18 @@
/** Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ]
* @param pos position of "@" token
*/
- JCAnnotation annotation(int pos) {
+ JCAnnotation annotation(int pos, AnnotationKind kind) {
// accept(AT); // AT consumed by caller
checkAnnotations();
+ if (kind == AnnotationKind.TYPE_ANNO)
+ checkTypeAnnotations();
JCTree ident = qualident();
List<JCExpression> fieldValues = annotationFieldValuesOpt();
- JCAnnotation ann = F.at(pos).Annotation(ident, fieldValues);
+ JCAnnotation ann;
+ if (kind == AnnotationKind.DEFAULT_ANNO)
+ ann = F.at(pos).Annotation(ident, fieldValues);
+ else
+ ann = F.at(pos).TypeAnnotation(ident, fieldValues);
storeEnd(ann, S.prevEndPos());
return ann;
}
@@ -2003,7 +2231,7 @@
case MONKEYS_AT:
pos = S.pos();
S.nextToken();
- return annotation(pos);
+ return annotation(pos, AnnotationKind.DEFAULT_ANNO);
case LBRACE:
pos = S.pos();
accept(LBRACE);
@@ -2357,7 +2585,7 @@
S.resetDeprecatedFlag();
}
int pos = S.pos();
- List<JCAnnotation> annotations = annotationsOpt();
+ List<JCAnnotation> annotations = annotationsOpt(AnnotationKind.DEFAULT_ANNO);
JCModifiers mods = F.at(annotations.isEmpty() ? Position.NOPOS : pos).Modifiers(flags, annotations);
List<JCExpression> typeArgs = typeArgumentsOpt();
int identPos = S.pos();
@@ -2460,16 +2688,23 @@
if (typarams.length() > 0 && mods.pos == Position.NOPOS) {
mods.pos = pos;
}
+
+ List<JCAnnotation> annosAfterParams = annotationsOpt(AnnotationKind.DEFAULT_ANNO);
+
Token token = S.token();
Name name = S.name();
pos = S.pos();
JCExpression type;
boolean isVoid = S.token() == VOID;
if (isVoid) {
+ if (annosAfterParams.nonEmpty())
+ illegal(annosAfterParams.head.pos);
type = to(F.at(pos).TypeIdent(TypeTags.VOID));
S.nextToken();
} else {
- type = parseType();
+ mods.annotations = mods.annotations.appendList(annosAfterParams);
+ // method returns types are un-annotated types
+ type = unannotatedType();
}
if (S.token() == LPAREN && !isInterface && type.getTag() == JCTree.IDENT) {
if (isInterface || name != className)
@@ -2505,15 +2740,15 @@
}
/** MethodDeclaratorRest =
- * FormalParameters BracketsOpt [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
+ * FormalParameters BracketsOpt [Annotations] [Throws TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
* VoidMethodDeclaratorRest =
- * FormalParameters [Throws TypeList] ( MethodBody | ";")
+ * FormalParameters [Annotations] [Throws TypeList] ( MethodBody | ";")
* InterfaceMethodDeclaratorRest =
- * FormalParameters BracketsOpt [THROWS TypeList] ";"
+ * FormalParameters BracketsOpt [Annotations] [THROWS TypeList] ";"
* VoidInterfaceMethodDeclaratorRest =
- * FormalParameters [THROWS TypeList] ";"
+ * FormalParameters [Annotations] [THROWS TypeList] ";"
* ConstructorDeclaratorRest =
- * "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody
+ * "(" FormalParameterListOpt ")" [Annotations] [THROWS TypeList] MethodBody
*/
JCTree methodDeclaratorRest(int pos,
JCModifiers mods,
@@ -2523,7 +2758,22 @@
boolean isInterface, boolean isVoid,
String dc) {
List<JCVariableDecl> params = formalParameters();
- if (!isVoid) type = bracketsOpt(type);
+
+ List<JCTypeAnnotation> receiverAnnotations;
+ if (!isVoid) {
+ // need to distinguish between receiver anno and array anno
+ // look at typeAnnotationsPushedBack comment
+ this.permitTypeAnnotationsPushBack = true;
+ type = methodReturnArrayRest(type);
+ this.permitTypeAnnotationsPushBack = false;
+ if (typeAnnotationsPushedBack == null)
+ receiverAnnotations = List.nil();
+ else
+ receiverAnnotations = typeAnnotationsPushedBack;
+ typeAnnotationsPushedBack = null;
+ } else
+ receiverAnnotations = typeAnnotationsOpt();
+
List<JCExpression> thrown = List.nil();
if (S.token() == THROWS) {
S.nextToken();
@@ -2552,20 +2802,51 @@
}
JCMethodDecl result =
toP(F.at(pos).MethodDef(mods, name, type, typarams,
- params, thrown,
+ params, receiverAnnotations, thrown,
body, defaultValue));
attach(result, dc);
return result;
}
- /** QualidentList = Qualident {"," Qualident}
+ /** Parses the array levels after the format parameters list, and append
+ * them to the return type, while preseving the order of type annotations
+ */
+ private JCExpression methodReturnArrayRest(JCExpression type) {
+ if (type.getTag() != JCTree.TYPEARRAY)
+ return bracketsOpt(type);
+
+ JCArrayTypeTree baseArray = (JCArrayTypeTree)type;
+ while (TreeInfo.typeIn(baseArray.elemtype) instanceof JCArrayTypeTree)
+ baseArray = (JCArrayTypeTree)TreeInfo.typeIn(baseArray.elemtype);
+
+ if (baseArray.elemtype.getTag() == JCTree.ANNOTATED_TYPE) {
+ JCAnnotatedType at = (JCAnnotatedType)baseArray.elemtype;
+ at.underlyingType = bracketsOpt(at.underlyingType);
+ } else {
+ baseArray.elemtype = bracketsOpt(baseArray.elemtype);
+ }
+
+ return type;
+ }
+
+ /** QualidentList = [Annotations] Qualident {"," [Annotations] Qualident}
*/
List<JCExpression> qualidentList() {
ListBuffer<JCExpression> ts = new ListBuffer<JCExpression>();
- ts.append(qualident());
+
+ List<JCTypeAnnotation> typeAnnos = typeAnnotationsOpt();
+ if (!typeAnnos.isEmpty())
+ ts.append(F.AnnotatedType(typeAnnos, qualident()));
+ else
+ ts.append(qualident());
while (S.token() == COMMA) {
S.nextToken();
- ts.append(qualident());
+
+ typeAnnos = typeAnnotationsOpt();
+ if (!typeAnnos.isEmpty())
+ ts.append(F.AnnotatedType(typeAnnos, qualident()));
+ else
+ ts.append(qualident());
}
return ts.toList();
}
@@ -2589,12 +2870,13 @@
}
}
- /** TypeParameter = TypeVariable [TypeParameterBound]
+ /** TypeParameter = [Annotations] TypeVariable [TypeParameterBound]
* TypeParameterBound = EXTENDS Type {"&" Type}
* TypeVariable = Ident
*/
JCTypeParameter typeParameter() {
int pos = S.pos();
+ List<JCTypeAnnotation> annos = typeAnnotationsOpt();
Name name = ident();
ListBuffer<JCExpression> bounds = new ListBuffer<JCExpression>();
if (S.token() == EXTENDS) {
@@ -2605,7 +2887,7 @@
bounds.append(parseType());
}
}
- return toP(F.at(pos).TypeParameter(name, bounds.toList()));
+ return toP(F.at(pos).TypeParameter(name, bounds.toList(), annos));
}
/** FormalParameters = "(" [ FormalParameterList ] ")"
@@ -2639,12 +2921,31 @@
*/
JCVariableDecl formalParameter() {
JCModifiers mods = optFinal(Flags.PARAMETER);
+ // need to distinguish between vararg annos and array annos
+ // look at typeAnnotaitonsPushedBack comment
+ this.permitTypeAnnotationsPushBack = true;
JCExpression type = parseType();
+ this.permitTypeAnnotationsPushBack = false;
+
if (S.token() == ELLIPSIS) {
+ List<JCTypeAnnotation> varargsAnnos = typeAnnotationsPushedBack;
+ typeAnnotationsPushedBack = null;
checkVarargs();
mods.flags |= Flags.VARARGS;
+ // insert var arg type annotations
+ if (varargsAnnos != null && varargsAnnos.nonEmpty())
+ type = F.at(S.pos()).AnnotatedType(varargsAnnos, type);
type = to(F.at(S.pos()).TypeArray(type));
+
S.nextToken();
+ } else {
+ // if not a var arg, then typeAnnotationsPushedBack should be null
+ if (typeAnnotationsPushedBack != null
+ && !typeAnnotationsPushedBack.isEmpty()) {
+ reportSyntaxError(typeAnnotationsPushedBack.head.pos,
+ "illegal.start.of.type");
+ }
+ typeAnnotationsPushedBack = null;
}
return variableDeclaratorId(mods, type);
}
@@ -2829,4 +3130,10 @@
allowAnnotations = true;
}
}
+ void checkTypeAnnotations() {
+ if (!allowTypeAnnotations) {
+ log.error(S.pos(), "type.annotations.not.supported.in.source", source.name);
+ allowTypeAnnotations = true;
+ }
+ }
}