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 }