ClassfileInspector.java revision 3294:9adfb22ff08f
1/*
2 * Copyright (c) 2012, 2015, 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
24package annotations.classfile;
25
26import java.io.*;
27import java.net.URL;
28
29import com.sun.tools.classfile.*;
30import com.sun.tools.classfile.ConstantPool.InvalidIndex;
31import 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 */
40public 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 visitBootstrapMethods(BootstrapMethods_attribute attr, T p) {
1187            return null;
1188        }
1189
1190        @Override
1191        public Void visitConcealedPackages(ConcealedPackages_attribute attr, T p) {
1192            return null;
1193        }
1194
1195        @Override
1196        public Void visitDefault(DefaultAttribute attr, T p) {
1197            return null;
1198        }
1199
1200        @Override
1201        public Void visitAnnotationDefault(AnnotationDefault_attribute attr, T p) {
1202            return null;
1203        }
1204
1205        @Override
1206        public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, T p) {
1207            return null;
1208        }
1209
1210        @Override
1211        public Void visitCode(Code_attribute attr, T p) {
1212            return null;
1213        }
1214
1215        @Override
1216        public Void visitCompilationID(CompilationID_attribute attr, T p) {
1217            return null;
1218        }
1219
1220        @Override
1221        public Void visitConstantValue(ConstantValue_attribute attr, T p) {
1222            return null;
1223        }
1224
1225        @Override
1226        public Void visitDeprecated(Deprecated_attribute attr, T p) {
1227            return null;
1228        }
1229
1230        @Override
1231        public Void visitEnclosingMethod(EnclosingMethod_attribute attr, T p) {
1232            return null;
1233        }
1234
1235        @Override
1236        public Void visitExceptions(Exceptions_attribute attr, T p) {
1237            return null;
1238        }
1239
1240        @Override
1241        public Void visitHashes(Hashes_attribute attr, T p) {
1242            return null;
1243        }
1244
1245        @Override
1246        public Void visitInnerClasses(InnerClasses_attribute attr, T p) {
1247            return null;
1248        }
1249
1250        @Override
1251        public Void visitLineNumberTable(LineNumberTable_attribute attr, T p) {
1252            return null;
1253        }
1254
1255        @Override
1256        public Void visitLocalVariableTable(LocalVariableTable_attribute attr, T p) {
1257            return null;
1258        }
1259
1260        @Override
1261        public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, T p) {
1262            return null;
1263        }
1264
1265        @Override
1266        public Void visitMainClass(MainClass_attribute attr, T p) {
1267            return null;
1268        }
1269
1270        @Override
1271        public Void visitMethodParameters(MethodParameters_attribute attr, T p) {
1272            return null;
1273        }
1274
1275        @Override
1276        public Void visitModule(Module_attribute attr, T p) {
1277            return null;
1278        }
1279
1280        @Override
1281        public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, T p) {
1282            return null;
1283        }
1284
1285        @Override
1286        public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, T p) {
1287            return null;
1288        }
1289
1290        @Override
1291        public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, T p) {
1292            return null;
1293        }
1294
1295        @Override
1296        public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, T p) {
1297            return null;
1298        }
1299
1300        @Override
1301        public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, T p) {
1302            return null;
1303        }
1304
1305        @Override
1306        public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, T p) {
1307            return null;
1308        }
1309
1310        @Override
1311        public Void visitSignature(Signature_attribute attr, T p) {
1312            return null;
1313        }
1314
1315        @Override
1316        public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, T p) {
1317            return null;
1318        }
1319
1320        @Override
1321        public Void visitSourceFile(SourceFile_attribute attr, T p) {
1322            return null;
1323        }
1324
1325        @Override
1326        public Void visitSourceID(SourceID_attribute attr, T p) {
1327            return null;
1328        }
1329
1330        @Override
1331        public Void visitStackMap(StackMap_attribute attr, T p) {
1332            return null;
1333        }
1334
1335        @Override
1336        public Void visitStackMapTable(StackMapTable_attribute attr, T p) {
1337            return null;
1338        }
1339
1340        @Override
1341        public Void visitSynthetic(Synthetic_attribute attr, T p) {
1342            return null;
1343        }
1344
1345        @Override
1346        public Void visitTargetPlatform(TargetPlatform_attribute attr, T p) {
1347            return null;
1348        }
1349
1350        @Override
1351        public Void visitVersion(Version_attribute attr, T p) {
1352            return null;
1353        }
1354
1355    }
1356
1357    private static final Attribute.Visitor<Void, ExpectedTypeAnnotation> typeAnnoMatcher
1358            = new AbstractAttributeVisitor<ExpectedTypeAnnotation>() {
1359
1360                @Override
1361                public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr,
1362                        ExpectedTypeAnnotation expected) {
1363                    if (expected.matchVisibility(true)) {
1364                        for (TypeAnnotation anno : attr.annotations) {
1365                            expected.matchAnnotation(anno);
1366                        }
1367                    }
1368
1369                    return null;
1370                }
1371
1372                @Override
1373                public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr,
1374                        ExpectedTypeAnnotation expected) {
1375                    if (expected.matchVisibility(false)) {
1376                        for (TypeAnnotation anno : attr.annotations) {
1377                            expected.matchAnnotation(anno);
1378                        }
1379                    }
1380
1381                    return null;
1382                }
1383            };
1384
1385    private static Attribute.Visitor<Void, ExpectedAnnotation> annoMatcher(ConstantPool cpool) {
1386        return new AbstractAttributeVisitor<ExpectedAnnotation>() {
1387
1388            @Override
1389            public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr,
1390                                                       ExpectedAnnotation expected) {
1391                if (expected.matchVisibility(true)) {
1392                    for(Annotation anno : attr.annotations) {
1393                        expected.matchAnnotation(cpool, anno);
1394                    }
1395                }
1396
1397                return null;
1398            }
1399
1400            @Override
1401            public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr,
1402                                                         ExpectedAnnotation expected) {
1403                if (expected.matchVisibility(false)) {
1404                    for(Annotation anno : attr.annotations) {
1405                        expected.matchAnnotation(cpool, anno);
1406                    }
1407                }
1408
1409                return null;
1410            }
1411        };
1412    }
1413
1414    private static Attribute.Visitor<Void, ExpectedParameterAnnotation> paramMatcher(ConstantPool cpool) {
1415        return new AbstractAttributeVisitor<ExpectedParameterAnnotation>() {
1416
1417            @Override
1418            public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr,
1419                                                                ExpectedParameterAnnotation expected) {
1420                if (expected.matchVisibility(true)) {
1421                    if (expected.index < attr.parameter_annotations.length) {
1422                        for(Annotation anno :
1423                                attr.parameter_annotations[expected.index]) {
1424                            expected.matchAnnotation(cpool, anno);
1425                        }
1426                    }
1427                }
1428
1429                return null;
1430            }
1431
1432            @Override
1433            public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr,
1434                                                                  ExpectedParameterAnnotation expected) {
1435                if (expected.matchVisibility(false)) {
1436                    if (expected.index < attr.parameter_annotations.length) {
1437                        for(Annotation anno :
1438                                attr.parameter_annotations[expected.index]) {
1439                            expected.matchAnnotation(cpool, anno);
1440                        }
1441                    }
1442                }
1443
1444                return null;
1445            }
1446        };
1447    }
1448}
1449