8008077: update reference impl for type-annotations

Reviewed-by: jjg
This commit is contained in:
Werner Dietl 2013-02-12 17:15:29 -08:00 committed by Jonathan Gibbons
parent 1ec5dfafe0
commit 464abcb4fa
19 changed files with 724 additions and 134 deletions

View File

@ -727,12 +727,13 @@ public class ClassWriter {
private void write(TypeAnnotation.Position p, ClassOutputStream out) { private void write(TypeAnnotation.Position p, ClassOutputStream out) {
out.writeByte(p.type.targetTypeValue()); out.writeByte(p.type.targetTypeValue());
switch (p.type) { switch (p.type) {
// type cast
case CAST:
// instanceof // instanceof
case INSTANCEOF: case INSTANCEOF:
// new expression // new expression
case NEW: case NEW:
// constructor/method reference receiver
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
out.writeShort(p.offset); out.writeShort(p.offset);
break; break;
// local variable // local variable
@ -779,9 +780,12 @@ public class ClassWriter {
case METHOD_FORMAL_PARAMETER: case METHOD_FORMAL_PARAMETER:
out.writeByte(p.parameter_index); out.writeByte(p.parameter_index);
break; break;
// type cast
case CAST:
// method/constructor/reference type argument // method/constructor/reference type argument
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT: case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT: case METHOD_REFERENCE_TYPE_ARGUMENT:
out.writeShort(p.offset); out.writeShort(p.offset);
out.writeByte(p.type_index); out.writeByte(p.type_index);
@ -790,10 +794,6 @@ public class ClassWriter {
case METHOD_RETURN: case METHOD_RETURN:
case FIELD: case FIELD:
break; break;
// lambda formal parameter
case LAMBDA_FORMAL_PARAMETER:
out.writeByte(p.parameter_index);
break;
case UNKNOWN: case UNKNOWN:
throw new AssertionError("ClassWriter: UNKNOWN target type should never occur!"); throw new AssertionError("ClassWriter: UNKNOWN target type should never occur!");
default: default:

View File

@ -86,12 +86,13 @@ public class TypeAnnotation {
position.type = type; position.type = type;
switch (type) { switch (type) {
// type cast
case CAST:
// instanceof // instanceof
case INSTANCEOF: case INSTANCEOF:
// new expression // new expression
case NEW: case NEW:
// constructor/method reference receiver
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
position.offset = cr.readUnsignedShort(); position.offset = cr.readUnsignedShort();
break; break;
// local variable // local variable
@ -142,9 +143,12 @@ public class TypeAnnotation {
case METHOD_FORMAL_PARAMETER: case METHOD_FORMAL_PARAMETER:
position.parameter_index = cr.readUnsignedByte(); position.parameter_index = cr.readUnsignedByte();
break; break;
// type cast
case CAST:
// method/constructor/reference type argument // method/constructor/reference type argument
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT: case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT: case METHOD_REFERENCE_TYPE_ARGUMENT:
position.offset = cr.readUnsignedShort(); position.offset = cr.readUnsignedShort();
position.type_index = cr.readUnsignedByte(); position.type_index = cr.readUnsignedByte();
@ -153,10 +157,6 @@ public class TypeAnnotation {
case METHOD_RETURN: case METHOD_RETURN:
case FIELD: case FIELD:
break; break;
// lambda formal parameter
case LAMBDA_FORMAL_PARAMETER:
position.parameter_index = cr.readUnsignedByte();
break;
case UNKNOWN: case UNKNOWN:
throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!"); throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!");
default: default:
@ -177,13 +177,14 @@ public class TypeAnnotation {
int n = 0; int n = 0;
n += 1; // TargetType tag is a byte n += 1; // TargetType tag is a byte
switch (pos.type) { switch (pos.type) {
// type cast
case CAST:
// instanceof // instanceof
case INSTANCEOF: case INSTANCEOF:
// new expression // new expression
case NEW: case NEW:
n += 2; // constructor/method reference receiver
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
n += 2; // offset
break; break;
// local variable // local variable
case LOCAL_VARIABLE: case LOCAL_VARIABLE:
@ -192,7 +193,7 @@ public class TypeAnnotation {
n += 2; // table_length; n += 2; // table_length;
int table_length = pos.lvarOffset.length; int table_length = pos.lvarOffset.length;
n += 2 * table_length; // offset n += 2 * table_length; // offset
n += 2 * table_length; // length; n += 2 * table_length; // length
n += 2 * table_length; // index n += 2 * table_length; // index
break; break;
// exception parameter // exception parameter
@ -206,7 +207,7 @@ public class TypeAnnotation {
// type parameter // type parameter
case CLASS_TYPE_PARAMETER: case CLASS_TYPE_PARAMETER:
case METHOD_TYPE_PARAMETER: case METHOD_TYPE_PARAMETER:
n += 1; // parameter_index; n += 1; // parameter_index
break; break;
// type parameter bound // type parameter bound
case CLASS_TYPE_PARAMETER_BOUND: case CLASS_TYPE_PARAMETER_BOUND:
@ -226,9 +227,12 @@ public class TypeAnnotation {
case METHOD_FORMAL_PARAMETER: case METHOD_FORMAL_PARAMETER:
n += 1; // parameter_index n += 1; // parameter_index
break; break;
// type cast
case CAST:
// method/constructor/reference type argument // method/constructor/reference type argument
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT: case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT: case METHOD_REFERENCE_TYPE_ARGUMENT:
n += 2; // offset n += 2; // offset
n += 1; // type index n += 1; // type index
@ -237,10 +241,6 @@ public class TypeAnnotation {
case METHOD_RETURN: case METHOD_RETURN:
case FIELD: case FIELD:
break; break;
// lambda formal parameter
case LAMBDA_FORMAL_PARAMETER:
n += 1; // parameter_index
break;
case UNKNOWN: case UNKNOWN:
throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!"); throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!");
default: default:
@ -377,12 +377,13 @@ public class TypeAnnotation {
sb.append(type); sb.append(type);
switch (type) { switch (type) {
// type cast
case CAST:
// instanceof // instanceof
case INSTANCEOF: case INSTANCEOF:
// new expression // new expression
case NEW: case NEW:
// constructor/method reference receiver
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
sb.append(", offset = "); sb.append(", offset = ");
sb.append(offset); sb.append(offset);
break; break;
@ -444,9 +445,12 @@ public class TypeAnnotation {
sb.append(", param_index = "); sb.append(", param_index = ");
sb.append(parameter_index); sb.append(parameter_index);
break; break;
// type cast
case CAST:
// method/constructor/reference type argument // method/constructor/reference type argument
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT: case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT: case METHOD_REFERENCE_TYPE_ARGUMENT:
sb.append(", offset = "); sb.append(", offset = ");
sb.append(offset); sb.append(offset);
@ -457,12 +461,6 @@ public class TypeAnnotation {
case METHOD_RETURN: case METHOD_RETURN:
case FIELD: case FIELD:
break; break;
// lambda formal parameter
case LAMBDA_FORMAL_PARAMETER:
// TODO: also needs an offset?
sb.append(", param_index = ");
sb.append(parameter_index);
break;
case UNKNOWN: case UNKNOWN:
sb.append(", position UNKNOWN!"); sb.append(", position UNKNOWN!");
break; break;
@ -564,34 +562,37 @@ public class TypeAnnotation {
/** For annotations on an exception parameter. */ /** For annotations on an exception parameter. */
EXCEPTION_PARAMETER(0x42, true), EXCEPTION_PARAMETER(0x42, true),
/** For annotations on a typecast. */
CAST(0x43, true),
/** For annotations on a type test. */ /** For annotations on a type test. */
INSTANCEOF(0x44, true), INSTANCEOF(0x43, true),
/** For annotations on an object creation expression. */ /** For annotations on an object creation expression. */
NEW(0x45, true), NEW(0x44, true),
/** For annotations on a constructor reference receiver. */
CONSTRUCTOR_REFERENCE(0x45, true),
/** For annotations on a method reference receiver. */
METHOD_REFERENCE(0x46, true),
/** For annotations on a typecast. */
CAST(0x47, true),
/** For annotations on a type argument of an object creation expression. */ /** For annotations on a type argument of an object creation expression. */
CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x46, true), CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x48, true),
/** For annotations on a type argument of a method call. */ /** For annotations on a type argument of a method call. */
METHOD_INVOCATION_TYPE_ARGUMENT(0x47, true), METHOD_INVOCATION_TYPE_ARGUMENT(0x49, true),
/** For annotations on a lambda parameter type. */ /** For annotations on a type argument of a constructor reference. */
LAMBDA_FORMAL_PARAMETER(0x48, true), CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(0x4A, true),
/** For annotations on a method reference. */
METHOD_REFERENCE(0x49, true),
/** For annotations on a type argument of a method reference. */ /** For annotations on a type argument of a method reference. */
METHOD_REFERENCE_TYPE_ARGUMENT(0x50, true), METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true),
/** For annotations with an unknown target. */ /** For annotations with an unknown target. */
UNKNOWN(0xFF); UNKNOWN(0xFF);
private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x50; private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x4B;
private final int targetTypeValue; private final int targetTypeValue;
private final boolean isLocal; private final boolean isLocal;

View File

@ -82,34 +82,37 @@ public enum TargetType {
/** For annotations on an exception parameter. */ /** For annotations on an exception parameter. */
EXCEPTION_PARAMETER(0x42, true), EXCEPTION_PARAMETER(0x42, true),
/** For annotations on a typecast. */
CAST(0x43, true),
/** For annotations on a type test. */ /** For annotations on a type test. */
INSTANCEOF(0x44, true), INSTANCEOF(0x43, true),
/** For annotations on an object creation expression. */ /** For annotations on an object creation expression. */
NEW(0x45, true), NEW(0x44, true),
/** For annotations on a constructor reference receiver. */
CONSTRUCTOR_REFERENCE(0x45, true),
/** For annotations on a method reference receiver. */
METHOD_REFERENCE(0x46, true),
/** For annotations on a typecast. */
CAST(0x47, true),
/** For annotations on a type argument of an object creation expression. */ /** For annotations on a type argument of an object creation expression. */
CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x46, true), CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x48, true),
/** For annotations on a type argument of a method call. */ /** For annotations on a type argument of a method call. */
METHOD_INVOCATION_TYPE_ARGUMENT(0x47, true), METHOD_INVOCATION_TYPE_ARGUMENT(0x49, true),
/** For annotations on a lambda parameter type. */ /** For annotations on a type argument of a constructor reference. */
LAMBDA_FORMAL_PARAMETER(0x48, true), CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(0x4A, true),
/** For annotations on a method reference. */
METHOD_REFERENCE(0x49, true),
/** For annotations on a type argument of a method reference. */ /** For annotations on a type argument of a method reference. */
METHOD_REFERENCE_TYPE_ARGUMENT(0x50, true), METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true),
/** For annotations with an unknown target. */ /** For annotations with an unknown target. */
UNKNOWN(0xFF); UNKNOWN(0xFF);
private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x92; private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x4B;
private final int targetTypeValue; private final int targetTypeValue;
private final boolean isLocal; private final boolean isLocal;

View File

@ -126,7 +126,8 @@ public class TypeAnnotationPosition {
// Tree position. // Tree position.
public int pos = -1; public int pos = -1;
// For typecasts, type tests, new (and locals, as start_pc). // For type casts, type tests, new, locals (as start_pc),
// and method and constructor reference type arguments.
public boolean isValidOffset = false; public boolean isValidOffset = false;
public int offset = -1; public int offset = -1;
@ -156,12 +157,13 @@ public class TypeAnnotationPosition {
sb.append(type); sb.append(type);
switch (type) { switch (type) {
// type cast
case CAST:
// instanceof // instanceof
case INSTANCEOF: case INSTANCEOF:
// new expression // new expression
case NEW: case NEW:
// constructor/method reference receiver
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
sb.append(", offset = "); sb.append(", offset = ");
sb.append(offset); sb.append(offset);
break; break;
@ -223,9 +225,12 @@ public class TypeAnnotationPosition {
sb.append(", param_index = "); sb.append(", param_index = ");
sb.append(parameter_index); sb.append(parameter_index);
break; break;
// type cast
case CAST:
// method/constructor/reference type argument // method/constructor/reference type argument
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT: case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT: case METHOD_REFERENCE_TYPE_ARGUMENT:
sb.append(", offset = "); sb.append(", offset = ");
sb.append(offset); sb.append(offset);
@ -236,12 +241,6 @@ public class TypeAnnotationPosition {
case METHOD_RETURN: case METHOD_RETURN:
case FIELD: case FIELD:
break; break;
// lambda formal parameter
case LAMBDA_FORMAL_PARAMETER:
// TODO: also needs an offset?
sb.append(", param_index = ");
sb.append(parameter_index);
break;
case UNKNOWN: case UNKNOWN:
sb.append(", position UNKNOWN!"); sb.append(", position UNKNOWN!");
break; break;

View File

@ -217,6 +217,9 @@ public class TypeAnnotations {
// Such an annotation is _not_ part of an JCAnnotatedType tree and we therefore // Such an annotation is _not_ part of an JCAnnotatedType tree and we therefore
// need to set its position explicitly. // need to set its position explicitly.
// The method returns a copy of type that contains these annotations. // The method returns a copy of type that contains these annotations.
//
// As a side effect the method sets the type annotation position of "annotations".
// Note that it is assumed that all annotations share the same position.
private static Type typeWithAnnotations(final JCTree typetree, final Type type, private static Type typeWithAnnotations(final JCTree typetree, final Type type,
final List<Attribute.TypeCompound> annotations, Log log) { final List<Attribute.TypeCompound> annotations, Log log) {
// System.out.printf("typeWithAnnotations(typetree: %s, type: %s, annotations: %s)%n", // System.out.printf("typeWithAnnotations(typetree: %s, type: %s, annotations: %s)%n",
@ -267,7 +270,9 @@ public class TypeAnnotations {
} }
Type arelemType = typeWithAnnotations(arTree.elemtype, arType.elemtype, annotations, log); Type arelemType = typeWithAnnotations(arTree.elemtype, arType.elemtype, annotations, log);
tomodify.elemtype = arelemType; tomodify.elemtype = arelemType;
for (Attribute.TypeCompound a : annotations) { {
// All annotations share the same position; modify the first one.
Attribute.TypeCompound a = annotations.get(0);
TypeAnnotationPosition p = a.position; TypeAnnotationPosition p = a.position;
p.location = p.location.prependList(depth.toList()); p.location = p.location.prependList(depth.toList());
} }
@ -345,10 +350,10 @@ public class TypeAnnotations {
if (depth.nonEmpty()) { if (depth.nonEmpty()) {
// Only need to change the annotation positions // Only need to change the annotation positions
// if they are on an enclosed type. // if they are on an enclosed type.
for (Attribute.TypeCompound a : annotations) { // All annotations share the same position; modify the first one.
TypeAnnotationPosition p = a.position; Attribute.TypeCompound a = annotations.get(0);
p.location = p.location.appendList(depth.toList()); TypeAnnotationPosition p = a.position;
} p.location = p.location.appendList(depth.toList());
} }
Type ret = typeWithAnnotations(type, enclTy, annotations); Type ret = typeWithAnnotations(type, enclTy, annotations);
@ -463,8 +468,7 @@ public class TypeAnnotations {
@Override @Override
public Type visitType(Type t, List<TypeCompound> s) { public Type visitType(Type t, List<TypeCompound> s) {
// Error? return new AnnotatedType(s, t);
return t;
} }
}; };
@ -575,6 +579,10 @@ public class TypeAnnotations {
System.out.println("Resolving tree: " + tree + " kind: " + tree.getKind()); System.out.println("Resolving tree: " + tree + " kind: " + tree.getKind());
System.out.println(" Framing tree: " + frame + " kind: " + frame.getKind()); System.out.println(" Framing tree: " + frame + " kind: " + frame.getKind());
*/ */
// Note that p.offset is set in
// com.sun.tools.javac.jvm.Gen.setTypeAnnotationPositions(int)
switch (frame.getKind()) { switch (frame.getKind()) {
case TYPE_CAST: case TYPE_CAST:
p.type = TargetType.CAST; p.type = TargetType.CAST;
@ -659,6 +667,45 @@ public class TypeAnnotations {
return; return;
} }
case MEMBER_REFERENCE: {
JCMemberReference mrframe = (JCMemberReference) frame;
if (mrframe.expr == tree) {
switch (mrframe.mode) {
case INVOKE:
p.type = TargetType.METHOD_REFERENCE;
break;
case NEW:
p.type = TargetType.CONSTRUCTOR_REFERENCE;
break;
default:
Assert.error("Unknown method reference mode " + mrframe.mode +
" for tree " + tree + " within frame " + frame);
}
p.pos = frame.pos;
} else if (mrframe.typeargs != null &&
mrframe.typeargs.contains(tree)) {
int arg = mrframe.typeargs.indexOf(tree);
p.type_index = arg;
switch (mrframe.mode) {
case INVOKE:
p.type = TargetType.METHOD_REFERENCE_TYPE_ARGUMENT;
break;
case NEW:
p.type = TargetType.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT;
break;
default:
Assert.error("Unknown method reference mode " + mrframe.mode +
" for tree " + tree + " within frame " + frame);
}
p.pos = frame.pos;
} else {
Assert.error("Could not determine type argument position of tree " + tree +
" within frame " + frame);
}
return;
}
case ARRAY_TYPE: { case ARRAY_TYPE: {
ListBuffer<TypePathEntry> index = ListBuffer.lb(); ListBuffer<TypePathEntry> index = ListBuffer.lb();
index = index.append(TypePathEntry.ARRAY); index = index.append(TypePathEntry.ARRAY);
@ -766,6 +813,14 @@ public class TypeAnnotations {
return; return;
} }
case INTERSECTION_TYPE: {
JCTypeIntersection isect = (JCTypeIntersection)frame;
p.type_index = isect.bounds.indexOf(tree);
List<JCTree> newPath = path.tail;
resolveFrame(newPath.head, newPath.tail.head, newPath, p);
return;
}
case METHOD_INVOCATION: { case METHOD_INVOCATION: {
JCMethodInvocation invocation = (JCMethodInvocation)frame; JCMethodInvocation invocation = (JCMethodInvocation)frame;
if (!invocation.typeargs.contains(tree)) { if (!invocation.typeargs.contains(tree)) {
@ -911,6 +966,8 @@ public class TypeAnnotations {
public void visitVarDef(final JCVariableDecl tree) { public void visitVarDef(final JCVariableDecl tree) {
if (tree.sym == null) { if (tree.sym == null) {
// Something is wrong already. Quietly ignore. // Something is wrong already. Quietly ignore.
} else if (tree.sym.getKind() == ElementKind.PARAMETER) {
// Parameters are handled in visitMethodDef above.
} else if (tree.sym.getKind() == ElementKind.FIELD) { } else if (tree.sym.getKind() == ElementKind.FIELD) {
if (sigOnly) { if (sigOnly) {
TypeAnnotationPosition pos = new TypeAnnotationPosition(); TypeAnnotationPosition pos = new TypeAnnotationPosition();
@ -924,7 +981,6 @@ public class TypeAnnotations {
pos.pos = tree.pos; pos.pos = tree.pos;
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
} else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) { } else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
// System.out.println("Found exception param: " + tree);
TypeAnnotationPosition pos = new TypeAnnotationPosition(); TypeAnnotationPosition pos = new TypeAnnotationPosition();
pos.type = TargetType.EXCEPTION_PARAMETER; pos.type = TargetType.EXCEPTION_PARAMETER;
pos.pos = tree.pos; pos.pos = tree.pos;
@ -934,9 +990,11 @@ public class TypeAnnotations {
pos.type = TargetType.RESOURCE_VARIABLE; pos.type = TargetType.RESOURCE_VARIABLE;
pos.pos = tree.pos; pos.pos = tree.pos;
separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos); separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
} else if (tree.sym.getKind() == ElementKind.ENUM_CONSTANT) {
// No type annotations can occur here.
} else { } else {
// There is nothing else in a variable declaration that needs separation. // There is nothing else in a variable declaration that needs separation.
// System.out.println("We found a: " + tree); Assert.error("Unhandled variable kind: " + tree + " of kind: " + tree.sym.getKind());
} }
push(tree); push(tree);

View File

@ -2068,7 +2068,15 @@ public class Types {
@Override @Override
public Type visitAnnotatedType(AnnotatedType t, Boolean recurse) { public Type visitAnnotatedType(AnnotatedType t, Boolean recurse) {
return new AnnotatedType(t.typeAnnotations, erasure(t.underlyingType, recurse)); Type erased = erasure(t.underlyingType, recurse);
if (erased.getKind() == TypeKind.ANNOTATED) {
// This can only happen when the underlying type is a
// type variable and the upper bound of it is annotated.
// The annotation on the type variable overrides the one
// on the bound.
erased = ((AnnotatedType)erased).underlyingType;
}
return new AnnotatedType(t.typeAnnotations, erased);
} }
}; };

View File

@ -766,6 +766,8 @@ public class Attr extends JCTree.Visitor {
JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile); JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
try { try {
memberEnter.typeAnnotate(initializer, env, env.info.enclVar);
annotate.flush();
Type itype = attribExpr(initializer, env, type); Type itype = attribExpr(initializer, env, type);
if (itype.constValue() != null) if (itype.constValue() != null)
return coerce(itype, type).constValue(); return coerce(itype, type).constValue();
@ -2539,7 +2541,7 @@ public class Attr extends JCTree.Visitor {
if (exprType.isErroneous()) { if (exprType.isErroneous()) {
//if the qualifier expression contains problems, //if the qualifier expression contains problems,
//give up atttribution of method reference //give up attribution of method reference
result = that.type = exprType; result = that.type = exprType;
return; return;
} }

View File

@ -1470,12 +1470,13 @@ public class ClassReader implements Completer {
position.type = type; position.type = type;
switch (type) { switch (type) {
// type cast
case CAST:
// instanceof // instanceof
case INSTANCEOF: case INSTANCEOF:
// new expression // new expression
case NEW: case NEW:
// constructor/method reference receiver
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
position.offset = nextChar(); position.offset = nextChar();
break; break;
// local variable // local variable
@ -1524,9 +1525,12 @@ public class ClassReader implements Completer {
case METHOD_FORMAL_PARAMETER: case METHOD_FORMAL_PARAMETER:
position.parameter_index = nextByte(); position.parameter_index = nextByte();
break; break;
// type cast
case CAST:
// method/constructor/reference type argument // method/constructor/reference type argument
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT: case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT: case METHOD_REFERENCE_TYPE_ARGUMENT:
position.offset = nextChar(); position.offset = nextChar();
position.type_index = nextByte(); position.type_index = nextByte();
@ -1535,10 +1539,6 @@ public class ClassReader implements Completer {
case METHOD_RETURN: case METHOD_RETURN:
case FIELD: case FIELD:
break; break;
// lambda formal parameter
case LAMBDA_FORMAL_PARAMETER:
position.parameter_index = nextByte();
break;
case UNKNOWN: case UNKNOWN:
throw new AssertionError("jvm.ClassReader: UNKNOWN target type should never occur!"); throw new AssertionError("jvm.ClassReader: UNKNOWN target type should never occur!");
default: default:

View File

@ -992,12 +992,13 @@ public class ClassWriter extends ClassFile {
void writePosition(TypeAnnotationPosition p) { void writePosition(TypeAnnotationPosition p) {
databuf.appendByte(p.type.targetTypeValue()); // TargetType tag is a byte databuf.appendByte(p.type.targetTypeValue()); // TargetType tag is a byte
switch (p.type) { switch (p.type) {
// type cast
case CAST:
// instanceof // instanceof
case INSTANCEOF: case INSTANCEOF:
// new expression // new expression
case NEW: case NEW:
// constructor/method reference receiver
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
databuf.appendChar(p.offset); databuf.appendChar(p.offset);
break; break;
// local variable // local variable
@ -1042,9 +1043,12 @@ public class ClassWriter extends ClassFile {
case METHOD_FORMAL_PARAMETER: case METHOD_FORMAL_PARAMETER:
databuf.appendByte(p.parameter_index); databuf.appendByte(p.parameter_index);
break; break;
// type cast
case CAST:
// method/constructor/reference type argument // method/constructor/reference type argument
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT: case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT: case METHOD_REFERENCE_TYPE_ARGUMENT:
databuf.appendChar(p.offset); databuf.appendChar(p.offset);
databuf.appendByte(p.type_index); databuf.appendByte(p.type_index);
@ -1053,10 +1057,6 @@ public class ClassWriter extends ClassFile {
case METHOD_RETURN: case METHOD_RETURN:
case FIELD: case FIELD:
break; break;
// lambda formal parameter
case LAMBDA_FORMAL_PARAMETER:
databuf.appendByte(p.parameter_index);
break;
case UNKNOWN: case UNKNOWN:
throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!"); throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!");
default: default:

View File

@ -1164,7 +1164,7 @@ public class JavacParser implements Parser {
} else return illegal(); } else return illegal();
break; break;
case MONKEYS_AT: case MONKEYS_AT:
// Only annotated cast types are valid // Only annotated cast types and method references are valid
List<JCAnnotation> typeAnnos = typeAnnotationsOpt(); List<JCAnnotation> typeAnnos = typeAnnotationsOpt();
if (typeAnnos.isEmpty()) { if (typeAnnos.isEmpty()) {
// else there would be no '@' // else there would be no '@'
@ -1175,17 +1175,27 @@ public class JavacParser implements Parser {
if ((mode & TYPE) == 0) { if ((mode & TYPE) == 0) {
// Type annotations on class literals no longer legal // Type annotations on class literals no longer legal
if (!expr.hasTag(Tag.SELECT)) { switch (expr.getTag()) {
case REFERENCE: {
JCMemberReference mref = (JCMemberReference) expr;
mref.expr = toP(F.at(pos).AnnotatedType(typeAnnos, mref.expr));
t = mref;
break;
}
case SELECT: {
JCFieldAccess sel = (JCFieldAccess) expr;
if (sel.name != names._class) {
return illegal();
} else {
log.error(token.pos, "no.annotations.on.dot.class");
return expr;
}
}
default:
return illegal(typeAnnos.head.pos); return illegal(typeAnnos.head.pos);
} }
JCFieldAccess sel = (JCFieldAccess)expr;
if (sel.name != names._class) {
return illegal();
} else {
log.error(token.pos, "no.annotations.on.dot.class");
return expr;
}
} else { } else {
// Type annotations targeting a cast // Type annotations targeting a cast
t = insertAnnotationsToMostInner(expr, typeAnnos, false); t = insertAnnotationsToMostInner(expr, typeAnnos, false);
@ -1457,18 +1467,40 @@ public class JavacParser implements Parser {
/** /**
* If we see an identifier followed by a '&lt;' it could be an unbound * If we see an identifier followed by a '&lt;' it could be an unbound
* method reference or a binary expression. To disambiguate, look for a * method reference or a binary expression. To disambiguate, look for a
* matching '&gt;' and see if the subsequent terminal is either '.' or '#'. * matching '&gt;' and see if the subsequent terminal is either '.' or '::'.
*/ */
@SuppressWarnings("fallthrough") @SuppressWarnings("fallthrough")
boolean isUnboundMemberRef() { boolean isUnboundMemberRef() {
int pos = 0, depth = 0; int pos = 0, depth = 0;
for (Token t = S.token(pos) ; ; t = S.token(++pos)) { outer: for (Token t = S.token(pos) ; ; t = S.token(++pos)) {
switch (t.kind) { switch (t.kind) {
case IDENTIFIER: case UNDERSCORE: case QUES: case EXTENDS: case SUPER: case IDENTIFIER: case UNDERSCORE: case QUES: case EXTENDS: case SUPER:
case DOT: case RBRACKET: case LBRACKET: case COMMA: case DOT: case RBRACKET: case LBRACKET: case COMMA:
case BYTE: case SHORT: case INT: case LONG: case FLOAT: case BYTE: case SHORT: case INT: case LONG: case FLOAT:
case DOUBLE: case BOOLEAN: case CHAR: case DOUBLE: case BOOLEAN: case CHAR:
case MONKEYS_AT:
break; break;
case LPAREN:
// skip annotation values
int nesting = 0;
for (; ; pos++) {
TokenKind tk2 = S.token(pos).kind;
switch (tk2) {
case EOF:
return false;
case LPAREN:
nesting++;
break;
case RPAREN:
nesting--;
if (nesting == 0) {
continue outer;
}
break;
}
}
case LT: case LT:
depth++; break; depth++; break;
case GTGTGT: case GTGTGT:
@ -1494,7 +1526,7 @@ public class JavacParser implements Parser {
/** /**
* If we see an identifier followed by a '&lt;' it could be an unbound * If we see an identifier followed by a '&lt;' it could be an unbound
* method reference or a binary expression. To disambiguate, look for a * method reference or a binary expression. To disambiguate, look for a
* matching '&gt;' and see if the subsequent terminal is either '.' or '#'. * matching '&gt;' and see if the subsequent terminal is either '.' or '::'.
*/ */
@SuppressWarnings("fallthrough") @SuppressWarnings("fallthrough")
ParensResult analyzeParens() { ParensResult analyzeParens() {

View File

@ -235,6 +235,7 @@ public class TreeInfo {
switch(tree.getTag()) { switch(tree.getTag()) {
case TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty(); case TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty();
case NEWCLASS: return isDiamond(((JCNewClass)tree).clazz); case NEWCLASS: return isDiamond(((JCNewClass)tree).clazz);
case ANNOTATED_TYPE: return isDiamond(((JCAnnotatedType)tree).underlyingType);
default: return false; default: return false;
} }
} }
@ -335,6 +336,8 @@ public class TreeInfo {
case TYPEAPPLY: case TYPEAPPLY:
case TYPEARRAY: case TYPEARRAY:
return true; return true;
case ANNOTATED_TYPE:
return isStaticSelector(((JCAnnotatedType)base).underlyingType, names);
default: default:
return false; return false;
} }

View File

@ -91,12 +91,13 @@ public class AnnotationWriter extends BasicWriter {
print(pos.type); print(pos.type);
switch (pos.type) { switch (pos.type) {
// type cast
case CAST:
// instanceof // instanceof
case INSTANCEOF: case INSTANCEOF:
// new expression // new expression
case NEW: case NEW:
// constructor/method reference receiver
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
if (showOffsets) { if (showOffsets) {
print(", offset="); print(", offset=");
print(pos.offset); print(pos.offset);
@ -162,9 +163,12 @@ public class AnnotationWriter extends BasicWriter {
print(", param_index="); print(", param_index=");
print(pos.parameter_index); print(pos.parameter_index);
break; break;
// type cast
case CAST:
// method/constructor/reference type argument // method/constructor/reference type argument
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT: case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT: case METHOD_REFERENCE_TYPE_ARGUMENT:
if (showOffsets) { if (showOffsets) {
print(", offset="); print(", offset=");
@ -177,11 +181,6 @@ public class AnnotationWriter extends BasicWriter {
case METHOD_RETURN: case METHOD_RETURN:
case FIELD: case FIELD:
break; break;
// lambda formal parameter
case LAMBDA_FORMAL_PARAMETER:
print(", param_index=");
print(pos.parameter_index);
break;
case UNKNOWN: case UNKNOWN:
throw new AssertionError("AnnotationWriter: UNKNOWN target type should never occur!"); throw new AssertionError("AnnotationWriter: UNKNOWN target type should never occur!");
default: default:

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8008077
* @summary Type annotations in a lazy constant need to be attributed
* in the correct order.
* @author Werner Dietl
* @compile LazyConstantValue.java
*/
import java.lang.annotation.*;
class ClassA {
Object o = ClassB.lcv;
}
class ClassB {
static final String[] lcv = new @TA String[0];
}
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@interface TA {}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8008077
* @summary Type annotations on a type variable, where the bound of
* the type variable is also annotated, need to be processed correctly.
* @author Werner Dietl
* @compile TypeVariable.java
*/
import java.lang.annotation.*;
class TypeVariable {
<TV extends @TA Object> TV cast(TV p) {
return (@TA TV) p;
}
}
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@interface TA {}

View File

@ -21,6 +21,8 @@
* questions. * questions.
*/ */
import java.lang.annotation.*;
/* /*
* @test * @test
* @bug 6843077 8006775 * @bug 6843077 8006775
@ -29,7 +31,8 @@
* @compile/fail VoidGenericMethod.java * @compile/fail VoidGenericMethod.java
*/ */
class VoidGenericMethod { class VoidGenericMethod {
public <T> @A void method() { } public @A <T> void method() { }
} }
@Target(ElementType.TYPE_USE)
@interface A { } @interface A { }

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8008077
* @summary new type annotation location: lambda expressions
* @compile Lambda.java
* @author Werner Dietl
*/
import java.lang.annotation.*;
public class Lambda {
interface LambdaInt {
<S, T> void generic(S p1, T p2);
}
static class LambdaImpl implements LambdaInt {
<S, T> LambdaImpl(S p1, T p2) {}
public <S, T> void generic(S p1, T p2) {}
}
LambdaInt getMethodRefTA(LambdaImpl r) {
return r::<@TA Object, @TB Object>generic;
}
LambdaInt getConstructorRefTA() {
return LambdaImpl::<@TA Object, @TB Object>new;
}
}
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@interface TA { }
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@interface TB { }

View File

@ -0,0 +1,262 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8008077
* @summary Test population of reference info for lambda expressions
* @compile -g Driver.java ReferenceInfoUtil.java Lambda.java
* @run main Driver Lambda
* @author Werner Dietl
*/
import static com.sun.tools.classfile.TypeAnnotation.TargetType.*;
public class Lambda {
@TADescriptions({
@TADescription(annotation = "TA", type = METHOD_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE),
@TADescription(annotation = "TB", type = METHOD_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE)
})
public String returnMethodRef1() {
return
"class Lambda {" +
" public String getName() { return \"Lambda!\"; }" +
"}" +
"class Test {" +
" java.util.function.Function<Lambda, String> lambda() {" +
" return @TA @TB Lambda::getName;" +
" }" +
"}";
}
@TADescriptions({
@TADescription(annotation = "TA", type = METHOD_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE),
@TADescription(annotation = "TB", type = METHOD_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 0 }),
@TADescription(annotation = "TC", type = METHOD_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 0 }),
@TADescription(annotation = "TD", type = METHOD_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 1 }),
@TADescription(annotation = "TE", type = METHOD_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 1 })
})
public String returnMethodRef2() {
return
"class Lambda<S, T> {" +
" public String getName() { return \"Lambda!\"; }" +
"}" +
"class Test {" +
" java.util.function.Function<Lambda<Integer, Float>, String> lambda() {" +
" return @TA Lambda<@TB @TC Integer, @TD @TE Float>::getName;" +
" }" +
"}";
}
@TADescriptions({
@TADescription(annotation = "CTA", type = METHOD_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE),
@TADescription(annotation = "CTB", type = METHOD_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 0 }),
@TADescription(annotation = "CTC", type = METHOD_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 1 })
})
public String returnMethodRef3() {
return
"class Lambda<S, T> {" +
" public String getName() { return \"Lambda!\"; }" +
"}" +
"@Target(ElementType.TYPE_USE)" +
"@interface CTA {" +
" String value();" +
"}" +
"@Target(ElementType.TYPE_USE)" +
"@interface CTB {" +
" int age();" +
"}" +
"@Target(ElementType.TYPE_USE)" +
"@interface CTC {" +
" String name();" +
"}" +
"class Test {" +
" java.util.function.Function<Lambda<Integer, Float>, String> lambda() {" +
" return @CTA(\"x\") Lambda<@CTB(age = 5) Integer, @CTC(name = \"y\") Float>::getName;" +
" }" +
"}";
}
@TADescriptions({
@TADescription(annotation = "TA", type = CONSTRUCTOR_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE),
@TADescription(annotation = "TB", type = CONSTRUCTOR_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE)
})
public String returnConstructorRef1() {
return
"class Lambda {" +
" Lambda() { }" +
"}" +
"class Test {" +
" Runnable lambda() {" +
" return @TA @TB Lambda::new;" +
" }" +
"}";
}
@TADescriptions({
@TADescription(annotation = "TA", type = CONSTRUCTOR_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE),
@TADescription(annotation = "TB", type = CONSTRUCTOR_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 0 }),
@TADescription(annotation = "TC", type = CONSTRUCTOR_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 0 }),
@TADescription(annotation = "TD", type = CONSTRUCTOR_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 1 }),
@TADescription(annotation = "TE", type = CONSTRUCTOR_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 1 })
})
public String returnConstructorRef2() {
return
"class Lambda<S, T> {" +
" Lambda() { }" +
"}" +
"class Test {" +
" Runnable lambda() {" +
" return @TA Lambda<@TB @TC Integer, @TD @TE Float>::new;" +
" }" +
"}";
}
@TADescriptions({
@TADescription(annotation = "CTA", type = CONSTRUCTOR_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE),
@TADescription(annotation = "CTB", type = CONSTRUCTOR_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 0 }),
@TADescription(annotation = "CTC", type = CONSTRUCTOR_REFERENCE,
offset = ReferenceInfoUtil.IGNORE_VALUE,
genericLocation = { 3, 1 })
})
public String returnConstructorRef3() {
return
"class Lambda<S, T> {" +
" Lambda() { }" +
"}" +
"@Target(ElementType.TYPE_USE)" +
"@interface CTA {" +
" String value();" +
"}" +
"@Target(ElementType.TYPE_USE)" +
"@interface CTB {" +
" int age();" +
"}" +
"@Target(ElementType.TYPE_USE)" +
"@interface CTC {" +
" String name();" +
"}" +
"class Test {" +
" Runnable lambda() {" +
" return @CTA(\"x\") Lambda<@CTB(age = 5) Integer, @CTC(name = \"y\") Float>::new;" +
" }" +
"}";
}
@TADescriptions({
@TADescription(annotation = "TA", type = METHOD_REFERENCE_TYPE_ARGUMENT,
offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TB", type = METHOD_REFERENCE_TYPE_ARGUMENT,
offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 1)
})
public String returnMethodRefTA1() {
return
"interface Lambda {" +
" <S, T> void generic(S p1, T p2);" +
"}" +
"class LambdaImpl implements Lambda {" +
" public <S, T> void generic(S p1, T p2) {}" +
"}" +
"class Test {" +
" Lambda lambda(LambdaImpl r) {" +
" return r::<@TA Object, @TB Object>generic;" +
" }" +
"}";
}
@TADescriptions({
@TADescription(annotation = "TA", type = CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT,
offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TB", type = CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT,
offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 1)
})
public String returnConstructorRefTA2() {
return
"interface Lambda {" +
" <S, T> void generic(S p1, T p2);" +
"}" +
"class LambdaImpl implements Lambda {" +
" <S, T> LambdaImpl(S p1, T p2) {}" +
" public <S, T> void generic(S p1, T p2) {}" +
"}" +
"class Test {" +
" Lambda lambda() {" +
" return LambdaImpl::<@TA Object, @TB Object>new;" +
" }" +
"}";
}
}

View File

@ -92,6 +92,28 @@ public class MethodParameters {
return "void test(Object b, @TC String @TA [] @TB [] a) { }"; return "void test(Object b, @TC String @TA [] @TB [] a) { }";
} }
@TADescriptions({
@TADescription(annotation = "TA", type = METHOD_FORMAL_PARAMETER,
genericLocation = { 0, 0 }, paramIndex = 1),
@TADescription(annotation = "TB", type = METHOD_FORMAL_PARAMETER,
genericLocation = { 0, 0 }, paramIndex = 1)
})
public String methodParamAsArray2() {
return "void test(Object b, @TA @TB String [] a) { }";
}
@TADescriptions({
@TADescription(annotation = "TA", type = METHOD_FORMAL_PARAMETER,
genericLocation = { 0, 0 }, paramIndex = 1),
@TADescription(annotation = "TB", type = METHOD_FORMAL_PARAMETER,
genericLocation = { 0, 0 }, paramIndex = 1),
@TADescription(annotation = "TC", type = METHOD_FORMAL_PARAMETER,
genericLocation = { 0, 0 }, paramIndex = 1)
})
public String methodParamAsArray3() {
return "void test(Object b, @TA @TB @TC String [] a) { }";
}
@TADescriptions({ @TADescriptions({
@TADescription(annotation = "TA", type = METHOD_FORMAL_PARAMETER, paramIndex = 1), @TADescription(annotation = "TA", type = METHOD_FORMAL_PARAMETER, paramIndex = 1),
@TADescription(annotation = "TB", type = METHOD_FORMAL_PARAMETER, @TADescription(annotation = "TB", type = METHOD_FORMAL_PARAMETER,

View File

@ -31,118 +31,170 @@ import static com.sun.tools.classfile.TypeAnnotation.TargetType.*;
*/ */
public class TypeCasts { public class TypeCasts {
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE) @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
public String returnObject() { public String returnObject() {
return "Object returnObject() { return (@TA String)null; }"; return "Object returnObject() { return (@TA String)null; }";
} }
@TADescriptions({ @TADescriptions({
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE), @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TB", type = CAST, @TADescription(annotation = "TB", type = CAST,
genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE), genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TC", type = CAST, @TADescription(annotation = "TC", type = CAST,
genericLocation = { 0, 0, 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE) genericLocation = { 0, 0, 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
}) })
public String returnObjectArray() { public String returnObjectArray() {
return "Object returnObjectArray() { return (@TC String @TA [] @TB [])null; }"; return "Object returnObjectArray() { return (@TC String @TA [] @TB [])null; }";
} }
@TADescriptions({ @TADescriptions({
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE), @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TB", type = CAST, @TADescription(annotation = "TB", type = CAST,
genericLocation = { 3, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE) genericLocation = { 3, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
}) })
public String returnObjectGeneric() { public String returnObjectGeneric() {
return "Object returnObjectGeneric() { return (@TA List<@TB String>)null; }"; return "Object returnObjectGeneric() { return (@TA List<@TB String>)null; }";
} }
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE) @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
public String returnPrim() { public String returnPrim() {
return "Object returnPrim() { return (@TA int)0; }"; return "Object returnPrim() { return (@TA int)0; }";
} }
@TADescriptions({ @TADescriptions({
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE), @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TB", type = CAST, @TADescription(annotation = "TB", type = CAST,
genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE) genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
}) })
public String returnPrimArray() { public String returnPrimArray() {
return "Object returnPrimArray() { return (@TB int @TA [])null; }"; return "Object returnPrimArray() { return (@TB int @TA [])null; }";
} }
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE) @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
public String initObject() { public String initObject() {
return "void initObject() { Object a = (@TA String)null; }"; return "void initObject() { Object a = (@TA String)null; }";
} }
@TADescriptions({ @TADescriptions({
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE), @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TB", type = CAST, @TADescription(annotation = "TB", type = CAST,
genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE) genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
}) })
public String initObjectArray() { public String initObjectArray() {
return "void initObjectArray() { Object a = (@TB String @TA [])null; }"; return "void initObjectArray() { Object a = (@TB String @TA [])null; }";
} }
@TADescriptions({ @TADescriptions({
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE), @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TB", type = CAST, @TADescription(annotation = "TB", type = CAST,
genericLocation = { 3, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE) genericLocation = { 3, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
}) })
public String initObjectGeneric() { public String initObjectGeneric() {
return "void initObjectGeneric() { Object a = (@TA List<@TB String>)null; }"; return "void initObjectGeneric() { Object a = (@TA List<@TB String>)null; }";
} }
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE) @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
public String initPrim() { public String initPrim() {
return "void initPrim() { Object a = (@TA int)0; }"; return "void initPrim() { Object a = (@TA int)0; }";
} }
@TADescriptions({ @TADescriptions({
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE), @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TB", type = CAST, @TADescription(annotation = "TB", type = CAST,
genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE) genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
}) })
public String initPrimArray() { public String initPrimArray() {
return "void initPrimArray() { Object a = (@TB int @TA [])null; }"; return "void initPrimArray() { Object a = (@TB int @TA [])null; }";
} }
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE) @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
public String eqtestObject() { public String eqtestObject() {
return "void eqtestObject() { if (null == (@TA String)null); }"; return "void eqtestObject() { if (null == (@TA String)null); }";
} }
@TADescriptions({ @TADescriptions({
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE), @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TB", type = CAST, @TADescription(annotation = "TB", type = CAST,
genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE) genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
}) })
public String eqtestObjectArray() { public String eqtestObjectArray() {
return "void eqtestObjectArray() { if (null == (@TB String @TA [])null); }"; return "void eqtestObjectArray() { if (null == (@TB String @TA [])null); }";
} }
@TADescriptions({ @TADescriptions({
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE), @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TB", type = CAST, @TADescription(annotation = "TB", type = CAST,
genericLocation = { 3, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE) genericLocation = { 3, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
}) })
public String eqtestObjectGeneric() { public String eqtestObjectGeneric() {
return "void eqtestObjectGeneric() { if (null == (@TA List<@TB String >)null); }"; return "void eqtestObjectGeneric() { if (null == (@TA List<@TB String >)null); }";
} }
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE) @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
// compiler optimizes away compile time constants casts // compiler optimizes away compile time constants casts
public String eqtestPrim() { public String eqtestPrim() {
return "void eqtestPrim(int a) { if (0 == (@TA int)a); }"; return "void eqtestPrim(int a) { if (0 == (@TA int)a); }";
} }
@TADescriptions({ @TADescriptions({
@TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE), @TADescription(annotation = "TA", type = CAST, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0),
@TADescription(annotation = "TB", type = CAST, @TADescription(annotation = "TB", type = CAST,
genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE) genericLocation = { 0, 0 }, offset = ReferenceInfoUtil.IGNORE_VALUE,
typeIndex = 0)
}) })
public String eqtestPrimArray() { public String eqtestPrimArray() {
return "void eqtestPrimArray() { if (null == (@TB int @TA [])null); }"; return "void eqtestPrimArray() { if (null == (@TB int @TA [])null); }";
} }
@TADescriptions({
@TADescription(annotation = "TA", type = CAST,
offset = ReferenceInfoUtil.IGNORE_VALUE, typeIndex = 0),
@TADescription(annotation = "TB", type = CAST,
offset = ReferenceInfoUtil.IGNORE_VALUE, typeIndex = 1),
@TADescription(annotation = "TC", type = CAST,
offset = ReferenceInfoUtil.IGNORE_VALUE, typeIndex = 1,
genericLocation = {3, 0})
})
public String intersection1() {
return "void intersection() { Object o = (@TA String & @TB Comparable<@TC String>) null; }";
}
@TADescriptions({
@TADescription(annotation = "TA", type = CAST,
offset = ReferenceInfoUtil.IGNORE_VALUE, typeIndex = 0),
@TADescription(annotation = "TB", type = CAST,
offset = ReferenceInfoUtil.IGNORE_VALUE, typeIndex = 1),
@TADescription(annotation = "TC", type = CAST,
offset = ReferenceInfoUtil.IGNORE_VALUE, typeIndex = 1,
genericLocation = {3, 0}),
@TADescription(annotation = "TD", type = CAST,
offset = ReferenceInfoUtil.IGNORE_VALUE, typeIndex = 2),
})
public String intersection2() {
return "void intersection() { Object o = (@TA String & @TB Comparable<@TC String> & @TD CharSequence) null; }";
}
} }