langtools/test/tools/javac/annotations/typeAnnotations/classfile/ClassfileInspector.java
changeset 27860 a48998a1fc72
parent 27840 66e93fa62eb3
parent 27859 f5bd37460a09
child 27861 094b68c3fc1b
equal deleted inserted replaced
27840:66e93fa62eb3 27860:a48998a1fc72
     1 /*
       
     2  * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 import java.lang.annotation.*;
       
    25 import java.io.*;
       
    26 import java.net.URL;
       
    27 import java.util.List;
       
    28 
       
    29 import com.sun.tools.classfile.*;
       
    30 
       
    31 /**
       
    32  * A class providing utilities for writing tests that inspect class
       
    33  * files directly, looking for specific type annotations.
       
    34  *
       
    35  * Note: this framework does not currently handle repeating
       
    36  * annotations.
       
    37  */
       
    38 public class ClassfileInspector {
       
    39 
       
    40     /**
       
    41      * A group of expected annotations to be found in a given class.
       
    42      * If the class name is null, then the template will be applied to
       
    43      * every class.
       
    44      */
       
    45     public static class Expected {
       
    46         /**
       
    47          * The name of the class.  If {@code null} this template will
       
    48          * apply to every class; otherwise, it will only be applied to
       
    49          * the named class.
       
    50          */
       
    51         public final String classname;
       
    52 
       
    53         /**
       
    54          * The expected class annotations.  These will be checked
       
    55          * against the class' attributes.
       
    56          */
       
    57         public final ExpectedTypeAnnotation[] classAnnos;
       
    58 
       
    59         /**
       
    60          * The expected method annotations.  These will be checked
       
    61          * against all methods in the class.
       
    62          */
       
    63         public final ExpectedMethodTypeAnnotation[] methodAnnos;
       
    64 
       
    65         /**
       
    66          * The expected field annotations.  These will be checked
       
    67          * against all fields in the class.
       
    68          */
       
    69         public final ExpectedFieldTypeAnnotation[] fieldAnnos;
       
    70 
       
    71         /**
       
    72          * Create an {@code Expected} from its components.
       
    73          *
       
    74          * @param classname The name of the class to match, or {@code
       
    75          *                  null} for all classes.
       
    76          * @param classAnnos The expected class annotations.
       
    77          * @param methodAnnos The expected method annotations.
       
    78          * @param fieldAnnos The expected field annotations.
       
    79          */
       
    80         public Expected(String classname,
       
    81                         ExpectedTypeAnnotation[] classAnnos,
       
    82                         ExpectedMethodTypeAnnotation[] methodAnnos,
       
    83                         ExpectedFieldTypeAnnotation[] fieldAnnos) {
       
    84             this.classname = classname;
       
    85             this.classAnnos = classAnnos;
       
    86             this.methodAnnos = methodAnnos;
       
    87             this.fieldAnnos = fieldAnnos;
       
    88         }
       
    89 
       
    90         public String toString() {
       
    91             final StringBuilder sb = new StringBuilder();
       
    92             final String newline = System.lineSeparator();
       
    93             sb.append("Expected on class ").append(classname);
       
    94             if (null != classAnnos) {
       
    95                 sb.append(newline).append("Class annotations:").append(newline);
       
    96                 for(ExpectedTypeAnnotation anno : classAnnos) {
       
    97                     sb.append(anno).append(newline);
       
    98                 }
       
    99             }
       
   100             if (null != methodAnnos) {
       
   101                 sb.append(newline).append("Method annotations:").append(newline);
       
   102                 for(ExpectedTypeAnnotation anno : methodAnnos) {
       
   103                     sb.append(anno).append(newline);
       
   104                 }
       
   105             }
       
   106             if (null != fieldAnnos) {
       
   107                 sb.append(newline).append("Field annotations:").append(newline);
       
   108                 for(ExpectedTypeAnnotation anno : fieldAnnos) {
       
   109                     sb.append(anno).append(newline);
       
   110                 }
       
   111             }
       
   112             return sb.toString();
       
   113         }
       
   114 
       
   115         /**
       
   116          * See if this template applies to a class.
       
   117          *
       
   118          * @param classname The classname to check.
       
   119          * @return Whether or not this template should apply.
       
   120          */
       
   121         public boolean matchClassName(String classname) {
       
   122             return this.classname == null || this.classname.equals(classname);
       
   123         }
       
   124 
       
   125         /**
       
   126          * After applying the template to all classes, check to see if
       
   127          * any of the expected annotations weren't matched.
       
   128          *
       
   129          * @return The number of missed matches.
       
   130          */
       
   131         public int check() {
       
   132             int count = 0;
       
   133             if (classAnnos != null) {
       
   134                 for(ExpectedTypeAnnotation expected : classAnnos) {
       
   135                     if (!expected.check()) {
       
   136                         count++;
       
   137                     }
       
   138                 }
       
   139             }
       
   140             if (methodAnnos != null) {
       
   141                 for(ExpectedMethodTypeAnnotation expected : methodAnnos) {
       
   142                     if (!expected.check()) {
       
   143                         count++;
       
   144                     }
       
   145                 }
       
   146             }
       
   147             if (fieldAnnos != null) {
       
   148                 for(ExpectedFieldTypeAnnotation expected : fieldAnnos) {
       
   149                     if (!expected.check()) {
       
   150                         count++;
       
   151                     }
       
   152                 }
       
   153             }
       
   154             return count;
       
   155         }
       
   156     }
       
   157 
       
   158     /**
       
   159      * An expected type annotation.  This is both a superclass for
       
   160      * method and field type annotations, as well as a class for type
       
   161      * annotations on a class.
       
   162      */
       
   163     public static class ExpectedTypeAnnotation {
       
   164         private int count = 0;
       
   165         protected final String expectedName;
       
   166         protected final int expectedCount;
       
   167         protected final TypeAnnotation.TargetType targetType;
       
   168         protected final int bound_index;
       
   169         protected final int parameter_index;
       
   170         protected final int type_index;
       
   171         protected final int exception_index;
       
   172         protected final TypeAnnotation.Position.TypePathEntry[] typePath;
       
   173         protected final boolean visibility;
       
   174 
       
   175         /**
       
   176          * Create an {@code ExpectedTypeAnnotation} from its
       
   177          * components.  It is usually a better idea to use a {@code
       
   178          * Builder} to do this.
       
   179          *
       
   180          * @param expectedName The expected annotation name.
       
   181          * @param visibility Whether this annotation should be runtime-visible.
       
   182          * @param expectedCount The number of annotations that should
       
   183          *                      be seen.  If 0, this asserts that the
       
   184          *                      described annotation is not present.
       
   185          * @param targetType The expected target type.
       
   186          * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
       
   187          * @param parameter_index The expected parameter index, or
       
   188          *                        {@code Integer.MIN_VALUE}.
       
   189          * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
       
   190          * @param exception_index The expected exception index, or
       
   191          *                        {@code Integer.MIN_VALUE}.
       
   192          * @param typePath The expected type path.
       
   193          */
       
   194         public ExpectedTypeAnnotation(String expectedName,
       
   195                                       boolean visibility,
       
   196                                       int expectedCount,
       
   197                                       TypeAnnotation.TargetType targetType,
       
   198                                       int bound_index,
       
   199                                       int parameter_index,
       
   200                                       int type_index,
       
   201                                       int exception_index,
       
   202                                       TypeAnnotation.Position.TypePathEntry... typePath) {
       
   203             this.expectedName = expectedName;
       
   204             this.visibility = visibility;
       
   205             this.expectedCount = expectedCount;
       
   206             this.targetType = targetType;
       
   207             this.bound_index = bound_index;
       
   208             this.parameter_index = parameter_index;
       
   209             this.type_index = type_index;
       
   210             this.exception_index = exception_index;
       
   211             this.typePath = typePath;
       
   212         }
       
   213 
       
   214         public String toString() {
       
   215             final StringBuilder sb = new StringBuilder();
       
   216             sb.append("Expected ");
       
   217             sb.append(expectedCount);
       
   218             sb.append(" annotation ");
       
   219             sb.append(expectedName);
       
   220             sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
       
   221             sb.append(targetType);
       
   222             sb.append(", bound_index = ");
       
   223             sb.append(bound_index);
       
   224             sb.append(", parameter_index = ");
       
   225             sb.append(parameter_index);
       
   226             sb.append(", type_index = ");
       
   227             sb.append(type_index);
       
   228             sb.append(", exception_index = ");
       
   229             sb.append(exception_index);
       
   230             sb.append(", type_path = [");
       
   231             for(int i = 0; i < typePath.length; i++) {
       
   232                 if (i != 0) {
       
   233                     sb.append(", ");
       
   234                 }
       
   235                 sb.append(typePath[i]);
       
   236             }
       
   237             sb.append("]");
       
   238             return sb.toString();
       
   239         }
       
   240 
       
   241         /**
       
   242          * See if this template matches the given visibility.
       
   243          *
       
   244          * @param Whether or not the annotation is visible at runtime.
       
   245          * @return Whether or not this template matches the visibility.
       
   246          */
       
   247         public boolean matchVisibility(boolean visibility) {
       
   248             return this.visibility == visibility;
       
   249         }
       
   250 
       
   251         /**
       
   252          * Attempty to match this template against an annotation.  If
       
   253          * it does match, then the match count for the template will
       
   254          * be incremented.  Otherwise, nothing will be done.
       
   255          *
       
   256          * @param anno The annotation to attempt to match.
       
   257          */
       
   258         public void matchAnnotation(TypeAnnotation anno) {
       
   259             boolean matches = true;
       
   260 
       
   261             try {
       
   262                 matches = anno.constant_pool.getUTF8Info(anno.annotation.type_index).value.equals("L" + expectedName + ";");
       
   263             } catch(Exception e) {
       
   264                 matches = false;
       
   265             }
       
   266 
       
   267             matches = matches && anno.position.type == targetType;
       
   268             matches = matches && anno.position.bound_index == bound_index;
       
   269             matches = matches && anno.position.parameter_index == parameter_index;
       
   270             matches = matches && anno.position.type_index == type_index;
       
   271             matches = matches && anno.position.exception_index == exception_index;
       
   272             matches = matches && anno.position.location.size() == typePath.length;
       
   273 
       
   274             if (matches) {
       
   275                 int i = 0;
       
   276                 for(TypeAnnotation.Position.TypePathEntry entry :
       
   277                          anno.position.location) {
       
   278                     matches = matches && typePath[i++].equals(entry);
       
   279                 }
       
   280             }
       
   281 
       
   282             if (matches) {
       
   283                 count++;
       
   284             }
       
   285         }
       
   286 
       
   287         /**
       
   288          * After all matching, check to see if the expected number of
       
   289          * matches equals the actual number.  If not, then print a
       
   290          * failure message and return {@code false}.
       
   291          *
       
   292          * @return Whether or not the expected number of matched
       
   293          *         equals the actual number.
       
   294          */
       
   295         public boolean check() {
       
   296             if (count != expectedCount) {
       
   297                 System.err.println(this + ", but saw " + count);
       
   298                 return false;
       
   299             } else {
       
   300                 return true;
       
   301             }
       
   302         }
       
   303 
       
   304         /**
       
   305          * A builder class for creating {@code
       
   306          * ExpectedTypeAnnotation}s in a more convenient fashion.  The
       
   307          * constructor for {@code ExpectedTypeAnnotation} takes a
       
   308          * large number of parameters (by necessity).  This class
       
   309          * allows users to construct a {@code ExpectedTypeAnnotation}s
       
   310          * using only the ones they need.
       
   311          */
       
   312         public static class Builder {
       
   313             protected final String expectedName;
       
   314             protected final int expectedCount;
       
   315             protected final TypeAnnotation.TargetType targetType;
       
   316             protected final boolean visibility;
       
   317             protected int bound_index = Integer.MIN_VALUE;
       
   318             protected int parameter_index = Integer.MIN_VALUE;
       
   319             protected int type_index = Integer.MIN_VALUE;
       
   320             protected int exception_index = Integer.MIN_VALUE;
       
   321             protected TypeAnnotation.Position.TypePathEntry[] typePath =
       
   322                 new TypeAnnotation.Position.TypePathEntry[0];
       
   323 
       
   324             /**
       
   325              * Create a {@code Builder} from the mandatory parameters.
       
   326              *
       
   327              * @param expectedName The expected annotation name.
       
   328              * @param targetType The expected target type.
       
   329              * @param visibility Whether this annotation should be runtime-visible.
       
   330              * @param expectedCount The number of annotations that should be seen.
       
   331              */
       
   332             public Builder(String expectedName,
       
   333                            TypeAnnotation.TargetType targetType,
       
   334                            boolean visibility,
       
   335                            int expectedCount) {
       
   336                 this.expectedName = expectedName;
       
   337                 this.visibility = visibility;
       
   338                 this.expectedCount = expectedCount;
       
   339                 this.targetType = targetType;
       
   340             }
       
   341 
       
   342             /**
       
   343              * Create an {@code ExpectedTypeAnnotation} from all
       
   344              * parameters that have been provided.  The default values
       
   345              * will be used for those that have not.
       
   346              *
       
   347              * @return The cretaed {@code ExpectedTypeAnnotation}.
       
   348              */
       
   349             public ExpectedTypeAnnotation build() {
       
   350                 return new ExpectedTypeAnnotation(expectedName, visibility,
       
   351                                                   expectedCount, targetType,
       
   352                                                   bound_index, parameter_index,
       
   353                                                   type_index, exception_index,
       
   354                                                   typePath);
       
   355             }
       
   356 
       
   357             /**
       
   358              * Provide a bound index parameter.
       
   359              *
       
   360              * @param bound_index The bound_index value.
       
   361              */
       
   362             public Builder setBoundIndex(int bound_index) {
       
   363                 this.bound_index = bound_index;
       
   364                 return this;
       
   365             }
       
   366 
       
   367             /**
       
   368              * Provide a parameter index parameter.
       
   369              *
       
   370              * @param bound_index The parameter_index value.
       
   371              */
       
   372             public Builder setParameterIndex(int parameter_index) {
       
   373                 this.parameter_index = parameter_index;
       
   374                 return this;
       
   375             }
       
   376 
       
   377             /**
       
   378              * Provide a type index parameter.
       
   379              *
       
   380              * @param type_index The type_index value.
       
   381              */
       
   382             public Builder setTypeIndex(int type_index) {
       
   383                 this.type_index = type_index;
       
   384                 return this;
       
   385             }
       
   386 
       
   387             /**
       
   388              * Provide an exception index parameter.
       
   389              *
       
   390              * @param exception_index The exception_index value.
       
   391              */
       
   392             public Builder setExceptionIndex(int exception_index) {
       
   393                 this.exception_index = exception_index;
       
   394                 return this;
       
   395             }
       
   396 
       
   397             /**
       
   398              * Provide a type path parameter.
       
   399              *
       
   400              * @param typePath The type path value.
       
   401              */
       
   402             public Builder setTypePath(TypeAnnotation.Position.TypePathEntry[] typePath) {
       
   403                 this.typePath = typePath;
       
   404                 return this;
       
   405             }
       
   406         }
       
   407     }
       
   408 
       
   409     /**
       
   410      * A type annotation found on a method.
       
   411      */
       
   412     public static class ExpectedMethodTypeAnnotation extends ExpectedTypeAnnotation {
       
   413         private final String methodname;
       
   414 
       
   415         /**
       
   416          * Create an {@code ExpectedMethodTypeAnnotation} from its
       
   417          * components.  It is usually a better idea to use a {@code
       
   418          * Builder} to do this.
       
   419          *
       
   420          * @param methodname The expected method name.
       
   421          * @param expectedName The expected annotation name.
       
   422          * @param visibility Whether this annotation should be runtime-visible.
       
   423          * @param expectedCount The number of annotations that should be seen.
       
   424          * @param targetType The expected target type.
       
   425          * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
       
   426          * @param parameter_index The expected parameter index, or
       
   427          *                        {@code Integer.MIN_VALUE}.
       
   428          * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
       
   429          * @param exception_index The expected exception index, or
       
   430          *                        {@code Integer.MIN_VALUE}.
       
   431          * @param typePath The expected type path.
       
   432          */
       
   433         public ExpectedMethodTypeAnnotation(String methodname,
       
   434                                             String expectedName,
       
   435                                             boolean visibility,
       
   436                                             int expectedCount,
       
   437                                             TypeAnnotation.TargetType targetType,
       
   438                                             int bound_index,
       
   439                                             int parameter_index,
       
   440                                             int type_index,
       
   441                                             int exception_index,
       
   442                                             TypeAnnotation.Position.TypePathEntry... typePath) {
       
   443             super(expectedName, visibility, expectedCount, targetType, bound_index,
       
   444                   parameter_index, type_index, exception_index, typePath);
       
   445             this.methodname = methodname;
       
   446         }
       
   447 
       
   448         public String toString() {
       
   449             final StringBuilder sb = new StringBuilder();
       
   450             sb.append("Expected ");
       
   451             sb.append(expectedCount);
       
   452             sb.append(" annotation ");
       
   453             sb.append(expectedName);
       
   454             sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
       
   455             sb.append(targetType);
       
   456             sb.append(", bound_index = ");
       
   457             sb.append(bound_index);
       
   458             sb.append(", parameter_index = ");
       
   459             sb.append(parameter_index);
       
   460             sb.append(", type_index = ");
       
   461             sb.append(type_index);
       
   462             sb.append(", exception_index = ");
       
   463             sb.append(exception_index);
       
   464             sb.append(", type_path = [");
       
   465             for(int i = 0; i < typePath.length; i++) {
       
   466                 if (i != 0) {
       
   467                     sb.append(", ");
       
   468                 }
       
   469                 sb.append(typePath[i]);
       
   470             }
       
   471             sb.append("]");
       
   472             sb.append(" on method ");
       
   473             sb.append(methodname);
       
   474             return sb.toString();
       
   475         }
       
   476 
       
   477         /**
       
   478          * See if this template applies to a method.
       
   479          *
       
   480          * @param methodname The method name to check.
       
   481          * @return Whether or not this template should apply.
       
   482          */
       
   483         public boolean matchMethodName(String methodname) {
       
   484             return this.methodname.equals(methodname);
       
   485         }
       
   486 
       
   487         /**
       
   488          * A builder class for creating {@code
       
   489          * ExpectedMethodTypeAnnotation}s in a more convenient fashion.  The
       
   490          * constructor for {@code ExpectedMethodTypeAnnotation} takes a
       
   491          * large number of parameters (by necessity).  This class
       
   492          * allows users to construct a {@code ExpectedMethodTypeAnnotation}s
       
   493          * using only the ones they need.
       
   494          */
       
   495         public static class Builder extends ExpectedTypeAnnotation.Builder {
       
   496             protected final String methodname;
       
   497 
       
   498             /**
       
   499              * Create a {@code Builder} from the mandatory parameters.
       
   500              *
       
   501              * @param methodname The expected method name.
       
   502              * @param expectedName The expected annotation name.
       
   503              * @param targetType The expected target type.
       
   504              * @param visibility Whether this annotation should be runtime-visible.
       
   505              * @param expectedCount The number of annotations that should be seen.
       
   506              */
       
   507             public Builder(String methodname,
       
   508                            String expectedName,
       
   509                            TypeAnnotation.TargetType targetType,
       
   510                            boolean visibility,
       
   511                            int expectedCount) {
       
   512                 super(expectedName, targetType, visibility, expectedCount);
       
   513                 this.methodname = methodname;
       
   514             }
       
   515 
       
   516             /**
       
   517              * Create an {@code ExpectedMethodTypeAnnotation} from all
       
   518              * parameters that have been provided.  The default values
       
   519              * will be used for those that have not.
       
   520              *
       
   521              * @return The cretaed {@code ExpectedMethodTypeAnnotation}.
       
   522              */
       
   523             public ExpectedMethodTypeAnnotation build() {
       
   524                 return new ExpectedMethodTypeAnnotation(methodname, expectedName,
       
   525                                                         visibility, expectedCount,
       
   526                                                         targetType, bound_index,
       
   527                                                         parameter_index, type_index,
       
   528                                                         exception_index, typePath);
       
   529             }
       
   530         }
       
   531     }
       
   532 
       
   533     /**
       
   534      * A type annotation found on a field.
       
   535      */
       
   536     public static class ExpectedFieldTypeAnnotation extends ExpectedTypeAnnotation {
       
   537         private final String fieldname;
       
   538 
       
   539         /**
       
   540          * Create an {@code ExpectedFieldTypeAnnotation} from its
       
   541          * components.  It is usually a better idea to use a {@code
       
   542          * Builder} to do this.
       
   543          *
       
   544          * @param fieldname The expected field name.
       
   545          * @param expectedName The expected annotation name.
       
   546          * @param visibility Whether this annotation should be runtime-visible.
       
   547          * @param expectedCount The number of annotations that should be seen.
       
   548          * @param targetType The expected target type.
       
   549          * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
       
   550          * @param parameter_index The expected parameter index, or
       
   551          *                        {@code Integer.MIN_VALUE}.
       
   552          * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
       
   553          * @param exception_index The expected exception index, or
       
   554          *                        {@code Integer.MIN_VALUE}.
       
   555          * @param typePath The expected type path.
       
   556          */
       
   557         public ExpectedFieldTypeAnnotation(String fieldname,
       
   558                                            String expectedName,
       
   559                                            boolean visibility,
       
   560                                            int expectedCount,
       
   561                                            TypeAnnotation.TargetType targetType,
       
   562                                            int bound_index,
       
   563                                            int parameter_index,
       
   564                                            int type_index,
       
   565                                            int exception_index,
       
   566                                            TypeAnnotation.Position.TypePathEntry... typePath) {
       
   567             super(expectedName, visibility, expectedCount, targetType, bound_index,
       
   568                   parameter_index, type_index, exception_index, typePath);
       
   569             this.fieldname = fieldname;
       
   570         }
       
   571 
       
   572         public String toString() {
       
   573             final StringBuilder sb = new StringBuilder();
       
   574             sb.append("Expected ").append(expectedCount)
       
   575             .append(" annotation ").append(expectedName)
       
   576             .append(visibility ? ", runtime visibile " : ", runtime invisibile ")
       
   577             .append(targetType)
       
   578             .append(", bound_index = ").append(bound_index)
       
   579             .append(", parameter_index = ").append(parameter_index)
       
   580             .append(", type_index = ").append(type_index)
       
   581             .append(", exception_index = ").append(exception_index)
       
   582             .append(", type_path = [");
       
   583 
       
   584             for(int i = 0; i < typePath.length; i++) {
       
   585                 if (i != 0) {
       
   586                     sb.append(", ");
       
   587                 }
       
   588                 sb.append(typePath[i]);
       
   589             }
       
   590             sb.append("]")
       
   591             .append(" on field ").append(fieldname);
       
   592             return sb.toString();
       
   593         }
       
   594 
       
   595         /**
       
   596          * See if this template applies to a field.
       
   597          *
       
   598          * @param fieldname The field name to check.
       
   599          * @return Whether or not this template should apply.
       
   600          */
       
   601         public boolean matchFieldName(String fieldname) {
       
   602             return this.fieldname.equals(fieldname);
       
   603         }
       
   604 
       
   605         /**
       
   606          * A builder class for creating {@code
       
   607          * ExpectedFieldTypeAnnotation}s in a more convenient fashion.  The
       
   608          * constructor for {@code ExpectedFieldTypeAnnotation} takes a
       
   609          * large number of parameters (by necessity).  This class
       
   610          * allows users to construct a {@code ExpectedFieldTypeAnnotation}s
       
   611          * using only the ones they need.
       
   612          */
       
   613         public static class Builder extends ExpectedTypeAnnotation.Builder {
       
   614             protected final String fieldname;
       
   615 
       
   616             /**
       
   617              * Create a {@code Builder} from the mandatory parameters.
       
   618              *
       
   619              * @param fieldname The expected field name.
       
   620              * @param expectedName The expected annotation name.
       
   621              * @param targetType The expected target type.
       
   622              * @param visibility Whether this annotation should be runtime-visible.
       
   623              * @param expectedCount The number of annotations that should be seen.
       
   624              */
       
   625             public Builder(String fieldname,
       
   626                            String expectedName,
       
   627                            TypeAnnotation.TargetType targetType,
       
   628                            boolean visibility,
       
   629                            int expectedCount) {
       
   630                 super(expectedName, targetType, visibility, expectedCount);
       
   631                 this.fieldname = fieldname;
       
   632             }
       
   633 
       
   634             /**
       
   635              * Create an {@code ExpectedFieldTypeAnnotation} from all
       
   636              * parameters that have been provided.  The default values
       
   637              * will be used for those that have not.
       
   638              *
       
   639              * @return The cretaed {@code ExpectedFieldTypeAnnotation}.
       
   640              */
       
   641             public ExpectedFieldTypeAnnotation build() {
       
   642                 return new ExpectedFieldTypeAnnotation(fieldname, expectedName,
       
   643                                                        visibility, expectedCount,
       
   644                                                        targetType, bound_index,
       
   645                                                        parameter_index, type_index,
       
   646                                                        exception_index, typePath);
       
   647             }
       
   648         }
       
   649     }
       
   650 
       
   651     private void matchClassTypeAnnotation(ClassFile classfile,
       
   652                                           ExpectedTypeAnnotation expected)
       
   653         throws ConstantPoolException {
       
   654         for(Attribute attr : classfile.attributes) {
       
   655             attr.accept(typeAnnoMatcher, expected);
       
   656         }
       
   657     }
       
   658 
       
   659     private void matchMethodTypeAnnotation(ClassFile classfile,
       
   660                                            ExpectedMethodTypeAnnotation expected)
       
   661         throws ConstantPoolException {
       
   662         for(Method meth : classfile.methods) {
       
   663             if (expected.matchMethodName(meth.getName(classfile.constant_pool))) {
       
   664                 for(Attribute attr : meth.attributes) {
       
   665                     attr.accept(typeAnnoMatcher, expected);
       
   666                 }
       
   667             }
       
   668         }
       
   669     }
       
   670 
       
   671     private void matchFieldTypeAnnotation(ClassFile classfile,
       
   672                                           ExpectedFieldTypeAnnotation expected)
       
   673         throws ConstantPoolException {
       
   674         for(Field field : classfile.fields) {
       
   675             if (expected.matchFieldName(field.getName(classfile.constant_pool))) {
       
   676                 for(Attribute attr : field.attributes) {
       
   677                     attr.accept(typeAnnoMatcher, expected);
       
   678                 }
       
   679             }
       
   680         }
       
   681     }
       
   682 
       
   683     private void matchClassTypeAnnotations(ClassFile classfile,
       
   684                                            ExpectedTypeAnnotation[] expected)
       
   685         throws ConstantPoolException {
       
   686         for(ExpectedTypeAnnotation one : expected) {
       
   687             matchClassTypeAnnotation(classfile, one);
       
   688         }
       
   689     }
       
   690 
       
   691     private void matchMethodTypeAnnotations(ClassFile classfile,
       
   692                                             ExpectedMethodTypeAnnotation[] expected)
       
   693         throws ConstantPoolException {
       
   694         for(ExpectedMethodTypeAnnotation one : expected) {
       
   695             matchMethodTypeAnnotation(classfile, one);
       
   696         }
       
   697     }
       
   698 
       
   699     private void matchFieldTypeAnnotations(ClassFile classfile,
       
   700                                            ExpectedFieldTypeAnnotation[] expected)
       
   701         throws ConstantPoolException {
       
   702         for(ExpectedFieldTypeAnnotation one : expected) {
       
   703             matchFieldTypeAnnotation(classfile, one);
       
   704         }
       
   705     }
       
   706 
       
   707     /**
       
   708      * Run a template on a single {@code ClassFile}.
       
   709      *
       
   710      * @param classfile The {@code ClassFile} on which to run tests.
       
   711      * @param expected The expected annotation template.
       
   712      */
       
   713     public void run(ClassFile classfile,
       
   714                     Expected... expected)
       
   715             throws ConstantPoolException {
       
   716         run(new ClassFile[] { classfile }, expected);
       
   717     }
       
   718 
       
   719     /**
       
   720      * Run a template on multiple {@code ClassFile}s.
       
   721      *
       
   722      * @param classfile The {@code ClassFile}s on which to run tests.
       
   723      * @param expected The expected annotation template.
       
   724      */
       
   725     public void run(ClassFile[] classfiles,
       
   726                     Expected... expected)
       
   727             throws ConstantPoolException {
       
   728         for(ClassFile classfile : classfiles) {
       
   729             for(Expected one : expected) {
       
   730                 if (one.matchClassName(classfile.getName())) {
       
   731                     if (one.classAnnos != null)
       
   732                         matchClassTypeAnnotations(classfile, one.classAnnos);
       
   733                     if (one.methodAnnos != null)
       
   734                         matchMethodTypeAnnotations(classfile, one.methodAnnos);
       
   735                     if (one.fieldAnnos != null)
       
   736                         matchFieldTypeAnnotations(classfile, one.fieldAnnos);
       
   737                 }
       
   738             }
       
   739         }
       
   740         int count = 0;
       
   741         for (Expected one : expected) {
       
   742             count += one.check();
       
   743         }
       
   744 
       
   745         if (count != 0) {
       
   746             throw new RuntimeException(count + " errors occurred in test");
       
   747         }
       
   748     }
       
   749 
       
   750     /**
       
   751      * Get a {@code ClassFile} from its file name.
       
   752      *
       
   753      * @param name The class' file name.
       
   754      * @return The {@code ClassFile}
       
   755      */
       
   756     public static ClassFile getClassFile(String name)
       
   757         throws IOException, ConstantPoolException {
       
   758         final URL url = ClassfileInspector.class.getResource(name);
       
   759         final InputStream in = url.openStream();
       
   760         try {
       
   761             return ClassFile.read(in);
       
   762         } finally {
       
   763             in.close();
       
   764         }
       
   765     }
       
   766 
       
   767     private static final Attribute.Visitor<Void, ExpectedTypeAnnotation> typeAnnoMatcher =
       
   768         new Attribute.Visitor<Void, ExpectedTypeAnnotation>() {
       
   769 
       
   770         @Override
       
   771         public Void visitBootstrapMethods(BootstrapMethods_attribute attr,
       
   772                                           ExpectedTypeAnnotation expected) {
       
   773             return null;
       
   774         }
       
   775 
       
   776         @Override
       
   777         public Void visitDefault(DefaultAttribute attr,
       
   778                                  ExpectedTypeAnnotation expected) {
       
   779             return null;
       
   780         }
       
   781 
       
   782         @Override
       
   783         public Void visitAnnotationDefault(AnnotationDefault_attribute attr,
       
   784                                            ExpectedTypeAnnotation expected) {
       
   785             return null;
       
   786         }
       
   787 
       
   788         @Override
       
   789         public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr,
       
   790                                              ExpectedTypeAnnotation expected) {
       
   791             return null;
       
   792         }
       
   793 
       
   794         @Override
       
   795         public Void visitCode(Code_attribute attr,
       
   796                               ExpectedTypeAnnotation expected) {
       
   797             return null;
       
   798         }
       
   799 
       
   800         @Override
       
   801         public Void visitCompilationID(CompilationID_attribute attr,
       
   802                                        ExpectedTypeAnnotation expected) {
       
   803             return null;
       
   804         }
       
   805 
       
   806         @Override
       
   807         public Void visitConstantValue(ConstantValue_attribute attr,
       
   808                                        ExpectedTypeAnnotation expected) {
       
   809             return null;
       
   810         }
       
   811 
       
   812         @Override
       
   813         public Void visitDeprecated(Deprecated_attribute attr,
       
   814                                     ExpectedTypeAnnotation expected) {
       
   815             return null;
       
   816         }
       
   817 
       
   818         @Override
       
   819         public Void visitEnclosingMethod(EnclosingMethod_attribute attr,
       
   820                                          ExpectedTypeAnnotation expected) {
       
   821             return null;
       
   822         }
       
   823 
       
   824         @Override
       
   825         public Void visitExceptions(Exceptions_attribute attr,
       
   826                                     ExpectedTypeAnnotation expected) {
       
   827             return null;
       
   828         }
       
   829 
       
   830         @Override
       
   831         public Void visitInnerClasses(InnerClasses_attribute attr,
       
   832                                       ExpectedTypeAnnotation expected) {
       
   833             return null;
       
   834         }
       
   835 
       
   836         @Override
       
   837         public Void visitLineNumberTable(LineNumberTable_attribute attr,
       
   838                                          ExpectedTypeAnnotation expected) {
       
   839             return null;
       
   840         }
       
   841 
       
   842         @Override
       
   843         public Void visitLocalVariableTable(LocalVariableTable_attribute attr,
       
   844                                             ExpectedTypeAnnotation expected) {
       
   845             return null;
       
   846         }
       
   847 
       
   848         @Override
       
   849         public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr,
       
   850                                                 ExpectedTypeAnnotation expected) {
       
   851             return null;
       
   852         }
       
   853 
       
   854         @Override
       
   855         public Void visitMethodParameters(MethodParameters_attribute attr,
       
   856                                           ExpectedTypeAnnotation expected) {
       
   857             return null;
       
   858         }
       
   859 
       
   860         @Override
       
   861             public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr,
       
   862                                                        ExpectedTypeAnnotation expected) {
       
   863             return null;
       
   864         }
       
   865 
       
   866         @Override
       
   867         public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr,
       
   868                                                      ExpectedTypeAnnotation expected) {
       
   869             return null;
       
   870         }
       
   871 
       
   872         @Override
       
   873         public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr,
       
   874                                                             ExpectedTypeAnnotation expected) {
       
   875             return null;
       
   876         }
       
   877 
       
   878         @Override
       
   879         public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr,
       
   880                                                               ExpectedTypeAnnotation expected) {
       
   881             return null;
       
   882         }
       
   883 
       
   884         @Override
       
   885         public Void visitSignature(Signature_attribute attr,
       
   886                                    ExpectedTypeAnnotation expected) {
       
   887             return null;
       
   888         }
       
   889 
       
   890         @Override
       
   891         public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr,
       
   892                                               ExpectedTypeAnnotation expected) {
       
   893             return null;
       
   894         }
       
   895 
       
   896         @Override
       
   897         public Void visitSourceFile(SourceFile_attribute attr,
       
   898                                     ExpectedTypeAnnotation expected) {
       
   899             return null;
       
   900         }
       
   901 
       
   902         @Override
       
   903         public Void visitSourceID(SourceID_attribute attr,
       
   904                                   ExpectedTypeAnnotation expected) {
       
   905             return null;
       
   906         }
       
   907 
       
   908         @Override
       
   909         public Void visitStackMap(StackMap_attribute attr,
       
   910                                   ExpectedTypeAnnotation expected) {
       
   911             return null;
       
   912         }
       
   913 
       
   914         @Override
       
   915         public Void visitStackMapTable(StackMapTable_attribute attr,
       
   916                                        ExpectedTypeAnnotation expected) {
       
   917             return null;
       
   918         }
       
   919 
       
   920         @Override
       
   921         public Void visitSynthetic(Synthetic_attribute attr,
       
   922                                    ExpectedTypeAnnotation expected) {
       
   923             return null;
       
   924         }
       
   925 
       
   926         @Override
       
   927         public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr,
       
   928                                                        ExpectedTypeAnnotation expected) {
       
   929             if (expected.matchVisibility(true)) {
       
   930                 for(TypeAnnotation anno : attr.annotations) {
       
   931                     expected.matchAnnotation(anno);
       
   932                 }
       
   933             }
       
   934 
       
   935             return null;
       
   936         }
       
   937 
       
   938         @Override
       
   939         public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr,
       
   940                                                          ExpectedTypeAnnotation expected) {
       
   941             if (expected.matchVisibility(false)) {
       
   942                 for(TypeAnnotation anno : attr.annotations) {
       
   943                     expected.matchAnnotation(anno);
       
   944                 }
       
   945             }
       
   946 
       
   947             return null;
       
   948         }
       
   949     };
       
   950 }