ClassfileInspector.java revision 3792:d516975e8110
1251875Speter/*
2251875Speter * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
3251875Speter * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4251875Speter *
5251875Speter * This code is free software; you can redistribute it and/or modify it
6251875Speter * under the terms of the GNU General Public License version 2 only, as
7251875Speter * published by the Free Software Foundation.
8251875Speter *
9251875Speter * This code is distributed in the hope that it will be useful, but WITHOUT
10251875Speter * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11251875Speter * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12251875Speter * version 2 for more details (a copy is included in the LICENSE file that
13251875Speter * accompanied this code).
14251875Speter *
15251875Speter * You should have received a copy of the GNU General Public License version
16251875Speter * 2 along with this work; if not, write to the Free Software Foundation,
17251875Speter * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18251875Speter *
19251875Speter * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20251875Speter * or visit www.oracle.com if you need additional information or have any
21251875Speter * questions.
22251875Speter */
23251875Speter
24251875Speterpackage annotations.classfile;
25251875Speter
26251875Speterimport java.io.*;
27251875Speterimport java.net.URL;
28251875Speter
29251875Speterimport com.sun.tools.classfile.*;
30251875Speterimport com.sun.tools.classfile.ConstantPool.InvalidIndex;
31251875Speterimport com.sun.tools.classfile.ConstantPool.UnexpectedEntry;
32251875Speter
33251875Speter/**
34251875Speter * A class providing utilities for writing tests that inspect class
35251875Speter * files directly, looking for specific type annotations.
36251875Speter *
37251875Speter * Note: this framework does not currently handle repeating
38251875Speter * annotations.
39251875Speter */
40251875Speterpublic class ClassfileInspector {
41251875Speter
42251875Speter    /**
43251875Speter     * A group of expected annotations to be found in a given class.
44251875Speter     * If the class name is null, then the template will be applied to
45251875Speter     * every class.
46251875Speter     */
47251875Speter    public static class Expected {
48251875Speter        /**
49251875Speter         * The name of the class.  If {@code null} this template will
50251875Speter         * apply to every class; otherwise, it will only be applied to
51251875Speter         * the named class.
52251875Speter         */
53251875Speter        public final String classname;
54251875Speter
55251875Speter        /**
56251875Speter         * The expected class annotations.  These will be checked
57251875Speter         * against the class' attributes.
58251875Speter         */
59251875Speter        public final ExpectedAnnotation[] classAnnos;
60251875Speter
61251875Speter        /**
62251875Speter         * The expected method annotations.  These will be checked
63251875Speter         * against all methods in the class.
64251875Speter         */
65251875Speter        public final ExpectedMethodAnnotation[] methodAnnos;
66251875Speter
67251875Speter        /**
68251875Speter         * The expected method parameter annotations.  These will be checked
69251875Speter         * against all methods in the class.
70251875Speter         */
71251875Speter        public final ExpectedParameterAnnotation[] methodParamAnnos;
72251875Speter
73251875Speter        /**
74251875Speter         * The expected field type annotations.  These will be checked
75251875Speter         * against all fields in the class.
76251875Speter         */
77251875Speter        public final ExpectedFieldAnnotation[] fieldAnnos;
78251875Speter
79251875Speter        /**
80251875Speter         * The expected class type annotations.  These will be checked
81251875Speter         * against the class' attributes.
82251875Speter         */
83251875Speter        public final ExpectedTypeAnnotation[] classTypeAnnos;
84251875Speter
85251875Speter        /**
86251875Speter         * The expected method type annotations.  These will be checked
87251875Speter         * against all methods in the class.
88251875Speter         */
89251875Speter        public final ExpectedMethodTypeAnnotation[] methodTypeAnnos;
90251875Speter
91251875Speter        /**
92251875Speter         * The expected field type annotations.  These will be checked
93251875Speter         * against all fields in the class.
94251875Speter         */
95251875Speter        public final ExpectedFieldTypeAnnotation[] fieldTypeAnnos;
96251875Speter
97251875Speter        /**
98251875Speter         * Create an {@code Expected} from all components.
99251875Speter         *
100251875Speter         * @param classname The name of the class to match, or {@code
101251875Speter         *                  null} for all classes.
102251875Speter         * @param classAnnos The expected class annotations.
103251875Speter         * @param methodAnnos The expected method annotations.
104251875Speter         * @param methodParamAnnos The expected method parameter annotations.
105251875Speter         * @param fieldAnnos The expected field annotations.
106251875Speter         * @param classTypeAnnos The expected class type annotations.
107251875Speter         * @param methodTypeAnnos The expected method type annotations.
108251875Speter         * @param fieldTypeAnnos The expected field type annotations.
109251875Speter         */
110251875Speter        public Expected(String classname,
111251875Speter                        ExpectedAnnotation[] classAnnos,
112251875Speter                        ExpectedMethodAnnotation[] methodAnnos,
113251875Speter                        ExpectedParameterAnnotation[] methodParamAnnos,
114251875Speter                        ExpectedFieldAnnotation[] fieldAnnos,
115251875Speter                        ExpectedTypeAnnotation[] classTypeAnnos,
116251875Speter                        ExpectedMethodTypeAnnotation[] methodTypeAnnos,
117251875Speter                        ExpectedFieldTypeAnnotation[] fieldTypeAnnos) {
118251875Speter            this.classname = classname;
119251875Speter            this.classAnnos = classAnnos;
120251875Speter            this.methodAnnos = methodAnnos;
121251875Speter            this.methodParamAnnos = methodParamAnnos;
122251875Speter            this.fieldAnnos = fieldAnnos;
123251875Speter            this.classTypeAnnos = classTypeAnnos;
124251875Speter            this.methodTypeAnnos = methodTypeAnnos;
125251875Speter            this.fieldTypeAnnos = fieldTypeAnnos;
126251875Speter        }
127251875Speter
128251875Speter        /**
129251875Speter         * Create an {@code Expected} from regular annotation components.
130251875Speter         *
131251875Speter         * @param classname The name of the class to match, or {@code
132251875Speter         *                  null} for all classes.
133251875Speter         * @param classAnnos The expected class annotations.
134251875Speter         * @param methodAnnos The expected method annotations.
135251875Speter         * @param methodParamAnnos The expected method parameter annotations.
136251875Speter         * @param fieldAnnos The expected field annotations.
137251875Speter         */
138251875Speter        public Expected(String classname,
139251875Speter                        ExpectedAnnotation[] classAnnos,
140251875Speter                        ExpectedMethodAnnotation[] methodAnnos,
141251875Speter                        ExpectedParameterAnnotation[] methodParamAnnos,
142251875Speter                        ExpectedFieldAnnotation[] fieldAnnos) {
143251875Speter            this(classname, classAnnos, methodAnnos, methodParamAnnos,
144251875Speter                 fieldAnnos, null, null, null);
145251875Speter        }
146251875Speter
147251875Speter        /**
148251875Speter         * Create an {@code Expected} from type annotation components.
149251875Speter         *
150251875Speter         * @param classname The name of the class to match, or {@code
151251875Speter         *                  null} for all classes.
152251875Speter         * @param classTypeAnnos The expected class type annotations.
153251875Speter         * @param methodTypeAnnos The expected method type annotations.
154251875Speter         * @param fieldTypeAnnos The expected field type annotations.
155251875Speter         */
156251875Speter        public Expected(String classname,
157251875Speter                        ExpectedTypeAnnotation[] classTypeAnnos,
158251875Speter                        ExpectedMethodTypeAnnotation[] methodTypeAnnos,
159251875Speter                        ExpectedFieldTypeAnnotation[] fieldTypeAnnos) {
160251875Speter            this(classname, null, null, null, null,
161251875Speter                 classTypeAnnos, methodTypeAnnos, fieldTypeAnnos);
162251875Speter        }
163251875Speter
164251875Speter        @Override
165251875Speter        public String toString() {
166251875Speter            final StringBuilder sb = new StringBuilder();
167251875Speter            final String newline = System.lineSeparator();
168251875Speter            sb.append("Expected on class ").append(classname);
169251875Speter            if (null != classAnnos) {
170251875Speter                sb.append(newline).append("Class annotations:").append(newline);
171251875Speter                for(ExpectedAnnotation anno : classAnnos) {
172251875Speter                    sb.append(anno).append(newline);
173251875Speter                }
174251875Speter            }
175251875Speter            if (null != methodAnnos) {
176251875Speter                sb.append(newline).append("Method annotations:").append(newline);
177253734Speter                for(ExpectedAnnotation anno : methodAnnos) {
178253734Speter                    sb.append(anno).append(newline);
179253734Speter                }
180253734Speter            }
181253734Speter            if (null != methodParamAnnos) {
182253734Speter                sb.append(newline).append("Method param annotations:").append(newline);
183253734Speter                for(ExpectedAnnotation anno : methodParamAnnos) {
184253734Speter                    sb.append(anno).append(newline);
185251875Speter                }
186251875Speter            }
187251875Speter            if (null != fieldAnnos) {
188251875Speter                sb.append(newline).append("Field annotations:").append(newline);
189251875Speter                for(ExpectedAnnotation anno : fieldAnnos) {
190251875Speter                    sb.append(anno).append(newline);
191251875Speter                }
192251875Speter            }
193251875Speter            if (null != classTypeAnnos) {
194251875Speter                sb.append(newline).append("Class type annotations:").append(newline);
195251875Speter                for(ExpectedAnnotation anno : classTypeAnnos) {
196251875Speter                    sb.append(anno).append(newline);
197251875Speter                }
198251875Speter            }
199251875Speter            if (null != methodTypeAnnos) {
200251875Speter                sb.append(newline).append("Method type annotations:").append(newline);
201251875Speter                for(ExpectedAnnotation anno : methodTypeAnnos) {
202251875Speter                    sb.append(anno).append(newline);
203251875Speter                }
204251875Speter            }
205251875Speter            if (null != fieldTypeAnnos) {
206251875Speter                sb.append(newline).append("Field type annotations:").append(newline);
207251875Speter                for(ExpectedAnnotation anno : fieldTypeAnnos) {
208251875Speter                    sb.append(anno).append(newline);
209251875Speter                }
210251875Speter            }
211251875Speter            return sb.toString();
212251875Speter        }
213251875Speter
214251875Speter        /**
215251875Speter         * See if this template applies to a class.
216251875Speter         *
217251875Speter         * @param classname The classname to check.
218251875Speter         * @return Whether or not this template should apply.
219251875Speter         */
220251875Speter        public boolean matchClassName(String classname) {
221251875Speter            return this.classname == null || this.classname.equals(classname);
222251875Speter        }
223251875Speter
224251875Speter        /**
225251875Speter         * After applying the template to all classes, check to see if
226251875Speter         * any of the expected annotations weren't matched.
227251875Speter         *
228251875Speter         * @return The number of missed matches.
229251875Speter         */
230251875Speter        public int check() {
231251875Speter            int count = 0;
232251875Speter            if (classAnnos != null) {
233251875Speter                for(ExpectedAnnotation expected : classAnnos) {
234251875Speter                    if (!expected.check()) {
235251875Speter                        count++;
236251875Speter                    }
237251875Speter                }
238251875Speter            }
239251875Speter            if (methodAnnos != null) {
240251875Speter                for(ExpectedAnnotation expected : methodAnnos) {
241251875Speter                    if (!expected.check()) {
242251875Speter                        count++;
243251875Speter                    }
244251875Speter                }
245251875Speter            }
246251875Speter            if (methodParamAnnos != null) {
247251875Speter                for(ExpectedAnnotation expected : methodParamAnnos) {
248251875Speter                    if (!expected.check()) {
249251875Speter                        count++;
250251875Speter                    }
251251875Speter                }
252251875Speter            }
253251875Speter            if (fieldAnnos != null) {
254251875Speter                for(ExpectedAnnotation expected : fieldAnnos) {
255253734Speter                    if (!expected.check()) {
256251875Speter                        count++;
257251875Speter                    }
258251875Speter                }
259251875Speter            }
260251875Speter            if (classTypeAnnos != null) {
261251875Speter                for(ExpectedAnnotation expected : classTypeAnnos) {
262251875Speter                    if (!expected.check()) {
263251875Speter                        count++;
264251875Speter                    }
265251875Speter                }
266251875Speter            }
267251875Speter            if (methodTypeAnnos != null) {
268251875Speter                for(ExpectedAnnotation expected : methodTypeAnnos) {
269251875Speter                    if (!expected.check()) {
270251875Speter                        count++;
271251875Speter                    }
272251875Speter                }
273251875Speter            }
274251875Speter            if (fieldTypeAnnos != null) {
275251875Speter                for(ExpectedAnnotation expected : fieldTypeAnnos) {
276251875Speter                    if (!expected.check()) {
277251875Speter                        count++;
278251875Speter                    }
279251875Speter                }
280251875Speter            }
281251875Speter            return count;
282251875Speter        }
283251875Speter    }
284251875Speter
285251875Speter    /**
286251875Speter     * An expected annotation.  This is both a superclass for
287251875Speter     * method, field, and type annotations, as well as a class for
288251875Speter     * annotations on a class.
289251875Speter     */
290251875Speter    public static class ExpectedAnnotation {
291251875Speter        protected int count = 0;
292251875Speter        protected final String expectedName;
293251875Speter        protected final int expectedCount;
294251875Speter        protected final boolean visibility;
295251875Speter
296251875Speter        /**
297251875Speter         * Create an {@code ExpectedAnnotation} from its
298251875Speter         * components.  It is usually a better idea to use a {@code
299251875Speter         * Builder} to do this.
300251875Speter         *
301251875Speter         * @param expectedName The expected annotation name.
302251875Speter         * @param visibility Whether this annotation should be runtime-visible.
303251875Speter         * @param expectedCount The number of annotations that should
304251875Speter         *                      be seen.  If 0, this asserts that the
305251875Speter         *                      described annotation is not present.
306251875Speter         */
307251875Speter        public ExpectedAnnotation(String expectedName,
308251875Speter                                  boolean visibility,
309251875Speter                                  int expectedCount) {
310251875Speter            this.expectedName = expectedName;
311251875Speter            this.visibility = visibility;
312251875Speter            this.expectedCount = expectedCount;
313251875Speter        }
314251875Speter
315251875Speter        @Override
316251875Speter        public String toString() {
317251875Speter            final StringBuilder sb = new StringBuilder();
318251875Speter            sb.append("Expected ");
319251875Speter            sb.append(expectedCount);
320251875Speter            sb.append(" annotation ");
321251875Speter            sb.append(expectedName);
322251875Speter            sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
323251875Speter            return sb.toString();
324251875Speter        }
325251875Speter
326251875Speter        /**
327251875Speter         * See if this template matches the given visibility.
328251875Speter         *
329251875Speter         * @param Whether or not the annotation is visible at runtime.
330251875Speter         * @return Whether or not this template matches the visibility.
331251875Speter         */
332251875Speter        public boolean matchVisibility(boolean visibility) {
333251875Speter            return this.visibility == visibility;
334251875Speter        }
335251875Speter
336251875Speter        /**
337251875Speter         * Attempty to match this template against an annotation.  If
338251875Speter         * it does match, then the match count for the template will
339251875Speter         * be incremented.  Otherwise, nothing will be done.
340251875Speter         *
341251875Speter         * @param anno The annotation to attempt to match.
342251875Speter         */
343251875Speter        public void matchAnnotation(ConstantPool cpool,
344251875Speter                                    Annotation anno) {
345251875Speter            if (checkMatch(cpool, anno)) {
346251875Speter                count++;
347251875Speter            }
348251875Speter        }
349251875Speter
350251875Speter        /**
351251875Speter         * Indicate whether an annotation matches this expected
352251875Speter         * annotation.
353251875Speter         *
354251875Speter         * @param ConstantPool The constant pool to use.
355251875Speter         * @param anno The annotation to check.
356251875Speter         * @return Whether the annotation matches.
357251875Speter         */
358251875Speter        protected boolean checkMatch(ConstantPool cpool,
359251875Speter                                     Annotation anno) {
360251875Speter            try {
361251875Speter                return cpool.getUTF8Info(anno.type_index).value.equals("L" + expectedName + ";");
362251875Speter            } catch (InvalidIndex | UnexpectedEntry e) {
363251875Speter                return false;
364251875Speter            }
365251875Speter        }
366251875Speter
367251875Speter        /**
368251875Speter         * After all matching, check to see if the expected number of
369251875Speter         * matches equals the actual number.  If not, then print a
370251875Speter         * failure message and return {@code false}.
371251875Speter         *
372251875Speter         * @return Whether or not the expected number of matched
373251875Speter         *         equals the actual number.
374251875Speter         */
375251875Speter        public boolean check() {
376251875Speter            if (count != expectedCount) {
377251875Speter                System.err.println(this + ", but saw " + count);
378251875Speter                return false;
379251875Speter            } else {
380251875Speter                return true;
381251875Speter            }
382251875Speter        }
383251875Speter    }
384251875Speter
385251875Speter    /**
386251875Speter     * An annotation found on a method.
387251875Speter     */
388251875Speter    public static class ExpectedMethodAnnotation extends ExpectedAnnotation {
389251875Speter        protected final String methodname;
390251875Speter
391251875Speter        /**
392251875Speter         * Create an {@code ExpectedMethodAnnotation} from its
393251875Speter         * components.  It is usually a better idea to use a {@code
394251875Speter         * Builder} to do this.
395251875Speter         *
396251875Speter         * @param methodname The expected method name.
397251875Speter         * @param expectedName The expected annotation name.
398251875Speter         * @param visibility Whether this annotation should be runtime-visible.
399251875Speter         * @param expectedCount The number of annotations that should be seen.
400251875Speter         */
401251875Speter        public ExpectedMethodAnnotation(String methodname,
402251875Speter                                        String expectedName,
403251875Speter                                        boolean visibility,
404251875Speter                                        int expectedCount) {
405251875Speter            super(expectedName, visibility, expectedCount);
406251875Speter            this.methodname = methodname;
407251875Speter        }
408251875Speter
409251875Speter        @Override
410251875Speter        public String toString() {
411251875Speter            final StringBuilder sb = new StringBuilder();
412251875Speter            sb.append("Expected ");
413251875Speter            sb.append(expectedCount);
414251875Speter            sb.append(" annotation ");
415251875Speter            sb.append(expectedName);
416251875Speter            sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
417251875Speter            sb.append(" on method ");
418251875Speter            sb.append(methodname);
419251875Speter            return sb.toString();
420251875Speter        }
421251875Speter
422251875Speter        /**
423251875Speter         * See if this template applies to a method.
424251875Speter         *
425251875Speter         * @param methodname The method name to check.
426251875Speter         * @return Whether or not this template should apply.
427251875Speter         */
428251875Speter        public boolean matchMethodName(String methodname) {
429251875Speter            return this.methodname.equals(methodname);
430251875Speter        }
431251875Speter
432251875Speter    }
433251875Speter
434251875Speter    /**
435251875Speter     * An annotation found on a method parameter.
436251875Speter     */
437251875Speter    public static class ExpectedParameterAnnotation
438251875Speter        extends ExpectedMethodAnnotation {
439251875Speter        protected final int index;
440251875Speter
441251875Speter        /**
442251875Speter         * Create an {@code ExpectedParameterAnnotation} from its
443251875Speter         * components.  It is usually a better idea to use a {@code
444251875Speter         * Builder} to do this.
445251875Speter         *
446251875Speter         * @param methodname The expected method name.
447251875Speter         * @param index The parameter index.
448251875Speter         * @param expectedName The expected annotation name.
449251875Speter         * @param visibility Whether this annotation should be runtime-visible.
450251875Speter         * @param expectedCount The number of annotations that should be seen.
451251875Speter         */
452251875Speter        public ExpectedParameterAnnotation(String methodname,
453251875Speter                                           int index,
454251875Speter                                           String expectedName,
455251875Speter                                           boolean visibility,
456251875Speter                                           int expectedCount) {
457251875Speter            super(methodname, expectedName, visibility, expectedCount);
458251875Speter            this.index = index;
459251875Speter        }
460251875Speter
461251875Speter        @Override
462251875Speter        public String toString() {
463251875Speter            final StringBuilder sb = new StringBuilder();
464251875Speter            sb.append("Expected ");
465251875Speter            sb.append(expectedCount);
466251875Speter            sb.append(" annotation ");
467251875Speter            sb.append(expectedName);
468251875Speter            sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
469251875Speter            sb.append(" on method ");
470251875Speter            sb.append(methodname);
471251875Speter            sb.append(" parameter ");
472251875Speter            sb.append(index);
473251875Speter            return sb.toString();
474251875Speter        }
475251875Speter
476251875Speter    }
477251875Speter
478251875Speter    /**
479251875Speter     * An annotation found on a field.
480251875Speter     */
481251875Speter    public static class ExpectedFieldAnnotation extends ExpectedAnnotation {
482251875Speter        private final String fieldname;
483251875Speter
484251875Speter        /**
485251875Speter         * Create an {@code ExpectedFieldAnnotation} from its
486251875Speter         * components.  It is usually a better idea to use a {@code
487251875Speter         * Builder} to do this.
488251875Speter         *
489251875Speter         * @param fieldname The expected field name.
490251875Speter         * @param expectedName The expected annotation name.
491251875Speter         * @param visibility Whether this annotation should be runtime-visible.
492251875Speter         * @param expectedCount The number of annotations that should be seen.
493251875Speter         */
494251875Speter        public ExpectedFieldAnnotation(String fieldname,
495251875Speter                                       String expectedName,
496251875Speter                                       boolean visibility,
497251875Speter                                       int expectedCount) {
498251875Speter            super(expectedName, visibility, expectedCount);
499251875Speter            this.fieldname = fieldname;
500251875Speter        }
501251875Speter
502251875Speter        @Override
503251875Speter        public String toString() {
504251875Speter            final StringBuilder sb = new StringBuilder();
505251875Speter            sb.append("Expected ").append(expectedCount)
506251875Speter            .append(" annotation ").append(expectedName)
507251875Speter            .append(visibility ? ", runtime visibile " : ", runtime invisibile ")
508251875Speter            .append(" on field ").append(fieldname);
509251875Speter            return sb.toString();
510251875Speter        }
511251875Speter
512251875Speter        /**
513251875Speter         * See if this template applies to a field.
514251875Speter         *
515251875Speter         * @param fieldname The field name to check.
516251875Speter         * @return Whether or not this template should apply.
517251875Speter         */
518251875Speter        public boolean matchFieldName(String fieldname) {
519251875Speter            return this.fieldname.equals(fieldname);
520251875Speter        }
521251875Speter
522251875Speter    }
523251875Speter
524251875Speter    /**
525251875Speter     * An expected type annotation.  This is both a superclass for
526251875Speter     * method and field type annotations, as well as a class for type
527251875Speter     * annotations on a class.
528251875Speter     */
529251875Speter    public static class ExpectedTypeAnnotation extends ExpectedAnnotation {
530251875Speter        protected final TypeAnnotation.TargetType targetType;
531251875Speter        protected final int bound_index;
532251875Speter        protected final int parameter_index;
533251875Speter        protected final int type_index;
534251875Speter        protected final int exception_index;
535251875Speter        protected final TypeAnnotation.Position.TypePathEntry[] typePath;
536251875Speter
537251875Speter        /**
538251875Speter         * Create an {@code ExpectedTypeAnnotation} from its
539251875Speter         * components.  It is usually a better idea to use a {@code
540251875Speter         * Builder} to do this.
541251875Speter         *
542251875Speter         * @param expectedName The expected annotation name.
543251875Speter         * @param visibility Whether this annotation should be runtime-visible.
544251875Speter         * @param expectedCount The number of annotations that should
545251875Speter         *                      be seen.  If 0, this asserts that the
546251875Speter         *                      described annotation is not present.
547251875Speter         * @param targetType The expected target type.
548251875Speter         * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
549251875Speter         * @param parameter_index The expected parameter index, or
550251875Speter         *                        {@code Integer.MIN_VALUE}.
551251875Speter         * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
552251875Speter         * @param exception_index The expected exception index, or
553251875Speter         *                        {@code Integer.MIN_VALUE}.
554251875Speter         * @param typePath The expected type path.
555266735Speter         */
556251875Speter        public ExpectedTypeAnnotation(String expectedName,
557251875Speter                                      boolean visibility,
558251875Speter                                      int expectedCount,
559251875Speter                                      TypeAnnotation.TargetType targetType,
560251875Speter                                      int bound_index,
561251875Speter                                      int parameter_index,
562251875Speter                                      int type_index,
563251875Speter                                      int exception_index,
564251875Speter                                      TypeAnnotation.Position.TypePathEntry... typePath) {
565251875Speter            super(expectedName, visibility, expectedCount);
566251875Speter            this.targetType = targetType;
567251875Speter            this.bound_index = bound_index;
568251875Speter            this.parameter_index = parameter_index;
569251875Speter            this.type_index = type_index;
570251875Speter            this.exception_index = exception_index;
571251875Speter            this.typePath = typePath;
572251875Speter        }
573251875Speter
574251875Speter        @Override
575251875Speter        public String toString() {
576251875Speter            final StringBuilder sb = new StringBuilder();
577251875Speter            sb.append("Expected ");
578251875Speter            sb.append(expectedCount);
579251875Speter            sb.append(" annotation ");
580251875Speter            sb.append(expectedName);
581251875Speter            sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
582251875Speter            sb.append(targetType);
583251875Speter            sb.append(", bound_index = ");
584251875Speter            sb.append(bound_index);
585251875Speter            sb.append(", parameter_index = ");
586251875Speter            sb.append(parameter_index);
587251875Speter            sb.append(", type_index = ");
588251875Speter            sb.append(type_index);
589251875Speter            sb.append(", exception_index = ");
590251875Speter            sb.append(exception_index);
591251875Speter            sb.append(", type_path = [");
592251875Speter            for(int i = 0; i < typePath.length; i++) {
593251875Speter                if (i != 0) {
594251875Speter                    sb.append(", ");
595251875Speter                }
596251875Speter                sb.append(typePath[i]);
597251875Speter            }
598251875Speter            sb.append("]");
599251875Speter            return sb.toString();
600251875Speter        }
601251875Speter
602251875Speter        @Override
603251875Speter        public void matchAnnotation(ConstantPool cpool,
604251875Speter                                    Annotation anno) {}
605251875Speter
606251875Speter        public void matchAnnotation(TypeAnnotation anno) {
607251875Speter            if (checkMatch(anno)) {
608251875Speter                count++;
609251875Speter            }
610251875Speter        }
611251875Speter
612251875Speter        public boolean checkMatch(TypeAnnotation anno) {
613251875Speter            boolean matches = checkMatch(anno.constant_pool, anno.annotation);
614251875Speter
615251875Speter            matches = matches && anno.position.type == targetType;
616251875Speter            matches = matches && anno.position.bound_index == bound_index;
617251875Speter            matches = matches && anno.position.parameter_index == parameter_index;
618251875Speter            matches = matches && anno.position.type_index == type_index;
619251875Speter            matches = matches && anno.position.exception_index == exception_index;
620251875Speter            matches = matches && anno.position.location.size() == typePath.length;
621251875Speter
622251875Speter            if (matches) {
623251875Speter                int i = 0;
624251875Speter                for(TypeAnnotation.Position.TypePathEntry entry :
625251875Speter                         anno.position.location) {
626251875Speter                    matches = matches && typePath[i++].equals(entry);
627251875Speter                }
628251875Speter            }
629251875Speter
630251875Speter            return matches;
631251875Speter        }
632251875Speter
633251875Speter        /**
634251875Speter         * A builder class for creating {@code
635251875Speter         * ExpectedTypeAnnotation}s in a more convenient fashion.  The
636251875Speter         * constructor for {@code ExpectedTypeAnnotation} takes a
637251875Speter         * large number of parameters (by necessity).  This class
638251875Speter         * allows users to construct a {@code ExpectedTypeAnnotation}s
639251875Speter         * using only the ones they need.
640251875Speter         */
641251875Speter        public static class Builder {
642251875Speter            protected final String expectedName;
643251875Speter            protected final boolean visibility;
644251875Speter            protected final int expectedCount;
645251875Speter            protected final TypeAnnotation.TargetType targetType;
646251875Speter            protected int bound_index = Integer.MIN_VALUE;
647251875Speter            protected int parameter_index = Integer.MIN_VALUE;
648251875Speter            protected int type_index = Integer.MIN_VALUE;
649251875Speter            protected int exception_index = Integer.MIN_VALUE;
650251875Speter            protected TypeAnnotation.Position.TypePathEntry[] typePath =
651251875Speter                new TypeAnnotation.Position.TypePathEntry[0];
652251875Speter
653251875Speter            /**
654251875Speter             * Create a {@code Builder} from the mandatory parameters.
655251875Speter             *
656251875Speter             * @param expectedName The expected annotation name.
657251875Speter             * @param targetType The expected target type.
658251875Speter             * @param visibility Whether this annotation should be runtime-visible.
659251875Speter             * @param expectedCount The number of annotations that should be seen.
660251875Speter             */
661251875Speter            public Builder(String expectedName,
662251875Speter                           TypeAnnotation.TargetType targetType,
663251875Speter                           boolean visibility,
664251875Speter                           int expectedCount) {
665251875Speter                this.expectedName = expectedName;
666251875Speter                this.visibility = visibility;
667251875Speter                this.expectedCount = expectedCount;
668251875Speter                this.targetType = targetType;
669251875Speter            }
670251875Speter
671251875Speter            /**
672251875Speter             * Create an {@code ExpectedTypeAnnotation} from all
673251875Speter             * parameters that have been provided.  The default values
674251875Speter             * will be used for those that have not.
675251875Speter             *
676251875Speter             * @return The cretaed {@code ExpectedTypeAnnotation}.
677251875Speter             */
678251875Speter            public ExpectedTypeAnnotation build() {
679251875Speter                return new ExpectedTypeAnnotation(expectedName, visibility,
680251875Speter                                                  expectedCount, targetType,
681251875Speter                                                  bound_index, parameter_index,
682251875Speter                                                  type_index, exception_index,
683251875Speter                                                  typePath);
684251875Speter            }
685251875Speter
686251875Speter            /**
687251875Speter             * Provide a bound index parameter.
688251875Speter             *
689251875Speter             * @param bound_index The bound_index value.
690251875Speter             */
691251875Speter            public Builder setBoundIndex(int bound_index) {
692251875Speter                this.bound_index = bound_index;
693251875Speter                return this;
694251875Speter            }
695251875Speter
696251875Speter            /**
697251875Speter             * Provide a parameter index parameter.
698251875Speter             *
699251875Speter             * @param bound_index The parameter_index value.
700251875Speter             */
701251875Speter            public Builder setParameterIndex(int parameter_index) {
702251875Speter                this.parameter_index = parameter_index;
703251875Speter                return this;
704251875Speter            }
705251875Speter
706251875Speter            /**
707251875Speter             * Provide a type index parameter.
708251875Speter             *
709251875Speter             * @param type_index The type_index value.
710251875Speter             */
711251875Speter            public Builder setTypeIndex(int type_index) {
712251875Speter                this.type_index = type_index;
713251875Speter                return this;
714251875Speter            }
715251875Speter
716251875Speter            /**
717251875Speter             * Provide an exception index parameter.
718251875Speter             *
719251875Speter             * @param exception_index The exception_index value.
720251875Speter             */
721251875Speter            public Builder setExceptionIndex(int exception_index) {
722251875Speter                this.exception_index = exception_index;
723251875Speter                return this;
724251875Speter            }
725251875Speter
726251875Speter            /**
727251875Speter             * Provide a type path parameter.
728251875Speter             *
729251875Speter             * @param typePath The type path value.
730251875Speter             */
731251875Speter            public Builder setTypePath(TypeAnnotation.Position.TypePathEntry[] typePath) {
732251875Speter                this.typePath = typePath;
733251875Speter                return this;
734251875Speter            }
735251875Speter        }
736251875Speter    }
737251875Speter
738251875Speter    /**
739251875Speter     * A type annotation found on a method.
740251875Speter     */
741251875Speter    public static class ExpectedMethodTypeAnnotation extends ExpectedTypeAnnotation {
742251875Speter        private final String methodname;
743251875Speter
744251875Speter        /**
745251875Speter         * Create an {@code ExpectedMethodTypeAnnotation} from its
746251875Speter         * components.  It is usually a better idea to use a {@code
747251875Speter         * Builder} to do this.
748251875Speter         *
749251875Speter         * @param methodname The expected method name.
750251875Speter         * @param expectedName The expected annotation name.
751251875Speter         * @param visibility Whether this annotation should be runtime-visible.
752251875Speter         * @param expectedCount The number of annotations that should be seen.
753251875Speter         * @param targetType The expected target type.
754251875Speter         * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
755251875Speter         * @param parameter_index The expected parameter index, or
756251875Speter         *                        {@code Integer.MIN_VALUE}.
757251875Speter         * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
758251875Speter         * @param exception_index The expected exception index, or
759251875Speter         *                        {@code Integer.MIN_VALUE}.
760251875Speter         * @param typePath The expected type path.
761251875Speter         */
762251875Speter        public ExpectedMethodTypeAnnotation(String methodname,
763251875Speter                                            String expectedName,
764251875Speter                                            boolean visibility,
765251875Speter                                            int expectedCount,
766251875Speter                                            TypeAnnotation.TargetType targetType,
767251875Speter                                            int bound_index,
768251875Speter                                            int parameter_index,
769251875Speter                                            int type_index,
770251875Speter                                            int exception_index,
771251875Speter                                            TypeAnnotation.Position.TypePathEntry... typePath) {
772251875Speter            super(expectedName, visibility, expectedCount, targetType, bound_index,
773251875Speter                  parameter_index, type_index, exception_index, typePath);
774251875Speter            this.methodname = methodname;
775251875Speter        }
776251875Speter
777251875Speter        @Override
778251875Speter        public String toString() {
779251875Speter            final StringBuilder sb = new StringBuilder();
780251875Speter            sb.append("Expected ");
781251875Speter            sb.append(expectedCount);
782251875Speter            sb.append(" annotation ");
783251875Speter            sb.append(expectedName);
784251875Speter            sb.append(visibility ? ", runtime visibile " : ", runtime invisibile ");
785251875Speter            sb.append(targetType);
786251875Speter            sb.append(", bound_index = ");
787251875Speter            sb.append(bound_index);
788251875Speter            sb.append(", parameter_index = ");
789251875Speter            sb.append(parameter_index);
790251875Speter            sb.append(", type_index = ");
791251875Speter            sb.append(type_index);
792251875Speter            sb.append(", exception_index = ");
793251875Speter            sb.append(exception_index);
794251875Speter            sb.append(", type_path = [");
795251875Speter            for(int i = 0; i < typePath.length; i++) {
796251875Speter                if (i != 0) {
797251875Speter                    sb.append(", ");
798251875Speter                }
799251875Speter                sb.append(typePath[i]);
800251875Speter            }
801251875Speter            sb.append("]");
802251875Speter            sb.append(" on method ");
803251875Speter            sb.append(methodname);
804251875Speter            return sb.toString();
805251875Speter        }
806251875Speter
807251875Speter        /**
808251875Speter         * See if this template applies to a method.
809251875Speter         *
810251875Speter         * @param methodname The method name to check.
811251875Speter         * @return Whether or not this template should apply.
812251875Speter         */
813251875Speter        public boolean matchMethodName(String methodname) {
814251875Speter            return this.methodname.equals(methodname);
815251875Speter        }
816251875Speter
817251875Speter        /**
818251875Speter         * A builder class for creating {@code
819251875Speter         * ExpectedMethodTypeAnnotation}s in a more convenient fashion.  The
820251875Speter         * constructor for {@code ExpectedMethodTypeAnnotation} takes a
821251875Speter         * large number of parameters (by necessity).  This class
822251875Speter         * allows users to construct a {@code ExpectedMethodTypeAnnotation}s
823251875Speter         * using only the ones they need.
824251875Speter         */
825251875Speter        public static class Builder extends ExpectedTypeAnnotation.Builder {
826251875Speter            protected final String methodname;
827251875Speter
828251875Speter            /**
829251875Speter             * Create a {@code Builder} from the mandatory parameters.
830251875Speter             *
831251875Speter             * @param methodname The expected method name.
832251875Speter             * @param expectedName The expected annotation name.
833251875Speter             * @param targetType The expected target type.
834251875Speter             * @param visibility Whether this annotation should be runtime-visible.
835251875Speter             * @param expectedCount The number of annotations that should be seen.
836251875Speter             */
837251875Speter            public Builder(String methodname,
838251875Speter                           String expectedName,
839251875Speter                           TypeAnnotation.TargetType targetType,
840251875Speter                           boolean visibility,
841251875Speter                           int expectedCount) {
842251875Speter                super(expectedName, targetType, visibility, expectedCount);
843251875Speter                this.methodname = methodname;
844251875Speter            }
845251875Speter
846251875Speter            /**
847251875Speter             * Create an {@code ExpectedMethodTypeAnnotation} from all
848251875Speter             * parameters that have been provided.  The default values
849251875Speter             * will be used for those that have not.
850251875Speter             *
851251875Speter             * @return The created {@code ExpectedMethodTypeAnnotation}.
852251875Speter             */
853251875Speter            @Override
854251875Speter            public ExpectedMethodTypeAnnotation build() {
855251875Speter                return new ExpectedMethodTypeAnnotation(methodname, expectedName,
856251875Speter                                                        visibility, expectedCount,
857251875Speter                                                        targetType, bound_index,
858251875Speter                                                        parameter_index, type_index,
859251875Speter                                                        exception_index, typePath);
860251875Speter            }
861251875Speter        }
862251875Speter    }
863251875Speter
864251875Speter    /**
865251875Speter     * A type annotation found on a field.
866251875Speter     */
867251875Speter    public static class ExpectedFieldTypeAnnotation extends ExpectedTypeAnnotation {
868251875Speter        private final String fieldname;
869251875Speter
870251875Speter        /**
871251875Speter         * Create an {@code ExpectedFieldTypeAnnotation} from its
872251875Speter         * components.  It is usually a better idea to use a {@code
873251875Speter         * Builder} to do this.
874251875Speter         *
875251875Speter         * @param fieldname The expected field name.
876251875Speter         * @param expectedName The expected annotation name.
877251875Speter         * @param visibility Whether this annotation should be runtime-visible.
878251875Speter         * @param expectedCount The number of annotations that should be seen.
879251875Speter         * @param targetType The expected target type.
880251875Speter         * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}.
881251875Speter         * @param parameter_index The expected parameter index, or
882251875Speter         *                        {@code Integer.MIN_VALUE}.
883251875Speter         * @param type_index The expected type index, or {@code Integer.MIN_VALUE}.
884251875Speter         * @param exception_index The expected exception index, or
885251875Speter         *                        {@code Integer.MIN_VALUE}.
886251875Speter         * @param typePath The expected type path.
887251875Speter         */
888251875Speter        public ExpectedFieldTypeAnnotation(String fieldname,
889251875Speter                                           String expectedName,
890251875Speter                                           boolean visibility,
891251875Speter                                           int expectedCount,
892251875Speter                                           TypeAnnotation.TargetType targetType,
893251875Speter                                           int bound_index,
894251875Speter                                           int parameter_index,
895251875Speter                                           int type_index,
896251875Speter                                           int exception_index,
897251875Speter                                           TypeAnnotation.Position.TypePathEntry... typePath) {
898251875Speter            super(expectedName, visibility, expectedCount, targetType, bound_index,
899251875Speter                  parameter_index, type_index, exception_index, typePath);
900251875Speter            this.fieldname = fieldname;
901251875Speter        }
902251875Speter
903251875Speter        @Override
904251875Speter        public String toString() {
905251875Speter            final StringBuilder sb = new StringBuilder();
906251875Speter            sb.append("Expected ").append(expectedCount)
907251875Speter            .append(" annotation ").append(expectedName)
908251875Speter            .append(visibility ? ", runtime visibile " : ", runtime invisibile ")
909251875Speter            .append(targetType)
910251875Speter            .append(", bound_index = ").append(bound_index)
911251875Speter            .append(", parameter_index = ").append(parameter_index)
912251875Speter            .append(", type_index = ").append(type_index)
913251875Speter            .append(", exception_index = ").append(exception_index)
914251875Speter            .append(", type_path = [");
915251875Speter
916251875Speter            for(int i = 0; i < typePath.length; i++) {
917251875Speter                if (i != 0) {
918251875Speter                    sb.append(", ");
919251875Speter                }
920251875Speter                sb.append(typePath[i]);
921251875Speter            }
922251875Speter            sb.append("]")
923251875Speter            .append(" on field ").append(fieldname);
924251875Speter            return sb.toString();
925251875Speter        }
926251875Speter
927251875Speter        /**
928251875Speter         * See if this template applies to a field.
929251875Speter         *
930251875Speter         * @param fieldname The field name to check.
931251875Speter         * @return Whether or not this template should apply.
932251875Speter         */
933251875Speter        public boolean matchFieldName(String fieldname) {
934251875Speter            return this.fieldname.equals(fieldname);
935251875Speter        }
936251875Speter
937251875Speter        /**
938251875Speter         * A builder class for creating {@code
939251875Speter         * ExpectedFieldTypeAnnotation}s in a more convenient fashion.  The
940251875Speter         * constructor for {@code ExpectedFieldTypeAnnotation} takes a
941251875Speter         * large number of parameters (by necessity).  This class
942251875Speter         * allows users to construct a {@code ExpectedFieldTypeAnnotation}s
943251875Speter         * using only the ones they need.
944251875Speter         */
945251875Speter        public static class Builder extends ExpectedTypeAnnotation.Builder {
946251875Speter            protected final String fieldname;
947251875Speter
948251875Speter            /**
949251875Speter             * Create a {@code Builder} from the mandatory parameters.
950251875Speter             *
951251875Speter             * @param fieldname The expected field name.
952251875Speter             * @param expectedName The expected annotation name.
953251875Speter             * @param targetType The expected target type.
954251875Speter             * @param visibility Whether this annotation should be runtime-visible.
955251875Speter             * @param expectedCount The number of annotations that should be seen.
956251875Speter             */
957251875Speter            public Builder(String fieldname,
958251875Speter                           String expectedName,
959251875Speter                           TypeAnnotation.TargetType targetType,
960251875Speter                           boolean visibility,
961251875Speter                           int expectedCount) {
962251875Speter                super(expectedName, targetType, visibility, expectedCount);
963251875Speter                this.fieldname = fieldname;
964251875Speter            }
965251875Speter
966251875Speter            /**
967251875Speter             * Create an {@code ExpectedFieldTypeAnnotation} from all
968251875Speter             * parameters that have been provided.  The default values
969251875Speter             * will be used for those that have not.
970251875Speter             *
971251875Speter             * @return The created {@code ExpectedFieldTypeAnnotation}.
972251875Speter             */
973251875Speter            @Override
974251875Speter            public ExpectedFieldTypeAnnotation build() {
975251875Speter                return new ExpectedFieldTypeAnnotation(fieldname, expectedName,
976251875Speter                                                       visibility, expectedCount,
977251875Speter                                                       targetType, bound_index,
978251875Speter                                                       parameter_index, type_index,
979251875Speter                                                       exception_index, typePath);
980251875Speter            }
981251875Speter        }
982251875Speter    }
983251875Speter
984251875Speter    private void matchClassAnnotation(ClassFile classfile,
985251875Speter                                      ExpectedAnnotation expected)
986251875Speter        throws ConstantPoolException {
987251875Speter        for(Attribute attr : classfile.attributes) {
988251875Speter            attr.accept(annoMatcher(classfile.constant_pool), expected);
989251875Speter        }
990251875Speter    }
991251875Speter
992251875Speter    private void matchMethodAnnotation(ClassFile classfile,
993251875Speter                                       ExpectedMethodAnnotation expected)
994251875Speter        throws ConstantPoolException {
995251875Speter        for(Method meth : classfile.methods) {
996251875Speter            if (expected.matchMethodName(meth.getName(classfile.constant_pool))) {
997251875Speter                for(Attribute attr : meth.attributes) {
998251875Speter                    attr.accept(annoMatcher(classfile.constant_pool), expected);
999251875Speter                }
1000251875Speter            }
1001251875Speter        }
1002251875Speter    }
1003251875Speter
1004251875Speter    private void matchParameterAnnotation(ClassFile classfile,
1005251875Speter                                          ExpectedParameterAnnotation expected)
1006251875Speter        throws ConstantPoolException {
1007251875Speter        for(Method meth : classfile.methods) {
1008251875Speter            if (expected.matchMethodName(meth.getName(classfile.constant_pool))) {
1009251875Speter                for(Attribute attr : meth.attributes) {
1010251875Speter                    attr.accept(paramMatcher(classfile.constant_pool), expected);
1011251875Speter                }
1012251875Speter            }
1013251875Speter        }
1014251875Speter    }
1015251875Speter
1016251875Speter    private void matchFieldAnnotation(ClassFile classfile,
1017251875Speter                                      ExpectedFieldAnnotation expected)
1018251875Speter        throws ConstantPoolException {
1019251875Speter        for(Field field : classfile.fields) {
1020251875Speter            if (expected.matchFieldName(field.getName(classfile.constant_pool))) {
1021251875Speter                for(Attribute attr : field.attributes) {
1022251875Speter                    attr.accept(annoMatcher(classfile.constant_pool), expected);
1023251875Speter                }
1024251875Speter            }
1025251875Speter        }
1026251875Speter    }
1027251875Speter
1028251875Speter    private void matchClassTypeAnnotation(ClassFile classfile,
1029251875Speter                                          ExpectedTypeAnnotation expected)
1030251875Speter        throws ConstantPoolException {
1031251875Speter        for(Attribute attr : classfile.attributes) {
1032251875Speter            attr.accept(typeAnnoMatcher, expected);
1033251875Speter        }
1034251875Speter    }
1035251875Speter
1036251875Speter    private void matchMethodTypeAnnotation(ClassFile classfile,
1037251875Speter                                           ExpectedMethodTypeAnnotation expected)
1038251875Speter        throws ConstantPoolException {
1039251875Speter        for(Method meth : classfile.methods) {
1040251875Speter            if (expected.matchMethodName(meth.getName(classfile.constant_pool))) {
1041251875Speter                for(Attribute attr : meth.attributes) {
1042251875Speter                    attr.accept(typeAnnoMatcher, expected);
1043251875Speter                }
1044251875Speter            }
1045251875Speter        }
1046251875Speter    }
1047251875Speter
1048251875Speter    private void matchFieldTypeAnnotation(ClassFile classfile,
1049251875Speter                                          ExpectedFieldTypeAnnotation expected)
1050251875Speter        throws ConstantPoolException {
1051251875Speter        for(Field field : classfile.fields) {
1052251875Speter            if (expected.matchFieldName(field.getName(classfile.constant_pool))) {
1053251875Speter                for(Attribute attr : field.attributes) {
1054251875Speter                    attr.accept(typeAnnoMatcher, expected);
1055251875Speter                }
1056251875Speter            }
1057251875Speter        }
1058251875Speter    }
1059251875Speter
1060251875Speter    private void matchClassAnnotations(ClassFile classfile,
1061251875Speter                                       ExpectedAnnotation[] expected)
1062251875Speter        throws ConstantPoolException {
1063251875Speter        for(ExpectedAnnotation one : expected) {
1064251875Speter            matchClassAnnotation(classfile, one);
1065251875Speter        }
1066251875Speter    }
1067251875Speter
1068251875Speter    private void matchMethodAnnotations(ClassFile classfile,
1069251875Speter                                        ExpectedMethodAnnotation[] expected)
1070251875Speter        throws ConstantPoolException {
1071251875Speter        for(ExpectedMethodAnnotation one : expected) {
1072251875Speter            matchMethodAnnotation(classfile, one);
1073251875Speter        }
1074251875Speter    }
1075251875Speter
1076251875Speter    private void matchParameterAnnotations(ClassFile classfile,
1077251875Speter                                           ExpectedParameterAnnotation[] expected)
1078251875Speter        throws ConstantPoolException {
1079251875Speter        for(ExpectedParameterAnnotation one : expected) {
1080251875Speter            matchParameterAnnotation(classfile, one);
1081251875Speter        }
1082251875Speter    }
1083251875Speter
1084251875Speter    private void matchFieldAnnotations(ClassFile classfile,
1085251875Speter                                       ExpectedFieldAnnotation[] expected)
1086251875Speter        throws ConstantPoolException {
1087251875Speter        for(ExpectedFieldAnnotation one : expected) {
1088251875Speter            matchFieldAnnotation(classfile, one);
1089251875Speter        }
1090251875Speter    }
1091251875Speter
1092251875Speter    private void matchClassTypeAnnotations(ClassFile classfile,
1093251875Speter                                           ExpectedTypeAnnotation[] expected)
1094251875Speter        throws ConstantPoolException {
1095251875Speter        for(ExpectedTypeAnnotation one : expected) {
1096251875Speter            matchClassTypeAnnotation(classfile, one);
1097251875Speter        }
1098251875Speter    }
1099251875Speter
1100251875Speter    private void matchMethodTypeAnnotations(ClassFile classfile,
1101251875Speter                                            ExpectedMethodTypeAnnotation[] expected)
1102251875Speter        throws ConstantPoolException {
1103251875Speter        for(ExpectedMethodTypeAnnotation one : expected) {
1104251875Speter            matchMethodTypeAnnotation(classfile, one);
1105251875Speter        }
1106251875Speter    }
1107251875Speter
1108251875Speter    private void matchFieldTypeAnnotations(ClassFile classfile,
1109251875Speter                                           ExpectedFieldTypeAnnotation[] expected)
1110251875Speter        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 visitModulePackages(ModulePackages_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 visitModuleHashes(ModuleHashes_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 visitModuleMainClass(ModuleMainClass_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 visitModuleTarget(ModuleTarget_attribute attr, T p) {
1347            return null;
1348        }
1349
1350        @Override
1351        public Void visitModuleVersion(ModuleVersion_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