8065132: Parameter annotations not updated when synthetic parameters are prepended
Summary: Cause javac to add synthetic parameters to Runtime[In]VisibleParameterAnnotations attributes
Reviewed-by: jjg, jfranck
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Fri Nov 21 10:38:43 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java Fri Nov 21 16:36:39 2014 -0500
@@ -640,6 +640,27 @@
}
+ private void writeParamAnnotations(List<VarSymbol> params,
+ RetentionPolicy retention) {
+ for (VarSymbol s : params) {
+ ListBuffer<Attribute.Compound> buf = new ListBuffer<>();
+ for (Attribute.Compound a : s.getRawAttributes())
+ if (types.getRetention(a) == retention)
+ buf.append(a);
+ databuf.appendChar(buf.length());
+ for (Attribute.Compound a : buf)
+ writeCompoundAttribute(a);
+ }
+
+ }
+
+ private void writeParamAnnotations(MethodSymbol m,
+ RetentionPolicy retention) {
+ databuf.appendByte(m.params.length() + m.extraParams.length());
+ writeParamAnnotations(m.extraParams, retention);
+ writeParamAnnotations(m.params, retention);
+ }
+
/** Write method parameter annotations;
* return number of attributes written.
*/
@@ -662,31 +683,13 @@
int attrCount = 0;
if (hasVisible) {
int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations);
- databuf.appendByte(m.params.length());
- for (VarSymbol s : m.params) {
- ListBuffer<Attribute.Compound> buf = new ListBuffer<>();
- for (Attribute.Compound a : s.getRawAttributes())
- if (types.getRetention(a) == RetentionPolicy.RUNTIME)
- buf.append(a);
- databuf.appendChar(buf.length());
- for (Attribute.Compound a : buf)
- writeCompoundAttribute(a);
- }
+ writeParamAnnotations(m, RetentionPolicy.RUNTIME);
endAttr(attrIndex);
attrCount++;
}
if (hasInvisible) {
int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations);
- databuf.appendByte(m.params.length());
- for (VarSymbol s : m.params) {
- ListBuffer<Attribute.Compound> buf = new ListBuffer<>();
- for (Attribute.Compound a : s.getRawAttributes())
- if (types.getRetention(a) == RetentionPolicy.CLASS)
- buf.append(a);
- databuf.appendChar(buf.length());
- for (Attribute.Compound a : buf)
- writeCompoundAttribute(a);
- }
+ writeParamAnnotations(m, RetentionPolicy.CLASS);
endAttr(attrIndex);
attrCount++;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/lib/annotations/annotations/classfile/ClassfileInspector.java Fri Nov 21 16:36:39 2014 -0500
@@ -0,0 +1,1733 @@
+/*
+ * 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.
+ */
+
+package annotations.classfile;
+
+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 ExpectedAnnotation[] classAnnos;
+
+ /**
+ * The expected method annotations. These will be checked
+ * against all methods in the class.
+ */
+ public final ExpectedMethodAnnotation[] methodAnnos;
+
+ /**
+ * The expected method parameter annotations. These will be checked
+ * against all methods in the class.
+ */
+ public final ExpectedParameterAnnotation[] methodParamAnnos;
+
+ /**
+ * The expected field type annotations. These will be checked
+ * against all fields in the class.
+ */
+ public final ExpectedFieldAnnotation[] fieldAnnos;
+
+ /**
+ * The expected class type annotations. These will be checked
+ * against the class' attributes.
+ */
+ public final ExpectedTypeAnnotation[] classTypeAnnos;
+
+ /**
+ * The expected method type annotations. These will be checked
+ * against all methods in the class.
+ */
+ public final ExpectedMethodTypeAnnotation[] methodTypeAnnos;
+
+ /**
+ * The expected field type annotations. These will be checked
+ * against all fields in the class.
+ */
+ public final ExpectedFieldTypeAnnotation[] fieldTypeAnnos;
+
+ /**
+ * Create an {@code Expected} from all 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 methodParamAnnos The expected method parameter annotations.
+ * @param fieldAnnos The expected field annotations.
+ * @param classTypeAnnos The expected class type annotations.
+ * @param methodTypeAnnos The expected method type annotations.
+ * @param fieldTypeAnnos The expected field type annotations.
+ */
+ public Expected(String classname,
+ ExpectedAnnotation[] classAnnos,
+ ExpectedMethodAnnotation[] methodAnnos,
+ ExpectedParameterAnnotation[] methodParamAnnos,
+ ExpectedFieldAnnotation[] fieldAnnos,
+ ExpectedTypeAnnotation[] classTypeAnnos,
+ ExpectedMethodTypeAnnotation[] methodTypeAnnos,
+ ExpectedFieldTypeAnnotation[] fieldTypeAnnos) {
+ this.classname = classname;
+ this.classAnnos = classAnnos;
+ this.methodAnnos = methodAnnos;
+ this.methodParamAnnos = methodParamAnnos;
+ this.fieldAnnos = fieldAnnos;
+ this.classTypeAnnos = classTypeAnnos;
+ this.methodTypeAnnos = methodTypeAnnos;
+ this.fieldTypeAnnos = fieldTypeAnnos;
+ }
+
+ /**
+ * Create an {@code Expected} from regular annotation 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 methodParamAnnos The expected method parameter annotations.
+ * @param fieldAnnos The expected field annotations.
+ */
+ public Expected(String classname,
+ ExpectedAnnotation[] classAnnos,
+ ExpectedMethodAnnotation[] methodAnnos,
+ ExpectedParameterAnnotation[] methodParamAnnos,
+ ExpectedFieldAnnotation[] fieldAnnos) {
+ this(classname, classAnnos, methodAnnos, methodParamAnnos,
+ fieldAnnos, null, null, null);
+ }
+
+ /**
+ * Create an {@code Expected} from type annotation components.
+ *
+ * @param classname The name of the class to match, or {@code
+ * null} for all classes.
+ * @param classTypeAnnos The expected class type annotations.
+ * @param methodTypeAnnos The expected method type annotations.
+ * @param fieldTypeAnnos The expected field type annotations.
+ */
+ public Expected(String classname,
+ ExpectedTypeAnnotation[] classTypeAnnos,
+ ExpectedMethodTypeAnnotation[] methodTypeAnnos,
+ ExpectedFieldTypeAnnotation[] fieldTypeAnnos) {
+ this(classname, null, null, null, null,
+ classTypeAnnos, methodTypeAnnos, fieldTypeAnnos);
+ }
+
+ 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(ExpectedAnnotation anno : classAnnos) {
+ sb.append(anno).append(newline);
+ }
+ }
+ if (null != methodAnnos) {
+ sb.append(newline).append("Method annotations:").append(newline);
+ for(ExpectedAnnotation anno : methodAnnos) {
+ sb.append(anno).append(newline);
+ }
+ }
+ if (null != methodParamAnnos) {
+ sb.append(newline).append("Method param annotations:").append(newline);
+ for(ExpectedAnnotation anno : methodParamAnnos) {
+ sb.append(anno).append(newline);
+ }
+ }
+ if (null != fieldAnnos) {
+ sb.append(newline).append("Field annotations:").append(newline);
+ for(ExpectedAnnotation anno : fieldAnnos) {
+ sb.append(anno).append(newline);
+ }
+ }
+ if (null != classTypeAnnos) {
+ sb.append(newline).append("Class type annotations:").append(newline);
+ for(ExpectedAnnotation anno : classTypeAnnos) {
+ sb.append(anno).append(newline);
+ }
+ }
+ if (null != methodTypeAnnos) {
+ sb.append(newline).append("Method type annotations:").append(newline);
+ for(ExpectedAnnotation anno : methodTypeAnnos) {
+ sb.append(anno).append(newline);
+ }
+ }
+ if (null != fieldTypeAnnos) {
+ sb.append(newline).append("Field type annotations:").append(newline);
+ for(ExpectedAnnotation anno : fieldTypeAnnos) {
+ 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(ExpectedAnnotation expected : classAnnos) {
+ if (!expected.check()) {
+ count++;
+ }
+ }
+ }
+ if (methodAnnos != null) {
+ for(ExpectedAnnotation expected : methodAnnos) {
+ if (!expected.check()) {
+ count++;
+ }
+ }
+ }
+ if (methodParamAnnos != null) {
+ for(ExpectedAnnotation expected : methodParamAnnos) {
+ if (!expected.check()) {
+ count++;
+ }
+ }
+ }
+ if (fieldAnnos != null) {
+ for(ExpectedAnnotation expected : fieldAnnos) {
+ if (!expected.check()) {
+ count++;
+ }
+ }
+ }
+ if (classTypeAnnos != null) {
+ for(ExpectedAnnotation expected : classTypeAnnos) {
+ if (!expected.check()) {
+ count++;
+ }
+ }
+ }
+ if (methodTypeAnnos != null) {
+ for(ExpectedAnnotation expected : methodTypeAnnos) {
+ if (!expected.check()) {
+ count++;
+ }
+ }
+ }
+ if (fieldTypeAnnos != null) {
+ for(ExpectedAnnotation expected : fieldTypeAnnos) {
+ if (!expected.check()) {
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+ }
+
+ /**
+ * An expected annotation. This is both a superclass for
+ * method, field, and type annotations, as well as a class for
+ * annotations on a class.
+ */
+ public static class ExpectedAnnotation {
+ protected int count = 0;
+ protected final String expectedName;
+ protected final int expectedCount;
+ protected final boolean visibility;
+
+ /**
+ * Create an {@code ExpectedAnnotation} 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.
+ */
+ public ExpectedAnnotation(String expectedName,
+ boolean visibility,
+ int expectedCount) {
+ this.expectedName = expectedName;
+ this.visibility = visibility;
+ this.expectedCount = expectedCount;
+ }
+
+ 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 ");
+ 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(ConstantPool cpool,
+ Annotation anno) {
+ if (checkMatch(cpool, anno)) {
+ count++;
+ }
+ }
+
+ /**
+ * Indicate whether an annotation matches this expected
+ * annotation.
+ *
+ * @param ConstantPool The constant pool to use.
+ * @param anno The annotation to check.
+ * @return Whether the annotation matches.
+ */
+ protected boolean checkMatch(ConstantPool cpool,
+ Annotation anno) {
+ try {
+ return cpool.getUTF8Info(anno.type_index).value.equals("L" + expectedName + ";");
+ } catch(Exception e) {
+ return false;
+ }
+ }
+
+ /**
+ * 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;
+ }
+ }
+ }
+
+ /**
+ * An annotation found on a method.
+ */
+ public static class ExpectedMethodAnnotation extends ExpectedAnnotation {
+ protected final String methodname;
+
+ /**
+ * Create an {@code ExpectedMethodAnnotation} 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.
+ */
+ public ExpectedMethodAnnotation(String methodname,
+ String expectedName,
+ boolean visibility,
+ int expectedCount) {
+ super(expectedName, visibility, expectedCount);
+ 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(" 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);
+ }
+
+ }
+
+ /**
+ * An annotation found on a method parameter.
+ */
+ public static class ExpectedParameterAnnotation
+ extends ExpectedMethodAnnotation {
+ protected final int index;
+
+ /**
+ * Create an {@code ExpectedParameterAnnotation} from its
+ * components. It is usually a better idea to use a {@code
+ * Builder} to do this.
+ *
+ * @param methodname The expected method name.
+ * @param index The parameter index.
+ * @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.
+ */
+ public ExpectedParameterAnnotation(String methodname,
+ int index,
+ String expectedName,
+ boolean visibility,
+ int expectedCount) {
+ super(methodname, expectedName, visibility, expectedCount);
+ this.index = index;
+ }
+
+ 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(" on method ");
+ sb.append(methodname);
+ sb.append(" parameter " + index);
+ return sb.toString();
+ }
+
+ }
+
+ /**
+ * An annotation found on a field.
+ */
+ public static class ExpectedFieldAnnotation extends ExpectedAnnotation {
+ private final String fieldname;
+
+ /**
+ * Create an {@code ExpectedFieldAnnotation} 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.
+ */
+ public ExpectedFieldAnnotation(String fieldname,
+ String expectedName,
+ boolean visibility,
+ int expectedCount) {
+ super(expectedName, visibility, expectedCount);
+ 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(" 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);
+ }
+
+ }
+
+ /**
+ * 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 extends ExpectedAnnotation {
+ 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;
+
+ /**
+ * 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) {
+ super(expectedName, visibility, 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();
+ }
+
+ @Override
+ public void matchAnnotation(ConstantPool cpool,
+ Annotation anno) {}
+
+ public void matchAnnotation(TypeAnnotation anno) {
+ if (checkMatch(anno)) {
+ count++;
+ }
+ }
+
+ public boolean checkMatch(TypeAnnotation anno) {
+ boolean matches = checkMatch(anno.constant_pool, anno.annotation);
+
+ 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);
+ }
+ }
+
+ return matches;
+ }
+
+ /**
+ * 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 boolean visibility;
+ protected final int expectedCount;
+ protected final TypeAnnotation.TargetType targetType;
+ 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 matchClassAnnotation(ClassFile classfile,
+ ExpectedAnnotation expected)
+ throws ConstantPoolException {
+ for(Attribute attr : classfile.attributes) {
+ attr.accept(annoMatcher(classfile.constant_pool), expected);
+ }
+ }
+
+ private void matchMethodAnnotation(ClassFile classfile,
+ ExpectedMethodAnnotation expected)
+ throws ConstantPoolException {
+ for(Method meth : classfile.methods) {
+ if (expected.matchMethodName(meth.getName(classfile.constant_pool))) {
+ for(Attribute attr : meth.attributes) {
+ attr.accept(annoMatcher(classfile.constant_pool), expected);
+ }
+ }
+ }
+ }
+
+ private void matchParameterAnnotation(ClassFile classfile,
+ ExpectedParameterAnnotation expected)
+ throws ConstantPoolException {
+ for(Method meth : classfile.methods) {
+ if (expected.matchMethodName(meth.getName(classfile.constant_pool))) {
+ for(Attribute attr : meth.attributes) {
+ attr.accept(paramMatcher(classfile.constant_pool), expected);
+ }
+ }
+ }
+ }
+
+ private void matchFieldAnnotation(ClassFile classfile,
+ ExpectedFieldAnnotation expected)
+ throws ConstantPoolException {
+ for(Field field : classfile.fields) {
+ if (expected.matchFieldName(field.getName(classfile.constant_pool))) {
+ for(Attribute attr : field.attributes) {
+ attr.accept(annoMatcher(classfile.constant_pool), expected);
+ }
+ }
+ }
+ }
+
+ 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 matchClassAnnotations(ClassFile classfile,
+ ExpectedAnnotation[] expected)
+ throws ConstantPoolException {
+ for(ExpectedAnnotation one : expected) {
+ matchClassAnnotation(classfile, one);
+ }
+ }
+
+ private void matchMethodAnnotations(ClassFile classfile,
+ ExpectedMethodAnnotation[] expected)
+ throws ConstantPoolException {
+ for(ExpectedMethodAnnotation one : expected) {
+ matchMethodAnnotation(classfile, one);
+ }
+ }
+
+ private void matchParameterAnnotations(ClassFile classfile,
+ ExpectedParameterAnnotation[] expected)
+ throws ConstantPoolException {
+ for(ExpectedParameterAnnotation one : expected) {
+ matchParameterAnnotation(classfile, one);
+ }
+ }
+
+ private void matchFieldAnnotations(ClassFile classfile,
+ ExpectedFieldAnnotation[] expected)
+ throws ConstantPoolException {
+ for(ExpectedFieldAnnotation one : expected) {
+ matchFieldAnnotation(classfile, one);
+ }
+ }
+
+ 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)
+ matchClassAnnotations(classfile, one.classAnnos);
+ if (one.methodAnnos != null)
+ matchMethodAnnotations(classfile, one.methodAnnos);
+ if (one.methodParamAnnos != null)
+ matchParameterAnnotations(classfile, one.methodParamAnnos);
+ if (one.fieldAnnos != null)
+ matchFieldAnnotations(classfile, one.fieldAnnos);
+ if (one.classTypeAnnos != null)
+ matchClassTypeAnnotations(classfile, one.classTypeAnnos);
+ if (one.methodTypeAnnos != null)
+ matchMethodTypeAnnotations(classfile, one.methodTypeAnnos);
+ if (one.fieldTypeAnnos != null)
+ matchFieldTypeAnnotations(classfile, one.fieldTypeAnnos);
+ }
+ }
+ }
+ 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.
+ * @param host A class in the same package.
+ * @return The {@code ClassFile}
+ */
+ public static ClassFile getClassFile(String name,
+ Class<?> host)
+ throws IOException, ConstantPoolException {
+ final URL url = host.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;
+ }
+ };
+
+ private static Attribute.Visitor<Void, ExpectedAnnotation> annoMatcher(ConstantPool cpool) {
+ return new Attribute.Visitor<Void, ExpectedAnnotation>() {
+
+ @Override
+ public Void visitBootstrapMethods(BootstrapMethods_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitDefault(DefaultAttribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitAnnotationDefault(AnnotationDefault_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitCode(Code_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitCompilationID(CompilationID_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitConstantValue(ConstantValue_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitDeprecated(Deprecated_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitEnclosingMethod(EnclosingMethod_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitExceptions(Exceptions_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitInnerClasses(InnerClasses_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitLineNumberTable(LineNumberTable_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitLocalVariableTable(LocalVariableTable_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitMethodParameters(MethodParameters_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSignature(Signature_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSourceFile(SourceFile_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSourceID(SourceID_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitStackMap(StackMap_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitStackMapTable(StackMapTable_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSynthetic(Synthetic_attribute attr,
+ ExpectedAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr,
+ ExpectedAnnotation expected) {
+ if (expected.matchVisibility(true)) {
+ for(Annotation anno : attr.annotations) {
+ expected.matchAnnotation(cpool, anno);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr,
+ ExpectedAnnotation expected) {
+ if (expected.matchVisibility(false)) {
+ for(Annotation anno : attr.annotations) {
+ expected.matchAnnotation(cpool, anno);
+ }
+ }
+
+ return null;
+ }
+ };
+ }
+
+ private static Attribute.Visitor<Void, ExpectedParameterAnnotation> paramMatcher(ConstantPool cpool) {
+ return new Attribute.Visitor<Void, ExpectedParameterAnnotation>() {
+
+ @Override
+ public Void visitBootstrapMethods(BootstrapMethods_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitDefault(DefaultAttribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitAnnotationDefault(AnnotationDefault_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitCode(Code_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitCompilationID(CompilationID_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitConstantValue(ConstantValue_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitDeprecated(Deprecated_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitEnclosingMethod(EnclosingMethod_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitExceptions(Exceptions_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitInnerClasses(InnerClasses_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitLineNumberTable(LineNumberTable_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitLocalVariableTable(LocalVariableTable_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitMethodParameters(MethodParameters_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSignature(Signature_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSourceFile(SourceFile_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSourceID(SourceID_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitStackMap(StackMap_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitStackMapTable(StackMapTable_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitSynthetic(Synthetic_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ if (expected.matchVisibility(true)) {
+ if (expected.index < attr.parameter_annotations.length) {
+ for(Annotation anno :
+ attr.parameter_annotations[expected.index]) {
+ expected.matchAnnotation(cpool, anno);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr,
+ ExpectedParameterAnnotation expected) {
+ if (expected.matchVisibility(false)) {
+ if (expected.index < attr.parameter_annotations.length) {
+ for(Annotation anno :
+ attr.parameter_annotations[expected.index]) {
+ expected.matchAnnotation(cpool, anno);
+ }
+ }
+ }
+
+ return null;
+ }
+ };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/SyntheticParameters.java Fri Nov 21 16:36:39 2014 -0500
@@ -0,0 +1,198 @@
+/*
+ * 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
+ * @bug 8065132
+ * @summary Test generation of annotations on inner class parameters.
+ * @library /lib/annotations/
+ * @run main SyntheticParameters
+ */
+
+import annotations.classfile.ClassfileInspector;
+
+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,
+ null,
+ new ExpectedParameterAnnotation[] {
+ (ExpectedParameterAnnotation)
+ // Assert there is no annotation on the
+ // this$0 parameter.
+ new ExpectedParameterAnnotation(
+ "<init>",
+ 0,
+ "A",
+ true,
+ 0),
+ (ExpectedParameterAnnotation)
+ // Assert there is an annotation on the
+ // first parameter.
+ new ExpectedParameterAnnotation(
+ "<init>",
+ 1,
+ "A",
+ true,
+ 1),
+ (ExpectedParameterAnnotation)
+ new ExpectedParameterAnnotation(
+ "foo",
+ 0,
+ "A",
+ true,
+ 1),
+ (ExpectedParameterAnnotation)
+ new ExpectedParameterAnnotation(
+ "foo",
+ 1,
+ "A",
+ true,
+ 0),
+ (ExpectedParameterAnnotation)
+ // Assert there is no annotation on the
+ // this$0 parameter.
+ new ExpectedParameterAnnotation(
+ "<init>",
+ 0,
+ "B",
+ false,
+ 0),
+ (ExpectedParameterAnnotation)
+ // Assert there is an annotation on the
+ // first parameter.
+ new ExpectedParameterAnnotation(
+ "<init>",
+ 1,
+ "B",
+ false,
+ 1),
+ (ExpectedParameterAnnotation)
+ new ExpectedParameterAnnotation(
+ "foo",
+ 0,
+ "B",
+ false,
+ 1),
+ (ExpectedParameterAnnotation)
+ new ExpectedParameterAnnotation(
+ "foo",
+ 1,
+ "B",
+ false,
+ 0)
+ },
+ null);
+ private static final Expected Foo_expected =
+ new Expected("SyntheticParameters$Foo",
+ null,
+ null,
+ new ExpectedParameterAnnotation[] {
+ (ExpectedParameterAnnotation)
+ // Assert there is no annotation on the
+ // $enum$name parameter.
+ new ExpectedParameterAnnotation(
+ "<init>",
+ 0,
+ "A",
+ true,
+ 0),
+ (ExpectedParameterAnnotation)
+ // Assert there is no annotation on the
+ // $enum$ordinal parameter.
+ new ExpectedParameterAnnotation(
+ "<init>",
+ 1,
+ "A",
+ true,
+ 0),
+ (ExpectedParameterAnnotation)
+ // Assert there is an annotation on the
+ // first parameter.
+ new ExpectedParameterAnnotation(
+ "<init>",
+ 2,
+ "A",
+ true,
+ 1),
+ (ExpectedParameterAnnotation)
+ // Assert there is no annotation on the
+ // $enum$name parameter.
+ new ExpectedParameterAnnotation(
+ "<init>",
+ 0,
+ "B",
+ false,
+ 0),
+ (ExpectedParameterAnnotation)
+ // Assert there is no annotation on the
+ // $enum$ordinal parameter.
+ new ExpectedParameterAnnotation(
+ "<init>",
+ 1,
+ "B",
+ false,
+ 0),
+ (ExpectedParameterAnnotation)
+ // Assert there is an annotation on the
+ // first parameter.
+ new ExpectedParameterAnnotation(
+ "<init>",
+ 2,
+ "B",
+ false,
+ 1)
+ },
+ null);
+
+ public static void main(String... args) throws Exception {
+ new SyntheticParameters().run(
+ new ClassFile[] { getClassFile(Inner_class, Inner.class),
+ getClassFile(Foo_class, Foo.class) },
+ new Expected[] { Inner_expected, Foo_expected });
+ }
+
+ public class Inner {
+ public Inner(@A @B int a) {}
+ public void foo(@A @B int a, int b) {}
+ }
+
+ public static enum Foo {
+ ONE(null);
+ Foo(@A @B Object a) {}
+ }
+}
+
+@Retention(RetentionPolicy.RUNTIME)
+@interface A {}
+
+@Retention(RetentionPolicy.CLASS)
+@interface B {}
--- a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileInspector.java Fri Nov 21 10:38:43 2014 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,950 +0,0 @@
-/*
- * 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;
- }
- };
-}
--- a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/SyntheticParameters.java Fri Nov 21 10:38:43 2014 -0800
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/SyntheticParameters.java Fri Nov 21 16:36:39 2014 -0500
@@ -24,10 +24,12 @@
/*
* @test SyntheticParameters
* @summary Test generation of annotations on inner class parameters.
- * @build ClassfileInspector
+ * @library /lib/annotations/
* @run main SyntheticParameters
*/
+import annotations.classfile.ClassfileInspector;
+
import java.io.*;
import java.lang.annotation.*;
@@ -111,7 +113,8 @@
public static void main(String... args) throws Exception {
new SyntheticParameters().run(
- new ClassFile[] { getClassFile(Inner_class), getClassFile(Foo_class) },
+ new ClassFile[] { getClassFile(Inner_class, Inner.class),
+ getClassFile(Foo_class, Foo.class) },
new Expected[] { Inner_expected, Foo_expected });
}