1 /*
   2  * Copyright (c) 2012, 2018, 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 package annotations.classfile;
  25 
  26 import java.io.*;
  27 import java.net.URL;
  28 
  29 import com.sun.tools.classfile.*;
  30 import com.sun.tools.classfile.ConstantPool.InvalidIndex;
  31 import com.sun.tools.classfile.ConstantPool.UnexpectedEntry;
  32 
  33 /**
  34  * A class providing utilities for writing tests that inspect class
  35  * files directly, looking for specific type annotations.
  36  *
  37  * Note: this framework does not currently handle repeating
  38  * annotations.
  39  */
  40 public class ClassfileInspector {
  41 
  42     /**
  43      * A group of expected annotations to be found in a given class.
  44      * If the class name is null, then the template will be applied to
  45      * every class.
  46      */
  47     public static class Expected {
  48         /**
  49          * The name of the class.  If {@code null} this template will
  50          * apply to every class; otherwise, it will only be applied to
  51          * the named class.
  52          */
  53         public final String classname;
  54 
  55         /**
  56          * The expected class annotations.  These will be checked
  57          * against the class' attributes.
  58          */
  59         public final ExpectedAnnotation[] classAnnos;
  60 
  61         /**
  62          * The expected method annotations.  These will be checked
  63          * against all methods in the class.
  64          */
  65         public final ExpectedMethodAnnotation[] methodAnnos;
  66 
  67         /**
  68          * The expected method parameter annotations.  These will be checked
  69          * against all methods in the class.
  70          */
  71         public final ExpectedParameterAnnotation[] methodParamAnnos;
  72 
  73         /**
  74          * The expected field type annotations.  These will be checked
  75          * against all fields in the class.
  76          */
  77         public final ExpectedFieldAnnotation[] fieldAnnos;
  78 
  79         /**
  80          * The expected class type annotations.  These will be checked
  81          * against the class' attributes.
  82          */
  83         public final ExpectedTypeAnnotation[] classTypeAnnos;
  84 
  85         /**
  86          * The expected method type annotations.  These will be checked
  87          * against all methods in the class.
  88          */
  89         public final ExpectedMethodTypeAnnotation[] methodTypeAnnos;
  90 
  91         /**
  92          * The expected field type annotations.  These will be checked
  93          * against all fields in the class.
  94          */
  95         public final ExpectedFieldTypeAnnotation[] fieldTypeAnnos;
  96 
  97         /**
  98          * Create an {@code Expected} from all components.
  99          *
 100          * @param classname The name of the class to match, or {@code
 101          *                  null} for all classes.
 102          * @param classAnnos The expected class annotations.
 103          * @param methodAnnos The expected method annotations.
 104          * @param methodParamAnnos The expected method parameter annotations.
 105          * @param fieldAnnos The expected field annotations.
 106          * @param classTypeAnnos The expected class type annotations.
 107          * @param methodTypeAnnos The expected method type annotations.
 108          * @param fieldTypeAnnos The expected field type annotations.
 109          */
 110         public Expected(String classname,
 111                         ExpectedAnnotation[] classAnnos,
 112                         ExpectedMethodAnnotation[] methodAnnos,
 113                         ExpectedParameterAnnotation[] methodParamAnnos,
 114                         ExpectedFieldAnnotation[] fieldAnnos,
 115                         ExpectedTypeAnnotation[] classTypeAnnos,
 116                         ExpectedMethodTypeAnnotation[] methodTypeAnnos,
 117                         ExpectedFieldTypeAnnotation[] fieldTypeAnnos) {
 118             this.classname = classname;
 119             this.classAnnos = classAnnos;
 120             this.methodAnnos = methodAnnos;
 121             this.methodParamAnnos = methodParamAnnos;
 122             this.fieldAnnos = fieldAnnos;
 123             this.classTypeAnnos = classTypeAnnos;
 124             this.methodTypeAnnos = methodTypeAnnos;
 125             this.fieldTypeAnnos = fieldTypeAnnos;
 126         }
 127 
 128         /**
 129          * Create an {@code Expected} from regular annotation components.
 130          *
 131          * @param classname The name of the class to match, or {@code
 132          *                  null} for all classes.
 133          * @param classAnnos The expected class annotations.
 134          * @param methodAnnos The expected method annotations.
 135          * @param methodParamAnnos The expected method parameter annotations.
 136          * @param fieldAnnos The expected field annotations.
 137          */
 138         public Expected(String classname,
 139                         ExpectedAnnotation[] classAnnos,
 140                         ExpectedMethodAnnotation[] methodAnnos,
 141                         ExpectedParameterAnnotation[] methodParamAnnos,
 142                         ExpectedFieldAnnotation[] fieldAnnos) {
 143             this(classname, classAnnos, methodAnnos, methodParamAnnos,
 144                  fieldAnnos, null, null, null);
 145         }
 146 
 147         /**
 148          * Create an {@code Expected} from type annotation components.
 149          *
 150          * @param classname The name of the class to match, or {@code
 151          *                  null} for all classes.
 152          * @param classTypeAnnos The expected class type annotations.
 153          * @param methodTypeAnnos The expected method type annotations.
 154          * @param fieldTypeAnnos The expected field type annotations.
 155          */
 156         public Expected(String classname,
 157                         ExpectedTypeAnnotation[] classTypeAnnos,
 158                         ExpectedMethodTypeAnnotation[] methodTypeAnnos,
 159                         ExpectedFieldTypeAnnotation[] fieldTypeAnnos) {
 160             this(classname, null, null, null, null,
 161                  classTypeAnnos, methodTypeAnnos, fieldTypeAnnos);
 162         }
 163 
 164         @Override
 165         public String toString() {
 166             final StringBuilder sb = new StringBuilder();
 167             final String newline = System.lineSeparator();
 168             sb.append("Expected on class ").append(classname);
 169             if (null != classAnnos) {
 170                 sb.append(newline).append("Class annotations:").append(newline);
 171                 for(ExpectedAnnotation anno : classAnnos) {
 172                     sb.append(anno).append(newline);
 173                 }
 174             }
 175             if (null != methodAnnos) {
 176                 sb.append(newline).append("Method annotations:").append(newline);
 177                 for(ExpectedAnnotation anno : methodAnnos) {
 178                     sb.append(anno).append(newline);
 179                 }
 180             }
 181             if (null != methodParamAnnos) {
 182                 sb.append(newline).append("Method param annotations:").append(newline);
 183                 for(ExpectedAnnotation anno : methodParamAnnos) {
 184                     sb.append(anno).append(newline);
 185                 }
 186             }
 187             if (null != fieldAnnos) {
 188                 sb.append(newline).append("Field annotations:").append(newline);
 189                 for(ExpectedAnnotation anno : fieldAnnos) {
 190                     sb.append(anno).append(newline);
 191                 }
 192             }
 193             if (null != classTypeAnnos) {
 194                 sb.append(newline).append("Class type annotations:").append(newline);
 195                 for(ExpectedAnnotation anno : classTypeAnnos) {
 196                     sb.append(anno).append(newline);
 197                 }
 198             }
 199             if (null != methodTypeAnnos) {
 200                 sb.append(newline).append("Method type annotations:").append(newline);
 201                 for(ExpectedAnnotation anno : methodTypeAnnos) {
 202                     sb.append(anno).append(newline);
 203                 }
 204             }
 205             if (null != fieldTypeAnnos) {
 206                 sb.append(newline).append("Field type annotations:").append(newline);
 207                 for(ExpectedAnnotation anno : fieldTypeAnnos) {
 208                     sb.append(anno).append(newline);
 209                 }
 210             }
 211             return sb.toString();
 212         }
 213 
 214         /**
 215          * See if this template applies to a class.
 216          *
 217          * @param classname The classname to check.
 218          * @return Whether or not this template should apply.
 219          */
 220         public boolean matchClassName(String classname) {
 221             return this.classname == null || this.classname.equals(classname);
 222         }
 223 
 224         /**
 225          * After applying the template to all classes, check to see if
 226          * any of the expected annotations weren't matched.
 227          *
 228          * @return The number of missed matches.
 229          */
 230         public int check() {
 231             int count = 0;
 232             if (classAnnos != null) {
 233                 for(ExpectedAnnotation expected : classAnnos) {
 234                     if (!expected.check()) {
 235                         count++;
 236                     }
 237                 }
 238             }
 239             if (methodAnnos != null) {
 240                 for(ExpectedAnnotation expected : methodAnnos) {
 241                     if (!expected.check()) {
 242                         count++;
 243                     }
 244                 }
 245             }
 246             if (methodParamAnnos != null) {
 247                 for(ExpectedAnnotation expected : methodParamAnnos) {
 248                     if (!expected.check()) {
 249                         count++;
 250                     }
 251                 }
 252             }
 253             if (fieldAnnos != null) {
 254                 for(ExpectedAnnotation expected : fieldAnnos) {
 255                     if (!expected.check()) {
 256                         count++;
 257                     }
 258                 }
 259             }
 260             if (classTypeAnnos != null) {
 261                 for(ExpectedAnnotation expected : classTypeAnnos) {
 262                     if (!expected.check()) {
 263                         count++;
 264                     }
 265                 }
 266             }
 267             if (methodTypeAnnos != null) {
 268                 for(ExpectedAnnotation expected : methodTypeAnnos) {
 269                     if (!expected.check()) {
 270                         count++;
 271                     }
 272                 }
 273             }
 274             if (fieldTypeAnnos != null) {
 275                 for(ExpectedAnnotation expected : fieldTypeAnnos) {
 276                     if (!expected.check()) {
 277                         count++;
 278                     }
 279                 }
 280             }
 281             return count;
 282         }
 283     }
 284 
 285     /**
 286      * An expected annotation.  This is both a superclass for
 287      * method, field, and type annotations, as well as a class for
 288      * annotations on a class.
 289      */
 290     public static class ExpectedAnnotation {
 291         protected int count = 0;
 292         protected final String expectedName;
 293         protected final int expectedCount;
 294         protected final boolean visibility;
 295 
 296         /**
 297          * Create an {@code ExpectedAnnotation} from its
 298          * components.  It is usually a better idea to use a {@code
 299          * Builder} to do this.
 300          *
 301          * @param expectedName The expected annotation name.
 302          * @param visibility Whether this annotation should be runtime-visible.
 303          * @param expectedCount The number of annotations that should
 304          *                      be seen.  If 0, this asserts that the
 305          *                      described annotation is not present.
 306          */
 307         public ExpectedAnnotation(String expectedName,
 308                                   boolean visibility,
 309                                   int expectedCount) {
 310             this.expectedName = expectedName;
 311             this.visibility = visibility;
 312             this.expectedCount = expectedCount;
 313         }
 314 
 315         @Override
 316         public String toString() {
 317             final StringBuilder sb = new StringBuilder();
 318             sb.append("Expected ");
 319             sb.append(expectedCount);
 320             sb.append(" annotation ");
 321             sb.append(expectedName);
 322             sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
 323             return sb.toString();
 324         }
 325 
 326         /**
 327          * See if this template matches the given visibility.
 328          *
 329          * @param Whether or not the annotation is visible at runtime.
 330          * @return Whether or not this template matches the visibility.
 331          */
 332         public boolean matchVisibility(boolean visibility) {
 333             return this.visibility == visibility;
 334         }
 335 
 336         /**
 337          * Attempty to match this template against an annotation.  If
 338          * it does match, then the match count for the template will
 339          * be incremented.  Otherwise, nothing will be done.
 340          *
 341          * @param anno The annotation to attempt to match.
 342          */
 343         public void matchAnnotation(ConstantPool cpool,
 344                                     Annotation anno) {
 345             if (checkMatch(cpool, anno)) {
 346                 count++;
 347             }
 348         }
 349 
 350         /**
 351          * Indicate whether an annotation matches this expected
 352          * annotation.
 353          *
 354          * @param ConstantPool The constant pool to use.
 355          * @param anno The annotation to check.
 356          * @return Whether the annotation matches.
 357          */
 358         protected boolean checkMatch(ConstantPool cpool,
 359                                      Annotation anno) {
 360             try {
 361                 return cpool.getUTF8Info(anno.type_index).value.equals("L" + expectedName + ";");
 362             } catch (InvalidIndex | UnexpectedEntry e) {
 363                 return false;
 364             }
 365         }
 366 
 367         /**
 368          * After all matching, check to see if the expected number of
 369          * matches equals the actual number.  If not, then print a
 370          * failure message and return {@code false}.
 371          *
 372          * @return Whether or not the expected number of matched
 373          *         equals the actual number.
 374          */
 375         public boolean check() {
 376             if (count != expectedCount) {
 377                 System.err.println(this + ", but saw " + count);
 378                 return false;
 379             } else {
 380                 return true;
 381             }
 382         }
 383     }
 384 
 385     /**
 386      * An annotation found on a method.
 387      */
 388     public static class ExpectedMethodAnnotation extends ExpectedAnnotation {
 389         protected final String methodname;
 390 
 391         /**
 392          * Create an {@code ExpectedMethodAnnotation} from its
 393          * components.  It is usually a better idea to use a {@code
 394          * Builder} to do this.
 395          *
 396          * @param methodname The expected method name.
 397          * @param expectedName The expected annotation name.
 398          * @param visibility Whether this annotation should be runtime-visible.
 399          * @param expectedCount The number of annotations that should be seen.
 400          */
 401         public ExpectedMethodAnnotation(String methodname,
 402                                         String expectedName,
 403                                         boolean visibility,
 404                                         int expectedCount) {
 405             super(expectedName, visibility, expectedCount);
 406             this.methodname = methodname;
 407         }
 408 
 409         @Override
 410         public String toString() {
 411             final StringBuilder sb = new StringBuilder();
 412             sb.append("Expected ");
 413             sb.append(expectedCount);
 414             sb.append(" annotation ");
 415             sb.append(expectedName);
 416             sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
 417             sb.append(" on method ");
 418             sb.append(methodname);
 419             return sb.toString();
 420         }
 421 
 422         /**
 423          * See if this template applies to a method.
 424          *
 425          * @param methodname The method name to check.
 426          * @return Whether or not this template should apply.
 427          */
 428         public boolean matchMethodName(String methodname) {
 429             return this.methodname.equals(methodname);
 430         }
 431 
 432     }
 433 
 434     /**
 435      * An annotation found on a method parameter.
 436      */
 437     public static class ExpectedParameterAnnotation
 438         extends ExpectedMethodAnnotation {
 439         protected final int index;
 440 
 441         /**
 442          * Create an {@code ExpectedParameterAnnotation} from its
 443          * components.  It is usually a better idea to use a {@code
 444          * Builder} to do this.
 445          *
 446          * @param methodname The expected method name.
 447          * @param index The parameter index.
 448          * @param expectedName The expected annotation name.
 449          * @param visibility Whether this annotation should be runtime-visible.
 450          * @param expectedCount The number of annotations that should be seen.
 451          */
 452         public ExpectedParameterAnnotation(String methodname,
 453                                            int index,
 454                                            String expectedName,
 455                                            boolean visibility,
 456                                            int expectedCount) {
 457             super(methodname, expectedName, visibility, expectedCount);
 458             this.index = index;
 459         }
 460 
 461         @Override
 462         public String toString() {
 463             final StringBuilder sb = new StringBuilder();
 464             sb.append("Expected ");
 465             sb.append(expectedCount);
 466             sb.append(" annotation ");
 467             sb.append(expectedName);
 468             sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
 469             sb.append(" on method ");
 470             sb.append(methodname);
 471             sb.append(" parameter ");
 472             sb.append(index);
 473             return sb.toString();
 474         }
 475 
 476     }
 477 
 478     /**
 479      * An annotation found on a field.
 480      */
 481     public static class ExpectedFieldAnnotation extends ExpectedAnnotation {
 482         private final String fieldname;
 483 
 484         /**
 485          * Create an {@code ExpectedFieldAnnotation} from its
 486          * components.  It is usually a better idea to use a {@code
 487          * Builder} to do this.
 488          *
 489          * @param fieldname The expected field name.
 490          * @param expectedName The expected annotation name.
 491          * @param visibility Whether this annotation should be runtime-visible.
 492          * @param expectedCount The number of annotations that should be seen.
 493          */
 494         public ExpectedFieldAnnotation(String fieldname,
 495                                        String expectedName,
 496                                        boolean visibility,
 497                                        int expectedCount) {
 498             super(expectedName, visibility, expectedCount);
 499             this.fieldname = fieldname;
 500         }
 501 
 502         @Override
 503         public String toString() {
 504             final StringBuilder sb = new StringBuilder();
 505             sb.append("Expected ").append(expectedCount)
 506             .append(" annotation ").append(expectedName)
 507             .append(visibility ? ", runtime visibile " : ", runtime invisibile ")
 508             .append(" on field ").append(fieldname);
 509             return sb.toString();
 510         }
 511 
 512         /**
 513          * See if this template applies to a field.
 514          *
 515          * @param fieldname The field name to check.
 516          * @return Whether or not this template should apply.
 517          */
 518         public boolean matchFieldName(String fieldname) {
 519             return this.fieldname.equals(fieldname);
 520         }
 521 
 522     }
 523 
 524     /**
 525      * An expected type annotation.  This is both a superclass for
 526      * method and field type annotations, as well as a class for type
 527      * annotations on a class.
 528      */
 529     public static class ExpectedTypeAnnotation extends ExpectedAnnotation {
 530         protected final TypeAnnotation.TargetType targetType;
 531         protected final int bound_index;
 532         protected final int parameter_index;
 533         protected final int type_index;
 534         protected final int exception_index;
 535         protected final TypeAnnotation.Position.TypePathEntry[] typePath;
 536 
 537         /**
 538          * Create an {@code ExpectedTypeAnnotation} from its
 539          * components.  It is usually a better idea to use a {@code
 540          * Builder} to do this.
 541          *
 542          * @param expectedName The expected annotation name.
 543          * @param visibility Whether this annotation should be runtime-visible.
 544          * @param expectedCount The number of annotations that should
 545          *                      be seen.  If 0, this asserts that the
 546          *                      described annotation is not present.
 547          * @param targetType The expected target type.
 548          * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
 549          * @param parameter_index The expected parameter index, or
 550          *                        {@code Integer.MIN_VALUE}.
 551          * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
 552          * @param exception_index The expected exception index, or
 553          *                        {@code Integer.MIN_VALUE}.
 554          * @param typePath The expected type path.
 555          */
 556         public ExpectedTypeAnnotation(String expectedName,
 557                                       boolean visibility,
 558                                       int expectedCount,
 559                                       TypeAnnotation.TargetType targetType,
 560                                       int bound_index,
 561                                       int parameter_index,
 562                                       int type_index,
 563                                       int exception_index,
 564                                       TypeAnnotation.Position.TypePathEntry... typePath) {
 565             super(expectedName, visibility, expectedCount);
 566             this.targetType = targetType;
 567             this.bound_index = bound_index;
 568             this.parameter_index = parameter_index;
 569             this.type_index = type_index;
 570             this.exception_index = exception_index;
 571             this.typePath = typePath;
 572         }
 573 
 574         @Override
 575         public String toString() {
 576             final StringBuilder sb = new StringBuilder();
 577             sb.append("Expected ");
 578             sb.append(expectedCount);
 579             sb.append(" annotation ");
 580             sb.append(expectedName);
 581             sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
 582             sb.append(targetType);
 583             sb.append(", bound_index = ");
 584             sb.append(bound_index);
 585             sb.append(", parameter_index = ");
 586             sb.append(parameter_index);
 587             sb.append(", type_index = ");
 588             sb.append(type_index);
 589             sb.append(", exception_index = ");
 590             sb.append(exception_index);
 591             sb.append(", type_path = [");
 592             for(int i = 0; i < typePath.length; i++) {
 593                 if (i != 0) {
 594                     sb.append(", ");
 595                 }
 596                 sb.append(typePath[i]);
 597             }
 598             sb.append("]");
 599             return sb.toString();
 600         }
 601 
 602         @Override
 603         public void matchAnnotation(ConstantPool cpool,
 604                                     Annotation anno) {}
 605 
 606         public void matchAnnotation(TypeAnnotation anno) {
 607             if (checkMatch(anno)) {
 608                 count++;
 609             }
 610         }
 611 
 612         public boolean checkMatch(TypeAnnotation anno) {
 613             boolean matches = checkMatch(anno.constant_pool, anno.annotation);
 614 
 615             matches = matches && anno.position.type == targetType;
 616             matches = matches && anno.position.bound_index == bound_index;
 617             matches = matches && anno.position.parameter_index == parameter_index;
 618             matches = matches && anno.position.type_index == type_index;
 619             matches = matches && anno.position.exception_index == exception_index;
 620             matches = matches && anno.position.location.size() == typePath.length;
 621 
 622             if (matches) {
 623                 int i = 0;
 624                 for(TypeAnnotation.Position.TypePathEntry entry :
 625                          anno.position.location) {
 626                     matches = matches && typePath[i++].equals(entry);
 627                 }
 628             }
 629 
 630             return matches;
 631         }
 632 
 633         /**
 634          * A builder class for creating {@code
 635          * ExpectedTypeAnnotation}s in a more convenient fashion.  The
 636          * constructor for {@code ExpectedTypeAnnotation} takes a
 637          * large number of parameters (by necessity).  This class
 638          * allows users to construct a {@code ExpectedTypeAnnotation}s
 639          * using only the ones they need.
 640          */
 641         public static class Builder {
 642             protected final String expectedName;
 643             protected final boolean visibility;
 644             protected final int expectedCount;
 645             protected final TypeAnnotation.TargetType targetType;
 646             protected int bound_index = Integer.MIN_VALUE;
 647             protected int parameter_index = Integer.MIN_VALUE;
 648             protected int type_index = Integer.MIN_VALUE;
 649             protected int exception_index = Integer.MIN_VALUE;
 650             protected TypeAnnotation.Position.TypePathEntry[] typePath =
 651                 new TypeAnnotation.Position.TypePathEntry[0];
 652 
 653             /**
 654              * Create a {@code Builder} from the mandatory parameters.
 655              *
 656              * @param expectedName The expected annotation name.
 657              * @param targetType The expected target type.
 658              * @param visibility Whether this annotation should be runtime-visible.
 659              * @param expectedCount The number of annotations that should be seen.
 660              */
 661             public Builder(String expectedName,
 662                            TypeAnnotation.TargetType targetType,
 663                            boolean visibility,
 664                            int expectedCount) {
 665                 this.expectedName = expectedName;
 666                 this.visibility = visibility;
 667                 this.expectedCount = expectedCount;
 668                 this.targetType = targetType;
 669             }
 670 
 671             /**
 672              * Create an {@code ExpectedTypeAnnotation} from all
 673              * parameters that have been provided.  The default values
 674              * will be used for those that have not.
 675              *
 676              * @return The cretaed {@code ExpectedTypeAnnotation}.
 677              */
 678             public ExpectedTypeAnnotation build() {
 679                 return new ExpectedTypeAnnotation(expectedName, visibility,
 680                                                   expectedCount, targetType,
 681                                                   bound_index, parameter_index,
 682                                                   type_index, exception_index,
 683                                                   typePath);
 684             }
 685 
 686             /**
 687              * Provide a bound index parameter.
 688              *
 689              * @param bound_index The bound_index value.
 690              */
 691             public Builder setBoundIndex(int bound_index) {
 692                 this.bound_index = bound_index;
 693                 return this;
 694             }
 695 
 696             /**
 697              * Provide a parameter index parameter.
 698              *
 699              * @param bound_index The parameter_index value.
 700              */
 701             public Builder setParameterIndex(int parameter_index) {
 702                 this.parameter_index = parameter_index;
 703                 return this;
 704             }
 705 
 706             /**
 707              * Provide a type index parameter.
 708              *
 709              * @param type_index The type_index value.
 710              */
 711             public Builder setTypeIndex(int type_index) {
 712                 this.type_index = type_index;
 713                 return this;
 714             }
 715 
 716             /**
 717              * Provide an exception index parameter.
 718              *
 719              * @param exception_index The exception_index value.
 720              */
 721             public Builder setExceptionIndex(int exception_index) {
 722                 this.exception_index = exception_index;
 723                 return this;
 724             }
 725 
 726             /**
 727              * Provide a type path parameter.
 728              *
 729              * @param typePath The type path value.
 730              */
 731             public Builder setTypePath(TypeAnnotation.Position.TypePathEntry[] typePath) {
 732                 this.typePath = typePath;
 733                 return this;
 734             }
 735         }
 736     }
 737 
 738     /**
 739      * A type annotation found on a method.
 740      */
 741     public static class ExpectedMethodTypeAnnotation extends ExpectedTypeAnnotation {
 742         private final String methodname;
 743 
 744         /**
 745          * Create an {@code ExpectedMethodTypeAnnotation} from its
 746          * components.  It is usually a better idea to use a {@code
 747          * Builder} to do this.
 748          *
 749          * @param methodname The expected method name.
 750          * @param expectedName The expected annotation name.
 751          * @param visibility Whether this annotation should be runtime-visible.
 752          * @param expectedCount The number of annotations that should be seen.
 753          * @param targetType The expected target type.
 754          * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
 755          * @param parameter_index The expected parameter index, or
 756          *                        {@code Integer.MIN_VALUE}.
 757          * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
 758          * @param exception_index The expected exception index, or
 759          *                        {@code Integer.MIN_VALUE}.
 760          * @param typePath The expected type path.
 761          */
 762         public ExpectedMethodTypeAnnotation(String methodname,
 763                                             String expectedName,
 764                                             boolean visibility,
 765                                             int expectedCount,
 766                                             TypeAnnotation.TargetType targetType,
 767                                             int bound_index,
 768                                             int parameter_index,
 769                                             int type_index,
 770                                             int exception_index,
 771                                             TypeAnnotation.Position.TypePathEntry... typePath) {
 772             super(expectedName, visibility, expectedCount, targetType, bound_index,
 773                   parameter_index, type_index, exception_index, typePath);
 774             this.methodname = methodname;
 775         }
 776 
 777         @Override
 778         public String toString() {
 779             final StringBuilder sb = new StringBuilder();
 780             sb.append("Expected ");
 781             sb.append(expectedCount);
 782             sb.append(" annotation ");
 783             sb.append(expectedName);
 784             sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
 785             sb.append(targetType);
 786             sb.append(", bound_index = ");
 787             sb.append(bound_index);
 788             sb.append(", parameter_index = ");
 789             sb.append(parameter_index);
 790             sb.append(", type_index = ");
 791             sb.append(type_index);
 792             sb.append(", exception_index = ");
 793             sb.append(exception_index);
 794             sb.append(", type_path = [");
 795             for(int i = 0; i < typePath.length; i++) {
 796                 if (i != 0) {
 797                     sb.append(", ");
 798                 }
 799                 sb.append(typePath[i]);
 800             }
 801             sb.append("]");
 802             sb.append(" on method ");
 803             sb.append(methodname);
 804             return sb.toString();
 805         }
 806 
 807         /**
 808          * See if this template applies to a method.
 809          *
 810          * @param methodname The method name to check.
 811          * @return Whether or not this template should apply.
 812          */
 813         public boolean matchMethodName(String methodname) {
 814             return this.methodname.equals(methodname);
 815         }
 816 
 817         /**
 818          * A builder class for creating {@code
 819          * ExpectedMethodTypeAnnotation}s in a more convenient fashion.  The
 820          * constructor for {@code ExpectedMethodTypeAnnotation} takes a
 821          * large number of parameters (by necessity).  This class
 822          * allows users to construct a {@code ExpectedMethodTypeAnnotation}s
 823          * using only the ones they need.
 824          */
 825         public static class Builder extends ExpectedTypeAnnotation.Builder {
 826             protected final String methodname;
 827 
 828             /**
 829              * Create a {@code Builder} from the mandatory parameters.
 830              *
 831              * @param methodname The expected method name.
 832              * @param expectedName The expected annotation name.
 833              * @param targetType The expected target type.
 834              * @param visibility Whether this annotation should be runtime-visible.
 835              * @param expectedCount The number of annotations that should be seen.
 836              */
 837             public Builder(String methodname,
 838                            String expectedName,
 839                            TypeAnnotation.TargetType targetType,
 840                            boolean visibility,
 841                            int expectedCount) {
 842                 super(expectedName, targetType, visibility, expectedCount);
 843                 this.methodname = methodname;
 844             }
 845 
 846             /**
 847              * Create an {@code ExpectedMethodTypeAnnotation} from all
 848              * parameters that have been provided.  The default values
 849              * will be used for those that have not.
 850              *
 851              * @return The created {@code ExpectedMethodTypeAnnotation}.
 852              */
 853             @Override
 854             public ExpectedMethodTypeAnnotation build() {
 855                 return new ExpectedMethodTypeAnnotation(methodname, expectedName,
 856                                                         visibility, expectedCount,
 857                                                         targetType, bound_index,
 858                                                         parameter_index, type_index,
 859                                                         exception_index, typePath);
 860             }
 861         }
 862     }
 863 
 864     /**
 865      * A type annotation found on a field.
 866      */
 867     public static class ExpectedFieldTypeAnnotation extends ExpectedTypeAnnotation {
 868         private final String fieldname;
 869 
 870         /**
 871          * Create an {@code ExpectedFieldTypeAnnotation} from its
 872          * components.  It is usually a better idea to use a {@code
 873          * Builder} to do this.
 874          *
 875          * @param fieldname The expected field name.
 876          * @param expectedName The expected annotation name.
 877          * @param visibility Whether this annotation should be runtime-visible.
 878          * @param expectedCount The number of annotations that should be seen.
 879          * @param targetType The expected target type.
 880          * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
 881          * @param parameter_index The expected parameter index, or
 882          *                        {@code Integer.MIN_VALUE}.
 883          * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
 884          * @param exception_index The expected exception index, or
 885          *                        {@code Integer.MIN_VALUE}.
 886          * @param typePath The expected type path.
 887          */
 888         public ExpectedFieldTypeAnnotation(String fieldname,
 889                                            String expectedName,
 890                                            boolean visibility,
 891                                            int expectedCount,
 892                                            TypeAnnotation.TargetType targetType,
 893                                            int bound_index,
 894                                            int parameter_index,
 895                                            int type_index,
 896                                            int exception_index,
 897                                            TypeAnnotation.Position.TypePathEntry... typePath) {
 898             super(expectedName, visibility, expectedCount, targetType, bound_index,
 899                   parameter_index, type_index, exception_index, typePath);
 900             this.fieldname = fieldname;
 901         }
 902 
 903         @Override
 904         public String toString() {
 905             final StringBuilder sb = new StringBuilder();
 906             sb.append("Expected ").append(expectedCount)
 907             .append(" annotation ").append(expectedName)
 908             .append(visibility ? ", runtime visibile " : ", runtime invisibile ")
 909             .append(targetType)
 910             .append(", bound_index = ").append(bound_index)
 911             .append(", parameter_index = ").append(parameter_index)
 912             .append(", type_index = ").append(type_index)
 913             .append(", exception_index = ").append(exception_index)
 914             .append(", type_path = [");
 915 
 916             for(int i = 0; i < typePath.length; i++) {
 917                 if (i != 0) {
 918                     sb.append(", ");
 919                 }
 920                 sb.append(typePath[i]);
 921             }
 922             sb.append("]")
 923             .append(" on field ").append(fieldname);
 924             return sb.toString();
 925         }
 926 
 927         /**
 928          * See if this template applies to a field.
 929          *
 930          * @param fieldname The field name to check.
 931          * @return Whether or not this template should apply.
 932          */
 933         public boolean matchFieldName(String fieldname) {
 934             return this.fieldname.equals(fieldname);
 935         }
 936 
 937         /**
 938          * A builder class for creating {@code
 939          * ExpectedFieldTypeAnnotation}s in a more convenient fashion.  The
 940          * constructor for {@code ExpectedFieldTypeAnnotation} takes a
 941          * large number of parameters (by necessity).  This class
 942          * allows users to construct a {@code ExpectedFieldTypeAnnotation}s
 943          * using only the ones they need.
 944          */
 945         public static class Builder extends ExpectedTypeAnnotation.Builder {
 946             protected final String fieldname;
 947 
 948             /**
 949              * Create a {@code Builder} from the mandatory parameters.
 950              *
 951              * @param fieldname The expected field name.
 952              * @param expectedName The expected annotation name.
 953              * @param targetType The expected target type.
 954              * @param visibility Whether this annotation should be runtime-visible.
 955              * @param expectedCount The number of annotations that should be seen.
 956              */
 957             public Builder(String fieldname,
 958                            String expectedName,
 959                            TypeAnnotation.TargetType targetType,
 960                            boolean visibility,
 961                            int expectedCount) {
 962                 super(expectedName, targetType, visibility, expectedCount);
 963                 this.fieldname = fieldname;
 964             }
 965 
 966             /**
 967              * Create an {@code ExpectedFieldTypeAnnotation} from all
 968              * parameters that have been provided.  The default values
 969              * will be used for those that have not.
 970              *
 971              * @return The created {@code ExpectedFieldTypeAnnotation}.
 972              */
 973             @Override
 974             public ExpectedFieldTypeAnnotation build() {
 975                 return new ExpectedFieldTypeAnnotation(fieldname, expectedName,
 976                                                        visibility, expectedCount,
 977                                                        targetType, bound_index,
 978                                                        parameter_index, type_index,
 979                                                        exception_index, typePath);
 980             }
 981         }
 982     }
 983 
 984     private void matchClassAnnotation(ClassFile classfile,
 985                                       ExpectedAnnotation expected)
 986         throws ConstantPoolException {
 987         for(Attribute attr : classfile.attributes) {
 988             attr.accept(annoMatcher(classfile.constant_pool), expected);
 989         }
 990     }
 991 
 992     private void matchMethodAnnotation(ClassFile classfile,
 993                                        ExpectedMethodAnnotation expected)
 994         throws ConstantPoolException {
 995         for(Method meth : classfile.methods) {
 996             if (expected.matchMethodName(meth.getName(classfile.constant_pool))) {
 997                 for(Attribute attr : meth.attributes) {
 998                     attr.accept(annoMatcher(classfile.constant_pool), expected);
 999                 }
1000             }
1001         }
1002     }
1003 
1004     private void matchParameterAnnotation(ClassFile classfile,
1005                                           ExpectedParameterAnnotation expected)
1006         throws ConstantPoolException {
1007         for(Method meth : classfile.methods) {
1008             if (expected.matchMethodName(meth.getName(classfile.constant_pool))) {
1009                 for(Attribute attr : meth.attributes) {
1010                     attr.accept(paramMatcher(classfile.constant_pool), expected);
1011                 }
1012             }
1013         }
1014     }
1015 
1016     private void matchFieldAnnotation(ClassFile classfile,
1017                                       ExpectedFieldAnnotation expected)
1018         throws ConstantPoolException {
1019         for(Field field : classfile.fields) {
1020             if (expected.matchFieldName(field.getName(classfile.constant_pool))) {
1021                 for(Attribute attr : field.attributes) {
1022                     attr.accept(annoMatcher(classfile.constant_pool), expected);
1023                 }
1024             }
1025         }
1026     }
1027 
1028     private void matchClassTypeAnnotation(ClassFile classfile,
1029                                           ExpectedTypeAnnotation expected)
1030         throws ConstantPoolException {
1031         for(Attribute attr : classfile.attributes) {
1032             attr.accept(typeAnnoMatcher, expected);
1033         }
1034     }
1035 
1036     private void matchMethodTypeAnnotation(ClassFile classfile,
1037                                            ExpectedMethodTypeAnnotation expected)
1038         throws ConstantPoolException {
1039         for(Method meth : classfile.methods) {
1040             if (expected.matchMethodName(meth.getName(classfile.constant_pool))) {
1041                 for(Attribute attr : meth.attributes) {
1042                     attr.accept(typeAnnoMatcher, expected);
1043                 }
1044             }
1045         }
1046     }
1047 
1048     private void matchFieldTypeAnnotation(ClassFile classfile,
1049                                           ExpectedFieldTypeAnnotation expected)
1050         throws ConstantPoolException {
1051         for(Field field : classfile.fields) {
1052             if (expected.matchFieldName(field.getName(classfile.constant_pool))) {
1053                 for(Attribute attr : field.attributes) {
1054                     attr.accept(typeAnnoMatcher, expected);
1055                 }
1056             }
1057         }
1058     }
1059 
1060     private void matchClassAnnotations(ClassFile classfile,
1061                                        ExpectedAnnotation[] expected)
1062         throws ConstantPoolException {
1063         for(ExpectedAnnotation one : expected) {
1064             matchClassAnnotation(classfile, one);
1065         }
1066     }
1067 
1068     private void matchMethodAnnotations(ClassFile classfile,
1069                                         ExpectedMethodAnnotation[] expected)
1070         throws ConstantPoolException {
1071         for(ExpectedMethodAnnotation one : expected) {
1072             matchMethodAnnotation(classfile, one);
1073         }
1074     }
1075 
1076     private void matchParameterAnnotations(ClassFile classfile,
1077                                            ExpectedParameterAnnotation[] expected)
1078         throws ConstantPoolException {
1079         for(ExpectedParameterAnnotation one : expected) {
1080             matchParameterAnnotation(classfile, one);
1081         }
1082     }
1083 
1084     private void matchFieldAnnotations(ClassFile classfile,
1085                                        ExpectedFieldAnnotation[] expected)
1086         throws ConstantPoolException {
1087         for(ExpectedFieldAnnotation one : expected) {
1088             matchFieldAnnotation(classfile, one);
1089         }
1090     }
1091 
1092     private void matchClassTypeAnnotations(ClassFile classfile,
1093                                            ExpectedTypeAnnotation[] expected)
1094         throws ConstantPoolException {
1095         for(ExpectedTypeAnnotation one : expected) {
1096             matchClassTypeAnnotation(classfile, one);
1097         }
1098     }
1099 
1100     private void matchMethodTypeAnnotations(ClassFile classfile,
1101                                             ExpectedMethodTypeAnnotation[] expected)
1102         throws ConstantPoolException {
1103         for(ExpectedMethodTypeAnnotation one : expected) {
1104             matchMethodTypeAnnotation(classfile, one);
1105         }
1106     }
1107 
1108     private void matchFieldTypeAnnotations(ClassFile classfile,
1109                                            ExpectedFieldTypeAnnotation[] expected)
1110         throws ConstantPoolException {
1111         for(ExpectedFieldTypeAnnotation one : expected) {
1112             matchFieldTypeAnnotation(classfile, one);
1113         }
1114     }
1115 
1116     /**
1117      * Run a template on a single {@code ClassFile}.
1118      *
1119      * @param classfile The {@code ClassFile} on which to run tests.
1120      * @param expected The expected annotation template.
1121      */
1122     public void run(ClassFile classfile,
1123                     Expected... expected)
1124             throws ConstantPoolException {
1125         run(new ClassFile[] { classfile }, expected);
1126     }
1127 
1128     /**
1129      * Run a template on multiple {@code ClassFile}s.
1130      *
1131      * @param classfile The {@code ClassFile}s on which to run tests.
1132      * @param expected The expected annotation template.
1133      */
1134     public void run(ClassFile[] classfiles,
1135                     Expected... expected)
1136             throws ConstantPoolException {
1137         for(ClassFile classfile : classfiles) {
1138             for(Expected one : expected) {
1139                 if (one.matchClassName(classfile.getName())) {
1140                     if (one.classAnnos != null)
1141                         matchClassAnnotations(classfile, one.classAnnos);
1142                     if (one.methodAnnos != null)
1143                         matchMethodAnnotations(classfile, one.methodAnnos);
1144                     if (one.methodParamAnnos != null)
1145                         matchParameterAnnotations(classfile, one.methodParamAnnos);
1146                     if (one.fieldAnnos != null)
1147                         matchFieldAnnotations(classfile, one.fieldAnnos);
1148                     if (one.classTypeAnnos != null)
1149                         matchClassTypeAnnotations(classfile, one.classTypeAnnos);
1150                     if (one.methodTypeAnnos != null)
1151                         matchMethodTypeAnnotations(classfile, one.methodTypeAnnos);
1152                     if (one.fieldTypeAnnos != null)
1153                         matchFieldTypeAnnotations(classfile, one.fieldTypeAnnos);
1154                 }
1155             }
1156         }
1157         int count = 0;
1158         for (Expected one : expected) {
1159             count += one.check();
1160         }
1161 
1162         if (count != 0) {
1163             throw new RuntimeException(count + " errors occurred in test");
1164         }
1165     }
1166 
1167     /**
1168      * Get a {@code ClassFile} from its file name.
1169      *
1170      * @param name The class' file name.
1171      * @param host A class in the same package.
1172      * @return The {@code ClassFile}
1173      */
1174     public static ClassFile getClassFile(String name,
1175                                          Class<?> host)
1176         throws IOException, ConstantPoolException {
1177         final URL url = host.getResource(name);
1178         try (InputStream in = url.openStream()) {
1179             return ClassFile.read(in);
1180         }
1181     }
1182 
1183     private static class AbstractAttributeVisitor<T> implements Attribute.Visitor<Void, T> {
1184 
1185         @Override
1186         public Void visitDefault(DefaultAttribute attr, T p) {
1187             return null;
1188         }
1189 
1190         @Override
1191         public Void visitAnnotationDefault(AnnotationDefault_attribute attr, T p) {
1192             return null;
1193         }
1194 
1195         @Override
1196         public Void visitBootstrapMethods(BootstrapMethods_attribute attr, T p) {
1197             return null;
1198         }
1199 
1200         @Override
1201         public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, T p) {
1202             return null;
1203         }
1204 
1205         @Override
1206         public Void visitCode(Code_attribute attr, T p) {
1207             return null;
1208         }
1209 
1210         @Override
1211         public Void visitCompilationID(CompilationID_attribute attr, T p) {
1212             return null;
1213         }
1214 
1215         @Override
1216         public Void visitConstantValue(ConstantValue_attribute attr, T p) {
1217             return null;
1218         }
1219 
1220         @Override
1221         public Void visitDeprecated(Deprecated_attribute attr, T p) {
1222             return null;
1223         }
1224 
1225         @Override
1226         public Void visitEnclosingMethod(EnclosingMethod_attribute attr, T p) {
1227             return null;
1228         }
1229 
1230         @Override
1231         public Void visitExceptions(Exceptions_attribute attr, T p) {
1232             return null;
1233         }
1234 
1235         @Override
1236         public Void visitInnerClasses(InnerClasses_attribute attr, T p) {
1237             return null;
1238         }
1239 
1240         @Override
1241         public Void visitLineNumberTable(LineNumberTable_attribute attr, T p) {
1242             return null;
1243         }
1244 
1245         @Override
1246         public Void visitLocalVariableTable(LocalVariableTable_attribute attr, T p) {
1247             return null;
1248         }
1249 
1250         @Override
1251         public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, T p) {
1252             return null;
1253         }
1254 
1255         @Override
1256           public Void visitNestHost(NestHost_attribute attr, T p) {
1257             return null;
1258         }
1259 
1260         @Override
1261         public Void visitMethodParameters(MethodParameters_attribute attr, T p) {
1262             return null;
1263         }
1264 
1265         @Override
1266         public Void visitModule(Module_attribute attr, T p) {
1267             return null;
1268         }
1269 
1270         @Override
1271         public Void visitModuleHashes(ModuleHashes_attribute attr, T p) {
1272             return null;
1273         }
1274 
1275         @Override
1276         public Void visitModuleMainClass(ModuleMainClass_attribute attr, T p) {
1277             return null;
1278         }
1279 
1280         @Override
1281         public Void visitModulePackages(ModulePackages_attribute attr, T p) {
1282             return null;
1283         }
1284 
1285         @Override
1286         public Void visitModuleResolution(ModuleResolution_attribute attr, T p) {
1287             return null;
1288         }
1289 
1290         @Override
1291         public Void visitModuleTarget(ModuleTarget_attribute attr, T p) {
1292             return null;
1293         }
1294 
1295         @Override
1296         public Void visitNestMembers(NestMembers_attribute attr, T p) {
1297             return null;
1298         }
1299 
1300         @Override
1301         public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, T p) {
1302             return null;
1303         }
1304 
1305         @Override
1306         public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, T p) {
1307             return null;
1308         }
1309 
1310         @Override
1311         public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, T p) {
1312             return null;
1313         }
1314 
1315         @Override
1316         public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, T p) {
1317             return null;
1318         }
1319 
1320         @Override
1321         public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, T p) {
1322             return null;
1323         }
1324 
1325         @Override
1326         public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, T p) {
1327             return null;
1328         }
1329 
1330         @Override
1331         public Void visitSignature(Signature_attribute attr, T p) {
1332             return null;
1333         }
1334 
1335         @Override
1336         public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, T p) {
1337             return null;
1338         }
1339 
1340         @Override
1341         public Void visitSourceFile(SourceFile_attribute attr, T p) {
1342             return null;
1343         }
1344 
1345         @Override
1346         public Void visitSourceID(SourceID_attribute attr, T p) {
1347             return null;
1348         }
1349 
1350         @Override
1351         public Void visitStackMap(StackMap_attribute attr, T p) {
1352             return null;
1353         }
1354 
1355         @Override
1356         public Void visitStackMapTable(StackMapTable_attribute attr, T p) {
1357             return null;
1358         }
1359 
1360         @Override
1361         public Void visitSynthetic(Synthetic_attribute attr, T p) {
1362             return null;
1363         }
1364     }
1365 
1366     private static final Attribute.Visitor<Void, ExpectedTypeAnnotation> typeAnnoMatcher
1367             = new AbstractAttributeVisitor<ExpectedTypeAnnotation>() {
1368 
1369                 @Override
1370                 public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr,
1371                         ExpectedTypeAnnotation expected) {
1372                     if (expected.matchVisibility(true)) {
1373                         for (TypeAnnotation anno : attr.annotations) {
1374                             expected.matchAnnotation(anno);
1375                         }
1376                     }
1377 
1378                     return null;
1379                 }
1380 
1381                 @Override
1382                 public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr,
1383                         ExpectedTypeAnnotation expected) {
1384                     if (expected.matchVisibility(false)) {
1385                         for (TypeAnnotation anno : attr.annotations) {
1386                             expected.matchAnnotation(anno);
1387                         }
1388                     }
1389 
1390                     return null;
1391                 }
1392             };
1393 
1394     private static Attribute.Visitor<Void, ExpectedAnnotation> annoMatcher(ConstantPool cpool) {
1395         return new AbstractAttributeVisitor<ExpectedAnnotation>() {
1396 
1397             @Override
1398             public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr,
1399                                                        ExpectedAnnotation expected) {
1400                 if (expected.matchVisibility(true)) {
1401                     for(Annotation anno : attr.annotations) {
1402                         expected.matchAnnotation(cpool, anno);
1403                     }
1404                 }
1405 
1406                 return null;
1407             }
1408 
1409             @Override
1410             public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr,
1411                                                          ExpectedAnnotation expected) {
1412                 if (expected.matchVisibility(false)) {
1413                     for(Annotation anno : attr.annotations) {
1414                         expected.matchAnnotation(cpool, anno);
1415                     }
1416                 }
1417 
1418                 return null;
1419             }
1420         };
1421     }
1422 
1423     private static Attribute.Visitor<Void, ExpectedParameterAnnotation> paramMatcher(ConstantPool cpool) {
1424         return new AbstractAttributeVisitor<ExpectedParameterAnnotation>() {
1425 
1426             @Override
1427             public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr,
1428                                                                 ExpectedParameterAnnotation expected) {
1429                 if (expected.matchVisibility(true)) {
1430                     if (expected.index < attr.parameter_annotations.length) {
1431                         for(Annotation anno :
1432                                 attr.parameter_annotations[expected.index]) {
1433                             expected.matchAnnotation(cpool, anno);
1434                         }
1435                     }
1436                 }
1437 
1438                 return null;
1439             }
1440 
1441             @Override
1442             public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr,
1443                                                                   ExpectedParameterAnnotation expected) {
1444                 if (expected.matchVisibility(false)) {
1445                     if (expected.index < attr.parameter_annotations.length) {
1446                         for(Annotation anno :
1447                                 attr.parameter_annotations[expected.index]) {
1448                             expected.matchAnnotation(cpool, anno);
1449                         }
1450                     }
1451                 }
1452 
1453                 return null;
1454             }
1455         };
1456     }
1457 }