8029012: parameter_index for type annotation not updated after outer.this added
Summary: Fix javac's handling of type annotations when synthetic parameters are added
Reviewed-by: jjg, mcimadamore
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Thu Nov 06 17:39:57 2014 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotationPosition.java Fri Nov 07 07:54:35 2014 -0500
@@ -145,7 +145,7 @@
public final int bound_index;
// For type parameter and method parameter
- public final int parameter_index;
+ public int parameter_index;
// For class extends, implements, and throws clauses
public final int type_index;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Thu Nov 06 17:39:57 2014 -0500
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Fri Nov 07 07:54:35 2014 -0500
@@ -2642,9 +2642,10 @@
syms.intType, tree.sym);
ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
+ MethodSymbol m = tree.sym;
tree.params = tree.params.prepend(ordParam).prepend(nameParam);
-
- MethodSymbol m = tree.sym;
+ incrementParamTypeAnnoIndexes(m, 2);
+
m.extraParams = m.extraParams.prepend(ordParam.sym);
m.extraParams = m.extraParams.prepend(nameParam.sym);
Type olderasure = m.erasure(types);
@@ -2667,6 +2668,17 @@
}
}
//where
+ private void incrementParamTypeAnnoIndexes(MethodSymbol m,
+ int amount) {
+ for (final Attribute.TypeCompound anno : m.getRawTypeAttributes()) {
+ // Increment the parameter_index of any existing formal
+ // parameter annotations.
+ if (anno.position.type == TargetType.METHOD_FORMAL_PARAMETER) {
+ anno.position.parameter_index += amount;
+ }
+ }
+ }
+
private void visitMethodDefInternal(JCMethodDecl tree) {
if (tree.name == names.init &&
(currentClass.isInner() || currentClass.isLocal())) {
@@ -2697,8 +2709,10 @@
// Add this$n (if needed) in front of and free variables behind
// constructor parameter list.
tree.params = tree.params.appendList(fvdefs);
- if (currentClass.hasOuterInstance())
+ if (currentClass.hasOuterInstance()) {
tree.params = tree.params.prepend(otdef);
+ incrementParamTypeAnnoIndexes(m, 1);
+ }
// If this is an initial constructor, i.e., it does not start with
// this(...), insert initializers for this$n and proxies
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileInspector.java Fri Nov 07 07:54:35 2014 -0500
@@ -0,0 +1,950 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.annotation.*;
+import java.io.*;
+import java.net.URL;
+import java.util.List;
+
+import com.sun.tools.classfile.*;
+
+/**
+ * A class providing utilities for writing tests that inspect class
+ * files directly, looking for specific type annotations.
+ *
+ * Note: this framework does not currently handle repeating
+ * annotations.
+ */
+public class ClassfileInspector {
+
+ /**
+ * A group of expected annotations to be found in a given class.
+ * If the class name is null, then the template will be applied to
+ * every class.
+ */
+ public static class Expected {
+ /**
+ * The name of the class. If {@code null} this template will
+ * apply to every class; otherwise, it will only be applied to
+ * the named class.
+ */
+ public final String classname;
+
+ /**
+ * The expected class annotations. These will be checked
+ * against the class' attributes.
+ */
+ public final ExpectedTypeAnnotation[] classAnnos;
+
+ /**
+ * The expected method annotations. These will be checked
+ * against all methods in the class.
+ */
+ public final ExpectedMethodTypeAnnotation[] methodAnnos;
+
+ /**
+ * The expected field annotations. These will be checked
+ * against all fields in the class.
+ */
+ public final ExpectedFieldTypeAnnotation[] fieldAnnos;
+
+ /**
+ * Create an {@code Expected} from its components.
+ *
+ * @param classname The name of the class to match, or {@code
+ * null} for all classes.
+ * @param classAnnos The expected class annotations.
+ * @param methodAnnos The expected method annotations.
+ * @param fieldAnnos The expected field annotations.
+ */
+ public Expected(String classname,
+ ExpectedTypeAnnotation[] classAnnos,
+ ExpectedMethodTypeAnnotation[] methodAnnos,
+ ExpectedFieldTypeAnnotation[] fieldAnnos) {
+ this.classname = classname;
+ this.classAnnos = classAnnos;
+ this.methodAnnos = methodAnnos;
+ this.fieldAnnos = fieldAnnos;
+ }
+
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ final String newline = System.lineSeparator();
+ sb.append("Expected on class ").append(classname);
+ if (null != classAnnos) {
+ sb.append(newline).append("Class annotations:").append(newline);
+ for(ExpectedTypeAnnotation anno : classAnnos) {
+ sb.append(anno).append(newline);
+ }
+ }
+ if (null != methodAnnos) {
+ sb.append(newline).append("Method annotations:").append(newline);
+ for(ExpectedTypeAnnotation anno : methodAnnos) {
+ sb.append(anno).append(newline);
+ }
+ }
+ if (null != fieldAnnos) {
+ sb.append(newline).append("Field annotations:").append(newline);
+ for(ExpectedTypeAnnotation anno : fieldAnnos) {
+ sb.append(anno).append(newline);
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * See if this template applies to a class.
+ *
+ * @param classname The classname to check.
+ * @return Whether or not this template should apply.
+ */
+ public boolean matchClassName(String classname) {
+ return this.classname == null || this.classname.equals(classname);
+ }
+
+ /**
+ * After applying the template to all classes, check to see if
+ * any of the expected annotations weren't matched.
+ *
+ * @return The number of missed matches.
+ */
+ public int check() {
+ int count = 0;
+ if (classAnnos != null) {
+ for(ExpectedTypeAnnotation expected : classAnnos) {
+ if (!expected.check()) {
+ count++;
+ }
+ }
+ }
+ if (methodAnnos != null) {
+ for(ExpectedMethodTypeAnnotation expected : methodAnnos) {
+ if (!expected.check()) {
+ count++;
+ }
+ }
+ }
+ if (fieldAnnos != null) {
+ for(ExpectedFieldTypeAnnotation expected : fieldAnnos) {
+ if (!expected.check()) {
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+ }
+
+ /**
+ * An expected type annotation. This is both a superclass for
+ * method and field type annotations, as well as a class for type
+ * annotations on a class.
+ */
+ public static class ExpectedTypeAnnotation {
+ private int count = 0;
+ protected final String expectedName;
+ protected final int expectedCount;
+ protected final TypeAnnotation.TargetType targetType;
+ protected final int bound_index;
+ protected final int parameter_index;
+ protected final int type_index;
+ protected final int exception_index;
+ protected final TypeAnnotation.Position.TypePathEntry[] typePath;
+ protected final boolean visibility;
+
+ /**
+ * Create an {@code ExpectedTypeAnnotation} from its
+ * components. It is usually a better idea to use a {@code
+ * Builder} to do this.
+ *
+ * @param expectedName The expected annotation name.
+ * @param visibility Whether this annotation should be runtime-visible.
+ * @param expectedCount The number of annotations that should
+ * be seen. If 0, this asserts that the
+ * described annotation is not present.
+ * @param targetType The expected target type.
+ * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
+ * @param parameter_index The expected parameter index, or
+ * {@code Integer.MIN_VALUE}.
+ * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
+ * @param exception_index The expected exception index, or
+ * {@code Integer.MIN_VALUE}.
+ * @param typePath The expected type path.
+ */
+ public ExpectedTypeAnnotation(String expectedName,
+ boolean visibility,
+ int expectedCount,
+ TypeAnnotation.TargetType targetType,
+ int bound_index,
+ int parameter_index,
+ int type_index,
+ int exception_index,
+ TypeAnnotation.Position.TypePathEntry... typePath) {
+ this.expectedName = expectedName;
+ this.visibility = visibility;
+ this.expectedCount = expectedCount;
+ this.targetType = targetType;
+ this.bound_index = bound_index;
+ this.parameter_index = parameter_index;
+ this.type_index = type_index;
+ this.exception_index = exception_index;
+ this.typePath = typePath;
+ }
+
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Expected ");
+ sb.append(expectedCount);
+ sb.append(" annotation ");
+ sb.append(expectedName);
+ sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
+ sb.append(targetType);
+ sb.append(", bound_index = ");
+ sb.append(bound_index);
+ sb.append(", parameter_index = ");
+ sb.append(parameter_index);
+ sb.append(", type_index = ");
+ sb.append(type_index);
+ sb.append(", exception_index = ");
+ sb.append(exception_index);
+ sb.append(", type_path = [");
+ for(int i = 0; i < typePath.length; i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append(typePath[i]);
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ /**
+ * See if this template matches the given visibility.
+ *
+ * @param Whether or not the annotation is visible at runtime.
+ * @return Whether or not this template matches the visibility.
+ */
+ public boolean matchVisibility(boolean visibility) {
+ return this.visibility == visibility;
+ }
+
+ /**
+ * Attempty to match this template against an annotation. If
+ * it does match, then the match count for the template will
+ * be incremented. Otherwise, nothing will be done.
+ *
+ * @param anno The annotation to attempt to match.
+ */
+ public void matchAnnotation(TypeAnnotation anno) {
+ boolean matches = true;
+
+ try {
+ matches = anno.constant_pool.getUTF8Info(anno.annotation.type_index).value.equals("L" + expectedName + ";");
+ } catch(Exception e) {
+ matches = false;
+ }
+
+ matches = matches && anno.position.type == targetType;
+ matches = matches && anno.position.bound_index == bound_index;
+ matches = matches && anno.position.parameter_index == parameter_index;
+ matches = matches && anno.position.type_index == type_index;
+ matches = matches && anno.position.exception_index == exception_index;
+ matches = matches && anno.position.location.size() == typePath.length;
+
+ if (matches) {
+ int i = 0;
+ for(TypeAnnotation.Position.TypePathEntry entry :
+ anno.position.location) {
+ matches = matches && typePath[i++].equals(entry);
+ }
+ }
+
+ if (matches) {
+ count++;
+ }
+ }
+
+ /**
+ * After all matching, check to see if the expected number of
+ * matches equals the actual number. If not, then print a
+ * failure message and return {@code false}.
+ *
+ * @return Whether or not the expected number of matched
+ * equals the actual number.
+ */
+ public boolean check() {
+ if (count != expectedCount) {
+ System.err.println(this + ", but saw " + count);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * A builder class for creating {@code
+ * ExpectedTypeAnnotation}s in a more convenient fashion. The
+ * constructor for {@code ExpectedTypeAnnotation} takes a
+ * large number of parameters (by necessity). This class
+ * allows users to construct a {@code ExpectedTypeAnnotation}s
+ * using only the ones they need.
+ */
+ public static class Builder {
+ protected final String expectedName;
+ protected final int expectedCount;
+ protected final TypeAnnotation.TargetType targetType;
+ protected final boolean visibility;
+ protected int bound_index = Integer.MIN_VALUE;
+ protected int parameter_index = Integer.MIN_VALUE;
+ protected int type_index = Integer.MIN_VALUE;
+ protected int exception_index = Integer.MIN_VALUE;
+ protected TypeAnnotation.Position.TypePathEntry[] typePath =
+ new TypeAnnotation.Position.TypePathEntry[0];
+
+ /**
+ * Create a {@code Builder} from the mandatory parameters.
+ *
+ * @param expectedName The expected annotation name.
+ * @param targetType The expected target type.
+ * @param visibility Whether this annotation should be runtime-visible.
+ * @param expectedCount The number of annotations that should be seen.
+ */
+ public Builder(String expectedName,
+ TypeAnnotation.TargetType targetType,
+ boolean visibility,
+ int expectedCount) {
+ this.expectedName = expectedName;
+ this.visibility = visibility;
+ this.expectedCount = expectedCount;
+ this.targetType = targetType;
+ }
+
+ /**
+ * Create an {@code ExpectedTypeAnnotation} from all
+ * parameters that have been provided. The default values
+ * will be used for those that have not.
+ *
+ * @return The cretaed {@code ExpectedTypeAnnotation}.
+ */
+ public ExpectedTypeAnnotation build() {
+ return new ExpectedTypeAnnotation(expectedName, visibility,
+ expectedCount, targetType,
+ bound_index, parameter_index,
+ type_index, exception_index,
+ typePath);
+ }
+
+ /**
+ * Provide a bound index parameter.
+ *
+ * @param bound_index The bound_index value.
+ */
+ public Builder setBoundIndex(int bound_index) {
+ this.bound_index = bound_index;
+ return this;
+ }
+
+ /**
+ * Provide a parameter index parameter.
+ *
+ * @param bound_index The parameter_index value.
+ */
+ public Builder setParameterIndex(int parameter_index) {
+ this.parameter_index = parameter_index;
+ return this;
+ }
+
+ /**
+ * Provide a type index parameter.
+ *
+ * @param type_index The type_index value.
+ */
+ public Builder setTypeIndex(int type_index) {
+ this.type_index = type_index;
+ return this;
+ }
+
+ /**
+ * Provide an exception index parameter.
+ *
+ * @param exception_index The exception_index value.
+ */
+ public Builder setExceptionIndex(int exception_index) {
+ this.exception_index = exception_index;
+ return this;
+ }
+
+ /**
+ * Provide a type path parameter.
+ *
+ * @param typePath The type path value.
+ */
+ public Builder setTypePath(TypeAnnotation.Position.TypePathEntry[] typePath) {
+ this.typePath = typePath;
+ return this;
+ }
+ }
+ }
+
+ /**
+ * A type annotation found on a method.
+ */
+ public static class ExpectedMethodTypeAnnotation extends ExpectedTypeAnnotation {
+ private final String methodname;
+
+ /**
+ * Create an {@code ExpectedMethodTypeAnnotation} from its
+ * components. It is usually a better idea to use a {@code
+ * Builder} to do this.
+ *
+ * @param methodname The expected method name.
+ * @param expectedName The expected annotation name.
+ * @param visibility Whether this annotation should be runtime-visible.
+ * @param expectedCount The number of annotations that should be seen.
+ * @param targetType The expected target type.
+ * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
+ * @param parameter_index The expected parameter index, or
+ * {@code Integer.MIN_VALUE}.
+ * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
+ * @param exception_index The expected exception index, or
+ * {@code Integer.MIN_VALUE}.
+ * @param typePath The expected type path.
+ */
+ public ExpectedMethodTypeAnnotation(String methodname,
+ String expectedName,
+ boolean visibility,
+ int expectedCount,
+ TypeAnnotation.TargetType targetType,
+ int bound_index,
+ int parameter_index,
+ int type_index,
+ int exception_index,
+ TypeAnnotation.Position.TypePathEntry... typePath) {
+ super(expectedName, visibility, expectedCount, targetType, bound_index,
+ parameter_index, type_index, exception_index, typePath);
+ this.methodname = methodname;
+ }
+
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Expected ");
+ sb.append(expectedCount);
+ sb.append(" annotation ");
+ sb.append(expectedName);
+ sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
+ sb.append(targetType);
+ sb.append(", bound_index = ");
+ sb.append(bound_index);
+ sb.append(", parameter_index = ");
+ sb.append(parameter_index);
+ sb.append(", type_index = ");
+ sb.append(type_index);
+ sb.append(", exception_index = ");
+ sb.append(exception_index);
+ sb.append(", type_path = [");
+ for(int i = 0; i < typePath.length; i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append(typePath[i]);
+ }
+ sb.append("]");
+ sb.append(" on method ");
+ sb.append(methodname);
+ return sb.toString();
+ }
+
+ /**
+ * See if this template applies to a method.
+ *
+ * @param methodname The method name to check.
+ * @return Whether or not this template should apply.
+ */
+ public boolean matchMethodName(String methodname) {
+ return this.methodname.equals(methodname);
+ }
+
+ /**
+ * A builder class for creating {@code
+ * ExpectedMethodTypeAnnotation}s in a more convenient fashion. The
+ * constructor for {@code ExpectedMethodTypeAnnotation} takes a
+ * large number of parameters (by necessity). This class
+ * allows users to construct a {@code ExpectedMethodTypeAnnotation}s
+ * using only the ones they need.
+ */
+ public static class Builder extends ExpectedTypeAnnotation.Builder {
+ protected final String methodname;
+
+ /**
+ * Create a {@code Builder} from the mandatory parameters.
+ *
+ * @param methodname The expected method name.
+ * @param expectedName The expected annotation name.
+ * @param targetType The expected target type.
+ * @param visibility Whether this annotation should be runtime-visible.
+ * @param expectedCount The number of annotations that should be seen.
+ */
+ public Builder(String methodname,
+ String expectedName,
+ TypeAnnotation.TargetType targetType,
+ boolean visibility,
+ int expectedCount) {
+ super(expectedName, targetType, visibility, expectedCount);
+ this.methodname = methodname;
+ }
+
+ /**
+ * Create an {@code ExpectedMethodTypeAnnotation} from all
+ * parameters that have been provided. The default values
+ * will be used for those that have not.
+ *
+ * @return The cretaed {@code ExpectedMethodTypeAnnotation}.
+ */
+ public ExpectedMethodTypeAnnotation build() {
+ return new ExpectedMethodTypeAnnotation(methodname, expectedName,
+ visibility, expectedCount,
+ targetType, bound_index,
+ parameter_index, type_index,
+ exception_index, typePath);
+ }
+ }
+ }
+
+ /**
+ * A type annotation found on a field.
+ */
+ public static class ExpectedFieldTypeAnnotation extends ExpectedTypeAnnotation {
+ private final String fieldname;
+
+ /**
+ * Create an {@code ExpectedFieldTypeAnnotation} from its
+ * components. It is usually a better idea to use a {@code
+ * Builder} to do this.
+ *
+ * @param fieldname The expected field name.
+ * @param expectedName The expected annotation name.
+ * @param visibility Whether this annotation should be runtime-visible.
+ * @param expectedCount The number of annotations that should be seen.
+ * @param targetType The expected target type.
+ * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
+ * @param parameter_index The expected parameter index, or
+ * {@code Integer.MIN_VALUE}.
+ * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
+ * @param exception_index The expected exception index, or
+ * {@code Integer.MIN_VALUE}.
+ * @param typePath The expected type path.
+ */
+ public ExpectedFieldTypeAnnotation(String fieldname,
+ String expectedName,
+ boolean visibility,
+ int expectedCount,
+ TypeAnnotation.TargetType targetType,
+ int bound_index,
+ int parameter_index,
+ int type_index,
+ int exception_index,
+ TypeAnnotation.Position.TypePathEntry... typePath) {
+ super(expectedName, visibility, expectedCount, targetType, bound_index,
+ parameter_index, type_index, exception_index, typePath);
+ this.fieldname = fieldname;
+ }
+
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("Expected ").append(expectedCount)
+ .append(" annotation ").append(expectedName)
+ .append(visibility ? ", runtime visibile " : ", runtime invisibile ")
+ .append(targetType)
+ .append(", bound_index = ").append(bound_index)
+ .append(", parameter_index = ").append(parameter_index)
+ .append(", type_index = ").append(type_index)
+ .append(", exception_index = ").append(exception_index)
+ .append(", type_path = [");
+
+ for(int i = 0; i < typePath.length; i++) {
+ if (i != 0) {
+ sb.append(", ");
+ }
+ sb.append(typePath[i]);
+ }
+ sb.append("]")
+ .append(" on field ").append(fieldname);
+ return sb.toString();
+ }
+
+ /**
+ * See if this template applies to a field.
+ *
+ * @param fieldname The field name to check.
+ * @return Whether or not this template should apply.
+ */
+ public boolean matchFieldName(String fieldname) {
+ return this.fieldname.equals(fieldname);
+ }
+
+ /**
+ * A builder class for creating {@code
+ * ExpectedFieldTypeAnnotation}s in a more convenient fashion. The
+ * constructor for {@code ExpectedFieldTypeAnnotation} takes a
+ * large number of parameters (by necessity). This class
+ * allows users to construct a {@code ExpectedFieldTypeAnnotation}s
+ * using only the ones they need.
+ */
+ public static class Builder extends ExpectedTypeAnnotation.Builder {
+ protected final String fieldname;
+
+ /**
+ * Create a {@code Builder} from the mandatory parameters.
+ *
+ * @param fieldname The expected field name.
+ * @param expectedName The expected annotation name.
+ * @param targetType The expected target type.
+ * @param visibility Whether this annotation should be runtime-visible.
+ * @param expectedCount The number of annotations that should be seen.
+ */
+ public Builder(String fieldname,
+ String expectedName,
+ TypeAnnotation.TargetType targetType,
+ boolean visibility,
+ int expectedCount) {
+ super(expectedName, targetType, visibility, expectedCount);
+ this.fieldname = fieldname;
+ }
+
+ /**
+ * Create an {@code ExpectedFieldTypeAnnotation} from all
+ * parameters that have been provided. The default values
+ * will be used for those that have not.
+ *
+ * @return The cretaed {@code ExpectedFieldTypeAnnotation}.
+ */
+ public ExpectedFieldTypeAnnotation build() {
+ return new ExpectedFieldTypeAnnotation(fieldname, expectedName,
+ visibility, expectedCount,
+ targetType, bound_index,
+ parameter_index, type_index,
+ exception_index, typePath);
+ }
+ }
+ }
+
+ private void matchClassTypeAnnotation(ClassFile classfile,
+ ExpectedTypeAnnotation expected)
+ throws ConstantPoolException {
+ for(Attribute attr : classfile.attributes) {
+ attr.accept(typeAnnoMatcher, expected);
+ }
+ }
+
+ private void matchMethodTypeAnnotation(ClassFile classfile,
+ ExpectedMethodTypeAnnotation expected)
+ throws ConstantPoolException {
+ for(Method meth : classfile.methods) {
+ if (expected.matchMethodName(meth.getName(classfile.constant_pool))) {
+ for(Attribute attr : meth.attributes) {
+ attr.accept(typeAnnoMatcher, expected);
+ }
+ }
+ }
+ }
+
+ private void matchFieldTypeAnnotation(ClassFile classfile,
+ ExpectedFieldTypeAnnotation expected)
+ throws ConstantPoolException {
+ for(Field field : classfile.fields) {
+ if (expected.matchFieldName(field.getName(classfile.constant_pool))) {
+ for(Attribute attr : field.attributes) {
+ attr.accept(typeAnnoMatcher, expected);
+ }
+ }
+ }
+ }
+
+ private void matchClassTypeAnnotations(ClassFile classfile,
+ ExpectedTypeAnnotation[] expected)
+ throws ConstantPoolException {
+ for(ExpectedTypeAnnotation one : expected) {
+ matchClassTypeAnnotation(classfile, one);
+ }
+ }
+
+ private void matchMethodTypeAnnotations(ClassFile classfile,
+ ExpectedMethodTypeAnnotation[] expected)
+ throws ConstantPoolException {
+ for(ExpectedMethodTypeAnnotation one : expected) {
+ matchMethodTypeAnnotation(classfile, one);
+ }
+ }
+
+ private void matchFieldTypeAnnotations(ClassFile classfile,
+ ExpectedFieldTypeAnnotation[] expected)
+ throws ConstantPoolException {
+ for(ExpectedFieldTypeAnnotation one : expected) {
+ matchFieldTypeAnnotation(classfile, one);
+ }
+ }
+
+ /**
+ * Run a template on a single {@code ClassFile}.
+ *
+ * @param classfile The {@code ClassFile} on which to run tests.
+ * @param expected The expected annotation template.
+ */
+ public void run(ClassFile classfile,
+ Expected... expected)
+ throws ConstantPoolException {
+ run(new ClassFile[] { classfile }, expected);
+ }
+
+ /**
+ * Run a template on multiple {@code ClassFile}s.
+ *
+ * @param classfile The {@code ClassFile}s on which to run tests.
+ * @param expected The expected annotation template.
+ */
+ public void run(ClassFile[] classfiles,
+ Expected... expected)
+ throws ConstantPoolException {
+ for(ClassFile classfile : classfiles) {
+ for(Expected one : expected) {
+ if (one.matchClassName(classfile.getName())) {
+ if (one.classAnnos != null)
+ matchClassTypeAnnotations(classfile, one.classAnnos);
+ if (one.methodAnnos != null)
+ matchMethodTypeAnnotations(classfile, one.methodAnnos);
+ if (one.fieldAnnos != null)
+ matchFieldTypeAnnotations(classfile, one.fieldAnnos);
+ }
+ }
+ }
+ int count = 0;
+ for (Expected one : expected) {
+ count += one.check();
+ }
+
+ if (count != 0) {
+ throw new RuntimeException(count + " errors occurred in test");
+ }
+ }
+
+ /**
+ * Get a {@code ClassFile} from its file name.
+ *
+ * @param name The class' file name.
+ * @return The {@code ClassFile}
+ */
+ public static ClassFile getClassFile(String name)
+ throws IOException, ConstantPoolException {
+ final URL url = ClassfileInspector.class.getResource(name);
+ final InputStream in = url.openStream();
+ try {
+ return ClassFile.read(in);
+ } finally {
+ in.close();
+ }
+ }
+
+ private static final Attribute.Visitor<Void, ExpectedTypeAnnotation> typeAnnoMatcher =
+ new Attribute.Visitor<Void, ExpectedTypeAnnotation>() {
+
+ @Override
+ public Void visitBootstrapMethods(BootstrapMethods_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitDefault(DefaultAttribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitAnnotationDefault(AnnotationDefault_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitCode(Code_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitCompilationID(CompilationID_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitConstantValue(ConstantValue_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitDeprecated(Deprecated_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitEnclosingMethod(EnclosingMethod_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitExceptions(Exceptions_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitInnerClasses(InnerClasses_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitLineNumberTable(LineNumberTable_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitLocalVariableTable(LocalVariableTable_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitMethodParameters(MethodParameters_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSignature(Signature_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSourceFile(SourceFile_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSourceID(SourceID_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitStackMap(StackMap_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitStackMapTable(StackMapTable_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSynthetic(Synthetic_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ if (expected.matchVisibility(true)) {
+ for(TypeAnnotation anno : attr.annotations) {
+ expected.matchAnnotation(anno);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr,
+ ExpectedTypeAnnotation expected) {
+ if (expected.matchVisibility(false)) {
+ for(TypeAnnotation anno : attr.annotations) {
+ expected.matchAnnotation(anno);
+ }
+ }
+
+ return null;
+ }
+ };
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/SyntheticParameters.java Fri Nov 07 07:54:35 2014 -0500
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test SyntheticParameters
+ * @summary Test generation of annotations on inner class parameters.
+ * @build ClassfileInspector
+ * @run main SyntheticParameters
+ */
+
+import java.io.*;
+import java.lang.annotation.*;
+
+import com.sun.tools.classfile.*;
+
+public class SyntheticParameters extends ClassfileInspector {
+
+ private static final String Inner_class = "SyntheticParameters$Inner.class";
+ private static final String Foo_class = "SyntheticParameters$Foo.class";
+ private static final Expected Inner_expected =
+ new Expected("SyntheticParameters$Inner",
+ null,
+ new ExpectedMethodTypeAnnotation[] {
+ (ExpectedMethodTypeAnnotation)
+ // Assert there is no annotation on the
+ // this$0 parameter.
+ new ExpectedMethodTypeAnnotation.Builder(
+ "<init>",
+ "A",
+ TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
+ false,
+ 0).setParameterIndex(0).build(),
+ (ExpectedMethodTypeAnnotation)
+ // Assert there is an annotation on the
+ // first parameter.
+ new ExpectedMethodTypeAnnotation.Builder(
+ "<init>",
+ "A",
+ TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
+ false,
+ 1).setParameterIndex(1).build(),
+ (ExpectedMethodTypeAnnotation)
+ new ExpectedMethodTypeAnnotation.Builder(
+ "foo",
+ "A",
+ TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
+ false,
+ 1).setParameterIndex(0).build(),
+ (ExpectedMethodTypeAnnotation)
+ new ExpectedMethodTypeAnnotation.Builder(
+ "foo",
+ "A",
+ TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
+ false,
+ 0).setParameterIndex(1).build()
+ },
+ null);
+ private static final Expected Foo_expected =
+ new Expected("SyntheticParameters$Foo",
+ null,
+ new ExpectedMethodTypeAnnotation[] {
+ (ExpectedMethodTypeAnnotation)
+ // Assert there is no annotation on the
+ // $enum$name parameter.
+ new ExpectedMethodTypeAnnotation.Builder(
+ "<init>",
+ "A",
+ TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
+ false,
+ 0).setParameterIndex(0).build(),
+ (ExpectedMethodTypeAnnotation)
+ // Assert there is no annotation on the
+ // $enum$ordinal parameter.
+ new ExpectedMethodTypeAnnotation.Builder(
+ "<init>",
+ "A",
+ TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
+ false,
+ 0).setParameterIndex(1).build(),
+ (ExpectedMethodTypeAnnotation)
+ // Assert there is an annotation on the
+ // first parameter.
+ new ExpectedMethodTypeAnnotation.Builder(
+ "<init>",
+ "A",
+ TypeAnnotation.TargetType.METHOD_FORMAL_PARAMETER,
+ false,
+ 1).setParameterIndex(2).build()
+ },
+ null);
+
+ public static void main(String... args) throws Exception {
+ new SyntheticParameters().run(
+ new ClassFile[] { getClassFile(Inner_class), getClassFile(Foo_class) },
+ new Expected[] { Inner_expected, Foo_expected });
+ }
+
+ public class Inner {
+ public Inner(@A int a) {}
+ public void foo(@A int a, int b) {}
+ }
+
+ public static enum Foo {
+ ONE(null);
+ Foo(@A Object a) {}
+ }
+}
+
+@Target({ElementType.TYPE_USE})
+@interface A {}
--- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java Thu Nov 06 17:39:57 2014 -0500
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java Fri Nov 07 07:54:35 2014 -0500
@@ -43,7 +43,7 @@
@TADescription(annotation = "TA", type = METHOD_RETURN, genericLocation = {1, 0})
@TADescription(annotation = "TB", type = METHOD_RETURN, genericLocation = {1, 0})
- @TADescription(annotation = "TC", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
+ @TADescription(annotation = "TC", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
@TestClass("%TEST_CLASS_NAME%$Inner")
public String innerClass() {
return "class %TEST_CLASS_NAME% { class Inner {" +
@@ -56,7 +56,7 @@
@TADescription(annotation = "TB", type = METHOD_RETURN, genericLocation = {1, 0})
@TADescription(annotation = "TC", type = METHOD_RECEIVER)
@TADescription(annotation = "TD", type = METHOD_RETURN, genericLocation = {1, 0})
- @TADescription(annotation = "TE", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
+ @TADescription(annotation = "TE", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
@TestClass("%TEST_CLASS_NAME%$Inner")
public String innerClass2() {
return "class %TEST_CLASS_NAME% { class Inner {" +
@@ -70,7 +70,7 @@
@TADescription(annotation = "TC", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
@TADescription(annotation = "TD", type = METHOD_RECEIVER, genericLocation = {1, 0})
@TADescription(annotation = "TE", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
- @TADescription(annotation = "TF", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
+ @TADescription(annotation = "TF", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
@TestClass("Outer$Middle$Inner")
public String innerClass3() {
return "class Outer { class Middle { class Inner {" +
@@ -89,7 +89,7 @@
@TADescription(annotation = "RTAs", type = METHOD_RETURN, genericLocation = {1, 0})
@TADescription(annotation = "RTBs", type = METHOD_RETURN, genericLocation = {1, 0})
- @TADescription(annotation = "RTCs", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
+ @TADescription(annotation = "RTCs", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
@TestClass("%TEST_CLASS_NAME%$Inner")
public String innerClassRepeatableAnnotation() {
return "class %TEST_CLASS_NAME% { class Inner {" +
@@ -102,7 +102,7 @@
@TADescription(annotation = "RTBs", type = METHOD_RETURN, genericLocation = {1, 0})
@TADescription(annotation = "RTCs", type = METHOD_RECEIVER)
@TADescription(annotation = "RTDs", type = METHOD_RETURN, genericLocation = {1, 0})
- @TADescription(annotation = "RTEs", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
+ @TADescription(annotation = "RTEs", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
@TestClass("%TEST_CLASS_NAME%$Inner")
public String innerClassRepeatableAnnotation2() {
return "class %TEST_CLASS_NAME% { class Inner {" +
@@ -116,7 +116,7 @@
@TADescription(annotation = "RTCs", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
@TADescription(annotation = "RTDs", type = METHOD_RECEIVER, genericLocation = {1, 0})
@TADescription(annotation = "RTEs", type = METHOD_RETURN, genericLocation = {1, 0, 1, 0})
- @TADescription(annotation = "RTFs", type = METHOD_FORMAL_PARAMETER, paramIndex = 0)
+ @TADescription(annotation = "RTFs", type = METHOD_FORMAL_PARAMETER, paramIndex = 1)
@TestClass("Outer$Middle$Inner")
public String innerClassRepatableAnnotation3() {
return "class Outer { class Middle { class Inner {" +