# HG changeset patch
# User jjg
# Date 1358976444 28800
# Node ID ee1eebe7e210eeebbf921e53fac635c7752f9060
# Parent 5a8d00abf076c62ab4b7ddf5051d011b40450a98
8006775: JSR 308: Compiler changes in JDK8
Reviewed-by: jjg
Contributed-by: mernst@cs.washington.edu, wmdietl@cs.washington.edu, mpapi@csail.mit.edu, mahmood@notnoop.com
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/javadoc/AnnotatedType.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/javadoc/AnnotatedType.java Wed Jan 23 13:27:24 2013 -0800
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.javadoc;
+
+
+/**
+ * Represents an annotated type.
+ * For example:
+ *
{
+ R visitAnnotatedType(AnnotatedTypeTree node, P p);
R visitAnnotation(AnnotationTree node, P p);
R visitMethodInvocation(MethodInvocationTree node, P p);
R visitAssert(AssertTree node, P p);
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java
--- a/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -47,4 +47,5 @@
public interface TypeParameterTree extends Tree {
Name getName();
List extends Tree> getBounds();
+ List extends AnnotationTree> getAnnotations();
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java
--- a/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/source/util/SimpleTreeVisitor.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -260,6 +260,10 @@
return defaultAction(node, p);
}
+ public R visitAnnotatedType(AnnotatedTypeTree node, P p) {
+ return defaultAction(node, p);
+ }
+
public R visitErroneous(ErroneousTree node, P p) {
return defaultAction(node, p);
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/source/util/TaskEvent.java
--- a/langtools/src/share/classes/com/sun/source/util/TaskEvent.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/source/util/TaskEvent.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -60,7 +60,7 @@
**/
GENERATE,
/**
- * For events relating to overall annotaion processing.
+ * For events relating to overall annotation processing.
**/
ANNOTATION_PROCESSING,
/**
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/source/util/TreeScanner.java
--- a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -138,6 +138,7 @@
r = scanAndReduce(node.getReturnType(), p, r);
r = scanAndReduce(node.getTypeParameters(), p, r);
r = scanAndReduce(node.getParameters(), p, r);
+ r = scanAndReduce(node.getReceiverParameter(), p, r);
r = scanAndReduce(node.getThrows(), p, r);
r = scanAndReduce(node.getBody(), p, r);
r = scanAndReduce(node.getDefaultValue(), p, r);
@@ -376,7 +377,8 @@
}
public R visitTypeParameter(TypeParameterTree node, P p) {
- R r = scan(node.getBounds(), p);
+ R r = scan(node.getAnnotations(), p);
+ r = scanAndReduce(node.getBounds(), p, r);
return r;
}
@@ -394,6 +396,12 @@
return r;
}
+ public R visitAnnotatedType(AnnotatedTypeTree node, P p) {
+ R r = scan(node.getAnnotations(), p);
+ r = scanAndReduce(node.getUnderlyingType(), p, r);
+ return r;
+ }
+
public R visitOther(Tree node, P p) {
return null;
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/classfile/Attribute.java
--- a/langtools/src/share/classes/com/sun/tools/classfile/Attribute.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Attribute.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -56,6 +56,8 @@
public static final String RuntimeInvisibleAnnotations = "RuntimeInvisibleAnnotations";
public static final String RuntimeVisibleParameterAnnotations = "RuntimeVisibleParameterAnnotations";
public static final String RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations";
+ public static final String RuntimeVisibleTypeAnnotations = "RuntimeVisibleTypeAnnotations";
+ public static final String RuntimeInvisibleTypeAnnotations = "RuntimeInvisibleTypeAnnotations";
public static final String Signature = "Signature";
public static final String SourceDebugExtension = "SourceDebugExtension";
public static final String SourceFile = "SourceFile";
@@ -120,6 +122,8 @@
standardAttributes.put(RuntimeInvisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations_attribute.class);
standardAttributes.put(RuntimeVisibleAnnotations, RuntimeVisibleAnnotations_attribute.class);
standardAttributes.put(RuntimeVisibleParameterAnnotations, RuntimeVisibleParameterAnnotations_attribute.class);
+ standardAttributes.put(RuntimeVisibleTypeAnnotations, RuntimeVisibleTypeAnnotations_attribute.class);
+ standardAttributes.put(RuntimeInvisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations_attribute.class);
standardAttributes.put(Signature, Signature_attribute.class);
standardAttributes.put(SourceID, SourceID_attribute.class);
}
@@ -178,6 +182,8 @@
R visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, P p);
R visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, P p);
R visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, P p);
+ R visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, P p);
+ R visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, P p);
R visitSignature(Signature_attribute attr, P p);
R visitSourceDebugExtension(SourceDebugExtension_attribute attr, P p);
R visitSourceFile(SourceFile_attribute attr, P p);
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java
--- a/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/classfile/ClassWriter.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -498,6 +498,16 @@
return null;
}
+ public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, ClassOutputStream out) {
+ annotationWriter.write(attr.annotations, out);
+ return null;
+ }
+
+ public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, ClassOutputStream out) {
+ annotationWriter.write(attr.annotations, out);
+ return null;
+ }
+
public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, ClassOutputStream out) {
out.writeByte(attr.parameter_annotations.length);
for (Annotation[] annos: attr.parameter_annotations)
@@ -657,6 +667,12 @@
write(anno, out);
}
+ public void write(TypeAnnotation[] annos, ClassOutputStream out) {
+ out.writeShort(annos.length);
+ for (TypeAnnotation anno: annos)
+ write(anno, out);
+ }
+
public void write(Annotation anno, ClassOutputStream out) {
out.writeShort(anno.type_index);
out.writeShort(anno.element_value_pairs.length);
@@ -664,6 +680,11 @@
write(p, out);
}
+ public void write(TypeAnnotation anno, ClassOutputStream out) {
+ write(anno.position, out);
+ write(anno.annotation, out);
+ }
+
public void write(element_value_pair pair, ClassOutputStream out) {
out.writeShort(pair.element_name_index);
write(pair.value, out);
@@ -702,5 +723,89 @@
return null;
}
+ // TODO: Move this to TypeAnnotation to be closer with similar logic?
+ private void write(TypeAnnotation.Position p, ClassOutputStream out) {
+ out.writeByte(p.type.targetTypeValue());
+ switch (p.type) {
+ // type cast
+ case CAST:
+ // instanceof
+ case INSTANCEOF:
+ // new expression
+ case NEW:
+ out.writeShort(p.offset);
+ break;
+ // local variable
+ case LOCAL_VARIABLE:
+ // resource variable
+ case RESOURCE_VARIABLE:
+ int table_length = p.lvarOffset.length;
+ out.writeShort(table_length);
+ for (int i = 0; i < table_length; ++i) {
+ out.writeShort(1); // for table length
+ out.writeShort(p.lvarOffset[i]);
+ out.writeShort(p.lvarLength[i]);
+ out.writeShort(p.lvarIndex[i]);
+ }
+ break;
+ // exception parameter
+ case EXCEPTION_PARAMETER:
+ out.writeByte(p.exception_index);
+ break;
+ // method receiver
+ case METHOD_RECEIVER:
+ // Do nothing
+ break;
+ // type parameters
+ case CLASS_TYPE_PARAMETER:
+ case METHOD_TYPE_PARAMETER:
+ out.writeByte(p.parameter_index);
+ break;
+ // type parameters bounds
+ case CLASS_TYPE_PARAMETER_BOUND:
+ case METHOD_TYPE_PARAMETER_BOUND:
+ out.writeByte(p.parameter_index);
+ out.writeByte(p.bound_index);
+ break;
+ // class extends or implements clause
+ case CLASS_EXTENDS:
+ out.writeByte(p.type_index);
+ break;
+ // throws
+ case THROWS:
+ out.writeByte(p.type_index);
+ break;
+ // method parameter
+ case METHOD_FORMAL_PARAMETER:
+ out.writeByte(p.parameter_index);
+ break;
+ // method/constructor/reference type argument
+ case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_REFERENCE_TYPE_ARGUMENT:
+ out.writeShort(p.offset);
+ out.writeByte(p.type_index);
+ break;
+ // We don't need to worry about these
+ case METHOD_RETURN:
+ case FIELD:
+ break;
+ // lambda formal parameter
+ case LAMBDA_FORMAL_PARAMETER:
+ out.writeByte(p.parameter_index);
+ break;
+ case UNKNOWN:
+ throw new AssertionError("ClassWriter: UNKNOWN target type should never occur!");
+ default:
+ throw new AssertionError("ClassWriter: Unknown target type for position: " + p);
+ }
+
+ { // Append location data for generics/arrays.
+ // TODO: check for overrun?
+ out.writeByte((byte)p.location.size());
+ for (int i : TypeAnnotation.Position.getBinaryFromTypePath(p.location))
+ out.writeByte((byte)i);
+ }
+ }
}
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/classfile/RuntimeInvisibleTypeAnnotations_attribute.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/classfile/RuntimeInvisibleTypeAnnotations_attribute.java Wed Jan 23 13:27:24 2013 -0800
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.tools.classfile;
+
+import java.io.IOException;
+
+/**
+ * See JSR 308 specification, Section 3.
+ *
+ * This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+public class RuntimeInvisibleTypeAnnotations_attribute extends RuntimeTypeAnnotations_attribute {
+ RuntimeInvisibleTypeAnnotations_attribute(ClassReader cr, int name_index, int length)
+ throws IOException, Annotation.InvalidAnnotation {
+ super(cr, name_index, length);
+ }
+
+ public RuntimeInvisibleTypeAnnotations_attribute(ConstantPool cp, TypeAnnotation[] annotations)
+ throws ConstantPoolException {
+ this(cp.getUTF8Index(Attribute.RuntimeInvisibleTypeAnnotations), annotations);
+ }
+
+ public RuntimeInvisibleTypeAnnotations_attribute(int name_index, TypeAnnotation[] annotations) {
+ super(name_index, annotations);
+ }
+
+ public R accept(Visitor visitor, P p) {
+ return visitor.visitRuntimeInvisibleTypeAnnotations(this, p);
+ }
+}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/classfile/RuntimeTypeAnnotations_attribute.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/classfile/RuntimeTypeAnnotations_attribute.java Wed Jan 23 13:27:24 2013 -0800
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2007, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.tools.classfile;
+
+import java.io.IOException;
+
+/**
+ * See JSR 308 specification, Section 3.
+ *
+ * This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+public abstract class RuntimeTypeAnnotations_attribute extends Attribute {
+ protected RuntimeTypeAnnotations_attribute(ClassReader cr, int name_index, int length)
+ throws IOException, Annotation.InvalidAnnotation {
+ super(name_index, length);
+ int num_annotations = cr.readUnsignedShort();
+ annotations = new TypeAnnotation[num_annotations];
+ for (int i = 0; i < annotations.length; i++)
+ annotations[i] = new TypeAnnotation(cr);
+ }
+
+ protected RuntimeTypeAnnotations_attribute(int name_index, TypeAnnotation[] annotations) {
+ super(name_index, length(annotations));
+ this.annotations = annotations;
+ }
+
+ private static int length(TypeAnnotation[] annos) {
+ int n = 2;
+ for (TypeAnnotation anno: annos)
+ n += anno.length();
+ return n;
+ }
+
+ public final TypeAnnotation[] annotations;
+}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/classfile/RuntimeVisibleTypeAnnotations_attribute.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/classfile/RuntimeVisibleTypeAnnotations_attribute.java Wed Jan 23 13:27:24 2013 -0800
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.tools.classfile;
+
+import java.io.IOException;
+
+/**
+ * See JSR 308 specification, Section 3.
+ *
+ *
This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+public class RuntimeVisibleTypeAnnotations_attribute extends RuntimeTypeAnnotations_attribute {
+ RuntimeVisibleTypeAnnotations_attribute(ClassReader cr, int name_index, int length)
+ throws IOException, Annotation.InvalidAnnotation {
+ super(cr, name_index, length);
+ }
+
+ public RuntimeVisibleTypeAnnotations_attribute(ConstantPool cp, TypeAnnotation[] annotations)
+ throws ConstantPoolException {
+ this(cp.getUTF8Index(Attribute.RuntimeVisibleTypeAnnotations), annotations);
+ }
+
+ public RuntimeVisibleTypeAnnotations_attribute(int name_index, TypeAnnotation[] annotations) {
+ super(name_index, annotations);
+ }
+
+ public R accept(Visitor visitor, P p) {
+ return visitor.visitRuntimeVisibleTypeAnnotations(this, p);
+ }
+}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/classfile/TypeAnnotation.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/classfile/TypeAnnotation.java Wed Jan 23 13:27:24 2013 -0800
@@ -0,0 +1,656 @@
+/*
+ * Copyright (c) 2009, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.tools.classfile;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.sun.tools.classfile.TypeAnnotation.Position.TypePathEntry;
+
+/**
+ * See JSR 308 specification, Section 3.
+ *
+ * This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.
+ */
+public class TypeAnnotation {
+ TypeAnnotation(ClassReader cr) throws IOException, Annotation.InvalidAnnotation {
+ constant_pool = cr.getConstantPool();
+ position = read_position(cr);
+ annotation = new Annotation(cr);
+ }
+
+ public TypeAnnotation(ConstantPool constant_pool,
+ Annotation annotation, Position position) {
+ this.constant_pool = constant_pool;
+ this.position = position;
+ this.annotation = annotation;
+ }
+
+ public int length() {
+ int n = annotation.length();
+ n += position_length(position);
+ return n;
+ }
+
+ @Override
+ public String toString() {
+ try {
+ return "@" + constant_pool.getUTF8Value(annotation.type_index).toString().substring(1) +
+ " pos: " + position.toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return e.toString();
+ }
+ }
+
+ public final ConstantPool constant_pool;
+ public final Position position;
+ public final Annotation annotation;
+
+ private static Position read_position(ClassReader cr) throws IOException, Annotation.InvalidAnnotation {
+ // Copied from ClassReader
+ int tag = cr.readUnsignedByte(); // TargetType tag is a byte
+ if (!TargetType.isValidTargetTypeValue(tag))
+ throw new Annotation.InvalidAnnotation("TypeAnnotation: Invalid type annotation target type value: " + String.format("0x%02X", tag));
+
+ TargetType type = TargetType.fromTargetTypeValue(tag);
+
+ Position position = new Position();
+ position.type = type;
+
+ switch (type) {
+ // type cast
+ case CAST:
+ // instanceof
+ case INSTANCEOF:
+ // new expression
+ case NEW:
+ position.offset = cr.readUnsignedShort();
+ break;
+ // local variable
+ case LOCAL_VARIABLE:
+ // resource variable
+ case RESOURCE_VARIABLE:
+ int table_length = cr.readUnsignedShort();
+ position.lvarOffset = new int[table_length];
+ position.lvarLength = new int[table_length];
+ position.lvarIndex = new int[table_length];
+ for (int i = 0; i < table_length; ++i) {
+ position.lvarOffset[i] = cr.readUnsignedShort();
+ position.lvarLength[i] = cr.readUnsignedShort();
+ position.lvarIndex[i] = cr.readUnsignedShort();
+ }
+ break;
+ // exception parameter
+ case EXCEPTION_PARAMETER:
+ position.exception_index = cr.readUnsignedByte();
+ break;
+ // method receiver
+ case METHOD_RECEIVER:
+ // Do nothing
+ break;
+ // type parameter
+ case CLASS_TYPE_PARAMETER:
+ case METHOD_TYPE_PARAMETER:
+ position.parameter_index = cr.readUnsignedByte();
+ break;
+ // type parameter bound
+ case CLASS_TYPE_PARAMETER_BOUND:
+ case METHOD_TYPE_PARAMETER_BOUND:
+ position.parameter_index = cr.readUnsignedByte();
+ position.bound_index = cr.readUnsignedByte();
+ break;
+ // class extends or implements clause
+ case CLASS_EXTENDS:
+ int in = cr.readUnsignedShort();
+ if (in == 0xFFFF)
+ in = -1;
+ position.type_index = in;
+ break;
+ // throws
+ case THROWS:
+ position.type_index = cr.readUnsignedShort();
+ break;
+ // method parameter
+ case METHOD_FORMAL_PARAMETER:
+ position.parameter_index = cr.readUnsignedByte();
+ break;
+ // method/constructor/reference type argument
+ case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_REFERENCE_TYPE_ARGUMENT:
+ position.offset = cr.readUnsignedShort();
+ position.type_index = cr.readUnsignedByte();
+ break;
+ // We don't need to worry about these
+ case METHOD_RETURN:
+ case FIELD:
+ break;
+ // lambda formal parameter
+ case LAMBDA_FORMAL_PARAMETER:
+ position.parameter_index = cr.readUnsignedByte();
+ break;
+ case UNKNOWN:
+ throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!");
+ default:
+ throw new AssertionError("TypeAnnotation: Unknown target type: " + type);
+ }
+
+ { // Write type path
+ int len = cr.readUnsignedByte();
+ List loc = new ArrayList(len);
+ for (int i = 0; i < len * TypePathEntry.bytesPerEntry; ++i)
+ loc.add(cr.readUnsignedByte());
+ position.location = Position.getTypePathFromBinary(loc);
+ }
+ return position;
+ }
+
+ private static int position_length(Position pos) {
+ int n = 0;
+ n += 1; // TargetType tag is a byte
+ switch (pos.type) {
+ // type cast
+ case CAST:
+ // instanceof
+ case INSTANCEOF:
+ // new expression
+ case NEW:
+ n += 2;
+ break;
+ // local variable
+ case LOCAL_VARIABLE:
+ // resource variable
+ case RESOURCE_VARIABLE:
+ n += 2; // table_length;
+ int table_length = pos.lvarOffset.length;
+ n += 2 * table_length; // offset
+ n += 2 * table_length; // length;
+ n += 2 * table_length; // index
+ break;
+ // exception parameter
+ case EXCEPTION_PARAMETER:
+ n += 1; // exception_index
+ break;
+ // method receiver
+ case METHOD_RECEIVER:
+ // Do nothing
+ break;
+ // type parameter
+ case CLASS_TYPE_PARAMETER:
+ case METHOD_TYPE_PARAMETER:
+ n += 1; // parameter_index;
+ break;
+ // type parameter bound
+ case CLASS_TYPE_PARAMETER_BOUND:
+ case METHOD_TYPE_PARAMETER_BOUND:
+ n += 1; // parameter_index
+ n += 1; // bound_index
+ break;
+ // class extends or implements clause
+ case CLASS_EXTENDS:
+ n += 2; // type_index
+ break;
+ // throws
+ case THROWS:
+ n += 2; // type_index
+ break;
+ // method parameter
+ case METHOD_FORMAL_PARAMETER:
+ n += 1; // parameter_index
+ break;
+ // method/constructor/reference type argument
+ case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_REFERENCE_TYPE_ARGUMENT:
+ n += 2; // offset
+ n += 1; // type index
+ break;
+ // We don't need to worry about these
+ case METHOD_RETURN:
+ case FIELD:
+ break;
+ // lambda formal parameter
+ case LAMBDA_FORMAL_PARAMETER:
+ n += 1; // parameter_index
+ break;
+ case UNKNOWN:
+ throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!");
+ default:
+ throw new AssertionError("TypeAnnotation: Unknown target type: " + pos.type);
+ }
+
+ {
+ n += 1; // length
+ n += TypePathEntry.bytesPerEntry * pos.location.size(); // bytes for actual array
+ }
+
+ return n;
+ }
+
+ // Code duplicated from com.sun.tools.javac.code.TypeAnnotationPosition
+ public static class Position {
+ public enum TypePathEntryKind {
+ ARRAY(0),
+ INNER_TYPE(1),
+ WILDCARD(2),
+ TYPE_ARGUMENT(3);
+
+ public final int tag;
+
+ private TypePathEntryKind(int tag) {
+ this.tag = tag;
+ }
+ }
+
+ public static class TypePathEntry {
+ /** The fixed number of bytes per TypePathEntry. */
+ public static final int bytesPerEntry = 2;
+
+ public final TypePathEntryKind tag;
+ public final int arg;
+
+ public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY);
+ public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE);
+ public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD);
+
+ private TypePathEntry(TypePathEntryKind tag) {
+ if (!(tag == TypePathEntryKind.ARRAY ||
+ tag == TypePathEntryKind.INNER_TYPE ||
+ tag == TypePathEntryKind.WILDCARD)) {
+ throw new AssertionError("Invalid TypePathEntryKind: " + tag);
+ }
+ this.tag = tag;
+ this.arg = 0;
+ }
+
+ public TypePathEntry(TypePathEntryKind tag, int arg) {
+ if (tag != TypePathEntryKind.TYPE_ARGUMENT) {
+ throw new AssertionError("Invalid TypePathEntryKind: " + tag);
+ }
+ this.tag = tag;
+ this.arg = arg;
+ }
+
+ public static TypePathEntry fromBinary(int tag, int arg) {
+ if (arg != 0 && tag != TypePathEntryKind.TYPE_ARGUMENT.tag) {
+ throw new AssertionError("Invalid TypePathEntry tag/arg: " + tag + "/" + arg);
+ }
+ switch (tag) {
+ case 0:
+ return ARRAY;
+ case 1:
+ return INNER_TYPE;
+ case 2:
+ return WILDCARD;
+ case 3:
+ return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg);
+ default:
+ throw new AssertionError("Invalid TypePathEntryKind tag: " + tag);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return tag.toString() +
+ (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : "");
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (! (other instanceof TypePathEntry)) {
+ return false;
+ }
+ TypePathEntry tpe = (TypePathEntry) other;
+ return this.tag == tpe.tag && this.arg == tpe.arg;
+ }
+
+ @Override
+ public int hashCode() {
+ return this.tag.hashCode() * 17 + this.arg;
+ }
+ }
+
+ public TargetType type = TargetType.UNKNOWN;
+
+ // For generic/array types.
+ // TODO: or should we use null? Noone will use this object.
+ public List location = new ArrayList(0);
+
+ // Tree position.
+ public int pos = -1;
+
+ // For typecasts, type tests, new (and locals, as start_pc).
+ public boolean isValidOffset = false;
+ public int offset = -1;
+
+ // For locals. arrays same length
+ public int[] lvarOffset = null;
+ public int[] lvarLength = null;
+ public int[] lvarIndex = null;
+
+ // For type parameter bound
+ public int bound_index = Integer.MIN_VALUE;
+
+ // For type parameter and method parameter
+ public int parameter_index = Integer.MIN_VALUE;
+
+ // For class extends, implements, and throws clauses
+ public int type_index = Integer.MIN_VALUE;
+
+ // For exception parameters, index into exception table
+ public int exception_index = Integer.MIN_VALUE;
+
+ public Position() {}
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append('[');
+ sb.append(type);
+
+ switch (type) {
+ // type cast
+ case CAST:
+ // instanceof
+ case INSTANCEOF:
+ // new expression
+ case NEW:
+ sb.append(", offset = ");
+ sb.append(offset);
+ break;
+ // local variable
+ case LOCAL_VARIABLE:
+ // resource variable
+ case RESOURCE_VARIABLE:
+ if (lvarOffset == null) {
+ sb.append(", lvarOffset is null!");
+ break;
+ }
+ sb.append(", {");
+ for (int i = 0; i < lvarOffset.length; ++i) {
+ if (i != 0) sb.append("; ");
+ sb.append("start_pc = ");
+ sb.append(lvarOffset[i]);
+ sb.append(", length = ");
+ sb.append(lvarLength[i]);
+ sb.append(", index = ");
+ sb.append(lvarIndex[i]);
+ }
+ sb.append("}");
+ break;
+ // method receiver
+ case METHOD_RECEIVER:
+ // Do nothing
+ break;
+ // type parameter
+ case CLASS_TYPE_PARAMETER:
+ case METHOD_TYPE_PARAMETER:
+ sb.append(", param_index = ");
+ sb.append(parameter_index);
+ break;
+ // type parameter bound
+ case CLASS_TYPE_PARAMETER_BOUND:
+ case METHOD_TYPE_PARAMETER_BOUND:
+ sb.append(", param_index = ");
+ sb.append(parameter_index);
+ sb.append(", bound_index = ");
+ sb.append(bound_index);
+ break;
+ // class extends or implements clause
+ case CLASS_EXTENDS:
+ sb.append(", type_index = ");
+ sb.append(type_index);
+ break;
+ // throws
+ case THROWS:
+ sb.append(", type_index = ");
+ sb.append(type_index);
+ break;
+ // exception parameter
+ case EXCEPTION_PARAMETER:
+ sb.append(", exception_index = ");
+ sb.append(exception_index);
+ break;
+ // method parameter
+ case METHOD_FORMAL_PARAMETER:
+ sb.append(", param_index = ");
+ sb.append(parameter_index);
+ break;
+ // method/constructor/reference type argument
+ case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_REFERENCE_TYPE_ARGUMENT:
+ sb.append(", offset = ");
+ sb.append(offset);
+ sb.append(", type_index = ");
+ sb.append(type_index);
+ break;
+ // We don't need to worry about these
+ case METHOD_RETURN:
+ case FIELD:
+ break;
+ // lambda formal parameter
+ case LAMBDA_FORMAL_PARAMETER:
+ // TODO: also needs an offset?
+ sb.append(", param_index = ");
+ sb.append(parameter_index);
+ break;
+ case UNKNOWN:
+ sb.append(", position UNKNOWN!");
+ break;
+ default:
+ throw new AssertionError("Unknown target type: " + type);
+ }
+
+ // Append location data for generics/arrays.
+ if (!location.isEmpty()) {
+ sb.append(", location = (");
+ sb.append(location);
+ sb.append(")");
+ }
+
+ sb.append(", pos = ");
+ sb.append(pos);
+
+ sb.append(']');
+ return sb.toString();
+ }
+
+ /**
+ * Indicates whether the target tree of the annotation has been optimized
+ * away from classfile or not.
+ * @return true if the target has not been optimized away
+ */
+ public boolean emitToClassfile() {
+ return !type.isLocal() || isValidOffset;
+ }
+
+ /**
+ * Decode the binary representation for a type path and set
+ * the {@code location} field.
+ *
+ * @param list The bytecode representation of the type path.
+ */
+ public static List getTypePathFromBinary(List list) {
+ List loc = new ArrayList(list.size() / TypePathEntry.bytesPerEntry);
+ int idx = 0;
+ while (idx < list.size()) {
+ if (idx + 1 == list.size()) {
+ throw new AssertionError("Could not decode type path: " + list);
+ }
+ loc.add(TypePathEntry.fromBinary(list.get(idx), list.get(idx + 1)));
+ idx += 2;
+ }
+ return loc;
+ }
+
+ public static List getBinaryFromTypePath(List locs) {
+ List loc = new ArrayList(locs.size() * TypePathEntry.bytesPerEntry);
+ for (TypePathEntry tpe : locs) {
+ loc.add(tpe.tag.tag);
+ loc.add(tpe.arg);
+ }
+ return loc;
+ }
+ }
+
+ // Code duplicated from com.sun.tools.javac.code.TargetType
+ // The IsLocal flag could be removed here.
+ public enum TargetType {
+ /** For annotations on a class type parameter declaration. */
+ CLASS_TYPE_PARAMETER(0x00),
+
+ /** For annotations on a method type parameter declaration. */
+ METHOD_TYPE_PARAMETER(0x01),
+
+ /** For annotations on the type of an "extends" or "implements" clause. */
+ CLASS_EXTENDS(0x10),
+
+ /** For annotations on a bound of a type parameter of a class. */
+ CLASS_TYPE_PARAMETER_BOUND(0x11),
+
+ /** For annotations on a bound of a type parameter of a method. */
+ METHOD_TYPE_PARAMETER_BOUND(0x12),
+
+ /** For annotations on a field. */
+ FIELD(0x13),
+
+ /** For annotations on a method return type. */
+ METHOD_RETURN(0x14),
+
+ /** For annotations on the method receiver. */
+ METHOD_RECEIVER(0x15),
+
+ /** For annotations on a method parameter. */
+ METHOD_FORMAL_PARAMETER(0x16),
+
+ /** For annotations on a throws clause in a method declaration. */
+ THROWS(0x17),
+
+ /** For annotations on a local variable. */
+ LOCAL_VARIABLE(0x40, true),
+
+ /** For annotations on a resource variable. */
+ RESOURCE_VARIABLE(0x41, true),
+
+ /** For annotations on an exception parameter. */
+ EXCEPTION_PARAMETER(0x42, true),
+
+ /** For annotations on a typecast. */
+ CAST(0x43, true),
+
+ /** For annotations on a type test. */
+ INSTANCEOF(0x44, true),
+
+ /** For annotations on an object creation expression. */
+ NEW(0x45, true),
+
+ /** For annotations on a type argument of an object creation expression. */
+ CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x46, true),
+
+ /** For annotations on a type argument of a method call. */
+ METHOD_INVOCATION_TYPE_ARGUMENT(0x47, true),
+
+ /** For annotations on a lambda parameter type. */
+ LAMBDA_FORMAL_PARAMETER(0x48, true),
+
+ /** For annotations on a method reference. */
+ METHOD_REFERENCE(0x49, true),
+
+ /** For annotations on a type argument of a method reference. */
+ METHOD_REFERENCE_TYPE_ARGUMENT(0x50, true),
+
+ /** For annotations with an unknown target. */
+ UNKNOWN(0xFF);
+
+ private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x50;
+
+ private final int targetTypeValue;
+ private final boolean isLocal;
+
+ private TargetType(int targetTypeValue) {
+ this(targetTypeValue, false);
+ }
+
+ private TargetType(int targetTypeValue, boolean isLocal) {
+ if (targetTypeValue < 0
+ || targetTypeValue > 255)
+ throw new AssertionError("Attribute type value needs to be an unsigned byte: " + String.format("0x%02X", targetTypeValue));
+ this.targetTypeValue = targetTypeValue;
+ this.isLocal = isLocal;
+ }
+
+ /**
+ * Returns whether or not this TargetType represents an annotation whose
+ * target is exclusively a tree in a method body
+ *
+ * Note: wildcard bound targets could target a local tree and a class
+ * member declaration signature tree
+ */
+ public boolean isLocal() {
+ return isLocal;
+ }
+
+ public int targetTypeValue() {
+ return this.targetTypeValue;
+ }
+
+ private static final TargetType[] targets;
+
+ static {
+ targets = new TargetType[MAXIMUM_TARGET_TYPE_VALUE + 1];
+ TargetType[] alltargets = values();
+ for (TargetType target : alltargets) {
+ if (target.targetTypeValue != UNKNOWN.targetTypeValue)
+ targets[target.targetTypeValue] = target;
+ }
+ for (int i = 0; i <= MAXIMUM_TARGET_TYPE_VALUE; ++i) {
+ if (targets[i] == null)
+ targets[i] = UNKNOWN;
+ }
+ }
+
+ public static boolean isValidTargetTypeValue(int tag) {
+ if (tag == UNKNOWN.targetTypeValue)
+ return true;
+ return (tag >= 0 && tag < targets.length);
+ }
+
+ public static TargetType fromTargetTypeValue(int tag) {
+ if (tag == UNKNOWN.targetTypeValue)
+ return UNKNOWN;
+
+ if (tag < 0 || tag >= targets.length)
+ throw new AssertionError("Unknown TargetType: " + tag);
+ return targets[tag];
+ }
+ }
+}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractExecutableMemberWriter.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractExecutableMemberWriter.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractExecutableMemberWriter.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -139,6 +139,15 @@
}
}
+ protected void addReceiverAnnotations(ExecutableMemberDoc member,
+ Content tree) {
+ if (member.receiverAnnotations().length > 0) {
+ tree.addContent(writer.getSpace());
+ writer.addReceiverAnnotationInfo(member, tree);
+ }
+ }
+
+
/**
* Add all the parameters for the executable member.
*
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstructorWriterImpl.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -137,6 +137,7 @@
addName(constructor.name(), pre);
}
addParameters(constructor, pre);
+ writer.addReceiverAnnotationInfo(constructor, pre);
addExceptions(constructor, pre);
return pre;
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -1730,6 +1730,17 @@
}
/**
+ * Add the annotation types of the executable receiver.
+ *
+ * @param method the executable to write the receiver annotations for.
+ * @param htmltree the documentation tree to which the annotation info will be
+ * added
+ */
+ public void addReceiverAnnotationInfo(ExecutableMemberDoc method, Content htmltree) {
+ addAnnotationInfo(method, method.receiverAnnotations(), htmltree);
+ }
+
+ /**
* Adds the annotatation types for the given doc.
*
* @param doc the package to write annotations for
@@ -1799,6 +1810,26 @@
* documented.
*/
private List getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak) {
+ return getAnnotations(indent, descList, linkBreak, true);
+ }
+
+ /**
+ * Return the string representations of the annotation types for
+ * the given doc.
+ *
+ * A {@code null} {@code elementType} indicates that all the
+ * annotations should be returned without any filtering.
+ *
+ * @param indent the number of extra spaces to indent the annotations.
+ * @param descList the array of {@link AnnotationDesc}.
+ * @param linkBreak if true, add new line between each member value.
+ * @param elementType the type of targeted element (used for filtering
+ * type annotations from declaration annotations)
+ * @return an array of strings representing the annotations being
+ * documented.
+ */
+ public List getAnnotations(int indent, AnnotationDesc[] descList, boolean linkBreak,
+ boolean isJava5DeclarationLocation) {
List results = new ArrayList();
StringBuilder annotation;
for (int i = 0; i < descList.length; i++) {
@@ -1812,6 +1843,11 @@
(!isAnnotationDocumented && !isContainerDocumented)) {
continue;
}
+ /* TODO: check logic here to correctly handle declaration
+ * and type annotations.
+ if (Util.isDeclarationAnnotation(annotationDoc, isJava5DeclarationLocation)) {
+ continue;
+ }*/
annotation = new StringBuilder();
isAnnotationDocumented = false;
LinkInfoImpl linkInfo = new LinkInfoImpl(configuration,
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -25,6 +25,8 @@
package com.sun.tools.doclets.formats.html;
+import java.util.List;
+
import com.sun.javadoc.*;
import com.sun.tools.doclets.internal.toolkit.*;
import com.sun.tools.doclets.internal.toolkit.util.*;
@@ -123,11 +125,50 @@
typeLinkInfo.excludeTypeBounds = linkInfo.excludeTypeBounds;
typeLinkInfo.excludeTypeParameterLinks = linkInfo.excludeTypeParameterLinks;
typeLinkInfo.linkToSelf = linkInfo.linkToSelf;
+ typeLinkInfo.isJava5DeclarationLocation = false;
LinkOutput output = getLinkOutput(typeLinkInfo);
((LinkInfoImpl) linkInfo).displayLength += typeLinkInfo.displayLength;
return output;
}
+ protected LinkOutput getTypeAnnotationLink(LinkInfo linkInfo,
+ AnnotationDesc annotation) {
+ throw new RuntimeException("Not implemented yet!");
+ }
+
+ public LinkOutput getTypeAnnotationLinks(LinkInfo linkInfo) {
+ LinkOutput output = getOutputInstance();
+ AnnotationDesc[] annotations;
+ if (linkInfo.type instanceof AnnotatedType) {
+ annotations = linkInfo.type.asAnnotatedType().annotations();
+ } else if (linkInfo.type instanceof TypeVariable) {
+ annotations = linkInfo.type.asTypeVariable().annotations();
+ } else {
+ return output;
+ }
+
+ if (annotations.length == 0)
+ return output;
+
+ List annos = m_writer.getAnnotations(0, annotations, false, linkInfo.isJava5DeclarationLocation);
+
+ boolean isFirst = true;
+ for (String anno : annos) {
+ if (!isFirst) {
+ linkInfo.displayLength += 1;
+ output.append(" ");
+ isFirst = false;
+ }
+ output.append(anno);
+ }
+ if (!annos.isEmpty()) {
+ linkInfo.displayLength += 1;
+ output.append(" ");
+ }
+
+ return output;
+ }
+
/**
* Given a class, return the appropriate tool tip.
*
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkInfoImpl.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkInfoImpl.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkInfoImpl.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -459,6 +459,8 @@
case CONTEXT_RETURN_TYPE:
case CONTEXT_SUMMARY_RETURN_TYPE:
+ excludeTypeBounds = true;
+ break;
case CONTEXT_EXECUTABLE_MEMBER_PARAM:
excludeTypeBounds = true;
break;
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/MethodWriterImpl.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -130,6 +130,7 @@
addName(method.name(), pre);
}
addParameters(method, pre);
+ addReceiverAnnotations(method, pre);
addExceptions(method, pre);
return pre;
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -26,9 +26,11 @@
package com.sun.tools.doclets.internal.toolkit.util;
import java.io.*;
+import java.lang.annotation.ElementType;
import java.util.*;
import com.sun.javadoc.*;
+import com.sun.javadoc.AnnotationDesc.ElementValuePair;
import com.sun.tools.doclets.internal.toolkit.*;
import javax.tools.StandardLocation;
@@ -304,9 +306,7 @@
//Try walking the tree.
addAllInterfaceTypes(results,
superType,
- superType instanceof ClassDoc ?
- ((ClassDoc) superType).interfaceTypes() :
- ((ParameterizedType) superType).interfaceTypes(),
+ interfaceTypesOf(superType),
false, configuration);
List resultsList = new ArrayList(results.values());
if (sort) {
@@ -315,6 +315,14 @@
return resultsList;
}
+ private static Type[] interfaceTypesOf(Type type) {
+ if (type instanceof AnnotatedType)
+ type = ((AnnotatedType)type).underlyingType();
+ return type instanceof ClassDoc ?
+ ((ClassDoc)type).interfaceTypes() :
+ ((ParameterizedType)type).interfaceTypes();
+ }
+
public static List getAllInterfaces(Type type, Configuration configuration) {
return getAllInterfaces(type, configuration, true);
}
@@ -325,9 +333,7 @@
if (superType == null)
return;
addAllInterfaceTypes(results, superType,
- superType instanceof ClassDoc ?
- ((ClassDoc) superType).interfaceTypes() :
- ((ParameterizedType) superType).interfaceTypes(),
+ interfaceTypesOf(superType),
raw, configuration);
}
@@ -337,9 +343,7 @@
if (superType == null)
return;
addAllInterfaceTypes(results, superType,
- superType instanceof ClassDoc ?
- ((ClassDoc) superType).interfaceTypes() :
- ((ParameterizedType) superType).interfaceTypes(),
+ interfaceTypesOf(superType),
false, configuration);
}
@@ -363,6 +367,9 @@
results.put(superInterface.asClassDoc(), superInterface);
}
}
+ if (type instanceof AnnotatedType)
+ type = ((AnnotatedType)type).underlyingType();
+
if (type instanceof ParameterizedType)
findAllInterfaceTypes(results, (ParameterizedType) type, configuration);
else if (((ClassDoc) type).typeParameters().length == 0)
@@ -494,6 +501,57 @@
return false;
}
+ private static boolean isDeclarationTarget(AnnotationDesc targetAnno) {
+ // The error recovery steps here are analogous to TypeAnnotations
+ ElementValuePair[] elems = targetAnno.elementValues();
+ if (elems == null
+ || elems.length != 1
+ || !"value".equals(elems[0].element().name())
+ || !(elems[0].value().value() instanceof AnnotationValue[]))
+ return true; // error recovery
+
+ AnnotationValue[] values = (AnnotationValue[])elems[0].value().value();
+ for (int i = 0; i < values.length; i++) {
+ Object value = values[i].value();
+ if (!(value instanceof FieldDoc))
+ return true; // error recovery
+
+ FieldDoc eValue = (FieldDoc)value;
+ if (Util.isJava5DeclarationElementType(eValue)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns true if the {@code annotationDoc} is to be treated
+ * as a declaration annotation, when targeting the
+ * {@code elemType} element type.
+ *
+ * @param annotationDoc the annotationDoc to check
+ * @param elemType the targeted elemType
+ * @return true if annotationDoc is a declaration annotation
+ */
+ public static boolean isDeclarationAnnotation(AnnotationTypeDoc annotationDoc,
+ boolean isJava5DeclarationLocation) {
+ if (!isJava5DeclarationLocation)
+ return false;
+ AnnotationDesc[] annotationDescList = annotationDoc.annotations();
+ // Annotations with no target are treated as declaration as well
+ if (annotationDescList.length==0)
+ return true;
+ for (int i = 0; i < annotationDescList.length; i++) {
+ if (annotationDescList[i].annotationType().qualifiedName().equals(
+ java.lang.annotation.Target.class.getName())) {
+ if (isDeclarationTarget(annotationDescList[i]))
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Return true if this class is linkable and false if we can't link to the
* desired class.
@@ -662,4 +720,25 @@
}
return false;
}
+
+ /**
+ * Test whether the given FieldDoc is one of the declaration annotation ElementTypes
+ * defined in Java 5.
+ * Instead of testing for one of the new enum constants added in Java 8, test for
+ * the old constants. This prevents bootstrapping problems.
+ *
+ * @param elt The FieldDoc to test
+ * @return true, iff the given ElementType is one of the constants defined in Java 5
+ * @since 1.8
+ */
+ public static boolean isJava5DeclarationElementType(FieldDoc elt) {
+ return elt.name().contentEquals(ElementType.ANNOTATION_TYPE.name()) ||
+ elt.name().contentEquals(ElementType.CONSTRUCTOR.name()) ||
+ elt.name().contentEquals(ElementType.FIELD.name()) ||
+ elt.name().contentEquals(ElementType.LOCAL_VARIABLE.name()) ||
+ elt.name().contentEquals(ElementType.METHOD.name()) ||
+ elt.name().contentEquals(ElementType.PACKAGE.name()) ||
+ elt.name().contentEquals(ElementType.PARAMETER.name()) ||
+ elt.name().contentEquals(ElementType.TYPE.name());
+ }
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/LinkFactory.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/LinkFactory.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/LinkFactory.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -61,6 +61,11 @@
//Just a primitive.
linkInfo.displayLength += type.typeName().length();
linkOutput.append(type.typeName());
+ } else if (type.asAnnotatedType() != null) {
+ linkOutput.append(getTypeAnnotationLinks(linkInfo));
+ linkInfo.type = type.asAnnotatedType().underlyingType();
+ linkOutput.append(getLinkOutput(linkInfo));
+ return linkOutput;
} else if (type.asWildcardType() != null) {
//Wildcard type.
linkInfo.isTypeBound = true;
@@ -82,6 +87,7 @@
linkOutput.append(getLinkOutput(linkInfo));
}
} else if (type.asTypeVariable()!= null) {
+ linkOutput.append(getTypeAnnotationLinks(linkInfo));
linkInfo.isTypeBound = true;
//A type variable.
Doc owner = type.asTypeVariable().owner();
@@ -175,6 +181,9 @@
protected abstract LinkOutput getTypeParameterLink(LinkInfo linkInfo,
Type typeParam);
+ protected abstract LinkOutput getTypeAnnotationLink(LinkInfo linkInfo,
+ AnnotationDesc annotation);
+
/**
* Return the links to the type parameters.
*
@@ -226,6 +235,24 @@
return output;
}
+ public LinkOutput getTypeAnnotationLinks(LinkInfo linkInfo) {
+ LinkOutput output = getOutputInstance();
+ if (linkInfo.type.asAnnotatedType() == null)
+ return output;
+ AnnotationDesc[] annotations = linkInfo.type.asAnnotatedType().annotations();
+ for (int i = 0; i < annotations.length; i++) {
+ if (i > 0) {
+ linkInfo.displayLength += 1;
+ output.append(" ");
+ }
+ output.append(getTypeAnnotationLink(linkInfo, annotations[i]));
+ }
+
+ linkInfo.displayLength += 1;
+ output.append(" ");
+ return output;
+ }
+
/**
* Return <, which is used in type parameters. Override this
* if your doclet uses something different.
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/LinkInfo.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/LinkInfo.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/links/LinkInfo.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -69,6 +69,12 @@
public boolean isTypeBound = false;
/**
+ * Whether the document element is in a Java 5 declaration
+ * location or not.
+ */
+ public boolean isJava5DeclarationLocation = true;
+
+ /**
* The label for the link.
*/
public String label;
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/Annotations.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Annotations.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Annotations.java Wed Jan 23 13:27:24 2013 -0800
@@ -48,7 +48,7 @@
*
* An instance of this class can be in one of three states:
*
- * NOT_STARTED indicates that the Symbol this instance belongs to have not been
+ * NOT_STARTED indicates that the Symbol this instance belongs to has not been
* annotated (yet). Specifically if the declaration is not annotated this
* instance will never move past NOT_STARTED. You can never go back to
* NOT_STARTED.
@@ -59,7 +59,7 @@
*
* "unnamed" this Annotations contains some attributes, possibly the final set.
* While in this state you can only prepend or append to the attributes not set
- * it directly. You can also move back to the IN_PROGRESS sate using reset().
+ * it directly. You can also move back to the IN_PROGRESS state using reset().
*
* This is NOT part of any supported API. If you write code that depends
* on this, you do so at your own risk. This code and its internal interfaces
@@ -67,14 +67,21 @@
*/
public class Annotations {
- private static final List NOT_STARTED = List.of(null);
- private static final List IN_PROGRESS = List.of(null);
+ private static final List DECL_NOT_STARTED = List.of(null);
+ private static final List DECL_IN_PROGRESS = List.of(null);
+
/*
* This field should never be null
*/
- private List attributes = NOT_STARTED;
+ private List attributes = DECL_NOT_STARTED;
+
/*
- * The Symbol this Annotations belong to
+ * This field should never be null
+ */
+ private List type_attributes = List.nil();
+
+ /*
+ * The Symbol this Annotations instance belongs to
*/
private final Symbol sym;
@@ -82,11 +89,15 @@
this.sym = sym;
}
- public List getAttributes() {
- return filterSentinels(attributes);
+ public List getDeclarationAttributes() {
+ return filterDeclSentinels(attributes);
}
- public void setAttributes(List a) {
+ public List getTypeAttributes() {
+ return type_attributes;
+ }
+
+ public void setDeclarationAttributes(List a) {
Assert.check(pendingCompletion() || !isStarted());
if (a == null) {
throw new NullPointerException();
@@ -94,31 +105,51 @@
attributes = a;
}
+ public void setTypeAttributes(List a) {
+ if (a == null) {
+ throw new NullPointerException();
+ }
+ type_attributes = a;
+ }
+
public void setAttributes(Annotations other) {
if (other == null) {
throw new NullPointerException();
}
- setAttributes(other.getAttributes());
+ setDeclarationAttributes(other.getDeclarationAttributes());
+ setTypeAttributes(other.getTypeAttributes());
+ }
+
+ public void setDeclarationAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) {
+ Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK));
+ this.setDeclarationAttributes(getAttributesForCompletion(ctx));
}
- public void setAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) {
- Assert.check(pendingCompletion() || (!isStarted() && sym.kind == PCK));
+ public void appendTypeAttributesWithCompletion(final Annotate.AnnotateRepeatedContext ctx) {
+ this.appendUniqueTypes(getAttributesForCompletion(ctx));
+ }
- Map> annotated = ctx.annotated;
+ private List getAttributesForCompletion(
+ final Annotate.AnnotateRepeatedContext ctx) {
+
+ Map> annotated = ctx.annotated;
boolean atLeastOneRepeated = false;
- List buf = List.nil();
- for (ListBuffer lb : annotated.values()) {
+ List buf = List.nil();
+ for (ListBuffer lb : annotated.values()) {
if (lb.size() == 1) {
buf = buf.prepend(lb.first());
} else { // repeated
- buf = buf.prepend(new Placeholder(lb.toList(), sym));
+ // This will break when other subtypes of Attributs.Compound
+ // are introduced, because PlaceHolder is a subtype of TypeCompound.
+ T res;
+ @SuppressWarnings("unchecked")
+ T ph = (T) new Placeholder(ctx, lb.toList(), sym);
+ res = ph;
+ buf = buf.prepend(res);
atLeastOneRepeated = true;
}
}
- // Add non-repeating attributes
- setAttributes(buf.reverse());
-
if (atLeastOneRepeated) {
// The Symbol s is now annotated with a combination of
// finished non-repeating annotations and placeholders for
@@ -138,7 +169,6 @@
// Queue a pass that will replace Attribute.Placeholders
// with Attribute.Compound (made from synthesized containers).
ctx.annotateRepeated(new Annotate.Annotator() {
-
@Override
public String toString() {
return "repeated annotation pass of: " + sym + " in: " + sym.owner;
@@ -150,10 +180,12 @@
}
});
}
+ // Add non-repeating attributes
+ return buf.reverse();
}
public Annotations reset() {
- attributes = IN_PROGRESS;
+ attributes = DECL_IN_PROGRESS;
return this;
}
@@ -163,12 +195,16 @@
|| attributes.isEmpty();
}
+ public boolean isTypesEmpty() {
+ return type_attributes.isEmpty();
+ }
+
public boolean pendingCompletion() {
- return attributes == IN_PROGRESS;
+ return attributes == DECL_IN_PROGRESS;
}
public Annotations append(List l) {
- attributes = filterSentinels(attributes);
+ attributes = filterDeclSentinels(attributes);
if (l.isEmpty()) {
; // no-op
@@ -180,8 +216,24 @@
return this;
}
+ public Annotations appendUniqueTypes(List l) {
+ if (l.isEmpty()) {
+ ; // no-op
+ } else if (type_attributes.isEmpty()) {
+ type_attributes = l;
+ } else {
+ // TODO: in case we expect a large number of annotations, this
+ // might be inefficient.
+ for (Attribute.TypeCompound tc : l) {
+ if (!type_attributes.contains(tc))
+ type_attributes = type_attributes.append(tc);
+ }
+ }
+ return this;
+ }
+
public Annotations prepend(List l) {
- attributes = filterSentinels(attributes);
+ attributes = filterDeclSentinels(attributes);
if (l.isEmpty()) {
; // no-op
@@ -193,19 +245,29 @@
return this;
}
- private List filterSentinels(List a) {
- return (a == IN_PROGRESS || a == NOT_STARTED)
+ private List filterDeclSentinels(List a) {
+ return (a == DECL_IN_PROGRESS || a == DECL_NOT_STARTED)
? List.nil()
: a;
}
private boolean isStarted() {
- return attributes != NOT_STARTED;
+ return attributes != DECL_NOT_STARTED;
}
private List getPlaceholders() {
List res = List.nil();
- for (Attribute.Compound a : filterSentinels(attributes)) {
+ for (Attribute.Compound a : filterDeclSentinels(attributes)) {
+ if (a instanceof Placeholder) {
+ res = res.prepend(a);
+ }
+ }
+ return res.reverse();
+ }
+
+ private List getTypePlaceholders() {
+ List res = List.nil();
+ for (Attribute.TypeCompound a : type_attributes) {
if (a instanceof Placeholder) {
res = res.prepend(a);
}
@@ -216,50 +278,78 @@
/*
* Replace Placeholders for repeating annotations with their containers
*/
- private void complete(Annotate.AnnotateRepeatedContext ctx) {
- Assert.check(!pendingCompletion());
+ private void complete(Annotate.AnnotateRepeatedContext ctx) {
Log log = ctx.log;
Env env = ctx.env;
JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile);
try {
+ // TODO: can we reduce duplication in the following branches?
+ if (ctx.isTypeCompound) {
+ Assert.check(!isTypesEmpty());
- if (isEmpty()) {
- return;
- }
+ if (isTypesEmpty()) {
+ return;
+ }
- List result = List.nil();
- for (Attribute.Compound a : getAttributes()) {
- if (a instanceof Placeholder) {
- Attribute.Compound replacement = replaceOne((Placeholder) a, ctx);
+ List result = List.nil();
+ for (Attribute.TypeCompound a : getTypeAttributes()) {
+ if (a instanceof Placeholder) {
+ @SuppressWarnings("unchecked")
+ Placeholder ph = (Placeholder) a;
+ Attribute.TypeCompound replacement = replaceOne(ph, ph.getRepeatedContext());
+
+ if (null != replacement) {
+ result = result.prepend(replacement);
+ }
+ } else {
+ result = result.prepend(a);
+ }
+ }
+
+ type_attributes = result.reverse();
- if (null != replacement) {
- result = result.prepend(replacement);
- }
- } else {
- result = result.prepend(a);
+ Assert.check(Annotations.this.getTypePlaceholders().isEmpty());
+ } else {
+ Assert.check(!pendingCompletion());
+
+ if (isEmpty()) {
+ return;
}
- }
+
+ List result = List.nil();
+ for (Attribute.Compound a : getDeclarationAttributes()) {
+ if (a instanceof Placeholder) {
+ @SuppressWarnings("unchecked")
+ Attribute.Compound replacement = replaceOne((Placeholder) a, ctx);
- attributes = result.reverse();
+ if (null != replacement) {
+ result = result.prepend(replacement);
+ }
+ } else {
+ result = result.prepend(a);
+ }
+ }
- Assert.check(Annotations.this.getPlaceholders().isEmpty());
+ attributes = result.reverse();
+
+ Assert.check(Annotations.this.getPlaceholders().isEmpty());
+ }
} finally {
log.useSource(oldSource);
}
}
- private Attribute.Compound replaceOne(Placeholder placeholder, Annotate.AnnotateRepeatedContext ctx) {
+ private T replaceOne(Placeholder placeholder, Annotate.AnnotateRepeatedContext ctx) {
Log log = ctx.log;
// Process repeated annotations
- Attribute.Compound validRepeated =
- ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym);
+ T validRepeated = ctx.processRepeatedAnnotations(placeholder.getPlaceholderFor(), sym);
if (validRepeated != null) {
// Check that the container isn't manually
// present along with repeated instances of
// its contained annotation.
- ListBuffer manualContainer = ctx.annotated.get(validRepeated.type.tsym);
+ ListBuffer manualContainer = ctx.annotated.get(validRepeated.type.tsym);
if (manualContainer != null) {
log.error(ctx.pos.get(manualContainer.first()), "invalid.repeatable.annotation.repeated.and.container.present",
manualContainer.first().type.tsym);
@@ -268,16 +358,20 @@
// A null return will delete the Placeholder
return validRepeated;
-
}
- private static class Placeholder extends Attribute.Compound {
+ private static class Placeholder extends Attribute.TypeCompound {
+
+ private final Annotate.AnnotateRepeatedContext ctx;
+ private final List placeholderFor;
+ private final Symbol on;
- private List placeholderFor;
- private Symbol on;
-
- public Placeholder(List placeholderFor, Symbol on) {
- super(Type.noType, List.>nil());
+ public Placeholder(Annotate.AnnotateRepeatedContext ctx, List placeholderFor, Symbol on) {
+ super(on.type, List.>nil(),
+ ctx.isTypeCompound ?
+ ((Attribute.TypeCompound)placeholderFor.head).position :
+ null);
+ this.ctx = ctx;
this.placeholderFor = placeholderFor;
this.on = on;
}
@@ -287,8 +381,12 @@
return "";
}
- public List getPlaceholderFor() {
+ public List getPlaceholderFor() {
return placeholderFor;
}
+
+ public Annotate.AnnotateRepeatedContext getRepeatedContext() {
+ return ctx;
+ }
}
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -217,6 +217,21 @@
}
}
+ public static class TypeCompound extends Compound {
+ public TypeAnnotationPosition position;
+ public TypeCompound(Compound compound,
+ TypeAnnotationPosition position) {
+ this(compound.type, compound.values, position);
+ }
+ public TypeCompound(Type type,
+ List> values,
+ TypeAnnotationPosition position) {
+ super(type, values);
+ this.position = position;
+ }
+
+ }
+
/** The value for an annotation element of an array type.
*/
public static class Array extends Attribute {
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/Flags.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Flags.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -233,23 +233,23 @@
public static final long PROPRIETARY = 1L<<38;
/**
- * Flag that marks a a multi-catch parameter
+ * Flag that marks a multi-catch parameter.
*/
public static final long UNION = 1L<<39;
/**
- * Flag that marks a special kind of bridge methods (the ones that
- * come from restricted supertype bounds)
+ * Flag that marks a special kind of bridge method (the ones that
+ * come from restricted supertype bounds).
*/
public static final long OVERRIDE_BRIDGE = 1L<<40;
/**
- * Flag that marks an 'effectively final' local variable
+ * Flag that marks an 'effectively final' local variable.
*/
public static final long EFFECTIVELY_FINAL = 1L<<41;
/**
- * Flag that marks non-override equivalent methods with the same signature
+ * Flag that marks non-override equivalent methods with the same signature.
*/
public static final long CLASH = 1L<<42;
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/Lint.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Lint.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Lint.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -74,7 +74,7 @@
* the given annotations.
*/
public Lint augment(Annotations annots) {
- return augmentor.augment(this, annots.getAttributes());
+ return augmentor.augment(this, annots.getDeclarationAttributes());
}
/**
@@ -82,7 +82,7 @@
* the given annotations and flags.
*/
public Lint augment(Annotations annots, long flags) {
- Lint l = augmentor.augment(this, annots.getAttributes());
+ Lint l = augmentor.augment(this, annots.getDeclarationAttributes());
if ((flags & DEPRECATED) != 0) {
if (l == this)
l = new Lint(this);
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/Printer.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -27,7 +27,10 @@
import java.util.Locale;
+import javax.lang.model.type.TypeKind;
+
import com.sun.tools.javac.api.Messages;
+import com.sun.tools.javac.code.Type.AnnotatedType;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.util.List;
@@ -35,7 +38,6 @@
import static com.sun.tools.javac.code.BoundKind.*;
import static com.sun.tools.javac.code.Flags.*;
-import static com.sun.tools.javac.code.TypeTag.ARRAY;
import static com.sun.tools.javac.code.TypeTag.CLASS;
import static com.sun.tools.javac.code.TypeTag.FORALL;
@@ -188,7 +190,7 @@
StringBuilder buf = new StringBuilder();
if (t.getEnclosingType().tag == CLASS && t.tsym.owner.kind == Kinds.TYP) {
buf.append(visit(t.getEnclosingType(), locale));
- buf.append(".");
+ buf.append('.');
buf.append(className(t, false, locale));
} else {
buf.append(className(t, true, locale));
@@ -196,7 +198,7 @@
if (t.getTypeArguments().nonEmpty()) {
buf.append('<');
buf.append(visitTypes(t.getTypeArguments(), locale));
- buf.append(">");
+ buf.append('>');
}
return buf.toString();
}
@@ -231,6 +233,17 @@
return visitType(t, locale);
}
+ @Override
+ public String visitAnnotatedType(AnnotatedType t, Locale locale) {
+ if (t.typeAnnotations != null &&
+ t.typeAnnotations.nonEmpty()) {
+ // TODO: better logic for arrays, ...
+ return "(" + t.typeAnnotations + " :: " + visit(t.underlyingType, locale) + ")";
+ } else {
+ return "({} :: " + visit(t.underlyingType, locale) + ")";
+ }
+ }
+
public String visitType(Type t, Locale locale) {
String s = (t.tsym == null || t.tsym.name == null)
? localize(locale, "compiler.misc.type.none")
@@ -296,8 +309,13 @@
args = args.tail;
buf.append(',');
}
- if (args.head.tag == ARRAY) {
- buf.append(visit(((ArrayType) args.head).elemtype, locale));
+ if (args.head.unannotatedType().getKind() == TypeKind.ARRAY) {
+ buf.append(visit(((ArrayType) args.head.unannotatedType()).elemtype, locale));
+ if (args.head.getAnnotations().nonEmpty()) {
+ buf.append(' ');
+ buf.append(args.head.getAnnotations());
+ buf.append(' ');
+ }
buf.append("...");
} else {
buf.append(visit(args.head, locale));
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/Source.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -176,9 +176,6 @@
public boolean allowTryWithResources() {
return compareTo(JDK1_7) >= 0;
}
- public boolean allowTypeAnnotations() {
- return compareTo(JDK1_7) >= 0;
- }
public boolean allowBinaryLiterals() {
return compareTo(JDK1_7) >= 0;
}
@@ -215,6 +212,9 @@
public boolean allowEffectivelyFinalInInnerClasses() {
return compareTo(JDK1_8) >= 0;
}
+ public boolean allowTypeAnnotations() {
+ return compareTo(JDK1_8) >= 0;
+ }
public boolean allowRepeatedAnnotations() {
return compareTo(JDK1_8) >= 0;
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Wed Jan 23 13:27:24 2013 -0800
@@ -84,7 +84,15 @@
* method to make sure that the class symbol is loaded.
*/
public List getRawAttributes() {
- return annotations.getAttributes();
+ return annotations.getDeclarationAttributes();
+ }
+
+ /** An accessor method for the type attributes of this symbol.
+ * Attributes of class symbols should be accessed through the accessor
+ * method to make sure that the class symbol is loaded.
+ */
+ public List getRawTypeAttributes() {
+ return annotations.getTypeAttributes();
}
/** Fetch a particular annotation from a symbol. */
@@ -455,6 +463,14 @@
}
/**
+ * TODO: Should there be a {@code
+ * javax.lang.model.element.Element.getTypeAnnotationMirrors()}.
+ */
+ public final List getTypeAnnotationMirrors() {
+ return getRawTypeAttributes();
+ }
+
+ /**
* @deprecated this method should never be used by javac internally.
*/
@Deprecated
@@ -795,6 +811,12 @@
return super.getRawAttributes();
}
+ @Override
+ public List getRawTypeAttributes() {
+ if (completer != null) complete();
+ return super.getRawTypeAttributes();
+ }
+
public Type erasure(Types types) {
if (erasure_field == null)
erasure_field = new ClassType(types.erasure(type.getEnclosingType()),
@@ -1387,7 +1409,7 @@
return defaultValue;
}
- public List getParameters() {
+ public List getParameters() {
return params();
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/TargetType.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/TargetType.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/TargetType.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -25,10 +25,7 @@
package com.sun.tools.javac.code;
-import java.util.EnumSet;
-import java.util.Set;
-
-import static com.sun.tools.javac.code.TargetType.TargetAttribute.*;
+import com.sun.tools.javac.util.Assert;
/**
* Describes the type of program element an extended annotation (or extended
@@ -44,178 +41,89 @@
* This code and its internal interfaces are subject to change or
* deletion without notice.
*/
+// Code duplicated in com.sun.tools.classfile.TypeAnnotation.TargetType
public enum TargetType {
-
- //
- // Some target types are commented out, because Java doesn't permit such
- // targets. They are included here to confirm that their omission is
- // intentional omission not an accidental omission.
- //
-
- /** For annotations on typecasts. */
- TYPECAST(0x00, IsLocal),
-
- /** For annotations on a type argument or nested array of a typecast. */
- TYPECAST_GENERIC_OR_ARRAY(0x01, HasLocation, IsLocal),
-
- /** For annotations on type tests. */
- INSTANCEOF(0x02, IsLocal),
-
- /** For annotations on a type argument or nested array of a type test. */
- INSTANCEOF_GENERIC_OR_ARRAY(0x03, HasLocation, IsLocal),
-
- /** For annotations on object creation expressions. */
- NEW(0x04, IsLocal),
-
- /**
- * For annotations on a type argument or nested array of an object creation
- * expression.
- */
- NEW_GENERIC_OR_ARRAY(0x05, HasLocation, IsLocal),
-
-
- /** For annotations on the method receiver. */
- METHOD_RECEIVER(0x06),
-
- // invalid location
- //@Deprecated METHOD_RECEIVER_GENERIC_OR_ARRAY(0x07, HasLocation),
-
- /** For annotations on local variables. */
- LOCAL_VARIABLE(0x08, IsLocal),
+ /** For annotations on a class type parameter declaration. */
+ CLASS_TYPE_PARAMETER(0x00),
- /** For annotations on a type argument or nested array of a local. */
- LOCAL_VARIABLE_GENERIC_OR_ARRAY(0x09, HasLocation, IsLocal),
-
- // handled by regular annotations
- //@Deprecated METHOD_RETURN(0x0A),
-
- /**
- * For annotations on a type argument or nested array of a method return
- * type.
- */
- METHOD_RETURN_GENERIC_OR_ARRAY(0x0B, HasLocation),
-
- // handled by regular annotations
- //@Deprecated METHOD_PARAMETER(0x0C),
-
- /** For annotations on a type argument or nested array of a method parameter. */
- METHOD_PARAMETER_GENERIC_OR_ARRAY(0x0D, HasLocation),
-
- // handled by regular annotations
- //@Deprecated FIELD(0x0E),
-
- /** For annotations on a type argument or nested array of a field. */
- FIELD_GENERIC_OR_ARRAY(0x0F, HasLocation),
-
- /** For annotations on a bound of a type parameter of a class. */
- CLASS_TYPE_PARAMETER_BOUND(0x10, HasBound, HasParameter),
-
- /**
- * For annotations on a type argument or nested array of a bound of a type
- * parameter of a class.
- */
- CLASS_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY(0x11, HasBound, HasLocation, HasParameter),
-
- /** For annotations on a bound of a type parameter of a method. */
- METHOD_TYPE_PARAMETER_BOUND(0x12, HasBound, HasParameter),
-
- /**
- * For annotations on a type argument or nested array of a bound of a type
- * parameter of a method.
- */
- METHOD_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY(0x13, HasBound, HasLocation, HasParameter),
+ /** For annotations on a method type parameter declaration. */
+ METHOD_TYPE_PARAMETER(0x01),
/** For annotations on the type of an "extends" or "implements" clause. */
- CLASS_EXTENDS(0x14),
+ CLASS_EXTENDS(0x10),
+
+ /** For annotations on a bound of a type parameter of a class. */
+ CLASS_TYPE_PARAMETER_BOUND(0x11),
+
+ /** For annotations on a bound of a type parameter of a method. */
+ METHOD_TYPE_PARAMETER_BOUND(0x12),
- /** For annotations on the inner type of an "extends" or "implements" clause. */
- CLASS_EXTENDS_GENERIC_OR_ARRAY(0x15, HasLocation),
+ /** For annotations on a field. */
+ FIELD(0x13),
+
+ /** For annotations on a method return type. */
+ METHOD_RETURN(0x14),
+
+ /** For annotations on the method receiver. */
+ METHOD_RECEIVER(0x15),
+
+ /** For annotations on a method parameter. */
+ METHOD_FORMAL_PARAMETER(0x16),
/** For annotations on a throws clause in a method declaration. */
- THROWS(0x16),
+ THROWS(0x17),
- // invalid location
- //@Deprecated THROWS_GENERIC_OR_ARRAY(0x17, HasLocation),
+ /** For annotations on a local variable. */
+ LOCAL_VARIABLE(0x40, true),
+
+ /** For annotations on a resource variable. */
+ RESOURCE_VARIABLE(0x41, true),
- /** For annotations in type arguments of object creation expressions. */
- NEW_TYPE_ARGUMENT(0x18, IsLocal),
- NEW_TYPE_ARGUMENT_GENERIC_OR_ARRAY(0x19, HasLocation, IsLocal),
+ /** For annotations on an exception parameter. */
+ EXCEPTION_PARAMETER(0x42, true),
- METHOD_TYPE_ARGUMENT(0x1A, IsLocal),
- METHOD_TYPE_ARGUMENT_GENERIC_OR_ARRAY(0x1B, HasLocation, IsLocal),
+ /** For annotations on a typecast. */
+ CAST(0x43, true),
+
+ /** For annotations on a type test. */
+ INSTANCEOF(0x44, true),
- WILDCARD_BOUND(0x1C, HasBound),
- WILDCARD_BOUND_GENERIC_OR_ARRAY(0x1D, HasBound, HasLocation),
+ /** For annotations on an object creation expression. */
+ NEW(0x45, true),
- CLASS_LITERAL(0x1E, IsLocal),
- CLASS_LITERAL_GENERIC_OR_ARRAY(0x1F, HasLocation, IsLocal),
+ /** For annotations on a type argument of an object creation expression. */
+ CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x46, true),
- METHOD_TYPE_PARAMETER(0x20, HasParameter),
+ /** For annotations on a type argument of a method call. */
+ METHOD_INVOCATION_TYPE_ARGUMENT(0x47, true),
- // invalid location
- //@Deprecated METHOD_TYPE_PARAMETER_GENERIC_OR_ARRAY(0x21, HasLocation, HasParameter),
+ /** For annotations on a lambda parameter type. */
+ LAMBDA_FORMAL_PARAMETER(0x48, true),
- CLASS_TYPE_PARAMETER(0x22, HasParameter),
+ /** For annotations on a method reference. */
+ METHOD_REFERENCE(0x49, true),
- // invalid location
- //@Deprecated CLASS_TYPE_PARAMETER_GENERIC_OR_ARRAY(0x23, HasLocation, HasParameter),
+ /** For annotations on a type argument of a method reference. */
+ METHOD_REFERENCE_TYPE_ARGUMENT(0x50, true),
/** For annotations with an unknown target. */
- UNKNOWN(-1);
+ UNKNOWN(0xFF);
- static final int MAXIMUM_TARGET_TYPE_VALUE = 0x22;
+ private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x92;
private final int targetTypeValue;
- private final Set flags;
+ private final boolean isLocal;
- TargetType(int targetTypeValue, TargetAttribute... attributes) {
- if (targetTypeValue < Byte.MIN_VALUE
- || targetTypeValue > Byte.MAX_VALUE)
- throw new AssertionError("attribute type value needs to be a byte: " + targetTypeValue);
- this.targetTypeValue = (byte)targetTypeValue;
- flags = EnumSet.noneOf(TargetAttribute.class);
- for (TargetAttribute attr : attributes)
- flags.add(attr);
- }
-
- /**
- * Returns whether or not this TargetType represents an annotation whose
- * target is an inner type of a generic or array type.
- *
- * @return true if this TargetType represents an annotation on an inner
- * type, false otherwise
- */
- public boolean hasLocation() {
- return flags.contains(HasLocation);
+ private TargetType(int targetTypeValue) {
+ this(targetTypeValue, false);
}
- public TargetType getGenericComplement() {
- if (hasLocation())
- return this;
- else
- return fromTargetTypeValue(targetTypeValue() + 1);
- }
-
- /**
- * Returns whether or not this TargetType represents an annotation whose
- * target has a parameter index.
- *
- * @return true if this TargetType has a parameter index,
- * false otherwise
- */
- public boolean hasParameter() {
- return flags.contains(HasParameter);
- }
-
- /**
- * Returns whether or not this TargetType represents an annotation whose
- * target is a type parameter bound.
- *
- * @return true if this TargetType represents an type parameter bound
- * annotation, false otherwise
- */
- public boolean hasBound() {
- return flags.contains(HasBound);
+ private TargetType(int targetTypeValue, boolean isLocal) {
+ if (targetTypeValue < 0
+ || targetTypeValue > 255)
+ Assert.error("Attribute type value needs to be an unsigned byte: " + String.format("0x%02X", targetTypeValue));
+ this.targetTypeValue = targetTypeValue;
+ this.isLocal = isLocal;
}
/**
@@ -226,7 +134,7 @@
* member declaration signature tree
*/
public boolean isLocal() {
- return flags.contains(IsLocal);
+ return isLocal;
}
public int targetTypeValue() {
@@ -239,7 +147,7 @@
targets = new TargetType[MAXIMUM_TARGET_TYPE_VALUE + 1];
TargetType[] alltargets = values();
for (TargetType target : alltargets) {
- if (target.targetTypeValue >= 0)
+ if (target.targetTypeValue != UNKNOWN.targetTypeValue)
targets[target.targetTypeValue] = target;
}
for (int i = 0; i <= MAXIMUM_TARGET_TYPE_VALUE; ++i) {
@@ -249,22 +157,18 @@
}
public static boolean isValidTargetTypeValue(int tag) {
- if (((byte)tag) == ((byte)UNKNOWN.targetTypeValue))
+ if (tag == UNKNOWN.targetTypeValue)
return true;
return (tag >= 0 && tag < targets.length);
}
public static TargetType fromTargetTypeValue(int tag) {
- if (((byte)tag) == ((byte)UNKNOWN.targetTypeValue))
+ if (tag == UNKNOWN.targetTypeValue)
return UNKNOWN;
if (tag < 0 || tag >= targets.length)
- throw new IllegalArgumentException("Unknown TargetType: " + tag);
+ Assert.error("Unknown TargetType: " + tag);
return targets[tag];
}
-
- static enum TargetAttribute {
- HasLocation, HasParameter, HasBound, IsLocal;
- }
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/Type.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -31,6 +31,7 @@
import java.util.Map;
import java.util.Set;
+import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.*;
import com.sun.tools.javac.code.Symbol.*;
@@ -87,7 +88,7 @@
*/
protected TypeTag tag;
- /** The defining class / interface / package / type variable
+ /** The defining class / interface / package / type variable.
*/
public TypeSymbol tsym;
@@ -166,7 +167,7 @@
/**
* Get the representation of this type used for modelling purposes.
* By default, this is itself. For ErrorType, a different value
- * may be provided,
+ * may be provided.
*/
public Type getModelType() {
return this;
@@ -245,6 +246,14 @@
return this;
}
+ /**
+ * If this is an annotated type, return the underlying type.
+ * Otherwise, return the type itself.
+ */
+ public Type unannotatedType() {
+ return this;
+ }
+
/** Return the base types of a list of types.
*/
public static List baseTypes(List ts) {
@@ -339,8 +348,11 @@
args = args.tail;
buf.append(',');
}
- if (args.head.tag == ARRAY) {
- buf.append(((ArrayType)args.head).elemtype);
+ if (args.head.unannotatedType().tag == ARRAY) {
+ buf.append(((ArrayType)args.head.unannotatedType()).elemtype);
+ if (args.head.getAnnotations().nonEmpty()) {
+ buf.append(args.head.getAnnotations());
+ }
buf.append("...");
} else {
buf.append(args.head);
@@ -350,10 +362,12 @@
/** Access methods.
*/
+ public List extends AnnotationMirror> getAnnotations() { return List.nil(); }
public List getTypeArguments() { return List.nil(); }
- public Type getEnclosingType() { return null; }
+ public Type getEnclosingType() { return null; }
public List getParameterTypes() { return List.nil(); }
public Type getReturnType() { return null; }
+ public Type getReceiverType() { return null; }
public List getThrownTypes() { return List.nil(); }
public Type getUpperBound() { return null; }
public Type getLowerBound() { return null; }
@@ -600,7 +614,7 @@
/** The enclosing type of this type. If this is the type of an inner
* class, outer_field refers to the type of its enclosing
- * instance class, in all other cases it referes to noType.
+ * instance class, in all other cases it refers to noType.
*/
private Type outer_field;
@@ -974,6 +988,10 @@
public Type restype;
public List thrown;
+ /** The type annotations on the method receiver.
+ */
+ public Type recvtype;
+
public MethodType(List argtypes,
Type restype,
List thrown,
@@ -1000,6 +1018,7 @@
public List getParameterTypes() { return argtypes; }
public Type getReturnType() { return restype; }
+ public Type getReceiverType() { return recvtype; }
public List getThrownTypes() { return thrown; }
public boolean isErroneous() {
@@ -1028,6 +1047,7 @@
for (List l = argtypes; l.nonEmpty(); l = l.tail)
l.head.complete();
restype.complete();
+ recvtype.complete();
for (List l = thrown; l.nonEmpty(); l = l.tail)
l.head.complete();
}
@@ -1112,7 +1132,11 @@
}
@Override
- public Type getUpperBound() { return bound; }
+ public Type getUpperBound() {
+ if ((bound == null || bound.tag == NONE) && this != tsym.type)
+ bound = tsym.type.getUpperBound();
+ return bound;
+ }
int rank_field = -1;
@@ -1183,6 +1207,7 @@
public Type getEnclosingType() { return qtype.getEnclosingType(); }
public List getParameterTypes() { return qtype.getParameterTypes(); }
public Type getReturnType() { return qtype.getReturnType(); }
+ public Type getReceiverType() { return qtype.getReceiverType(); }
public List getThrownTypes() { return qtype.getThrownTypes(); }
public List allparams() { return qtype.allparams(); }
public Type getUpperBound() { return qtype.getUpperBound(); }
@@ -1435,7 +1460,7 @@
}
public Type constType(Object constValue) { return this; }
- public Type getEnclosingType() { return this; }
+ public Type getEnclosingType() { return this; }
public Type getReturnType() { return this; }
public Type asSub(Symbol sym) { return this; }
public Type map(Mapping f) { return this; }
@@ -1461,11 +1486,165 @@
}
}
+ public static class AnnotatedType extends Type
+ implements javax.lang.model.type.AnnotatedType {
+ /** The type annotations on this type.
+ */
+ public List typeAnnotations;
+
+ /** The underlying type that is annotated.
+ */
+ public Type underlyingType;
+
+ public AnnotatedType(Type underlyingType) {
+ super(underlyingType.tag, underlyingType.tsym);
+ this.typeAnnotations = List.nil();
+ this.underlyingType = underlyingType;
+ Assert.check(underlyingType.getKind() != TypeKind.ANNOTATED,
+ "Can't annotate already annotated type: " + underlyingType);
+ }
+
+ public AnnotatedType(List typeAnnotations,
+ Type underlyingType) {
+ super(underlyingType.tag, underlyingType.tsym);
+ this.typeAnnotations = typeAnnotations;
+ this.underlyingType = underlyingType;
+ Assert.check(underlyingType.getKind() != TypeKind.ANNOTATED,
+ "Can't annotate already annotated type: " + underlyingType +
+ "; adding: " + typeAnnotations);
+ }
+
+ @Override
+ public TypeKind getKind() {
+ return TypeKind.ANNOTATED;
+ }
+
+ @Override
+ public List extends AnnotationMirror> getAnnotations() {
+ return typeAnnotations;
+ }
+
+ @Override
+ public TypeMirror getUnderlyingType() {
+ return underlyingType;
+ }
+
+ @Override
+ public Type unannotatedType() {
+ return underlyingType;
+ }
+
+ @Override
+ public R accept(Type.Visitor v, S s) {
+ return v.visitAnnotatedType(this, s);
+ }
+
+ @Override
+ public R accept(TypeVisitor v, P p) {
+ return v.visitAnnotated(this, p);
+ }
+
+ @Override
+ public Type map(Mapping f) {
+ underlyingType.map(f);
+ return this;
+ }
+
+ @Override
+ public Type constType(Object constValue) { return underlyingType.constType(constValue); }
+ @Override
+ public Type getEnclosingType() { return underlyingType.getEnclosingType(); }
+
+ @Override
+ public Type getReturnType() { return underlyingType.getReturnType(); }
+ @Override
+ public List getTypeArguments() { return underlyingType.getTypeArguments(); }
+ @Override
+ public List getParameterTypes() { return underlyingType.getParameterTypes(); }
+ @Override
+ public Type getReceiverType() { return underlyingType.getReceiverType(); }
+ @Override
+ public List getThrownTypes() { return underlyingType.getThrownTypes(); }
+ @Override
+ public Type getUpperBound() { return underlyingType.getUpperBound(); }
+ @Override
+ public Type getLowerBound() { return underlyingType.getLowerBound(); }
+
+ @Override
+ public boolean isErroneous() { return underlyingType.isErroneous(); }
+ @Override
+ public boolean isCompound() { return underlyingType.isCompound(); }
+ @Override
+ public boolean isInterface() { return underlyingType.isInterface(); }
+ @Override
+ public List allparams() { return underlyingType.allparams(); }
+ @Override
+ public boolean isNumeric() { return underlyingType.isNumeric(); }
+ @Override
+ public boolean isReference() { return underlyingType.isReference(); }
+ @Override
+ public boolean isParameterized() { return underlyingType.isParameterized(); }
+ @Override
+ public boolean isRaw() { return underlyingType.isRaw(); }
+ @Override
+ public boolean isFinal() { return underlyingType.isFinal(); }
+ @Override
+ public boolean isSuperBound() { return underlyingType.isSuperBound(); }
+ @Override
+ public boolean isExtendsBound() { return underlyingType.isExtendsBound(); }
+ @Override
+ public boolean isUnbound() { return underlyingType.isUnbound(); }
+
+ @Override
+ public String toString() {
+ // TODO more logic for arrays, etc.
+ if (typeAnnotations != null &&
+ !typeAnnotations.isEmpty()) {
+ return "(" + typeAnnotations.toString() + " :: " + underlyingType.toString() + ")";
+ } else {
+ return "({} :: " + underlyingType.toString() +")";
+ }
+ }
+
+ @Override
+ public boolean contains(Type t) { return underlyingType.contains(t); }
+
+ // TODO: attach annotations?
+ @Override
+ public Type withTypeVar(Type t) { return underlyingType.withTypeVar(t); }
+
+ // TODO: attach annotations?
+ @Override
+ public TypeSymbol asElement() { return underlyingType.asElement(); }
+
+ // TODO: attach annotations?
+ @Override
+ public MethodType asMethodType() { return underlyingType.asMethodType(); }
+
+ @Override
+ public void complete() { underlyingType.complete(); }
+
+ @Override
+ public TypeMirror getComponentType() { return ((ArrayType)underlyingType).getComponentType(); }
+
+ // The result is an ArrayType, but only in the model sense, not the Type sense.
+ public AnnotatedType makeVarargs() {
+ AnnotatedType atype = new AnnotatedType(((ArrayType)underlyingType).makeVarargs());
+ atype.typeAnnotations = this.typeAnnotations;
+ return atype;
+ }
+
+ @Override
+ public TypeMirror getExtendsBound() { return ((WildcardType)underlyingType).getExtendsBound(); }
+ @Override
+ public TypeMirror getSuperBound() { return ((WildcardType)underlyingType).getSuperBound(); }
+ }
+
/**
* A visitor for types. A visitor is used to implement operations
* (or relations) on types. Most common operations on types are
* binary relations and this interface is designed for binary
- * relations, that is, operations on the form
+ * relations, that is, operations of the form
* Type × S → R.
*
*
@@ -1486,6 +1665,7 @@
R visitForAll(ForAll t, S s);
R visitUndetVar(UndetVar t, S s);
R visitErrorType(ErrorType t, S s);
+ R visitAnnotatedType(AnnotatedType t, S s);
R visitType(Type t, S s);
}
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -25,6 +25,8 @@
package com.sun.tools.javac.code;
+import java.util.Iterator;
+
import com.sun.tools.javac.util.*;
/** A type annotation position.
@@ -34,12 +36,92 @@
* This code and its internal interfaces are subject to change or
* deletion without notice.
*/
+// Code duplicated in com.sun.tools.classfile.TypeAnnotation.Position
public class TypeAnnotationPosition {
+ public enum TypePathEntryKind {
+ ARRAY(0),
+ INNER_TYPE(1),
+ WILDCARD(2),
+ TYPE_ARGUMENT(3);
+
+ public final int tag;
+
+ private TypePathEntryKind(int tag) {
+ this.tag = tag;
+ }
+ }
+
+ public static class TypePathEntry {
+ /** The fixed number of bytes per TypePathEntry. */
+ public static final int bytesPerEntry = 2;
+
+ public final TypePathEntryKind tag;
+ public final int arg;
+
+ public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY);
+ public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE);
+ public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD);
+
+ private TypePathEntry(TypePathEntryKind tag) {
+ Assert.check(tag == TypePathEntryKind.ARRAY ||
+ tag == TypePathEntryKind.INNER_TYPE ||
+ tag == TypePathEntryKind.WILDCARD,
+ "Invalid TypePathEntryKind: " + tag);
+ this.tag = tag;
+ this.arg = 0;
+ }
+
+ public TypePathEntry(TypePathEntryKind tag, int arg) {
+ Assert.check(tag == TypePathEntryKind.TYPE_ARGUMENT,
+ "Invalid TypePathEntryKind: " + tag);
+ this.tag = tag;
+ this.arg = arg;
+ }
+
+ public static TypePathEntry fromBinary(int tag, int arg) {
+ Assert.check(arg == 0 || tag == TypePathEntryKind.TYPE_ARGUMENT.tag,
+ "Invalid TypePathEntry tag/arg: " + tag + "/" + arg);
+ switch (tag) {
+ case 0:
+ return ARRAY;
+ case 1:
+ return INNER_TYPE;
+ case 2:
+ return WILDCARD;
+ case 3:
+ return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg);
+ default:
+ Assert.error("Invalid TypePathEntryKind tag: " + tag);
+ return null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return tag.toString() +
+ (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : "");
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (! (other instanceof TypePathEntry)) {
+ return false;
+ }
+ TypePathEntry tpe = (TypePathEntry) other;
+ return this.tag == tpe.tag && this.arg == tpe.arg;
+ }
+
+ @Override
+ public int hashCode() {
+ return this.tag.hashCode() * 17 + this.arg;
+ }
+ }
+
public TargetType type = TargetType.UNKNOWN;
// For generic/array types.
- public List location = List.nil();
+ public List location = List.nil();
// Tree position.
public int pos = -1;
@@ -59,11 +141,13 @@
// For type parameter and method parameter
public int parameter_index = Integer.MIN_VALUE;
- // For class extends, implements, and throws classes
+ // For class extends, implements, and throws clauses
public int type_index = Integer.MIN_VALUE;
- // For wildcards
- public TypeAnnotationPosition wildcard_position = null;
+ // For exception parameters, index into exception table
+ public int exception_index = Integer.MIN_VALUE;
+
+ public TypeAnnotationPosition() {}
@Override
public String toString() {
@@ -72,27 +156,27 @@
sb.append(type);
switch (type) {
- // type case
- case TYPECAST:
- case TYPECAST_GENERIC_OR_ARRAY:
- // object creation
+ // type cast
+ case CAST:
+ // instanceof
case INSTANCEOF:
- case INSTANCEOF_GENERIC_OR_ARRAY:
- // new expression
+ // new expression
case NEW:
- case NEW_GENERIC_OR_ARRAY:
- case NEW_TYPE_ARGUMENT:
- case NEW_TYPE_ARGUMENT_GENERIC_OR_ARRAY:
sb.append(", offset = ");
sb.append(offset);
break;
- // local variable
+ // local variable
case LOCAL_VARIABLE:
- case LOCAL_VARIABLE_GENERIC_OR_ARRAY:
+ // resource variable
+ case RESOURCE_VARIABLE:
+ if (lvarOffset == null) {
+ sb.append(", lvarOffset is null!");
+ break;
+ }
sb.append(", {");
for (int i = 0; i < lvarOffset.length; ++i) {
if (i != 0) sb.append("; ");
- sb.append(", start_pc = ");
+ sb.append("start_pc = ");
sb.append(lvarOffset[i]);
sb.append(", length = ");
sb.append(lvarLength[i]);
@@ -101,73 +185,72 @@
}
sb.append("}");
break;
- // method receiver
+ // method receiver
case METHOD_RECEIVER:
// Do nothing
break;
- // type parameters
+ // type parameter
case CLASS_TYPE_PARAMETER:
case METHOD_TYPE_PARAMETER:
sb.append(", param_index = ");
sb.append(parameter_index);
break;
- // type parameters bound
+ // type parameter bound
case CLASS_TYPE_PARAMETER_BOUND:
- case CLASS_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY:
case METHOD_TYPE_PARAMETER_BOUND:
- case METHOD_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY:
sb.append(", param_index = ");
sb.append(parameter_index);
sb.append(", bound_index = ");
sb.append(bound_index);
break;
- // wildcard
- case WILDCARD_BOUND:
- case WILDCARD_BOUND_GENERIC_OR_ARRAY:
- sb.append(", wild_card = ");
- sb.append(wildcard_position);
- break;
- // Class extends and implements clauses
+ // class extends or implements clause
case CLASS_EXTENDS:
- case CLASS_EXTENDS_GENERIC_OR_ARRAY:
sb.append(", type_index = ");
sb.append(type_index);
break;
- // throws
+ // throws
case THROWS:
sb.append(", type_index = ");
sb.append(type_index);
break;
- case CLASS_LITERAL:
- case CLASS_LITERAL_GENERIC_OR_ARRAY:
- sb.append(", offset = ");
- sb.append(offset);
+ // exception parameter
+ case EXCEPTION_PARAMETER:
+ sb.append(", exception_index = ");
+ sb.append(exception_index);
break;
- // method parameter: not specified
- case METHOD_PARAMETER_GENERIC_OR_ARRAY:
+ // method parameter
+ case METHOD_FORMAL_PARAMETER:
sb.append(", param_index = ");
sb.append(parameter_index);
break;
- // method type argument: wasn't specified
- case METHOD_TYPE_ARGUMENT:
- case METHOD_TYPE_ARGUMENT_GENERIC_OR_ARRAY:
+ // method/constructor/reference type argument
+ case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_REFERENCE_TYPE_ARGUMENT:
sb.append(", offset = ");
sb.append(offset);
sb.append(", type_index = ");
sb.append(type_index);
break;
- // We don't need to worry abut these
- case METHOD_RETURN_GENERIC_OR_ARRAY:
- case FIELD_GENERIC_OR_ARRAY:
+ // We don't need to worry about these
+ case METHOD_RETURN:
+ case FIELD:
+ break;
+ // lambda formal parameter
+ case LAMBDA_FORMAL_PARAMETER:
+ // TODO: also needs an offset?
+ sb.append(", param_index = ");
+ sb.append(parameter_index);
break;
case UNKNOWN:
+ sb.append(", position UNKNOWN!");
break;
default:
- // throw new AssertionError("unknown type: " + type);
+ Assert.error("Unknown target type: " + type);
}
// Append location data for generics/arrays.
- if (type.hasLocation()) {
+ if (!location.isEmpty()) {
sb.append(", location = (");
sb.append(location);
sb.append(")");
@@ -186,10 +269,33 @@
* @return true if the target has not been optimized away
*/
public boolean emitToClassfile() {
- if (type == TargetType.WILDCARD_BOUND
- || type == TargetType.WILDCARD_BOUND_GENERIC_OR_ARRAY)
- return wildcard_position.isValidOffset;
- else
- return !type.isLocal() || isValidOffset;
+ return !type.isLocal() || isValidOffset;
+ }
+
+ /**
+ * Decode the binary representation for a type path and set
+ * the {@code location} field.
+ *
+ * @param list The bytecode representation of the type path.
+ */
+ public static List getTypePathFromBinary(java.util.List list) {
+ ListBuffer loc = ListBuffer.lb();
+ Iterator iter = list.iterator();
+ while (iter.hasNext()) {
+ Integer fst = iter.next();
+ Assert.check(iter.hasNext(), "Could not decode type path: " + list);
+ Integer snd = iter.next();
+ loc = loc.append(TypePathEntry.fromBinary(fst, snd));
+ }
+ return loc.toList();
+ }
+
+ public static List getBinaryFromTypePath(java.util.List locs) {
+ ListBuffer loc = ListBuffer.lb();
+ for (TypePathEntry tpe : locs) {
+ loc = loc.append(tpe.tag.tag);
+ loc = loc.append(tpe.arg);
+ }
+ return loc.toList();
}
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java Wed Jan 23 13:27:24 2013 -0800
@@ -0,0 +1,1037 @@
+/*
+ * Copyright (c) 2009, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.tools.javac.code;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.type.TypeKind;
+
+import com.sun.tools.javac.code.Attribute;
+import com.sun.tools.javac.code.Attribute.TypeCompound;
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Kinds;
+import com.sun.tools.javac.code.Type.AnnotatedType;
+import com.sun.tools.javac.code.Type.ArrayType;
+import com.sun.tools.javac.code.Type.CapturedType;
+import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.code.Type.ErrorType;
+import com.sun.tools.javac.code.Type.ForAll;
+import com.sun.tools.javac.code.Type.MethodType;
+import com.sun.tools.javac.code.Type.PackageType;
+import com.sun.tools.javac.code.Type.TypeVar;
+import com.sun.tools.javac.code.Type.UndetVar;
+import com.sun.tools.javac.code.Type.Visitor;
+import com.sun.tools.javac.code.Type.WildcardType;
+import com.sun.tools.javac.code.TypeAnnotationPosition.TypePathEntry;
+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.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.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCTypeApply;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Names;
+
+/**
+ * Contains operations specific to processing type annotations.
+ * This class has two functions:
+ * separate declaration from type annotations and insert the type
+ * annotations to their types;
+ * and determine the TypeAnnotationPositions for all type annotations.
+ */
+public class TypeAnnotations {
+ // Class cannot be instantiated.
+ private TypeAnnotations() {}
+
+ /**
+ * Separate type annotations from declaration annotations and
+ * 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.
+ */
+ public static Annotator organizeTypeAnnotationsSignatures(final Symtab syms, final Names names,
+ final Log log, final JCClassDecl tree) {
+ return new Annotator() {
+ @Override
+ public void enterAnnotation() {
+ new TypeAnnotationPositions(syms, names, log, true).scan(tree);
+ }
+ };
+ }
+
+ /**
+ * This version only visits types in bodies, that is, field initializers,
+ * top-level blocks, and method bodies, and should be called from Attr.
+ */
+ public static void organizeTypeAnnotationsBodies(Symtab syms, Names names, Log log, JCClassDecl tree) {
+ new TypeAnnotationPositions(syms, names, log, false).scan(tree);
+ }
+
+ private static class TypeAnnotationPositions extends TreeScanner {
+
+ private enum AnnotationType { DECLARATION, TYPE, BOTH };
+
+ private final Symtab syms;
+ private final Names names;
+ private final Log log;
+ private final boolean sigOnly;
+
+ private TypeAnnotationPositions(Symtab syms, Names names, Log log, boolean sigOnly) {
+ this.syms = syms;
+ this.names = names;
+ this.log = log;
+ this.sigOnly = sigOnly;
+ }
+
+ /*
+ * When traversing the AST we keep the "frames" of visited
+ * trees in order to determine the position of annotations.
+ */
+ private ListBuffer frames = ListBuffer.lb();
+
+ protected void push(JCTree t) { frames = frames.prepend(t); }
+ protected JCTree pop() { return frames.next(); }
+ // could this be frames.elems.tail.head?
+ private JCTree peek2() { return frames.toList().tail.head; }
+
+ @Override
+ public void scan(JCTree tree) {
+ push(tree);
+ super.scan(tree);
+ pop();
+ }
+
+ /**
+ * Separates type annotations from declaration annotations.
+ * This step is needed because in certain locations (where declaration
+ * and type annotations can be mixed, e.g. the type of a field)
+ * we never build an JCAnnotatedType. This step finds these
+ * annotations and marks them as if they were part of the type.
+ */
+ private void separateAnnotationsKinds(JCTree typetree, Type type, Symbol sym,
+ TypeAnnotationPosition pos) {
+ /*
+ System.out.printf("separateAnnotationsKinds(typetree: %s, type: %s, symbol: %s, pos: %s%n",
+ typetree, type, sym, pos);
+ */
+ List annotations = sym.getRawAttributes();
+ ListBuffer declAnnos = new ListBuffer();
+ ListBuffer typeAnnos = new ListBuffer();
+
+ for (Attribute.Compound a : annotations) {
+ switch (annotationType(a, sym)) {
+ case DECLARATION:
+ declAnnos.append(a);
+ break;
+ case BOTH: {
+ declAnnos.append(a);
+ Attribute.TypeCompound ta = toTypeCompound(a, pos);
+ typeAnnos.append(ta);
+ break;
+ }
+ case TYPE: {
+ Attribute.TypeCompound ta = toTypeCompound(a, pos);
+ typeAnnos.append(ta);
+ break;
+ }
+ }
+ }
+
+ sym.annotations.reset();
+ sym.annotations.setDeclarationAttributes(declAnnos.toList());
+
+ List typeAnnotations = typeAnnos.toList();
+
+ if (type == null) {
+ // When type is null, put the type annotations to the symbol.
+ // This is used for constructor return annotations, for which
+ // no appropriate type exists.
+ sym.annotations.appendUniqueTypes(typeAnnotations);
+ return;
+ }
+
+ // type is non-null and annotations are added to that type
+ type = typeWithAnnotations(typetree, type, typeAnnotations, log);
+
+ if (sym.getKind() == ElementKind.METHOD) {
+ sym.type.asMethodType().restype = type;
+ } 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 ||
+ sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
+ // Make sure all type annotations from the symbol are also
+ // on the owner.
+ sym.owner.annotations.appendUniqueTypes(sym.getTypeAnnotationMirrors());
+ }
+ }
+
+ // This method has a similar purpose as
+ // {@link com.sun.tools.javac.parser.JavacParser.insertAnnotationsToMostInner(JCExpression, List, boolean)}
+ // We found a type annotation in a declaration annotation position,
+ // for example, on the return type.
+ // Such an annotation is _not_ part of an JCAnnotatedType tree and we therefore
+ // need to set its position explicitly.
+ // The method returns a copy of type that contains these annotations.
+ private static Type typeWithAnnotations(final JCTree typetree, final Type type,
+ final List annotations, Log log) {
+ // System.out.printf("typeWithAnnotations(typetree: %s, type: %s, annotations: %s)%n",
+ // typetree, type, annotations);
+ if (annotations.isEmpty()) {
+ return type;
+ }
+ if (type.hasTag(TypeTag.ARRAY)) {
+ Type toreturn;
+ Type.ArrayType tomodify;
+ Type.ArrayType arType;
+ {
+ Type touse = type;
+ if (type.getKind() == TypeKind.ANNOTATED) {
+ Type.AnnotatedType atype = (Type.AnnotatedType)type;
+ toreturn = new Type.AnnotatedType(atype.underlyingType);
+ ((Type.AnnotatedType)toreturn).typeAnnotations = atype.typeAnnotations;
+ touse = atype.underlyingType;
+ arType = (Type.ArrayType) touse;
+ tomodify = new Type.ArrayType(null, arType.tsym);
+ ((Type.AnnotatedType)toreturn).underlyingType = tomodify;
+ } else {
+ arType = (Type.ArrayType) touse;
+ tomodify = new Type.ArrayType(null, arType.tsym);
+ toreturn = tomodify;
+ }
+ }
+ JCArrayTypeTree arTree = arrayTypeTree(typetree);
+
+ ListBuffer depth = ListBuffer.lb();
+ depth = depth.append(TypePathEntry.ARRAY);
+ while (arType.elemtype.hasTag(TypeTag.ARRAY)) {
+ if (arType.elemtype.getKind() == TypeKind.ANNOTATED) {
+ Type.AnnotatedType aelemtype = (Type.AnnotatedType) arType.elemtype;
+ Type.AnnotatedType newAT = new Type.AnnotatedType(aelemtype.underlyingType);
+ tomodify.elemtype = newAT;
+ newAT.typeAnnotations = aelemtype.typeAnnotations;
+ arType = (Type.ArrayType) aelemtype.underlyingType;
+ tomodify = new Type.ArrayType(null, arType.tsym);
+ newAT.underlyingType = tomodify;
+ } else {
+ arType = (Type.ArrayType) arType.elemtype;
+ tomodify.elemtype = new Type.ArrayType(null, arType.tsym);
+ tomodify = (Type.ArrayType) tomodify.elemtype;
+ }
+ arTree = arrayTypeTree(arTree.elemtype);
+ depth = depth.append(TypePathEntry.ARRAY);
+ }
+ Type arelemType = typeWithAnnotations(arTree.elemtype, arType.elemtype, annotations, log);
+ tomodify.elemtype = arelemType;
+ for (Attribute.TypeCompound a : annotations) {
+ TypeAnnotationPosition p = a.position;
+ p.location = p.location.prependList(depth.toList());
+ }
+ return toreturn;
+ } else if (type.hasTag(TypeTag.TYPEVAR)) {
+ // Nothing to do for type variables.
+ return type;
+ } else {
+ Type enclTy = type;
+ Element enclEl = type.asElement();
+ JCTree enclTr = typetree;
+
+ while (enclEl != null &&
+ enclEl.getKind() != ElementKind.PACKAGE &&
+ enclTy != null &&
+ enclTy.getKind() != TypeKind.NONE &&
+ enclTy.getKind() != TypeKind.ERROR &&
+ (enclTr.getKind() == JCTree.Kind.MEMBER_SELECT ||
+ enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE ||
+ enclTr.getKind() == JCTree.Kind.ANNOTATED_TYPE)) {
+ // Iterate also over the type tree, not just the type: the type is already
+ // completely resolved and we cannot distinguish where the annotation
+ // belongs for a nested type.
+ if (enclTr.getKind() == JCTree.Kind.MEMBER_SELECT) {
+ // only change encl in this case.
+ enclTy = enclTy.getEnclosingType();
+ enclEl = enclEl.getEnclosingElement();
+ enclTr = ((JCFieldAccess)enclTr).getExpression();
+ } else if (enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE) {
+ enclTr = ((JCTypeApply)enclTr).getType();
+ } else {
+ // only other option because of while condition
+ enclTr = ((JCAnnotatedType)enclTr).getUnderlyingType();
+ }
+ }
+
+ /** We are trying to annotate some enclosing type,
+ * but nothing more exists.
+ */
+ if (enclTy != null &&
+ enclTy.getKind() == TypeKind.NONE &&
+ (enclTr.getKind() == JCTree.Kind.IDENTIFIER ||
+ enclTr.getKind() == JCTree.Kind.MEMBER_SELECT ||
+ enclTr.getKind() == JCTree.Kind.PARAMETERIZED_TYPE ||
+ enclTr.getKind() == JCTree.Kind.ANNOTATED_TYPE)) {
+ // TODO: also if it's "java. @A lang.Object", that is,
+ // if it's on a package?
+ log.error(enclTr.pos(), "cant.annotate.nested.type", enclTr.toString());
+ return type;
+ }
+
+ // At this point we have visited the part of the nested
+ // type that is written in the source code.
+ // Now count from here to the actual top-level class to determine
+ // the correct nesting.
+
+ // The genericLocation for the annotation.
+ ListBuffer depth = ListBuffer.lb();
+
+ Type topTy = enclTy;
+ while (enclEl != null &&
+ enclEl.getKind() != ElementKind.PACKAGE &&
+ topTy != null &&
+ topTy.getKind() != TypeKind.NONE &&
+ topTy.getKind() != TypeKind.ERROR) {
+ topTy = topTy.getEnclosingType();
+ enclEl = enclEl.getEnclosingElement();
+
+ if (topTy != null && topTy.getKind() != TypeKind.NONE) {
+ // Only count enclosing types.
+ depth = depth.append(TypePathEntry.INNER_TYPE);
+ }
+ }
+
+ if (depth.nonEmpty()) {
+ // Only need to change the annotation positions
+ // if they are on an enclosed type.
+ for (Attribute.TypeCompound a : annotations) {
+ TypeAnnotationPosition p = a.position;
+ p.location = p.location.appendList(depth.toList());
+ }
+ }
+
+ Type ret = typeWithAnnotations(type, enclTy, annotations);
+ return ret;
+ }
+ }
+
+ private static JCArrayTypeTree arrayTypeTree(JCTree typetree) {
+ if (typetree.getKind() == JCTree.Kind.ARRAY_TYPE) {
+ return (JCArrayTypeTree) typetree;
+ } else if (typetree.getKind() == JCTree.Kind.ANNOTATED_TYPE) {
+ return (JCArrayTypeTree) ((JCAnnotatedType)typetree).underlyingType;
+ } else {
+ Assert.error("Could not determine array type from type tree: " + typetree);
+ return null;
+ }
+ }
+
+ /** Return a copy of the first type that only differs by
+ * inserting the annotations to the left-most/inner-most type
+ * or the type given by stopAt.
+ *
+ * We need the stopAt parameter to know where on a type to
+ * put the annotations.
+ * If we have nested classes Outer > Middle > Inner, and we
+ * have the source type "@A Middle.Inner", we will invoke
+ * this method with type = Outer.Middle.Inner,
+ * stopAt = Middle.Inner, and annotations = @A.
+ *
+ * @param type The type to copy.
+ * @param stopAt The type to stop at.
+ * @param annotations The annotations to insert.
+ * @return A copy of type that contains the annotations.
+ */
+ private static Type typeWithAnnotations(final Type type,
+ final Type stopAt,
+ final List annotations) {
+ Visitor> visitor =
+ new Type.Visitor>() {
+ @Override
+ public Type visitClassType(ClassType t, List s) {
+ // assert that t.constValue() == null?
+ if (t == stopAt ||
+ t.getEnclosingType() == Type.noType) {
+ return new AnnotatedType(s, t);
+ } else {
+ ClassType ret = new ClassType(t.getEnclosingType().accept(this, s),
+ t.typarams_field, t.tsym);
+ ret.all_interfaces_field = t.all_interfaces_field;
+ ret.allparams_field = t.allparams_field;
+ ret.interfaces_field = t.interfaces_field;
+ ret.rank_field = t.rank_field;
+ ret.supertype_field = t.supertype_field;
+ return ret;
+ }
+ }
+
+ @Override
+ public Type visitAnnotatedType(AnnotatedType t, List s) {
+ return new AnnotatedType(t.typeAnnotations, t.underlyingType.accept(this, s));
+ }
+
+ @Override
+ public Type visitWildcardType(WildcardType t, List s) {
+ return new AnnotatedType(s, t);
+ }
+
+ @Override
+ public Type visitArrayType(ArrayType t, List s) {
+ ArrayType ret = new ArrayType(t.elemtype.accept(this, s), t.tsym);
+ return ret;
+ }
+
+ @Override
+ public Type visitMethodType(MethodType t, List s) {
+ // Impossible?
+ return t;
+ }
+
+ @Override
+ public Type visitPackageType(PackageType t, List s) {
+ // Impossible?
+ return t;
+ }
+
+ @Override
+ public Type visitTypeVar(TypeVar t, List s) {
+ return new AnnotatedType(s, t);
+ }
+
+ @Override
+ public Type visitCapturedType(CapturedType t, List s) {
+ return new AnnotatedType(s, t);
+ }
+
+ @Override
+ public Type visitForAll(ForAll t, List s) {
+ // Impossible?
+ return t;
+ }
+
+ @Override
+ public Type visitUndetVar(UndetVar t, List s) {
+ // Impossible?
+ return t;
+ }
+
+ @Override
+ public Type visitErrorType(ErrorType t, List s) {
+ return new AnnotatedType(s, t);
+ }
+
+ @Override
+ public Type visitType(Type t, List s) {
+ // Error?
+ return t;
+ }
+ };
+
+ return type.accept(visitor, annotations);
+ }
+
+ private static Attribute.TypeCompound toTypeCompound(Attribute.Compound a, TypeAnnotationPosition p) {
+ // It is safe to alias the position.
+ 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.
+ */
+
+ private void resolveFrame(JCTree tree, JCTree frame,
+ List path, TypeAnnotationPosition p) {
+ /*
+ System.out.println("Resolving tree: " + tree + " kind: " + tree.getKind());
+ System.out.println(" Framing tree: " + frame + " kind: " + frame.getKind());
+ */
+ switch (frame.getKind()) {
+ case TYPE_CAST:
+ p.type = TargetType.CAST;
+ p.pos = frame.pos;
+ return;
+
+ case INSTANCE_OF:
+ p.type = TargetType.INSTANCEOF;
+ p.pos = frame.pos;
+ return;
+
+ case NEW_CLASS:
+ JCNewClass frameNewClass = (JCNewClass)frame;
+ if (frameNewClass.typeargs.contains(tree)) {
+ p.type = TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT;
+ p.type_index = frameNewClass.typeargs.indexOf(tree);
+ } else {
+ p.type = TargetType.NEW;
+ }
+ p.pos = frame.pos;
+ return;
+
+ case NEW_ARRAY:
+ p.type = TargetType.NEW;
+ p.pos = frame.pos;
+ return;
+
+ case ANNOTATION_TYPE:
+ case CLASS:
+ case ENUM:
+ case INTERFACE:
+ p.pos = frame.pos;
+ if (((JCClassDecl)frame).extending == tree) {
+ p.type = TargetType.CLASS_EXTENDS;
+ p.type_index = -1;
+ } else if (((JCClassDecl)frame).implementing.contains(tree)) {
+ p.type = TargetType.CLASS_EXTENDS;
+ p.type_index = ((JCClassDecl)frame).implementing.indexOf(tree);
+ } else if (((JCClassDecl)frame).typarams.contains(tree)) {
+ p.type = TargetType.CLASS_TYPE_PARAMETER;
+ p.parameter_index = ((JCClassDecl)frame).typarams.indexOf(tree);
+ } else {
+ Assert.error("Could not determine position of tree " + tree +
+ " within frame " + frame);
+ }
+ return;
+
+ case METHOD: {
+ JCMethodDecl frameMethod = (JCMethodDecl) frame;
+ p.pos = frame.pos;
+ if (frameMethod.thrown.contains(tree)) {
+ p.type = TargetType.THROWS;
+ p.type_index = frameMethod.thrown.indexOf(tree);
+ } else if (frameMethod.restype == tree) {
+ p.type = TargetType.METHOD_RETURN;
+ } else if (frameMethod.typarams.contains(tree)) {
+ p.type = TargetType.METHOD_TYPE_PARAMETER;
+ p.parameter_index = frameMethod.typarams.indexOf(tree);
+ } else {
+ Assert.error("Could not determine position of tree " + tree +
+ " within frame " + frame);
+ }
+ return;
+ }
+
+ case PARAMETERIZED_TYPE: {
+ if (((JCTypeApply)frame).clazz == tree) {
+ // generic: RAW; noop
+ } else if (((JCTypeApply)frame).arguments.contains(tree)) {
+ JCTypeApply taframe = (JCTypeApply) frame;
+ int arg = taframe.arguments.indexOf(tree);
+ p.location = p.location.prepend(new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg));
+
+ locateNestedTypes(taframe.type, 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;
+ }
+
+ case ARRAY_TYPE: {
+ ListBuffer index = ListBuffer.lb();
+ index = index.append(TypePathEntry.ARRAY);
+ List newPath = path.tail;
+ while (true) {
+ JCTree npHead = newPath.tail.head;
+ if (npHead.hasTag(JCTree.Tag.TYPEARRAY)) {
+ newPath = newPath.tail;
+ index = index.append(TypePathEntry.ARRAY);
+ } else if (npHead.hasTag(JCTree.Tag.ANNOTATED_TYPE)) {
+ newPath = newPath.tail;
+ } else {
+ break;
+ }
+ }
+ p.location = p.location.prependList(index.toList());
+ resolveFrame(newPath.head, newPath.tail.head, newPath, p);
+ return;
+ }
+
+ case TYPE_PARAMETER:
+ if (path.tail.tail.head.hasTag(JCTree.Tag.CLASSDEF)) {
+ JCClassDecl clazz = (JCClassDecl)path.tail.tail.head;
+ p.type = TargetType.CLASS_TYPE_PARAMETER_BOUND;
+ p.parameter_index = clazz.typarams.indexOf(path.tail.head);
+ p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
+ if (((JCTypeParameter)frame).bounds.get(0).type.isInterface()) {
+ // Account for an implicit Object as bound 0
+ p.bound_index += 1;
+ }
+ } else if (path.tail.tail.head.hasTag(JCTree.Tag.METHODDEF)) {
+ JCMethodDecl method = (JCMethodDecl)path.tail.tail.head;
+ p.type = TargetType.METHOD_TYPE_PARAMETER_BOUND;
+ p.parameter_index = method.typarams.indexOf(path.tail.head);
+ p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
+ if (((JCTypeParameter)frame).bounds.get(0).type.isInterface()) {
+ // Account for an implicit Object as bound 0
+ p.bound_index += 1;
+ }
+ } else {
+ Assert.error("Could not determine position of tree " + tree +
+ " within frame " + frame);
+ }
+ p.pos = frame.pos;
+ return;
+
+ case VARIABLE:
+ VarSymbol v = ((JCVariableDecl)frame).sym;
+ p.pos = frame.pos;
+ switch (v.getKind()) {
+ case LOCAL_VARIABLE:
+ p.type = TargetType.LOCAL_VARIABLE;
+ break;
+ case FIELD:
+ p.type = TargetType.FIELD;
+ break;
+ case PARAMETER:
+ if (v.getQualifiedName().equals(names._this)) {
+ // TODO: Intro a separate ElementKind?
+ p.type = TargetType.METHOD_RECEIVER;
+ } else {
+ p.type = TargetType.METHOD_FORMAL_PARAMETER;
+ p.parameter_index = methodParamIndex(path, frame);
+ }
+ break;
+ case EXCEPTION_PARAMETER:
+ p.type = TargetType.EXCEPTION_PARAMETER;
+ break;
+ case RESOURCE_VARIABLE:
+ p.type = TargetType.RESOURCE_VARIABLE;
+ break;
+ default:
+ Assert.error("Found unexpected type annotation for variable: " + v + " with kind: " + v.getKind());
+ }
+ return;
+
+ case ANNOTATED_TYPE: {
+ if (frame == tree) {
+ // This is only true for the first annotated type we see.
+ // For any other annotated types along the path, we do
+ // not care about inner types.
+ JCAnnotatedType atypetree = (JCAnnotatedType) frame;
+ final Type utype = atypetree.underlyingType.type;
+ Symbol tsym = utype.tsym;
+ if (tsym.getKind().equals(ElementKind.TYPE_PARAMETER) ||
+ utype.getKind().equals(TypeKind.WILDCARD) ||
+ utype.getKind().equals(TypeKind.ARRAY)) {
+ // Type parameters, wildcards, and arrays have the declaring
+ // class/method as enclosing elements.
+ // There is actually nothing to do for them.
+ } else {
+ locateNestedTypes(utype, p);
+ }
+ }
+ List newPath = path.tail;
+ resolveFrame(newPath.head, newPath.tail.head, newPath, p);
+ return;
+ }
+
+ 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;
+ }
+
+ case METHOD_INVOCATION: {
+ JCMethodInvocation invocation = (JCMethodInvocation)frame;
+ if (!invocation.typeargs.contains(tree)) {
+ Assert.error("{" + tree + "} is not an argument in the invocation: " + invocation);
+ }
+ p.type = TargetType.METHOD_INVOCATION_TYPE_ARGUMENT;
+ p.pos = invocation.pos;
+ p.type_index = invocation.typeargs.indexOf(tree);
+ return;
+ }
+
+ case EXTENDS_WILDCARD:
+ case SUPER_WILDCARD: {
+ // Annotations in wildcard bounds
+ p.location = p.location.prepend(TypePathEntry.WILDCARD);
+ List newPath = path.tail;
+ resolveFrame(newPath.head, newPath.tail.head, newPath, p);
+ return;
+ }
+
+ case MEMBER_SELECT: {
+ List newPath = path.tail;
+ resolveFrame(newPath.head, newPath.tail.head, newPath, p);
+ return;
+ }
+
+ default:
+ Assert.error("Unresolved frame: " + frame + " of kind: " + frame.getKind() +
+ "\n Looking for tree: " + tree);
+ return;
+ }
+ }
+
+ private static void locateNestedTypes(Type type, TypeAnnotationPosition p) {
+ // The number of "steps" to get from the full type to the
+ // left-most outer type.
+ ListBuffer depth = ListBuffer.lb();
+
+ Type encl = type.getEnclosingType();
+ while (encl != null &&
+ encl.getKind() != TypeKind.NONE &&
+ encl.getKind() != TypeKind.ERROR) {
+ depth = depth.append(TypePathEntry.INNER_TYPE);
+ encl = encl.getEnclosingType();
+ }
+ if (depth.nonEmpty()) {
+ p.location = p.location.prependList(depth.toList());
+ }
+ }
+
+ private static int methodParamIndex(List path, JCTree param) {
+ List curr = path;
+ while (curr.head.getTag() != Tag.METHODDEF) {
+ curr = curr.tail;
+ }
+ JCMethodDecl method = (JCMethodDecl)curr.head;
+ return method.params.indexOf(param);
+ }
+
+ // Each class (including enclosed inner classes) is visited separately.
+ // This flag is used to prevent from visiting inner classes.
+ private boolean isInClass = false;
+
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ if (isInClass)
+ return;
+ isInClass = true;
+ if (sigOnly) {
+ scan(tree.mods);
+ scan(tree.typarams);
+ scan(tree.extending);
+ scan(tree.implementing);
+ }
+ scan(tree.defs);
+ }
+
+ /**
+ * Resolve declaration vs. type annotations in methods and
+ * then determine the positions.
+ */
+ @Override
+ public void visitMethodDef(final JCMethodDecl tree) {
+ if (tree.sym == null) {
+ // Something most be wrong, e.g. a class not found.
+ // Quietly ignore. (See test FailOver15.java)
+ return;
+ }
+ if (sigOnly) {
+ {
+ TypeAnnotationPosition pos = new TypeAnnotationPosition();
+ pos.type = TargetType.METHOD_RETURN;
+ if (tree.sym.isConstructor()) {
+ pos.pos = tree.pos;
+ // Use null to mark that the annotations go with the symbol.
+ separateAnnotationsKinds(tree, null, tree.sym, pos);
+ } else {
+ pos.pos = tree.restype.pos;
+ separateAnnotationsKinds(tree.restype, tree.sym.type.getReturnType(),
+ tree.sym, pos);
+ }
+ }
+ if (tree.recvparam != null && tree.recvparam.sym != null) {
+ // TODO: make sure there are no declaration annotations.
+ TypeAnnotationPosition pos = new TypeAnnotationPosition();
+ pos.type = TargetType.METHOD_RECEIVER;
+ pos.pos = tree.recvparam.vartype.pos;
+ separateAnnotationsKinds(tree.recvparam.vartype, tree.recvparam.sym.type,
+ tree.recvparam.sym, pos);
+ }
+ 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);
+ ++i;
+ }
+ }
+
+ push(tree);
+ // super.visitMethodDef(tree);
+ if (sigOnly) {
+ scan(tree.mods);
+ scan(tree.restype);
+ scan(tree.typarams);
+ scan(tree.recvparam);
+ scan(tree.params);
+ scan(tree.thrown);
+ } else {
+ scan(tree.defaultValue);
+ scan(tree.body);
+ }
+ pop();
+ }
+
+ /**
+ * Resolve declaration vs. type annotations in variable declarations and
+ * then determine the positions.
+ */
+ @Override
+ public void visitVarDef(final JCVariableDecl tree) {
+ if (tree.sym == null) {
+ // Something is wrong already. Quietly ignore.
+ } else if (tree.sym.getKind() == ElementKind.FIELD) {
+ if (sigOnly) {
+ TypeAnnotationPosition pos = new TypeAnnotationPosition();
+ pos.type = TargetType.FIELD;
+ pos.pos = tree.pos;
+ separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
+ }
+ } else if (tree.sym.getKind() == ElementKind.LOCAL_VARIABLE) {
+ TypeAnnotationPosition pos = new TypeAnnotationPosition();
+ pos.type = TargetType.LOCAL_VARIABLE;
+ pos.pos = tree.pos;
+ separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
+ } else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
+ // System.out.println("Found exception param: " + tree);
+ TypeAnnotationPosition pos = new TypeAnnotationPosition();
+ pos.type = TargetType.EXCEPTION_PARAMETER;
+ pos.pos = tree.pos;
+ 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;
+ separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
+ } else {
+ // There is nothing else in a variable declaration that needs separation.
+ // System.out.println("We found a: " + tree);
+ }
+
+ push(tree);
+ // super.visitVarDef(tree);
+ scan(tree.mods);
+ scan(tree.vartype);
+ if (!sigOnly) {
+ scan(tree.init);
+ }
+ pop();
+ }
+
+ @Override
+ public void visitBlock(JCBlock tree) {
+ // Do not descend into top-level blocks when only interested
+ // in the signature.
+ if (!sigOnly) {
+ scan(tree.stats);
+ }
+ }
+
+ @Override
+ public void visitAnnotatedType(JCAnnotatedType tree) {
+ push(tree);
+ findPosition(tree, tree, tree.annotations);
+ pop();
+ super.visitAnnotatedType(tree);
+ }
+
+ @Override
+ public void visitTypeParameter(JCTypeParameter tree) {
+ findPosition(tree, peek2(), tree.annotations);
+ super.visitTypeParameter(tree);
+ }
+
+ @Override
+ public void visitNewArray(JCNewArray tree) {
+ findPosition(tree, tree, tree.annotations);
+ int dimAnnosCount = tree.dimAnnotations.size();
+ ListBuffer depth = ListBuffer.lb();
+
+ // handle annotations associated with dimensions
+ for (int i = 0; i < dimAnnosCount; ++i) {
+ TypeAnnotationPosition p = new TypeAnnotationPosition();
+ p.pos = tree.pos;
+ p.type = TargetType.NEW;
+ if (i != 0) {
+ depth = depth.append(TypePathEntry.ARRAY);
+ p.location = p.location.appendList(depth.toList());
+ }
+
+ setTypeAnnotationPos(tree.dimAnnotations.get(i), p);
+ }
+
+ // handle "free" annotations
+ // int i = dimAnnosCount == 0 ? 0 : dimAnnosCount - 1;
+ // TODO: is depth.size == i here?
+ JCExpression elemType = tree.elemtype;
+ 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());
+ setTypeAnnotationPos(at.annotations, p);
+ elemType = at.underlyingType;
+ } else if (elemType.hasTag(JCTree.Tag.TYPEARRAY)) {
+ depth = depth.append(TypePathEntry.ARRAY);
+ elemType = ((JCArrayTypeTree)elemType).elemtype;
+ } else {
+ break;
+ }
+ }
+ scan(tree.elems);
+ }
+
+ private void findPosition(JCTree tree, JCTree frame, List annotations) {
+ if (!annotations.isEmpty()) {
+ /*
+ System.out.println("Finding pos for: " + annotations);
+ System.out.println(" tree: " + tree);
+ System.out.println(" frame: " + frame);
+ */
+ TypeAnnotationPosition p = new TypeAnnotationPosition();
+ resolveFrame(tree, frame, frames.toList(), p);
+ setTypeAnnotationPos(annotations, p);
+ }
+ }
+
+ private static void setTypeAnnotationPos(List annotations,
+ TypeAnnotationPosition position) {
+ for (JCAnnotation anno : annotations) {
+ ((Attribute.TypeCompound) anno.attribute).position = position;
+ }
+ }
+ }
+}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/code/Types.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -34,13 +34,14 @@
import java.util.Set;
import java.util.WeakHashMap;
+import javax.lang.model.type.TypeKind;
+
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
import com.sun.tools.javac.comp.Check;
import com.sun.tools.javac.jvm.ClassReader;
import com.sun.tools.javac.util.*;
-import com.sun.tools.javac.util.List;
import static com.sun.tools.javac.code.BoundKind.*;
import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Scope.*;
@@ -684,6 +685,8 @@
//where
private boolean isSubtypeUncheckedInternal(Type t, Type s, Warner warn) {
if (t.hasTag(ARRAY) && s.hasTag(ARRAY)) {
+ t = t.unannotatedType();
+ s = s.unannotatedType();
if (((ArrayType)t).elemtype.isPrimitive()) {
return isSameType(elemtype(t), elemtype(s));
} else {
@@ -709,7 +712,10 @@
}
private void checkUnsafeVarargsConversion(Type t, Type s, Warner warn) {
- if (t.tag != ARRAY || isReifiable(t)) return;
+ if (t.tag != ARRAY || isReifiable(t))
+ return;
+ t = t.unannotatedType();
+ s = s.unannotatedType();
ArrayType from = (ArrayType)t;
boolean shouldWarn = false;
switch (s.tag) {
@@ -742,6 +748,12 @@
if (t == s)
return true;
+ t = t.unannotatedType();
+ s = s.unannotatedType();
+
+ if (t == s)
+ return true;
+
if (s.isPartial())
return isSuperType(s, t);
@@ -1683,6 +1695,7 @@
case WILDCARD:
return elemtype(upperBound(t));
case ARRAY:
+ t = t.unannotatedType();
return ((ArrayType)t).elemtype;
case FORALL:
return elemtype(((ForAll)t).qtype);
@@ -2011,6 +2024,11 @@
public Type visitErrorType(ErrorType t, Boolean recurse) {
return t;
}
+
+ @Override
+ public Type visitAnnotatedType(AnnotatedType t, Boolean recurse) {
+ return new AnnotatedType(t.typeAnnotations, erasure(t.underlyingType, recurse));
+ }
};
private Mapping erasureFun = new Mapping ("erasure") {
@@ -2953,6 +2971,7 @@
* graph. Undefined for all but reference types.
*/
public int rank(Type t) {
+ t = t.unannotatedType();
switch(t.tag) {
case CLASS: {
ClassType cls = (ClassType)t;
@@ -3654,6 +3673,7 @@
t = subst(type1, t.tsym.type.getTypeArguments(), t.getTypeArguments());
}
}
+ t = t.unannotatedType();
ClassType cls = (ClassType)t;
if (cls.isRaw() || !cls.isParameterized())
return cls;
@@ -4172,6 +4192,8 @@
public R visitForAll(ForAll t, S s) { return visitType(t, s); }
public R visitUndetVar(UndetVar t, S s) { return visitType(t, s); }
public R visitErrorType(ErrorType t, S s) { return visitType(t, s); }
+ // Pretend annotations don't exist
+ public R visitAnnotatedType(AnnotatedType t, S s) { return visit(t.underlyingType, s); }
}
/**
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java Wed Jan 23 13:27:24 2013 -0800
@@ -26,6 +26,7 @@
package com.sun.tools.javac.comp;
import java.util.Map;
+
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.code.*;
@@ -87,20 +88,30 @@
private int enterCount = 0;
ListBuffer q = new ListBuffer();
+ ListBuffer typesQ = new ListBuffer();
ListBuffer repeatedQ = new ListBuffer();
+ ListBuffer afterRepeatedQ = new ListBuffer();
+
+ public void earlier(Annotator a) {
+ q.prepend(a);
+ }
public void normal(Annotator a) {
q.append(a);
}
- public void earlier(Annotator a) {
- q.prepend(a);
+ public void typeAnnotation(Annotator a) {
+ typesQ.append(a);
}
public void repeated(Annotator a) {
repeatedQ.append(a);
}
+ public void afterRepeated(Annotator a) {
+ afterRepeatedQ.append(a);
+ }
+
/** Called when the Enter phase starts. */
public void enterStart() {
enterCount++;
@@ -116,12 +127,18 @@
if (enterCount != 0) return;
enterCount++;
try {
- while (q.nonEmpty())
+ while (q.nonEmpty()) {
q.next().enterAnnotation();
-
+ }
+ while (typesQ.nonEmpty()) {
+ typesQ.next().enterAnnotation();
+ }
while (repeatedQ.nonEmpty()) {
repeatedQ.next().enterAnnotation();
}
+ while (afterRepeatedQ.nonEmpty()) {
+ afterRepeatedQ.next().enterAnnotation();
+ }
} finally {
enterCount--;
}
@@ -141,16 +158,18 @@
* This context contains all the information needed to synthesize new
* annotations trees by the completer for repeating annotations.
*/
- public class AnnotateRepeatedContext {
+ public class AnnotateRepeatedContext {
public final Env env;
- public final Map> annotated;
- public final Map pos;
+ public final Map> annotated;
+ public final Map pos;
public final Log log;
+ public final boolean isTypeCompound;
public AnnotateRepeatedContext(Env env,
- Map> annotated,
- Map pos,
- Log log) {
+ Map> annotated,
+ Map pos,
+ Log log,
+ boolean isTypeCompound) {
Assert.checkNonNull(env);
Assert.checkNonNull(annotated);
Assert.checkNonNull(pos);
@@ -160,6 +179,7 @@
this.annotated = annotated;
this.pos = pos;
this.log = log;
+ this.isTypeCompound = isTypeCompound;
}
/**
@@ -170,7 +190,7 @@
* @param repeatingAnnotations a List of repeating annotations
* @return a new Attribute.Compound that is the container for the repeatingAnnotations
*/
- public Attribute.Compound processRepeatedAnnotations(List repeatingAnnotations, Symbol sym) {
+ public T processRepeatedAnnotations(List repeatingAnnotations, Symbol sym) {
return Annotate.this.processRepeatedAnnotations(repeatingAnnotations, this, sym);
}
@@ -246,7 +266,12 @@
((MethodSymbol)method, value));
t.type = result;
}
- return new Attribute.Compound(a.type, buf.toList());
+ // TODO: this should be a TypeCompound if "a" is a JCTypeAnnotation.
+ // However, how do we find the correct position?
+ Attribute.Compound ac = new Attribute.Compound(a.type, buf.toList());
+ // TODO: is this something we want? Who would use it?
+ // a.attribute = ac;
+ return ac;
}
Attribute enterAttributeValue(Type expected,
@@ -329,6 +354,15 @@
return new Attribute.Error(attr.attribExpr(tree, env, expected));
}
+ Attribute.TypeCompound enterTypeAnnotation(JCAnnotation a,
+ Type expected,
+ Env env) {
+ Attribute.Compound c = enterAnnotation(a, expected, env);
+ Attribute.TypeCompound tc = new Attribute.TypeCompound(c.type, c.values, new TypeAnnotationPosition());
+ a.attribute = tc;
+ return tc;
+ }
+
/* *********************************
* Support for repeating annotations
***********************************/
@@ -337,10 +371,10 @@
* synthesized container annotation or null IFF all repeating
* annotation are invalid. This method reports errors/warnings.
*/
- private Attribute.Compound processRepeatedAnnotations(List annotations,
- AnnotateRepeatedContext ctx,
- Symbol on) {
- Attribute.Compound firstOccurrence = annotations.head;
+ private T processRepeatedAnnotations(List annotations,
+ AnnotateRepeatedContext ctx,
+ Symbol on) {
+ T firstOccurrence = annotations.head;
List repeated = List.nil();
Type origAnnoType = null;
Type arrayOfOrigAnnoType = null;
@@ -350,16 +384,16 @@
Assert.check(!annotations.isEmpty() &&
!annotations.tail.isEmpty()); // i.e. size() > 1
- for (List al = annotations;
+ for (List al = annotations;
!al.isEmpty();
al = al.tail)
{
- Attribute.Compound currentAnno = al.head;
+ T currentAnno = al.head;
origAnnoType = currentAnno.type;
if (arrayOfOrigAnnoType == null) {
arrayOfOrigAnnoType = types.makeArrayType(origAnnoType);
-}
+ }
Type currentContainerType = getContainingType(currentAnno, ctx.pos.get(currentAnno));
if (currentContainerType == null) {
@@ -383,25 +417,46 @@
if (!repeated.isEmpty()) {
repeated = repeated.reverse();
- JCAnnotation annoTree;
TreeMaker m = make.at(ctx.pos.get(firstOccurrence));
Pair p =
new Pair(containerValueSymbol,
new Attribute.Array(arrayOfOrigAnnoType, repeated));
- annoTree = m.Annotation(new Attribute.Compound(targetContainerType,
- List.of(p)));
+ if (ctx.isTypeCompound) {
+ /* TODO: the following code would be cleaner:
+ Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
+ ((Attribute.TypeCompound)annotations.head).position);
+ JCTypeAnnotation annoTree = m.TypeAnnotation(at);
+ at = enterTypeAnnotation(annoTree, targetContainerType, ctx.env);
+ */
+ // However, we directly construct the TypeCompound to keep the
+ // direct relation to the contained TypeCompounds.
+ Attribute.TypeCompound at = new Attribute.TypeCompound(targetContainerType, List.of(p),
+ ((Attribute.TypeCompound)annotations.head).position);
- if (!chk.annotationApplicable(annoTree, on))
- log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType);
+ // TODO: annotation applicability checks from below?
+
+ at.setSynthesized(true);
- if (!chk.validateAnnotationDeferErrors(annoTree))
- log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType);
+ @SuppressWarnings("unchecked")
+ T x = (T) at;
+ return x;
+ } else {
+ Attribute.Compound c = new Attribute.Compound(targetContainerType, List.of(p));
+ JCAnnotation annoTree = m.Annotation(c);
+
+ if (!chk.annotationApplicable(annoTree, on))
+ log.error(annoTree.pos(), "invalid.repeatable.annotation.incompatible.target", targetContainerType, origAnnoType);
- Attribute.Compound c = enterAnnotation(annoTree,
- targetContainerType,
- ctx.env);
- c.setSynthesized(true);
- return c;
+ if (!chk.validateAnnotationDeferErrors(annoTree))
+ log.error(annoTree.pos(), "duplicate.annotation.invalid.repeated", origAnnoType);
+
+ c = enterAnnotation(annoTree, targetContainerType, ctx.env);
+ c.setSynthesized(true);
+
+ @SuppressWarnings("unchecked")
+ T x = (T) c;
+ return x;
+ }
} else {
return null; // errors should have been reported elsewhere
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jan 23 13:27:24 2013 -0800
@@ -26,9 +26,9 @@
package com.sun.tools.javac.comp;
import java.util.*;
-import java.util.Set;
import javax.lang.model.element.ElementKind;
+import javax.lang.model.type.TypeKind;
import javax.tools.JavaFileObject;
import com.sun.source.tree.IdentifierTree;
@@ -45,7 +45,6 @@
import com.sun.tools.javac.comp.Infer.InferenceContext;
import com.sun.tools.javac.comp.Infer.InferenceContext.FreeTypeListener;
import com.sun.tools.javac.jvm.*;
-import com.sun.tools.javac.jvm.Target;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
@@ -880,6 +879,7 @@
deferredLintHandler.flush(tree.pos());
chk.checkDeprecatedAnnotation(tree.pos(), m);
+
// Create a new environment with local scope
// for attributing the method.
Env localEnv = memberEnter.methodEnv(tree, env);
@@ -923,6 +923,21 @@
// Check that result type is well-formed.
chk.validate(tree.restype, localEnv);
+ // Check that receiver type is well-formed.
+ if (tree.recvparam != null) {
+ // Use a new environment to check the receiver parameter.
+ // Otherwise I get "might not have been initialized" errors.
+ // Is there a better way?
+ Env newEnv = memberEnter.methodEnv(tree, env);
+ attribType(tree.recvparam, newEnv);
+ chk.validate(tree.recvparam, newEnv);
+ if (!(tree.recvparam.type == m.owner.type || types.isSameType(tree.recvparam.type, m.owner.type))) {
+ // The == covers the common non-generic case, but for generic classes we need isSameType;
+ // note that equals didn't work.
+ log.error(tree.recvparam.pos(), "incorrect.receiver.type");
+ }
+ }
+
// annotation method checks
if ((owner.flags() & ANNOTATION) != 0) {
// annotation method cannot have throws clause
@@ -996,9 +1011,14 @@
}
}
+ // Attribute all type annotations in the body
+ memberEnter.typeAnnotate(tree.body, localEnv, m);
+ annotate.flush();
+
// Attribute method body.
attribStat(tree.body, localEnv);
}
+
localEnv.info.scope.leave();
result = tree.type = m.type;
chk.validateAnnotations(tree.mods.annotations, m);
@@ -1019,6 +1039,12 @@
memberEnter.memberEnter(tree, env);
annotate.flush();
}
+ } else {
+ if (tree.init != null) {
+ // Field initializer expression need to be entered.
+ memberEnter.typeAnnotate(tree.init, env, tree.sym);
+ annotate.flush();
+ }
}
VarSymbol v = tree.sym;
@@ -1076,6 +1102,11 @@
new MethodSymbol(tree.flags | BLOCK, names.empty, null,
env.info.scope.owner);
if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++;
+
+ // Attribute all type annotations in the block
+ memberEnter.typeAnnotate(tree, localEnv, localEnv.info.scope.owner);
+ annotate.flush();
+
attribStats(tree.stats, localEnv);
} else {
// Create a new local environment with a local scope.
@@ -1847,10 +1878,24 @@
// If enclosing class is given, attribute it, and
// complete class name to be fully qualified
JCExpression clazz = tree.clazz; // Class field following new
- JCExpression clazzid = // Identifier in class field
- (clazz.hasTag(TYPEAPPLY))
- ? ((JCTypeApply) clazz).clazz
- : clazz;
+ JCExpression clazzid; // Identifier in class field
+ JCAnnotatedType annoclazzid; // Annotated type enclosing clazzid
+ annoclazzid = null;
+
+ if (clazz.hasTag(TYPEAPPLY)) {
+ clazzid = ((JCTypeApply) clazz).clazz;
+ if (clazzid.hasTag(ANNOTATED_TYPE)) {
+ annoclazzid = (JCAnnotatedType) clazzid;
+ clazzid = annoclazzid.underlyingType;
+ }
+ } else {
+ if (clazz.hasTag(ANNOTATED_TYPE)) {
+ annoclazzid = (JCAnnotatedType) clazz;
+ clazzid = annoclazzid.underlyingType;
+ } else {
+ clazzid = clazz;
+ }
+ }
JCExpression clazzid1 = clazzid; // The same in fully qualified form
@@ -1865,14 +1910,30 @@
// yields a clazz T.C.
Type encltype = chk.checkRefType(tree.encl.pos(),
attribExpr(tree.encl, env));
+ // TODO 308: in .new C, do we also want to add the type annotations
+ // from expr to the combined type, or not? Yes, do this.
clazzid1 = make.at(clazz.pos).Select(make.Type(encltype),
((JCIdent) clazzid).name);
- if (clazz.hasTag(TYPEAPPLY))
- clazz = make.at(tree.pos).
+
+ if (clazz.hasTag(ANNOTATED_TYPE)) {
+ JCAnnotatedType annoType = (JCAnnotatedType) clazz;
+ List annos = annoType.annotations;
+
+ if (annoType.underlyingType.hasTag(TYPEAPPLY)) {
+ clazzid1 = make.at(tree.pos).
+ TypeApply(clazzid1,
+ ((JCTypeApply) clazz).arguments);
+ }
+
+ clazzid1 = make.at(tree.pos).
+ AnnotatedType(annos, clazzid1);
+ } else if (clazz.hasTag(TYPEAPPLY)) {
+ clazzid1 = make.at(tree.pos).
TypeApply(clazzid1,
((JCTypeApply) clazz).arguments);
- else
- clazz = clazzid1;
+ }
+
+ clazz = clazzid1;
}
// Attribute clazz expression and store
@@ -1889,6 +1950,9 @@
tree.clazz.type = clazztype;
TreeInfo.setSymbol(clazzid, TreeInfo.symbol(clazzid1));
clazzid.type = ((JCIdent) clazzid).sym.type;
+ if (annoclazzid != null) {
+ annoclazzid.type = clazzid.type;
+ }
if (!clazztype.isErroneous()) {
if (cdef != null && clazztype.tsym.isInterface()) {
log.error(tree.encl.pos(), "anon.class.impl.intf.no.qual.for.new");
@@ -3255,8 +3319,18 @@
// Tree.Visitor.
else if (ownOuter.hasTag(CLASS) && site != ownOuter) {
Type normOuter = site;
- if (normOuter.hasTag(CLASS))
+ if (normOuter.hasTag(CLASS)) {
normOuter = types.asEnclosingSuper(site, ownOuter.tsym);
+ if (site.getKind() == TypeKind.ANNOTATED) {
+ // Propagate any type annotations.
+ // TODO: should asEnclosingSuper do this?
+ // Note that the type annotations in site will be updated
+ // by annotateType. Therefore, modify site instead
+ // of creating a new AnnotatedType.
+ ((AnnotatedType)site).underlyingType = normOuter;
+ normOuter = site;
+ }
+ }
if (normOuter == null) // perhaps from an import
normOuter = types.erasure(ownOuter);
if (normOuter != ownOuter)
@@ -3644,8 +3718,15 @@
tree.type = result = checkIntersection(tree, tree.bounds);
}
- public void visitTypeParameter(JCTypeParameter tree) {
- TypeVar typeVar = (TypeVar)tree.type;
+ public void visitTypeParameter(JCTypeParameter tree) {
+ TypeVar typeVar = (TypeVar) tree.type;
+
+ if (tree.annotations != null && tree.annotations.nonEmpty()) {
+ AnnotatedType antype = new AnnotatedType(typeVar);
+ annotateType(antype, tree.annotations);
+ tree.type = antype;
+ }
+
if (!typeVar.bound.isErroneous()) {
//fixup type-parameter bound computed in 'attribTypeVariables'
typeVar.bound = checkIntersection(tree, tree.bounds);
@@ -3741,6 +3822,44 @@
result = tree.type = syms.errType;
}
+ public void visitAnnotatedType(JCAnnotatedType tree) {
+ Type underlyingType = attribType(tree.getUnderlyingType(), env);
+ this.attribAnnotationTypes(tree.annotations, env);
+ AnnotatedType antype = new AnnotatedType(underlyingType);
+ annotateType(antype, tree.annotations);
+ result = tree.type = antype;
+ }
+
+ /**
+ * Apply the annotations to the particular type.
+ */
+ public void annotateType(final AnnotatedType type, final List annotations) {
+ if (annotations.isEmpty())
+ return;
+ annotate.typeAnnotation(new Annotate.Annotator() {
+ @Override
+ public String toString() {
+ return "annotate " + annotations + " onto " + type;
+ }
+ @Override
+ public void enterAnnotation() {
+ List compounds = fromAnnotations(annotations);
+ type.typeAnnotations = compounds;
+ }
+ });
+ }
+
+ private static List fromAnnotations(List annotations) {
+ if (annotations.isEmpty())
+ return List.nil();
+
+ ListBuffer buf = ListBuffer.lb();
+ for (JCAnnotation anno : annotations) {
+ buf.append((Attribute.TypeCompound) anno.attribute);
+ }
+ return buf.toList();
+ }
+
public void visitErroneous(JCErroneous tree) {
if (tree.errs != null)
for (JCTree err : tree.errs)
@@ -3972,6 +4091,12 @@
(c.flags() & ABSTRACT) == 0) {
checkSerialVersionUID(tree, c);
}
+
+ // Correctly organize the postions of the type annotations
+ TypeAnnotations.organizeTypeAnnotationsBodies(this.syms, this.names, this.log, tree);
+
+ // Check type annotations applicability rules
+ validateTypeAnnotations(tree);
}
// where
/** get a diagnostic position for an attribute of Type t, or null if attribute missing */
@@ -4029,6 +4154,94 @@
return types.capture(type);
}
+ private void validateTypeAnnotations(JCTree tree) {
+ tree.accept(typeAnnotationsValidator);
+ }
+ //where
+ private final JCTree.Visitor typeAnnotationsValidator =
+ new TreeScanner() {
+ public void visitAnnotation(JCAnnotation tree) {
+ if (tree.hasTag(TYPE_ANNOTATION)) {
+ // TODO: It seems to WMD as if the annotation in
+ // parameters, in particular also the recvparam, are never
+ // of type JCTypeAnnotation and therefore never checked!
+ // Luckily this check doesn't really do anything that isn't
+ // also done elsewhere.
+ chk.validateTypeAnnotation(tree, false);
+ }
+ super.visitAnnotation(tree);
+ }
+ public void visitTypeParameter(JCTypeParameter tree) {
+ chk.validateTypeAnnotations(tree.annotations, true);
+ scan(tree.bounds);
+ // Don't call super.
+ // This is needed because above we call validateTypeAnnotation with
+ // false, which would forbid annotations on type parameters.
+ // super.visitTypeParameter(tree);
+ }
+ public void visitMethodDef(JCMethodDecl tree) {
+ // Static methods cannot have receiver type annotations.
+ // In test case FailOver15.java, the nested method getString has
+ // a null sym, because an unknown class is instantiated.
+ // I would say it's safe to skip.
+ if (tree.sym != null && (tree.sym.flags() & Flags.STATIC) != 0) {
+ if (tree.recvparam != null) {
+ // TODO: better error message. Is the pos good?
+ log.error(tree.recvparam.pos(), "annotation.type.not.applicable");
+ }
+ }
+ if (tree.restype != null && tree.restype.type != null) {
+ validateAnnotatedType(tree.restype, tree.restype.type);
+ }
+ super.visitMethodDef(tree);
+ }
+ public void visitVarDef(final JCVariableDecl tree) {
+ if (tree.sym != null && tree.sym.type != null)
+ validateAnnotatedType(tree, tree.sym.type);
+ super.visitVarDef(tree);
+ }
+ public void visitTypeCast(JCTypeCast tree) {
+ if (tree.clazz != null && tree.clazz.type != null)
+ validateAnnotatedType(tree.clazz, tree.clazz.type);
+ super.visitTypeCast(tree);
+ }
+ public void visitTypeTest(JCInstanceOf tree) {
+ if (tree.clazz != null && tree.clazz.type != null)
+ validateAnnotatedType(tree.clazz, tree.clazz.type);
+ super.visitTypeTest(tree);
+ }
+ // TODO: what else do we need?
+ // public void visitNewClass(JCNewClass tree) {
+ // public void visitNewArray(JCNewArray tree) {
+
+ /* I would want to model this after
+ * com.sun.tools.javac.comp.Check.Validator.visitSelectInternal(JCFieldAccess)
+ * and override visitSelect and visitTypeApply.
+ * However, we only set the annotated type in the top-level type
+ * of the symbol.
+ * Therefore, we need to override each individual location where a type
+ * can occur.
+ */
+ private void validateAnnotatedType(final JCTree errtree, final Type type) {
+ if (type.getEnclosingType() != null &&
+ type != type.getEnclosingType()) {
+ validateEnclosingAnnotatedType(errtree, type.getEnclosingType());
+ }
+ for (Type targ : type.getTypeArguments()) {
+ validateAnnotatedType(errtree, targ);
+ }
+ }
+ private void validateEnclosingAnnotatedType(final JCTree errtree, final Type type) {
+ validateAnnotatedType(errtree, type);
+ if (type.tsym != null &&
+ type.tsym.isStatic() &&
+ type.getAnnotations().nonEmpty()) {
+ // Enclosing static classes cannot have type annotations.
+ log.error(errtree.pos(), "cant.annotate.static.class");
+ }
+ }
+ };
+
//
/**
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Wed Jan 23 13:27:24 2013 -0800
@@ -26,7 +26,7 @@
package com.sun.tools.javac.comp;
import java.util.*;
-import java.util.Set;
+
import javax.tools.JavaFileManager;
import com.sun.tools.javac.code.*;
@@ -101,6 +101,9 @@
context.put(checkKey, this);
names = Names.instance(context);
+ dfltTargetMeta = new Name[] { names.PACKAGE, names.TYPE,
+ names.FIELD, names.METHOD, names.CONSTRUCTOR,
+ names.ANNOTATION_TYPE, names.LOCAL_VARIABLE, names.PARAMETER};
log = Log.instance(context);
rs = Resolve.instance(context);
syms = Symtab.instance(context);
@@ -572,34 +575,27 @@
if (!tree.type.isErroneous() &&
(env.info.lint == null || env.info.lint.isEnabled(Lint.LintCategory.CAST))
&& types.isSameType(tree.expr.type, tree.clazz.type)
+ && !(ignoreAnnotatedCasts && TreeInfo.containsTypeAnnotation(tree.clazz))
&& !is292targetTypeCast(tree)) {
log.warning(Lint.LintCategory.CAST,
tree.pos(), "redundant.cast", tree.expr.type);
}
}
//where
- private boolean is292targetTypeCast(JCTypeCast tree) {
- boolean is292targetTypeCast = false;
- JCExpression expr = TreeInfo.skipParens(tree.expr);
- if (expr.hasTag(APPLY)) {
- JCMethodInvocation apply = (JCMethodInvocation)expr;
- Symbol sym = TreeInfo.symbol(apply.meth);
- is292targetTypeCast = sym != null &&
- sym.kind == MTH &&
- (sym.flags() & HYPOTHETICAL) != 0;
- }
- return is292targetTypeCast;
+ private boolean is292targetTypeCast(JCTypeCast tree) {
+ boolean is292targetTypeCast = false;
+ JCExpression expr = TreeInfo.skipParens(tree.expr);
+ if (expr.hasTag(APPLY)) {
+ JCMethodInvocation apply = (JCMethodInvocation)expr;
+ Symbol sym = TreeInfo.symbol(apply.meth);
+ is292targetTypeCast = sym != null &&
+ sym.kind == MTH &&
+ (sym.flags() & HYPOTHETICAL) != 0;
}
-
-
+ return is292targetTypeCast;
+ }
-//where
- /** Is type a type variable, or a (possibly multi-dimensional) array of
- * type variables?
- */
- boolean isTypeVar(Type t) {
- return t.hasTag(TYPEVAR) || t.hasTag(ARRAY) && isTypeVar(types.elemtype(t));
- }
+ private static final boolean ignoreAnnotatedCasts = true;
/** Check that a type is within some bounds.
*
@@ -853,7 +849,7 @@
// System.out.println("actuals: " + argtypes);
List formals = owntype.getParameterTypes();
Type last = useVarargs ? formals.last() : null;
- if (sym.name==names.init &&
+ if (sym.name == names.init &&
sym.owner == syms.enumSym)
formals = formals.tail.tail;
List args = argtrees;
@@ -1326,6 +1322,11 @@
}
}
+ @Override
+ public void visitAnnotatedType(JCAnnotatedType tree) {
+ tree.underlyingType.accept(this);
+ }
+
/** Default visitor method: do nothing.
*/
@Override
@@ -2246,7 +2247,7 @@
void checkImplementations(JCClassDecl tree) {
checkImplementations(tree, tree.sym, tree.sym);
}
-//where
+ //where
/** Check that all methods which implement some
* method in `ic' conform to the method they implement.
*/
@@ -2587,6 +2588,13 @@
validateAnnotation(a, s);
}
+ /** Check the type annotations.
+ */
+ public void validateTypeAnnotations(List annotations, boolean isTypeParameter) {
+ for (JCAnnotation a : annotations)
+ validateTypeAnnotation(a, isTypeParameter);
+ }
+
/** Check an annotation of a symbol.
*/
private void validateAnnotation(JCAnnotation a, Symbol s) {
@@ -2613,6 +2621,14 @@
}
}
+ public void validateTypeAnnotation(JCAnnotation a, boolean isTypeParameter) {
+ Assert.checkNonNull(a.type, "annotation tree hasn't been attributed yet: " + a);
+ validateAnnotationTree(a);
+
+ if (!isTypeAnnotation(a, isTypeParameter))
+ log.error(a.pos(), "annotation.type.not.applicable");
+ }
+
/**
* Validate the proposed container 'repeatable' on the
* annotation type symbol 's'. Report errors at position
@@ -2795,45 +2811,90 @@
return false;
}
+ /** Is the annotation applicable to type annotations? */
+ protected boolean isTypeAnnotation(JCAnnotation a, boolean isTypeParameter) {
+ Attribute.Compound atTarget =
+ a.annotationType.type.tsym.attribute(syms.annotationTargetType.tsym);
+ if (atTarget == null) {
+ // An annotation without @Target is not a type annotation.
+ return false;
+ }
+
+ Attribute atValue = atTarget.member(names.value);
+ if (!(atValue instanceof Attribute.Array)) {
+ return false; // error recovery
+ }
+
+ Attribute.Array arr = (Attribute.Array) atValue;
+ for (Attribute app : arr.values) {
+ if (!(app instanceof Attribute.Enum)) {
+ return false; // recovery
+ }
+ Attribute.Enum e = (Attribute.Enum) app;
+
+ if (e.value.name == names.TYPE_USE)
+ return true;
+ else if (isTypeParameter && e.value.name == names.TYPE_PARAMETER)
+ return true;
+ }
+ return false;
+ }
+
/** Is the annotation applicable to the symbol? */
boolean annotationApplicable(JCAnnotation a, Symbol s) {
Attribute.Array arr = getAttributeTargetAttribute(a.annotationType.type.tsym);
+ Name[] targets;
+
if (arr == null) {
- return true;
+ targets = defaultTargetMetaInfo(a, s);
+ } else {
+ // TODO: can we optimize this?
+ targets = new Name[arr.values.length];
+ for (int i=0; i typarams,
List params,
JCTree res,
+ JCVariableDecl recvparam,
List thrown,
Env env) {
@@ -368,6 +375,15 @@
// Attribute result type, if one is given.
Type restype = res == null ? syms.voidType : attr.attribType(res, env);
+ // Attribute receiver type, if one is given.
+ Type recvtype;
+ if (recvparam!=null) {
+ memberEnter(recvparam, env);
+ recvtype = recvparam.vartype.type;
+ } else {
+ recvtype = null;
+ }
+
// Attribute thrown exceptions.
ListBuffer thrownbuf = new ListBuffer();
for (List l = thrown; l.nonEmpty(); l = l.tail) {
@@ -376,10 +392,12 @@
exc = chk.checkClassType(l.head.pos(), exc);
thrownbuf.append(exc);
}
- Type mtype = new MethodType(argbuf.toList(),
+ MethodType mtype = new MethodType(argbuf.toList(),
restype,
thrownbuf.toList(),
syms.methodClass);
+ mtype.recvtype = recvtype;
+
return tvars.isEmpty() ? mtype : new ForAll(tvars, mtype);
}
@@ -573,7 +591,8 @@
try {
// Compute the method type
m.type = signature(tree.typarams, tree.params,
- tree.restype, tree.thrown,
+ tree.restype, tree.recvparam,
+ tree.thrown,
localEnv);
} finally {
chk.setDeferredLintHandler(prevLintHandler);
@@ -597,6 +616,10 @@
enclScope.enter(m);
}
annotateLater(tree.mods.annotations, localEnv, m);
+ // Visit the signature of the method. Note that
+ // TypeAnnotate doesn't descend into the body.
+ typeAnnotate(tree, localEnv, m);
+
if (tree.defaultValue != null)
annotateDefaultValueLater(tree.defaultValue, localEnv, m);
}
@@ -642,7 +665,7 @@
//(a plain array type) with the more precise VarargsType --- we need
//to do it this way because varargs is represented in the tree as a modifier
//on the parameter declaration, and not as a distinct type of array node.
- ArrayType atype = (ArrayType)tree.vartype.type;
+ ArrayType atype = (ArrayType)tree.vartype.type.unannotatedType();
tree.vartype.type = atype.makeVarargs();
}
Scope enclScope = enter.enterScope(env);
@@ -665,6 +688,8 @@
enclScope.enter(v);
}
annotateLater(tree.mods.annotations, localEnv, v);
+ typeAnnotate(tree.vartype, env, tree.sym);
+ annotate.flush();
v.pos = tree.pos;
}
@@ -759,7 +784,7 @@
log.error(annotations.head.pos,
"already.annotated",
kindName(s), s);
- enterAnnotations(annotations, localEnv, s);
+ actualEnterAnnotations(annotations, localEnv, s);
} finally {
log.useSource(prev);
}
@@ -781,7 +806,7 @@
}
/** Enter a set of annotations. */
- private void enterAnnotations(List annotations,
+ private void actualEnterAnnotations(List annotations,
Env env,
Symbol s) {
Map> annotated =
@@ -817,11 +842,11 @@
&& s.owner.kind != MTH
&& types.isSameType(c.type, syms.deprecatedType)) {
s.flags_field |= Flags.DEPRECATED;
- }
+ }
}
- s.annotations.setAttributesWithCompletion(
- annotate.new AnnotateRepeatedContext(env, annotated, pos, log));
+ s.annotations.setDeclarationAttributesWithCompletion(
+ annotate.new AnnotateRepeatedContext(env, annotated, pos, log, false));
}
/** Queue processing of an attribute default value. */
@@ -900,6 +925,12 @@
// create an environment for evaluating the base clauses
Env baseEnv = baseEnv(tree, env);
+ if (tree.extending != null)
+ typeAnnotate(tree.extending, baseEnv, sym);
+ for (JCExpression impl : tree.implementing)
+ typeAnnotate(impl, baseEnv, sym);
+ annotate.flush();
+
// Determine supertype.
Type supertype =
(tree.extending != null)
@@ -969,10 +1000,15 @@
if (hasDeprecatedAnnotation(tree.mods.annotations))
c.flags_field |= DEPRECATED;
annotateLater(tree.mods.annotations, baseEnv, c);
+ // class type parameters use baseEnv but everything uses env
chk.checkNonCyclicDecl(tree);
attr.attribTypeVariables(tree.typarams, baseEnv);
+ // Do this here, where we have the symbol.
+ for (JCTypeParameter tp : tree.typarams)
+ typeAnnotate(tp, baseEnv, sym);
+ annotate.flush();
// Add default constructor if needed.
if ((c.flags() & INTERFACE) == 0 &&
@@ -1050,12 +1086,120 @@
} finally {
isFirst = true;
}
+ }
+ annotate.afterRepeated(TypeAnnotations.organizeTypeAnnotationsSignatures(syms, names, log, tree));
+ }
- // commit pending annotations
- annotate.flush();
+ private void actualEnterTypeAnnotations(final List annotations,
+ final Env env,
+ final Symbol s) {
+ Map> annotated =
+ new LinkedHashMap>();
+ Map pos =
+ new HashMap();
+
+ for (List al = annotations; !al.isEmpty(); al = al.tail) {
+ JCAnnotation a = al.head;
+ Attribute.TypeCompound tc = annotate.enterTypeAnnotation(a,
+ syms.annotationType,
+ env);
+ if (tc == null) {
+ continue;
+ }
+
+ if (annotated.containsKey(a.type.tsym)) {
+ if (source.allowRepeatedAnnotations()) {
+ ListBuffer l = annotated.get(a.type.tsym);
+ l = l.append(tc);
+ annotated.put(a.type.tsym, l);
+ pos.put(tc, a.pos());
+ } else {
+ log.error(a.pos(), "duplicate.annotation");
+ }
+ } else {
+ annotated.put(a.type.tsym, ListBuffer.of(tc));
+ pos.put(tc, a.pos());
+ }
+ }
+
+ s.annotations.appendTypeAttributesWithCompletion(
+ annotate.new AnnotateRepeatedContext(env, annotated, pos, log, true));
+ }
+
+ public void typeAnnotate(final JCTree tree, final Env env, final Symbol sym) {
+ tree.accept(new TypeAnnotate(env, sym));
+ }
+
+ /**
+ * We need to use a TreeScanner, because it is not enough to visit the top-level
+ * annotations. We also need to visit type arguments, etc.
+ */
+ private class TypeAnnotate extends TreeScanner {
+ private Env env;
+ private Symbol sym;
+
+ public TypeAnnotate(final Env env, final Symbol sym) {
+ this.env = env;
+ this.sym = sym;
+ }
+
+ void annotateTypeLater(final List annotations) {
+ if (annotations.isEmpty()) {
+ return;
+ }
+
+ annotate.normal(new Annotate.Annotator() {
+ @Override
+ public String toString() {
+ return "type annotate " + annotations + " onto " + sym + " in " + sym.owner;
+ }
+ @Override
+ public void enterAnnotation() {
+ JavaFileObject prev = log.useSource(env.toplevel.sourcefile);
+ try {
+ actualEnterTypeAnnotations(annotations, env, sym);
+ } finally {
+ log.useSource(prev);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void visitAnnotatedType(final JCAnnotatedType tree) {
+ annotateTypeLater(tree.annotations);
+ super.visitAnnotatedType(tree);
+ }
+
+ @Override
+ public void visitTypeParameter(final JCTypeParameter tree) {
+ annotateTypeLater(tree.annotations);
+ super.visitTypeParameter(tree);
+ }
+
+ @Override
+ public void visitNewArray(final JCNewArray tree) {
+ annotateTypeLater(tree.annotations);
+ for (List dimAnnos : tree.dimAnnotations)
+ annotateTypeLater(dimAnnos);
+ super.visitNewArray(tree);
+ }
+
+ @Override
+ public void visitMethodDef(final JCMethodDecl tree) {
+ scan(tree.mods);
+ scan(tree.restype);
+ scan(tree.typarams);
+ scan(tree.recvparam);
+ scan(tree.params);
+ scan(tree.thrown);
+ scan(tree.defaultValue);
+ // Do not annotate the body, just the signature.
+ // scan(tree.body);
}
}
+
private Env baseEnv(JCClassDecl tree, Env env) {
Scope baseScope = new Scope(tree.sym);
//import already entered local classes into base scope
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -55,7 +55,6 @@
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
-import java.util.Set;
import javax.lang.model.element.ElementVisitor;
@@ -696,7 +695,7 @@
if (varargsFormal == null &&
argtypes.size() != formals.size()) {
- report(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
+ reportMC(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
}
while (argtypes.nonEmpty() && formals.head != varargsFormal) {
@@ -707,7 +706,7 @@
}
if (formals.head != varargsFormal) {
- report(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
+ reportMC(MethodCheckDiag.ARITY_MISMATCH, inferenceContext); // not enough args
}
if (useVarargs) {
@@ -724,7 +723,7 @@
}
}
- private void report(MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) {
+ private void reportMC(MethodCheckDiag diag, InferenceContext inferenceContext, Object... args) {
boolean inferDiag = inferenceContext != infer.emptyContext;
InapplicableMethodException ex = inferDiag ?
infer.inferenceException : inapplicableMethodException;
@@ -748,7 +747,7 @@
} else {
if (!isAccessible(env, t)) {
Symbol location = env.enclClass.sym;
- report(MethodCheckDiag.INACCESSIBLE_VARARGS, inferenceContext, t, Kinds.kindName(location), location);
+ reportMC(MethodCheckDiag.INACCESSIBLE_VARARGS, inferenceContext, t, Kinds.kindName(location), location);
}
}
}
@@ -761,7 +760,7 @@
@Override
public void report(DiagnosticPosition pos, JCDiagnostic details) {
- report(methodDiag, deferredAttrContext.inferenceContext, details);
+ reportMC(methodDiag, deferredAttrContext.inferenceContext, details);
}
};
return new MethodResultInfo(to, checkContext);
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -483,6 +483,7 @@
tree.restype = translate(tree.restype, null);
tree.typarams = List.nil();
tree.params = translateVarDefs(tree.params);
+ tree.recvparam = translate(tree.recvparam, null);
tree.thrown = translate(tree.thrown, null);
tree.body = translate(tree.body, tree.sym.erasure(types).getReturnType());
tree.type = erasure(tree.type);
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -351,8 +351,8 @@
/** Read a byte.
*/
- byte nextByte() {
- return buf[bp++];
+ int nextByte() {
+ return buf[bp++] & 0xFF;
}
/** Read an integer.
@@ -1172,6 +1172,19 @@
}
},
+ new AttributeReader(names.RuntimeVisibleTypeAnnotations, V52, CLASS_OR_MEMBER_ATTRIBUTE) {
+ protected void read(Symbol sym, int attrLen) {
+ attachTypeAnnotations(sym);
+ }
+ },
+
+ new AttributeReader(names.RuntimeInvisibleTypeAnnotations, V52, CLASS_OR_MEMBER_ATTRIBUTE) {
+ protected void read(Symbol sym, int attrLen) {
+ attachTypeAnnotations(sym);
+ }
+ },
+
+
// The following attributes for a Code attribute are not currently handled
// StackMapTable
// SourceDebugExtension
@@ -1381,6 +1394,17 @@
}
}
+ void attachTypeAnnotations(final Symbol sym) {
+ int numAttributes = nextChar();
+ if (numAttributes != 0) {
+ ListBuffer proxies =
+ ListBuffer.lb();
+ for (int i = 0; i < numAttributes; i++)
+ proxies.append(readTypeAnnotation());
+ annotate.normal(new TypeAnnotationCompleter(sym, proxies.toList()));
+ }
+ }
+
/** Attach the default value for an annotation element.
*/
void attachAnnotationDefault(final Symbol sym) {
@@ -1427,6 +1451,111 @@
return new CompoundAnnotationProxy(t, pairs.toList());
}
+ TypeAnnotationProxy readTypeAnnotation() {
+ TypeAnnotationPosition position = readPosition();
+ CompoundAnnotationProxy proxy = readCompoundAnnotation();
+
+ return new TypeAnnotationProxy(proxy, position);
+ }
+
+ TypeAnnotationPosition readPosition() {
+ int tag = nextByte(); // TargetType tag is a byte
+
+ if (!TargetType.isValidTargetTypeValue(tag))
+ throw this.badClassFile("bad.type.annotation.value", String.format("0x%02X", tag));
+
+ TypeAnnotationPosition position = new TypeAnnotationPosition();
+ TargetType type = TargetType.fromTargetTypeValue(tag);
+
+ position.type = type;
+
+ switch (type) {
+ // type cast
+ case CAST:
+ // instanceof
+ case INSTANCEOF:
+ // new expression
+ case NEW:
+ position.offset = nextChar();
+ break;
+ // local variable
+ case LOCAL_VARIABLE:
+ // resource variable
+ case RESOURCE_VARIABLE:
+ int table_length = nextChar();
+ position.lvarOffset = new int[table_length];
+ position.lvarLength = new int[table_length];
+ position.lvarIndex = new int[table_length];
+
+ for (int i = 0; i < table_length; ++i) {
+ position.lvarOffset[i] = nextChar();
+ position.lvarLength[i] = nextChar();
+ position.lvarIndex[i] = nextChar();
+ }
+ break;
+ // exception parameter
+ case EXCEPTION_PARAMETER:
+ position.exception_index = nextByte();
+ break;
+ // method receiver
+ case METHOD_RECEIVER:
+ // Do nothing
+ break;
+ // type parameter
+ case CLASS_TYPE_PARAMETER:
+ case METHOD_TYPE_PARAMETER:
+ position.parameter_index = nextByte();
+ break;
+ // type parameter bound
+ case CLASS_TYPE_PARAMETER_BOUND:
+ case METHOD_TYPE_PARAMETER_BOUND:
+ position.parameter_index = nextByte();
+ position.bound_index = nextByte();
+ break;
+ // class extends or implements clause
+ case CLASS_EXTENDS:
+ position.type_index = nextChar();
+ break;
+ // throws
+ case THROWS:
+ position.type_index = nextChar();
+ break;
+ // method parameter
+ case METHOD_FORMAL_PARAMETER:
+ position.parameter_index = nextByte();
+ break;
+ // method/constructor/reference type argument
+ case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_REFERENCE_TYPE_ARGUMENT:
+ position.offset = nextChar();
+ position.type_index = nextByte();
+ break;
+ // We don't need to worry about these
+ case METHOD_RETURN:
+ case FIELD:
+ break;
+ // lambda formal parameter
+ case LAMBDA_FORMAL_PARAMETER:
+ position.parameter_index = nextByte();
+ break;
+ case UNKNOWN:
+ throw new AssertionError("jvm.ClassReader: UNKNOWN target type should never occur!");
+ default:
+ throw new AssertionError("jvm.ClassReader: Unknown target type for position: " + position);
+ }
+
+ { // See whether there is location info and read it
+ int len = nextByte();
+ ListBuffer loc = ListBuffer.lb();
+ for (int i = 0; i < len * TypeAnnotationPosition.TypePathEntry.bytesPerEntry; ++i)
+ loc = loc.append(nextByte());
+ position.location = TypeAnnotationPosition.getTypePathFromBinary(loc.toList());
+ }
+
+ return position;
+ }
+
Attribute readAttributeValue() {
char c = (char) buf[bp++];
switch (c) {
@@ -1748,7 +1877,7 @@
Annotations annotations = sym.annotations;
List newList = deproxyCompoundList(l);
if (annotations.pendingCompletion()) {
- annotations.setAttributes(newList);
+ annotations.setDeclarationAttributes(newList);
} else {
annotations.append(newList);
}
@@ -1758,6 +1887,39 @@
}
}
+ class TypeAnnotationCompleter extends AnnotationCompleter {
+
+ List proxies;
+
+ TypeAnnotationCompleter(Symbol sym,
+ List proxies) {
+ super(sym, List.nil());
+ this.proxies = proxies;
+ }
+
+ List deproxyTypeCompoundList(List proxies) {
+ ListBuffer buf = ListBuffer.lb();
+ for (TypeAnnotationProxy proxy: proxies) {
+ Attribute.Compound compound = deproxyCompound(proxy.compound);
+ Attribute.TypeCompound typeCompound = new Attribute.TypeCompound(compound, proxy.position);
+ buf.add(typeCompound);
+ }
+ return buf.toList();
+ }
+
+ @Override
+ public void enterAnnotation() {
+ JavaFileObject previousClassFile = currentClassFile;
+ try {
+ currentClassFile = classFile;
+ List newList = deproxyTypeCompoundList(proxies);
+ sym.annotations.setTypeAttributes(newList.prependList(sym.getRawTypeAttributes()));
+ } finally {
+ currentClassFile = previousClassFile;
+ }
+ }
+ }
+
/************************************************************************
* Reading Symbols
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -31,12 +31,14 @@
import java.util.Set;
import java.util.HashSet;
+import javax.lang.model.type.TypeKind;
import javax.tools.JavaFileManager;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Attribute.RetentionPolicy;
+import com.sun.tools.javac.code.Attribute.TypeCompound;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.code.Types.UniqueType;
@@ -47,7 +49,6 @@
import com.sun.tools.javac.jvm.Pool.Variable;
import com.sun.tools.javac.util.*;
-import static com.sun.tools.javac.code.BoundKind.*;
import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Kinds.*;
import static com.sun.tools.javac.code.TypeTag.*;
@@ -68,19 +69,17 @@
protected static final Context.Key classWriterKey =
new Context.Key();
- private final Symtab syms;
-
private final Options options;
/** Switch: verbose output.
*/
private boolean verbose;
- /** Switch: scramble private names.
+ /** Switch: scramble private field names.
*/
private boolean scramble;
- /** Switch: scramble private names.
+ /** Switch: scramble all field names.
*/
private boolean scrambleAll;
@@ -96,7 +95,7 @@
*/
private boolean genCrt;
- /** Switch: describe the generated stackmap
+ /** Switch: describe the generated stackmap.
*/
boolean debugstackmap;
@@ -114,7 +113,7 @@
private Types types;
/** The initial sizes of the data and constant pool buffers.
- * sizes are increased when buffers get full.
+ * Sizes are increased when buffers get full.
*/
static final int DATA_BUF_SIZE = 0x0fff0;
static final int POOL_BUF_SIZE = 0x1fff0;
@@ -181,7 +180,6 @@
log = Log.instance(context);
names = Names.instance(context);
- syms = Symtab.instance(context);
options = Options.instance(context);
target = Target.instance(context);
source = Source.instance(context);
@@ -279,6 +277,7 @@
/** Assemble signature of given type in string buffer.
*/
void assembleSig(Type type) {
+ type = type.unannotatedType();
switch (type.getTag()) {
case BYTE:
sigbuf.appendByte('B');
@@ -379,6 +378,7 @@
}
void assembleClassSig(Type type) {
+ type = type.unannotatedType();
ClassType ct = (ClassType)type;
ClassSymbol c = (ClassSymbol)ct.tsym;
enterInner(c);
@@ -722,6 +722,7 @@
acount++;
}
acount += writeJavaAnnotations(sym.getRawAttributes());
+ acount += writeTypeAnnotations(sym.getRawTypeAttributes());
return acount;
}
@@ -838,6 +839,76 @@
return attrCount;
}
+ int writeTypeAnnotations(List typeAnnos) {
+ if (typeAnnos.isEmpty()) return 0;
+
+ ListBuffer visibles = ListBuffer.lb();
+ ListBuffer invisibles = ListBuffer.lb();
+
+ for (Attribute.TypeCompound tc : typeAnnos) {
+ if (tc.position == null || tc.position.type == TargetType.UNKNOWN) {
+ boolean found = false;
+ // TODO: the position for the container annotation of a
+ // repeating type annotation has to be set.
+ // This cannot be done when the container is created, because
+ // then the position is not determined yet.
+ // How can we link these pieces better together?
+ if (tc.values.size() == 1) {
+ Pair val = tc.values.get(0);
+ if (val.fst.getSimpleName().contentEquals("value") &&
+ val.snd instanceof Attribute.Array) {
+ Attribute.Array arr = (Attribute.Array) val.snd;
+ if (arr.values.length != 0 &&
+ arr.values[0] instanceof Attribute.TypeCompound) {
+ TypeCompound atycomp = (Attribute.TypeCompound) arr.values[0];
+ if (atycomp.position.type != TargetType.UNKNOWN) {
+ tc.position = atycomp.position;
+ found = true;
+ }
+ }
+ }
+ }
+ if (!found) {
+ // This happens for nested types like @A Outer. @B Inner.
+ // For method parameters we get the annotation twice! Once with
+ // a valid position, once unknown.
+ // TODO: find a cleaner solution.
+ // System.err.println("ClassWriter: Position UNKNOWN in type annotation: " + tc);
+ continue;
+ }
+ }
+ if (!tc.position.emitToClassfile())
+ continue;
+ switch (types.getRetention(tc)) {
+ case SOURCE: break;
+ case CLASS: invisibles.append(tc); break;
+ case RUNTIME: visibles.append(tc); break;
+ default: ;// /* fail soft */ throw new AssertionError(vis);
+ }
+ }
+
+ int attrCount = 0;
+ if (visibles.length() != 0) {
+ int attrIndex = writeAttr(names.RuntimeVisibleTypeAnnotations);
+ databuf.appendChar(visibles.length());
+ for (Attribute.TypeCompound p : visibles)
+ writeTypeAnnotation(p);
+ endAttr(attrIndex);
+ attrCount++;
+ }
+
+ if (invisibles.length() != 0) {
+ int attrIndex = writeAttr(names.RuntimeInvisibleTypeAnnotations);
+ databuf.appendChar(invisibles.length());
+ for (Attribute.TypeCompound p : invisibles)
+ writeTypeAnnotation(p);
+ endAttr(attrIndex);
+ attrCount++;
+ }
+
+ return attrCount;
+ }
+
/** A visitor to write an attribute including its leading
* single-character marker.
*/
@@ -914,6 +985,94 @@
p.snd.accept(awriter);
}
}
+
+ void writeTypeAnnotation(Attribute.TypeCompound c) {
+ writePosition(c.position);
+ writeCompoundAttribute(c);
+ }
+
+ void writePosition(TypeAnnotationPosition p) {
+ databuf.appendByte(p.type.targetTypeValue()); // TargetType tag is a byte
+ switch (p.type) {
+ // type cast
+ case CAST:
+ // instanceof
+ case INSTANCEOF:
+ // new expression
+ case NEW:
+ databuf.appendChar(p.offset);
+ break;
+ // local variable
+ case LOCAL_VARIABLE:
+ // resource variable
+ case RESOURCE_VARIABLE:
+ databuf.appendChar(p.lvarOffset.length); // for table length
+ for (int i = 0; i < p.lvarOffset.length; ++i) {
+ databuf.appendChar(p.lvarOffset[i]);
+ databuf.appendChar(p.lvarLength[i]);
+ databuf.appendChar(p.lvarIndex[i]);
+ }
+ break;
+ // exception parameter
+ case EXCEPTION_PARAMETER:
+ databuf.appendByte(p.exception_index);
+ break;
+ // method receiver
+ case METHOD_RECEIVER:
+ // Do nothing
+ break;
+ // type parameter
+ case CLASS_TYPE_PARAMETER:
+ case METHOD_TYPE_PARAMETER:
+ databuf.appendByte(p.parameter_index);
+ break;
+ // type parameter bound
+ case CLASS_TYPE_PARAMETER_BOUND:
+ case METHOD_TYPE_PARAMETER_BOUND:
+ databuf.appendByte(p.parameter_index);
+ databuf.appendByte(p.bound_index);
+ break;
+ // class extends or implements clause
+ case CLASS_EXTENDS:
+ databuf.appendChar(p.type_index);
+ break;
+ // throws
+ case THROWS:
+ databuf.appendChar(p.type_index);
+ break;
+ // method parameter
+ case METHOD_FORMAL_PARAMETER:
+ databuf.appendByte(p.parameter_index);
+ break;
+ // method/constructor/reference type argument
+ case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_INVOCATION_TYPE_ARGUMENT:
+ case METHOD_REFERENCE_TYPE_ARGUMENT:
+ databuf.appendChar(p.offset);
+ databuf.appendByte(p.type_index);
+ break;
+ // We don't need to worry about these
+ case METHOD_RETURN:
+ case FIELD:
+ break;
+ // lambda formal parameter
+ case LAMBDA_FORMAL_PARAMETER:
+ databuf.appendByte(p.parameter_index);
+ break;
+ case UNKNOWN:
+ throw new AssertionError("jvm.ClassWriter: UNKNOWN target type should never occur!");
+ default:
+ throw new AssertionError("jvm.ClassWriter: Unknown target type for position: " + p);
+ }
+
+ { // Append location data for generics/arrays.
+ databuf.appendByte(p.location.size());
+ java.util.List loc = TypeAnnotationPosition.getBinaryFromTypePath(p.location);
+ for (int i : loc)
+ databuf.appendByte((byte)i);
+ }
+ }
+
/**********************************************************************
* Writing Objects
**********************************************************************/
@@ -1661,6 +1820,7 @@
acount += writeFlagAttrs(c.flags());
acount += writeJavaAnnotations(c.getRawAttributes());
+ acount += writeTypeAnnotations(c.getRawTypeAttributes());
acount += writeEnclosingMethodAttribute(c);
acount += writeExtraClassAttributes(c);
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -1924,17 +1924,70 @@
if (length < Character.MAX_VALUE) {
v.length = length;
putVar(v);
+ fillLocalVarPosition(v);
}
}
}
state.defined.excl(adr);
}
+ private void fillLocalVarPosition(LocalVar lv) {
+ if (lv == null || lv.sym == null
+ || lv.sym.annotations.isTypesEmpty())
+ return;
+ for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) {
+ TypeAnnotationPosition p = ta.position;
+ p.lvarOffset = new int[] { (int)lv.start_pc };
+ p.lvarLength = new int[] { (int)lv.length };
+ p.lvarIndex = new int[] { (int)lv.reg };
+ p.isValidOffset = true;
+ }
+ }
+
+ // Method to be called after compressCatchTable to
+ // fill in the exception table index for type
+ // annotations on exception parameters.
+ public void fillExceptionParameterPositions() {
+ for (int i = 0; i < varBufferSize; ++i) {
+ LocalVar lv = varBuffer[i];
+ if (lv == null || lv.sym == null
+ || lv.sym.annotations.isTypesEmpty()
+ || !lv.sym.isExceptionParameter())
+ return;
+
+ int exidx = findExceptionIndex(lv);
+
+ for (Attribute.TypeCompound ta : lv.sym.getRawTypeAttributes()) {
+ TypeAnnotationPosition p = ta.position;
+ p.exception_index = exidx;
+ }
+ }
+ }
+
+ private int findExceptionIndex(LocalVar lv) {
+ List iter = catchInfo.toList();
+ int len = catchInfo.length();
+ for (int i = 0; i < len; ++i) {
+ char[] catchEntry = iter.head;
+ iter = iter.tail;
+ char handlerpc = catchEntry[2];
+ if (lv.start_pc == handlerpc + 1) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
/** Put a live variable range into the buffer to be output to the
* class file.
*/
void putVar(LocalVar var) {
- if (!varDebugInfo) return;
+ // Keep local variables if
+ // 1) we need them for debug information
+ // 2) it is an exception type and it contains type annotations
+ if (!varDebugInfo &&
+ (!var.sym.isExceptionParameter() ||
+ var.sym.annotations.isTypesEmpty())) return;
if ((var.sym.flags() & Flags.SYNTHETIC) != 0) return;
if (varBuffer == null)
varBuffer = new LocalVar[20];
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -1016,8 +1016,11 @@
code.frameBeforeLast = null;
}
- //compress exception table
+ // Compress exception table
code.compressCatchTable();
+
+ // Fill in type annotation positions for exception parameters
+ code.fillExceptionParameterPositions();
}
}
@@ -1738,6 +1741,7 @@
*************************************************************************/
public void visitApply(JCMethodInvocation tree) {
+ setTypeAnnotationPositions(tree.pos);
// Generate code for method.
Item m = genExpr(tree.meth, methodType);
// Generate code for all arguments, where the expected types are
@@ -1775,10 +1779,48 @@
result = items.makeStackItem(pt);
}
+ private void setTypeAnnotationPositions(int treePos) {
+ MethodSymbol meth = code.meth;
+
+ for (Attribute.TypeCompound ta : meth.getRawTypeAttributes()) {
+ if (ta.position.pos == treePos) {
+ ta.position.offset = code.cp;
+ ta.position.lvarOffset = new int[] { code.cp };
+ ta.position.isValidOffset = true;
+ }
+ }
+
+ if (code.meth.getKind() != javax.lang.model.element.ElementKind.CONSTRUCTOR
+ && code.meth.getKind() != javax.lang.model.element.ElementKind.STATIC_INIT)
+ return;
+
+ for (Attribute.TypeCompound ta : meth.owner.getRawTypeAttributes()) {
+ if (ta.position.pos == treePos) {
+ ta.position.offset = code.cp;
+ ta.position.lvarOffset = new int[] { code.cp };
+ ta.position.isValidOffset = true;
+ }
+ }
+
+ ClassSymbol clazz = meth.enclClass();
+ for (Symbol s : new com.sun.tools.javac.model.FilteredMemberList(clazz.members())) {
+ if (!s.getKind().isField())
+ continue;
+ for (Attribute.TypeCompound ta : s.getRawTypeAttributes()) {
+ if (ta.position.pos == treePos) {
+ ta.position.offset = code.cp;
+ ta.position.lvarOffset = new int[] { code.cp };
+ ta.position.isValidOffset = true;
+ }
+ }
+ }
+ }
+
public void visitNewClass(JCNewClass tree) {
// Enclosing instances or anonymous classes should have been eliminated
// by now.
Assert.check(tree.encl == null && tree.def == null);
+ setTypeAnnotationPositions(tree.pos);
code.emitop2(new_, makeRef(tree.pos(), tree.type));
code.emitop0(dup);
@@ -1793,6 +1835,7 @@
}
public void visitNewArray(JCNewArray tree) {
+ setTypeAnnotationPositions(tree.pos);
if (tree.elems != null) {
Type elemtype = types.elemtype(tree.type);
@@ -2122,6 +2165,7 @@
}
public void visitTypeCast(JCTypeCast tree) {
+ setTypeAnnotationPositions(tree.pos);
result = genExpr(tree.expr, tree.clazz.type).load();
// Additional code is only needed if we cast to a reference type
// which is not statically a supertype of the expression's type.
@@ -2138,6 +2182,7 @@
}
public void visitTypeTest(JCInstanceOf tree) {
+ setTypeAnnotationPositions(tree.pos);
genExpr(tree.expr, tree.expr.type).load();
code.emitop2(instanceof_, makeRef(tree.pos(), tree.clazz.type));
result = items.makeStackItem(syms.booleanType);
@@ -2184,7 +2229,7 @@
code.emitop2(ldc2, makeRef(tree.pos(), tree.selected.type));
result = items.makeStackItem(pt);
return;
- }
+ }
Symbol ssym = TreeInfo.symbol(tree.selected);
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/jvm/JNIWriter.java
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/JNIWriter.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/JNIWriter.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -158,7 +158,7 @@
return false;
/* temporary code for backwards compatibility */
- for (Attribute.Compound a: c.annotations.getAttributes()) {
+ for (Attribute.Compound a: c.annotations.getDeclarationAttributes()) {
if (a.type.tsym == syms.nativeHeaderType_old.tsym)
return true;
}
@@ -167,7 +167,7 @@
for (Scope.Entry i = c.members_field.elems; i != null; i = i.sibling) {
if (i.sym.kind == Kinds.MTH && (i.sym.flags() & Flags.NATIVE) != 0)
return true;
- for (Attribute.Compound a: i.sym.annotations.getAttributes()) {
+ for (Attribute.Compound a: i.sym.annotations.getDeclarationAttributes()) {
if (a.type.tsym == syms.nativeHeaderType.tsym)
return true;
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java
--- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -513,7 +513,7 @@
*/
public CompileState shouldStopPolicyIfNoError;
- /** A queue of all as yet unattributed classes.oLo
+ /** A queue of all as yet unattributed classes.
*/
public Todo todo;
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java
--- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacTypes.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -25,9 +25,9 @@
package com.sun.tools.javac.model;
+import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.EnumSet;
-import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -333,4 +333,28 @@
return results;
}
+
+ public List extends AnnotationMirror> typeAnnotationsOf(TypeMirror type) {
+ // TODO: these methods can be removed.
+ return null; // ((Type)type).typeAnnotations;
+ }
+
+ public A typeAnnotationOf(TypeMirror type,
+ Class annotationType) {
+ // TODO: these methods can be removed.
+ return null; // JavacElements.getAnnotation(((Type)type).typeAnnotations, annotationType);
+ }
+
+ public TypeMirror receiverTypeOf(ExecutableType type) {
+ return ((Type)type).asMethodType().recvtype;
+ }
+
+ /*
+ public A receiverTypeAnnotationOf(
+ ExecutableType type, Class annotationType) {
+ return JavacElements.getAnnotation(
+ ((Type)type).asMethodType().receiverTypeAnnotations,
+ annotationType);
+ }*/
+
}
diff -r 5a8d00abf076 -r ee1eebe7e210 langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Wed Jan 23 20:57:40 2013 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Wed Jan 23 13:27:24 2013 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -88,6 +88,41 @@
/** End position mappings container */
private final AbstractEndPosTable endPosTable;
+ // 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.
+ //
+ // 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 typeAnnotationsPushedBack = List.nil();
+
+ /**
+ * 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;
+
interface ErrorRecoveryAction {
JCTree doRecover(JavacParser parser);
}
@@ -126,6 +161,7 @@
this.allowDefaultMethods = source.allowDefaultMethods();
this.allowStaticInterfaceMethods = source.allowStaticInterfaceMethods();
this.allowIntersectionTypesInCast = source.allowIntersectionTypesInCast();
+ this.allowTypeAnnotations = source.allowTypeAnnotations();
this.keepDocComments = keepDocComments;
docComments = newDocCommentTable(keepDocComments, fac);
this.keepLineMap = keepLineMap;
@@ -215,6 +251,20 @@
*/
boolean keepLineMap;
+ /** Switch: should we recognize type annotations?
+ */
+ boolean allowTypeAnnotations;
+
+ /** Switch: is "this" allowed as an identifier?
+ * This is needed to parse receiver types.
+ */
+ boolean allowThisIdent;
+
+ /** The type of the method receiver, as specified by a first "this" parameter.
+ */
+ JCVariableDecl receiverParam;
+
+
/** When terms are parsed, the mode determines which is expected:
* mode = EXPR : an expression
* mode = TYPE : a type
@@ -558,6 +608,18 @@
nextToken();
return name;
}
+ } else if (token.kind == THIS) {
+ if (allowThisIdent) {
+ // Make sure we're using a supported source version.
+ checkTypeAnnotations();
+ Name name = token.name();
+ nextToken();
+ return name;
+ } else {
+ error(token.pos, "this.as.identifier");
+ nextToken();
+ return names.error;
+ }
} else if (token.kind == UNDERSCORE) {
warning(token.pos, "underscore.as.identifier");
Name name = token.name();
@@ -570,14 +632,21 @@
}
/**
- * Qualident = Ident { DOT Ident }
+ * Qualident = Ident { DOT [Annotations] Ident }
*/
- public JCExpression qualident() {
+ public JCExpression qualident(boolean allowAnnos) {
JCExpression t = toP(F.at(token.pos).Ident(ident()));
while (token.kind == DOT) {
int pos = token.pos;
nextToken();
+ List tyannos = null;
+ if (allowAnnos) {
+ tyannos = typeAnnotationsOpt();
+ }
t = toP(F.at(pos).Select(t, ident()));
+ if (tyannos != null && tyannos.nonEmpty()) {
+ t = toP(F.at(tyannos.head.pos).AnnotatedType(tyannos, t));
+ }
}
return t;
}
@@ -686,7 +755,7 @@
nextToken();
return t;
}
-//where
+ //where
boolean isZero(String s) {
char[] cs = s.toCharArray();
int base = ((cs.length > 1 && Character.toLowerCase(cs[1]) == 'x') ? 16 : 10);
@@ -706,7 +775,34 @@
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.
+ *
+ *
+ *
+ * Note that this method sets {@code mode} to {@code TYPE} first, before
+ * parsing annotations.
+ */
public JCExpression parseType() {
+ List annotations = typeAnnotationsOpt();
+ return parseType(annotations);
+ }
+
+ public JCExpression parseType(List annotations) {
+ JCExpression result = unannotatedType();
+
+ if (annotations.nonEmpty()) {
+ result = insertAnnotationsToMostInner(result, annotations, false);
+ }
+
+ return result;
+ }
+
+ public JCExpression unannotatedType() {
return term(TYPE);
}
@@ -864,7 +960,7 @@
opStackSupply.add(opStack);
return t;
}
-//where
+ //where
/** Construct a binary or type test node.
*/
private JCExpression makeOp(int pos,
@@ -943,9 +1039,9 @@
* | NEW [TypeArguments] Creator
* | "(" Arguments ")" "->" ( Expression | Block )
* | Ident "->" ( Expression | Block )
- * | Ident { "." Ident }
+ * | [Annotations] Ident { "." [Annotations] Ident }
* | Expression3 MemberReferenceSuffix
- * [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
+ * [ [Annotations] "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
* | Arguments
* | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator )
* ]
@@ -1067,6 +1163,34 @@
typeArgs = null;
} else return illegal();
break;
+ case MONKEYS_AT:
+ // Only annotated cast types are valid
+ List typeAnnos = typeAnnotationsOpt();
+ if (typeAnnos.isEmpty()) {
+ // else there would be no '@'
+ throw new AssertionError("Expected type annotations, but found none!");
+ }
+
+ JCExpression expr = term3();
+
+ if ((mode & TYPE) == 0) {
+ // Type annotations on class literals no longer legal
+ if (!expr.hasTag(Tag.SELECT)) {
+ 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 {
+ // Type annotations targeting a cast
+ t = insertAnnotationsToMostInner(expr, typeAnnos, false);
+ }
+ break;
case UNDERSCORE: case IDENTIFIER: case ASSERT: case ENUM:
if (typeArgs != null) return illegal();
if ((mode & EXPR) != 0 && peekToken(ARROW)) {
@@ -1075,6 +1199,13 @@
t = toP(F.at(token.pos).Ident(ident()));
loop: while (true) {
pos = token.pos;
+ final List annos = typeAnnotationsOpt();
+
+ // need to report an error later if LBRACKET is for array
+ // index access rather than array creation level
+ if (!annos.isEmpty() && token.kind != LBRACKET && token.kind != ELLIPSIS)
+ return illegal(annos.head.pos);
+
switch (token.kind) {
case LBRACKET:
nextToken();
@@ -1082,11 +1213,23 @@
nextToken();
t = bracketsOpt(t);
t = toP(F.at(pos).TypeArray(t));
- t = bracketsSuffix(t);
+ if (annos.nonEmpty()) {
+ t = toP(F.at(pos).AnnotatedType(annos, t));
+ }
+ // .class is only allowed if there were no annotations
+ JCExpression nt = bracketsSuffix(t);
+ if (nt != t && (annos.nonEmpty() || TreeInfo.containsTypeAnnotation(t))) {
+ // t and nt are different if bracketsSuffix parsed a .class.
+ // The check for nonEmpty covers the case when the whole array is annotated.
+ // Helper method isAnnotated looks for annos deeply within t.
+ syntaxError("no.annotations.on.dot.class");
+ }
+ t = nt;
} 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);
@@ -1096,6 +1239,7 @@
if ((mode & EXPR) != 0) {
mode = EXPR;
t = arguments(typeArgs, t);
+ if (!annos.isEmpty()) t = illegal(annos.head.pos);
typeArgs = null;
}
break loop;
@@ -1136,9 +1280,25 @@
break loop;
}
}
+
+ List tyannos = null;
+ if ((mode & TYPE) != 0 && token.kind == MONKEYS_AT) {
+ tyannos = typeAnnotationsOpt();
+ }
// typeArgs saved for next loop iteration.
t = toP(F.at(pos).Select(t, ident()));
+ if (tyannos != null && tyannos.nonEmpty()) {
+ t = toP(F.at(tyannos.head.pos).AnnotatedType(tyannos, t));
+ }
break;
+ case ELLIPSIS:
+ if (this.permitTypeAnnotationsPushBack) {
+ this.typeAnnotationsPushedBack = annos;
+ } else if (annos.nonEmpty()) {
+ // Don't return here -- error recovery attempt
+ illegal(annos.head.pos);
+ }
+ break loop;
case LT:
if ((mode & TYPE) == 0 && isUnboundMemberRef()) {
//this is an unbound method reference whose qualifier
@@ -1212,6 +1372,8 @@
if (typeArgs != null) illegal();
while (true) {
int pos1 = token.pos;
+ final List annos = typeAnnotationsOpt();
+
if (token.kind == LBRACKET) {
nextToken();
if ((mode & TYPE) != 0) {
@@ -1225,6 +1387,9 @@
mode = EXPR;
continue;
}
+ if (annos.nonEmpty()) {
+ t = toP(F.at(pos1).AnnotatedType(annos, t));
+ }
return t;
}
mode = oldmode;
@@ -1253,7 +1418,15 @@
t = innerCreator(pos2, typeArgs, t);
typeArgs = null;
} else {
+ List tyannos = null;
+ if ((mode & TYPE) != 0 && token.kind == MONKEYS_AT) {
+ // is the mode check needed?
+ tyannos = typeAnnotationsOpt();
+ }
t = toP(F.at(pos1).Select(t, ident()));
+ if (tyannos != null && tyannos.nonEmpty()) {
+ t = toP(F.at(tyannos.head.pos).AnnotatedType(tyannos, t));
+ }
t = argumentsOpt(typeArgs, typeArgumentsOpt(t));
typeArgs = null;
}
@@ -1263,6 +1436,12 @@
accept(COLCOL);
t = memberReferenceSuffix(pos1, t);
} else {
+ if (!annos.isEmpty()) {
+ if (permitTypeAnnotationsPushBack)
+ typeAnnotationsPushedBack = annos;
+ else
+ return illegal(annos.head.pos);
+ }
break;
}
}
@@ -1321,7 +1500,7 @@
ParensResult analyzeParens() {
int depth = 0;
boolean type = false;
- for (int lookahead = 0 ; ; lookahead++) {
+ outer: for (int lookahead = 0 ; ; lookahead++) {
TokenKind tk = S.token(lookahead).kind;
switch (tk) {
case EXTENDS: case SUPER: case COMMA:
@@ -1382,9 +1561,36 @@
break;
case FINAL:
case ELLIPSIS:
- case MONKEYS_AT:
//those can only appear in explicit lambdas
return ParensResult.EXPLICIT_LAMBDA;
+ case MONKEYS_AT:
+ type = true;
+ lookahead += 1; //skip '@'
+ while (peekToken(lookahead, DOT)) {
+ lookahead += 2;
+ }
+ if (peekToken(lookahead, LPAREN)) {
+ lookahead++;
+ //skip annotation values
+ int nesting = 0;
+ for (; ; lookahead++) {
+ TokenKind tk2 = S.token(lookahead).kind;
+ switch (tk2) {
+ case EOF:
+ return ParensResult.PARENS;
+ case LPAREN:
+ nesting++;
+ break;
+ case RPAREN:
+ nesting--;
+ if (nesting == 0) {
+ continue outer;
+ }
+ break;
+ }
+ }
+ }
+ break;
case LBRACKET:
if (peekToken(lookahead, RBRACKET, LAX_IDENTIFIER)) {
// '[', ']', Identifier/'_'/'assert'/'enum' -> explicit lambda
@@ -1618,25 +1824,27 @@
/**
* {@literal
* TypeArgument = Type
- * | "?"
- * | "?" EXTENDS Type {"&" Type}
- * | "?" SUPER Type
+ * | [Annotations] "?"
+ * | [Annotations] "?" EXTENDS Type {"&" Type}
+ * | [Annotations] "?" SUPER Type
* }
*/
JCExpression typeArgument() {
- if (token.kind != QUES) return parseType();
+ List annotations = typeAnnotationsOpt();
+ if (token.kind != QUES) return parseType(annotations);
int pos = token.pos;
nextToken();
+ JCExpression result;
if (token.kind == EXTENDS) {
TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.EXTENDS));
nextToken();
JCExpression bound = parseType();
- return F.at(pos).Wildcard(t, bound);
+ result = F.at(pos).Wildcard(t, bound);
} else if (token.kind == SUPER) {
TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.SUPER));
nextToken();
JCExpression bound = parseType();
- return F.at(pos).Wildcard(t, bound);
+ result = F.at(pos).Wildcard(t, bound);
} else if (LAX_IDENTIFIER.accepts(token.kind)) {
//error recovery
TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND);
@@ -1644,11 +1852,15 @@
JCIdent id = toP(F.at(token.pos).Ident(ident()));
JCErroneous err = F.at(pos).Erroneous(List.of(wc, id));
reportSyntaxError(err, "expected3", GT, EXTENDS, SUPER);
- return err;
+ result = err;
} else {
TypeBoundKind t = toP(F.at(pos).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, boolean diamondAllowed) {
@@ -1657,22 +1869,51 @@
return toP(F.at(pos).TypeApply(t, args));
}
- /** BracketsOpt = {"[" "]"}
+ /**
+ * BracketsOpt = { [Annotations] "[" "]" }*
+ *
+ *
+ *
+ * annotations
is the list of annotations targeting
+ * the expression t
.
*/
- private JCExpression bracketsOpt(JCExpression t) {
+ private JCExpression bracketsOpt(JCExpression t,
+ List annotations) {
+ List nextLevelAnnotations = typeAnnotationsOpt();
+
if (token.kind == LBRACKET) {
int pos = token.pos;
nextToken();
- t = bracketsOptCont(t, pos);
- F.at(pos);
+ t = bracketsOptCont(t, pos, nextLevelAnnotations);
+ } else if (!nextLevelAnnotations.isEmpty()) {
+ if (permitTypeAnnotationsPushBack) {
+ this.typeAnnotationsPushedBack = nextLevelAnnotations;
+ } else {
+ return illegal(nextLevelAnnotations.head.pos);
+ }
+ }
+
+ if (!annotations.isEmpty()) {
+ t = toP(F.at(token.pos).AnnotatedType(annotations, t));
}
return t;
}
- private JCArrayTypeTree bracketsOptCont(JCExpression t, int pos) {
+ /** BracketsOpt = [ "[" "]" { [Annotations] "[" "]"} ]
+ */
+ private JCExpression bracketsOpt(JCExpression t) {
+ return bracketsOpt(t, List.nil());
+ }
+
+ private JCExpression bracketsOptCont(JCExpression t, int pos,
+ List annotations) {
accept(RBRACKET);
t = bracketsOpt(t);
- return toP(F.at(pos).TypeArray(t));
+ t = toP(F.at(pos).TypeArray(t));
+ if (annotations.nonEmpty()) {
+ t = toP(F.at(pos).AnnotatedType(annotations, t));
+ }
+ return t;
}
/** BracketsSuffixExpr = "." CLASS
@@ -1686,7 +1927,7 @@
accept(CLASS);
if (token.pos == endPosTable.errorEndPos) {
// error recovery
- Name name = null;
+ Name name;
if (LAX_IDENTIFIER.accepts(token.kind)) {
name = token.name();
nextToken();
@@ -1724,8 +1965,8 @@
if (token.kind == LT) {
typeArgs = typeArguments(false);
}
- Name refName = null;
- ReferenceMode refMode = null;
+ Name refName;
+ ReferenceMode refMode;
if (token.kind == NEW) {
refMode = ReferenceMode.NEW;
refName = names.init;
@@ -1737,18 +1978,31 @@
return toP(F.at(t.getStartPosition()).Reference(refMode, refName, t, typeArgs));
}
- /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
+ /** Creator = [Annotations] Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
*/
JCExpression creator(int newpos, List typeArgs) {
+ List newAnnotations = typeAnnotationsOpt();
+
switch (token.kind) {
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, toP(F.at(newAnnotations.head.pos).AnnotatedType(newAnnotations, basicType())));
+ }
+ }
break;
default:
}
- JCExpression t = qualident();
+ JCExpression t = qualident(true);
+
+ // handle type annotations for non primitive arrays
+ if (newAnnotations.nonEmpty()) {
+ t = insertAnnotationsToMostInner(t, newAnnotations, false);
+ }
+
int oldmode = mode;
mode = TYPE;
boolean diamondFound = false;
@@ -1766,7 +2020,13 @@
}
int pos = token.pos;
nextToken();
+ List tyannos = typeAnnotationsOpt();
t = toP(F.at(pos).Select(t, ident()));
+
+ if (tyannos != null && tyannos.nonEmpty()) {
+ t = toP(F.at(tyannos.head.pos).AnnotatedType(tyannos, t));
+ }
+
if (token.kind == LT) {
lastTypeargsPos = token.pos;
checkGenerics();
@@ -1775,7 +2035,7 @@
}
}
mode = oldmode;
- if (token.kind == LBRACKET) {
+ if (token.kind == LBRACKET || token.kind == MONKEYS_AT) {
JCExpression e = arrayCreatorRest(newpos, t);
if (diamondFound) {
reportSyntaxError(lastTypeargsPos, "cannot.create.array.with.diamond");
@@ -1796,7 +2056,15 @@
}
return e;
} else if (token.kind == LPAREN) {
- return classCreatorRest(newpos, null, typeArgs, t);
+ JCNewClass newClass = classCreatorRest(newpos, null, typeArgs, t);
+ if (newClass.def != null) {
+ assert newClass.def.mods.annotations.isEmpty();
+ if (newAnnotations.nonEmpty()) {
+ newClass.def.mods.pos = earlier(newClass.def.mods.pos, newAnnotations.head.pos);
+ newClass.def.mods.annotations = List.convert(JCAnnotation.class, newAnnotations);
+ }
+ }
+ return newClass;
} else {
setErrorEndPos(token.pos);
reportSyntaxError(token.pos, "expected2", LPAREN, LBRACKET);
@@ -1805,10 +2073,17 @@
}
}
- /** InnerCreator = Ident [TypeArguments] ClassCreatorRest
+ /** InnerCreator = [Annotations] Ident [TypeArguments] ClassCreatorRest
*/
JCExpression innerCreator(int newpos, List typeArgs, JCExpression encl) {
+ List newAnnotations = typeAnnotationsOpt();
+
JCExpression t = toP(F.at(token.pos).Ident(ident()));
+
+ if (newAnnotations.nonEmpty()) {
+ t = toP(F.at(newAnnotations.head.pos).AnnotatedType(newAnnotations, t));
+ }
+
if (token.kind == LT) {
int oldmode = mode;
checkGenerics();
@@ -1818,35 +2093,65 @@
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 annos = typeAnnotationsOpt();
+
accept(LBRACKET);
if (token.kind == RBRACKET) {
accept(RBRACKET);
- elemtype = bracketsOpt(elemtype);
+ elemtype = bracketsOpt(elemtype, annos);
if (token.kind == LBRACE) {
- return arrayInitializer(newpos, elemtype);
+ JCNewArray na = (JCNewArray)arrayInitializer(newpos, elemtype);
+ if (annos.nonEmpty()) {
+ // when an array initializer is present then
+ // the parsed annotations should target the
+ // new array tree
+ // bracketsOpt inserts the annotation in
+ // elemtype, and it needs to be corrected
+ //
+ JCAnnotatedType annotated = (JCAnnotatedType)elemtype;
+ assert annotated.annotations == annos;
+ na.annotations = annotated.annotations;
+ na.elemtype = annotated.underlyingType;
+ }
+ return na;
} else {
JCExpression t = toP(F.at(newpos).NewArray(elemtype, List.nil(), null));
return syntaxError(token.pos, List.of(t), "array.dimension.missing");
}
} else {
ListBuffer dims = new ListBuffer();
+
+ // maintain array dimension type annotations
+ ListBuffer> dimAnnotations = ListBuffer.lb();
+ dimAnnotations.append(annos);
+
dims.append(parseExpression());
accept(RBRACKET);
- while (token.kind == LBRACKET) {
+ while (token.kind == LBRACKET
+ || token.kind == MONKEYS_AT) {
+ List maybeDimAnnos = typeAnnotationsOpt();
int pos = token.pos;
nextToken();
if (token.kind == RBRACKET) {
- elemtype = bracketsOptCont(elemtype, pos);
+ elemtype = bracketsOptCont(elemtype, pos, maybeDimAnnos);
} else {
- dims.append(parseExpression());
- accept(RBRACKET);
+ if (token.kind == 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.dimAnnotations = dimAnnotations.toList();
+ return na;
}
}
@@ -2254,6 +2559,7 @@
}
/** CatchClause = CATCH "(" FormalParameter ")" Block
+ * TODO: the "FormalParameter" is not correct, it uses the special "catchTypes" rule below.
*/
protected JCCatch catchClause() {
int pos = token.pos;
@@ -2276,7 +2582,9 @@
while (token.kind == BAR) {
checkMulticatch();
nextToken();
- catchTypes.add(qualident());
+ // Instead of qualident this is now parseType.
+ // But would that allow too much, e.g. arrays or generics?
+ catchTypes.add(parseType());
}
return catchTypes.toList();
}
@@ -2377,16 +2685,28 @@
}
/** AnnotationsOpt = { '@' Annotation }
+ *
+ * @param kind Whether to parse an ANNOTATION or TYPE_ANNOTATION
*/
- List annotationsOpt() {
+ List annotationsOpt(Tag kind) {
if (token.kind != MONKEYS_AT) return List.nil(); // optimization
ListBuffer buf = new ListBuffer();
+ int prevmode = mode;
while (token.kind == MONKEYS_AT) {
int pos = token.pos;
nextToken();
- buf.append(annotation(pos));
+ buf.append(annotation(pos, kind));
}
- return buf.toList();
+ lastmode = mode;
+ mode = prevmode;
+ List annotations = buf.toList();
+
+ return annotations;
+ }
+
+ List typeAnnotationsOpt() {
+ List annotations = annotationsOpt(Tag.TYPE_ANNOTATION);
+ return annotations;
}
/** ModifiersOpt = { Modifier }
@@ -2412,7 +2732,7 @@
if (token.deprecatedFlag()) {
flags |= Flags.DEPRECATED;
}
- int lastPos = Position.NOPOS;
+ int lastPos;
loop:
while (true) {
long flag;
@@ -2439,12 +2759,11 @@
if (flag == Flags.ANNOTATION) {
checkAnnotations();
if (token.kind != INTERFACE) {
- JCAnnotation ann = annotation(lastPos);
+ JCAnnotation ann = annotation(lastPos, Tag.ANNOTATION);
// if first modifier is an annotation, set pos to annotation's.
if (flags == 0 && annotations.isEmpty())
pos = ann.pos;
annotations.append(ann);
- lastPos = ann.pos;
flag = 0;
}
}
@@ -2468,14 +2787,27 @@
}
/** Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ]
+ *
* @param pos position of "@" token
+ * @param kind Whether to parse an ANNOTATION or TYPE_ANNOTATION
*/
- JCAnnotation annotation(int pos) {
+ JCAnnotation annotation(int pos, Tag kind) {
// accept(AT); // AT consumed by caller
checkAnnotations();
- JCTree ident = qualident();
+ if (kind == Tag.TYPE_ANNOTATION) {
+ checkTypeAnnotations();
+ }
+ JCTree ident = qualident(false);
List fieldValues = annotationFieldValuesOpt();
- JCAnnotation ann = F.at(pos).Annotation(ident, fieldValues);
+ JCAnnotation ann;
+ if (kind == Tag.ANNOTATION) {
+ ann = F.at(pos).Annotation(ident, fieldValues);
+ } else if (kind == Tag.TYPE_ANNOTATION) {
+ ann = F.at(pos).TypeAnnotation(ident, fieldValues);
+ } else {
+ throw new AssertionError("Unhandled annotation kind: " + kind);
+ }
+
storeEnd(ann, S.prevToken().endPos);
return ann;
}
@@ -2528,7 +2860,7 @@
case MONKEYS_AT:
pos = token.pos;
nextToken();
- return annotation(pos);
+ return annotation(pos, Tag.ANNOTATION);
case LBRACE:
pos = token.pos;
accept(LBRACE);
@@ -2683,7 +3015,7 @@
mods = null;
}
nextToken();
- pid = qualident();
+ pid = qualident(false);
accept(SEMI);
}
ListBuffer defs = new ListBuffer();
@@ -2934,7 +3266,7 @@
flags |= Flags.DEPRECATED;
}
int pos = token.pos;
- List annotations = annotationsOpt();
+ List annotations = annotationsOpt(Tag.ANNOTATION);
JCModifiers mods = F.at(annotations.isEmpty() ? Position.NOPOS : pos).Modifiers(flags, annotations);
List typeArgs = typeArgumentsOpt();
int identPos = token.pos;
@@ -3037,15 +3369,25 @@
mods.pos = pos;
storeEnd(mods, pos);
}
+ List annosAfterParams = annotationsOpt(Tag.ANNOTATION);
+
Token tk = token;
pos = token.pos;
JCExpression type;
boolean isVoid = token.kind == VOID;
if (isVoid) {
+ if (annosAfterParams.nonEmpty())
+ illegal(annosAfterParams.head.pos);
type = to(F.at(pos).TypeIdent(TypeTag.VOID));
nextToken();
} else {
- type = parseType();
+ if (annosAfterParams.nonEmpty()) {
+ mods.annotations = mods.annotations.appendList(annosAfterParams);
+ if (mods.pos == Position.NOPOS)
+ mods.pos = mods.annotations.head.pos;
+ }
+ // method returns types are un-annotated types
+ type = unannotatedType();
}
if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
if (isInterface || tk.name() != className)
@@ -3101,51 +3443,68 @@
if (isInterface && (mods.flags & Flags.STATIC) != 0) {
checkStaticInterfaceMethods();
}
- List params = formalParameters();
- if (!isVoid) type = bracketsOpt(type);
- List thrown = List.nil();
- if (token.kind == THROWS) {
- nextToken();
- thrown = qualidentList();
- }
- JCBlock body = null;
- JCExpression defaultValue;
- if (token.kind == LBRACE) {
- body = block();
- defaultValue = null;
- } else {
- if (token.kind == DEFAULT) {
- accept(DEFAULT);
- defaultValue = annotationValue();
+ JCVariableDecl prevReceiverParam = this.receiverParam;
+ try {
+ this.receiverParam = null;
+ // Parsing formalParameters sets the receiverParam, if present
+ List params = formalParameters();
+ if (!isVoid) type = bracketsOpt(type);
+ List thrown = List.nil();
+ if (token.kind == THROWS) {
+ nextToken();
+ thrown = qualidentList();
+ }
+ JCBlock body = null;
+ JCExpression defaultValue;
+ if (token.kind == LBRACE) {
+ body = block();
+ defaultValue = null;
} else {
- defaultValue = null;
- }
- accept(SEMI);
- if (token.pos <= endPosTable.errorEndPos) {
- // error recovery
- skip(false, true, false, false);
- if (token.kind == LBRACE) {
- body = block();
+ if (token.kind == DEFAULT) {
+ accept(DEFAULT);
+ defaultValue = annotationValue();
+ } else {
+ defaultValue = null;
+ }
+ accept(SEMI);
+ if (token.pos <= endPosTable.errorEndPos) {
+ // error recovery
+ skip(false, true, false, false);
+ if (token.kind == LBRACE) {
+ body = block();
+ }
}
}
+
+ JCMethodDecl result =
+ toP(F.at(pos).MethodDef(mods, name, type, typarams,
+ receiverParam, params, thrown,
+ body, defaultValue));
+ attach(result, dc);
+ return result;
+ } finally {
+ this.receiverParam = prevReceiverParam;
}
-
- JCMethodDecl result =
- toP(F.at(pos).MethodDef(mods, name, type, typarams,
- params, thrown,
- body, defaultValue));
- attach(result, dc);
- return result;
}
- /** QualidentList = Qualident {"," Qualident}
+ /** QualidentList = [Annotations] Qualident {"," [Annotations] Qualident}
*/
List qualidentList() {
ListBuffer ts = new ListBuffer();
- ts.append(qualident());
+
+ List typeAnnos = typeAnnotationsOpt();
+ if (!typeAnnos.isEmpty())
+ ts.append(toP(F.at(typeAnnos.head.pos).AnnotatedType(typeAnnos, qualident(true))));
+ else
+ ts.append(qualident(true));
while (token.kind == COMMA) {
nextToken();
- ts.append(qualident());
+
+ typeAnnos = typeAnnotationsOpt();
+ if (!typeAnnos.isEmpty())
+ ts.append(toP(F.at(typeAnnos.head.pos).AnnotatedType(typeAnnos, qualident(true))));
+ else
+ ts.append(qualident(true));
}
return ts.toList();
}
@@ -3174,13 +3533,14 @@
/**
* {@literal
- * TypeParameter = TypeVariable [TypeParameterBound]
+ * TypeParameter = [Annotations] TypeVariable [TypeParameterBound]
* TypeParameterBound = EXTENDS Type {"&" Type}
* TypeVariable = Ident
* }
*/
JCTypeParameter typeParameter() {
int pos = token.pos;
+ List annos = typeAnnotationsOpt();
Name name = ident();
ListBuffer bounds = new ListBuffer();
if (token.kind == EXTENDS) {
@@ -3191,7 +3551,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 ] ")"
@@ -3203,10 +3563,17 @@
}
List formalParameters(boolean lambdaParameters) {
ListBuffer params = new ListBuffer();
- JCVariableDecl lastParam = null;
+ JCVariableDecl lastParam;
accept(LPAREN);
if (token.kind != RPAREN) {
- params.append(lastParam = formalParameter(lambdaParameters));
+ this.allowThisIdent = true;
+ lastParam = formalParameter(lambdaParameters);
+ if (lastParam.name.contentEquals(TokenKind.THIS.name)) {
+ this.receiverParam = lastParam;
+ } else {
+ params.append(lastParam);
+ }
+ this.allowThisIdent = false;
while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
nextToken();
params.append(lastParam = formalParameter(lambdaParameters));
@@ -3241,6 +3608,77 @@
return mods;
}
+ /**
+ * Inserts the annotations (and possibly a new array level)
+ * to the left-most type in an array or nested type.
+ *
+ * When parsing a type like {@code @B Outer.Inner @A []}, the
+ * {@code @A} annotation should target the array itself, while
+ * {@code @B} targets the nested type {@code Outer}.
+ *
+ * Currently the parser parses the annotation first, then
+ * the array, and then inserts the annotation to the left-most
+ * nested type.
+ *
+ * When {@code createNewLevel} is true, then a new array
+ * level is inserted as the most inner type, and have the
+ * annotations target it. This is useful in the case of
+ * varargs, e.g. {@code String @A [] @B ...}, as the parser
+ * first parses the type {@code String @A []} then inserts
+ * a new array level with {@code @B} annotation.
+ */
+ private JCExpression insertAnnotationsToMostInner(
+ JCExpression type, List