1/*
2 * Copyright (c) 2013, 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
24/*
25 * @test
26 * @bug 8005085 8008762 8008751 8013065 8015323 8015257
27 * @summary Type annotations on anonymous and inner class.
28 *  Six TYPE_USE annotations are repeated(or not); Four combinations create
29 *  four test files, and each results in the test class and 2 anonymous classes.
30 *  Each element of these three classes is checked for expected number of the
31 *  four annotation Attributes. Expected annotation counts depend on type of
32 *  annotation place on type of element (a FIELD&TYPE_USE element on a field
33 *  results in 2). Elements with no annotations expect 0.
34 *  Source template is read in from testanoninner.template
35 *
36 * @modules jdk.jdeps/com.sun.tools.classfile
37 */
38import java.lang.annotation.*;
39import java.io.*;
40import java.util.List;
41import java.util.LinkedList;
42import com.sun.tools.classfile.*;
43import java.nio.file.Files;
44import java.nio.charset.*;
45import java.io.File;
46import java.io.IOException;
47
48
49import java.lang.annotation.*;
50import static java.lang.annotation.RetentionPolicy.*;
51import static java.lang.annotation.ElementType.*;
52
53/*
54 * A source template is read in and testname and annotations are inserted
55 * via replace().
56 */
57public class TestAnonInnerClasses extends ClassfileTestHelper {
58    // tally errors and test cases
59    int errors = 0;
60    int checks = 0;
61    //Note expected test count in case of skips due to bugs.
62    int tc = 0, xtc = 180; // 45 x 4 variations of repeated annotations.
63    File testSrc = new File(System.getProperty("test.src"));
64
65    String[] AnnoAttributes = {
66        Attribute.RuntimeVisibleTypeAnnotations,
67        Attribute.RuntimeInvisibleTypeAnnotations,
68        Attribute.RuntimeVisibleAnnotations,
69        Attribute.RuntimeInvisibleAnnotations
70    };
71
72    // template for source files
73    String srcTemplate = "testanoninner.template";
74
75    // Four test files generated based on combinations of repeating annotations.
76    Boolean As= false, Bs=true, Cs=false, Ds=false, TAs=false,TBs=false;
77    Boolean[][] bRepeat = new Boolean[][]{
78                 /* no repeats    */ {false, false, false, false, false, false},
79                 /* repeat A,C,TA */ {true,  false, true,  false, true,  false},
80                 /* repeat B,D,TB */ {false, true,  false, true,  false, true},
81                 /* repeat all    */ {true,  true,  true,  true,  true,  true}
82    };
83    // Save descriptions of failed test case; does not terminate upon a failure.
84    List<String> failed = new LinkedList<>();
85
86    public static void main(String[] args) throws Exception {
87        new TestAnonInnerClasses().run();
88    }
89
90    // Check annotation counts and make reports sufficiently descriptive to
91    // easily diagnose.
92    void check(String testcase, int vtaX, int itaX, int vaX, int iaX,
93                                int vtaA, int itaA, int vaA, int iaA) {
94
95        String descr = " checking " + testcase+" _TYPE_, expected: " +
96            vtaX + ", " + itaX + ", " + vaX + ", " + iaX + "; actual: " +
97            vtaA + ", " + itaA + ", " + vaA + ", " + iaA;
98        String description;
99        description=descr.replace("_TYPE_","RuntimeVisibleTypeAnnotations");
100        if (vtaX != vtaA) {
101            errors++;
102            failed.add(++checks + " " + testcase + ": (vtaX) " + vtaX +
103                       " != " + vtaA + " (vtaA)");
104            println(checks + " FAIL: " + description);
105        } else {
106            println(++checks + " PASS: " + description);
107        }
108        description=descr.replace("_TYPE_","RuntimeInvisibleTypeAnnotations");
109        if (itaX != itaA) {
110            errors++;
111            failed.add(++checks + " " + testcase + ": (itaX) " + itaX + " != " +
112                       itaA + " (itaA)");
113            println(checks + " FAIL: " + description);
114        } else {
115            println(++checks + " PASS: " + description);
116        }
117        description=descr.replace("_TYPE_","RuntimeVisibleAnnotations");
118        if (vaX != vaA) {
119            errors++;
120            failed.add(++checks + " " + testcase + ": (vaX) " + vaX + " != " +
121                       vaA + " (vaA)");
122            println(checks + " FAIL: " + description);
123        } else {
124            println(++checks + " PASS: " + description);
125        }
126        description=descr.replace("_TYPE_","RuntimeInvisibleAnnotations");
127        if (iaX != iaA) {
128            errors++;
129            failed.add(++checks + " " + testcase + ": (iaX) " + iaX + " != " +
130                       iaA + " (iaA)");
131            println(checks + " FAIL: " + description);
132        } else {
133            println(++checks + " PASS: " + description);
134        }
135        println("");
136    }
137
138    // Print failed cases (if any) and throw exception for fail.
139    void report() {
140        if (errors!=0) {
141            System.err.println("Failed tests: " + errors +
142                               "\nfailed test cases:\n");
143            for (String t: failed) System.err.println("  " + t);
144            throw new RuntimeException("FAIL: There were test failures.");
145        } else
146            System.out.println("PASSED all tests.");
147    }
148
149    void test(String ttype, ClassFile cf, Method m, Field f, boolean visible) {
150        int vtaActual = 0,
151            itaActual = 0,
152            vaActual = 0,
153            iaActual = 0,
154            vtaExp = 0,
155            itaExp = 0,
156            vaExp = 0,
157            iaExp = 0,
158            index = 0,
159            index2 = 0;
160        String memberName = null,
161            testcase = "undefined",
162            testClassName = null;
163        Attribute attr = null,
164            cattr = null;
165        Code_attribute CAttr = null;
166        // Get counts of 4 annotation Attributes on element being checked.
167        for (String AnnoType : AnnoAttributes) {
168            try {
169                switch (ttype) {
170                    case "METHOD":
171                        index = m.attributes.getIndex(cf.constant_pool,
172                                                      AnnoType);
173                        memberName = m.getName(cf.constant_pool);
174                        if (index != -1)
175                            attr = m.attributes.get(index);
176                        //fetch index annotations from code attribute.
177                        index2 = m.attributes.getIndex(cf.constant_pool,
178                                                       Attribute.Code);
179                        if (index2 != -1) {
180                            cattr = m.attributes.get(index2);
181                            assert cattr instanceof Code_attribute;
182                            CAttr = (Code_attribute)cattr;
183                            index2 = CAttr.attributes.getIndex(cf.constant_pool,
184                                                               AnnoType);
185                            if (index2 != -1)
186                                cattr = CAttr.attributes.get(index2);
187                        }
188                        break;
189                    case "FIELD":
190                        index = f.attributes.getIndex(cf.constant_pool,
191                                                      AnnoType);
192                        memberName = f.getName(cf.constant_pool);
193                        if (index != -1)
194                            attr = f.attributes.get(index);
195                        //fetch index annotations from code attribute.
196                        index2 = cf.attributes.getIndex(cf.constant_pool,
197                                                        Attribute.Code);
198                        if (index2!= -1) {
199                            cattr = cf.attributes.get(index2);
200                            assert cattr instanceof Code_attribute;
201                            CAttr = (Code_attribute)cattr;
202                            index2 = CAttr.attributes.getIndex(cf.constant_pool,
203                                                               AnnoType);
204                            if (index2!= -1)
205                                cattr = CAttr.attributes.get(index2);
206                        }
207                        break;
208
209                    default:
210                        memberName = cf.getName();
211                        index = cf.attributes.getIndex(cf.constant_pool,
212                                                       AnnoType);
213                        if (index!= -1) attr = cf.attributes.get(index);
214                        break;
215                }
216            }
217            catch (ConstantPoolException cpe) { cpe.printStackTrace(); }
218            try {
219                testClassName=cf.getName();
220                testcase = ttype + ": " + testClassName + ": " +
221                           memberName + ", ";
222            }
223            catch (ConstantPoolException cpe) { cpe.printStackTrace(); }
224            if (index != -1) {
225                switch (AnnoType) {
226                    case Attribute.RuntimeVisibleTypeAnnotations:
227                        //count RuntimeVisibleTypeAnnotations
228                        RuntimeVisibleTypeAnnotations_attribute RVTAa =
229                                (RuntimeVisibleTypeAnnotations_attribute)attr;
230                        vtaActual += RVTAa.annotations.length;
231                        break;
232                    case Attribute.RuntimeVisibleAnnotations:
233                        //count RuntimeVisibleAnnotations
234                        RuntimeVisibleAnnotations_attribute RVAa =
235                                (RuntimeVisibleAnnotations_attribute)attr;
236                        vaActual += RVAa.annotations.length;
237                        break;
238                    case Attribute.RuntimeInvisibleTypeAnnotations:
239                        //count RuntimeInvisibleTypeAnnotations
240                        RuntimeInvisibleTypeAnnotations_attribute RITAa =
241                                (RuntimeInvisibleTypeAnnotations_attribute)attr;
242                        itaActual += RITAa.annotations.length;
243                        break;
244                    case Attribute.RuntimeInvisibleAnnotations:
245                        //count RuntimeInvisibleAnnotations
246                        RuntimeInvisibleAnnotations_attribute RIAa =
247                                (RuntimeInvisibleAnnotations_attribute)attr;
248                        iaActual += RIAa.annotations.length;
249                        break;
250                }
251            }
252            // annotations from code attribute.
253            if (index2 != -1) {
254                switch (AnnoType) {
255                    case Attribute.RuntimeVisibleTypeAnnotations:
256                        //count RuntimeVisibleTypeAnnotations
257                        RuntimeVisibleTypeAnnotations_attribute RVTAa =
258                                (RuntimeVisibleTypeAnnotations_attribute)cattr;
259                        vtaActual += RVTAa.annotations.length;
260                        break;
261                    case Attribute.RuntimeVisibleAnnotations:
262                        //count RuntimeVisibleAnnotations
263                        RuntimeVisibleAnnotations_attribute RVAa =
264                                (RuntimeVisibleAnnotations_attribute)cattr;
265                        vaActual += RVAa.annotations.length;
266                        break;
267                    case Attribute.RuntimeInvisibleTypeAnnotations:
268                        //count RuntimeInvisibleTypeAnnotations
269                        RuntimeInvisibleTypeAnnotations_attribute RITAa =
270                                (RuntimeInvisibleTypeAnnotations_attribute)cattr;
271                        itaActual += RITAa.annotations.length;
272                        break;
273                    case Attribute.RuntimeInvisibleAnnotations:
274                        //count RuntimeInvisibleAnnotations
275                        RuntimeInvisibleAnnotations_attribute RIAa =
276                                (RuntimeInvisibleAnnotations_attribute)cattr;
277                        iaActual += RIAa.annotations.length;
278                        break;
279                }
280            }
281        }
282
283        switch (memberName) {
284            //METHODs
285            case "test" : vtaExp=4;  itaExp=4;  vaExp=0; iaExp=0; tc++; break;
286            case "mtest": vtaExp=4;  itaExp=4;  vaExp=1; iaExp=1; tc++; break;
287            case "m1":    vtaExp=2;  itaExp=2;  vaExp=1; iaExp=1; tc++; break;
288            case "m2":    vtaExp=4;  itaExp=4;  vaExp=1; iaExp=1; tc++; break;
289            case "m3":    vtaExp=10; itaExp=10; vaExp=1; iaExp=1; tc++; break;
290            case "tm":    vtaExp=6;  itaExp=6;  vaExp=1; iaExp=1; tc++; break;
291            //inner class
292            case "i_m1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
293            case "i_m2":  vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
294            case "i_um":  vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
295            //local class
296            case "l_m1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
297            case "l_m2":  vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
298            case "l_um":  vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
299            //anon class
300            case "mm_m1": vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
301            case "mm_m2": vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
302            case "mm_m3": vtaExp=10; itaExp=10;vaExp=1; iaExp=1; tc++; break;
303            case "mm_tm": vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
304            //InnerAnon class
305            case "ia_m1": vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
306            case "ia_m2": vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
307            case "ia_um": vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
308            //FIELDs
309            case "data":   vtaExp = 2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
310            case "odata1": vtaExp = 2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
311            case "pdata1": vtaExp = 2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
312            case "tdata":  vtaExp = 2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
313            case "sa1":    vtaExp = 6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
314            //inner class
315            case "i_odata1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
316            case "i_pdata1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
317            case "i_udata":   vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
318            case "i_sa1":     vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
319            case "i_tdata":   vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
320            //local class
321            case "l_odata1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
322            case "l_pdata1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
323            case "l_udata":   vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
324            case "l_sa1":     vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
325            case "l_tdata":   vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
326            //anon class
327            case "mm_odata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break;
328            case "mm_pdata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break;
329            case "mm_sa1":    vtaExp = 6; itaExp=6; vaExp=1; iaExp=1; tc++; break;
330            case "mm_tdata":  vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break;
331            // InnerAnon class
332            case "ia_odata1": vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
333            case "ia_pdata1": vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
334            case "ia_udata":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
335            case "ia_sa1":    vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
336            case "ia_tdata":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
337            case "IA":        vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
338            case "IN":        vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
339            // default cases are <init>, this$0, this$1, mmtest, atest
340            default:          vtaExp = 0;  itaExp=0; vaExp=0; iaExp=0;    break;
341        }
342        check(testcase,vtaExp,   itaExp,   vaExp,   iaExp,
343                       vtaActual,itaActual,vaActual,iaActual);
344    }
345
346    public void run() {
347        ClassFile cf   = null;
348        InputStream in = null;
349        int testcount  = 1;
350        File testFile  = null;
351        // Generate source, check methods and fields for each combination.
352        for (Boolean[] bCombo : bRepeat) {
353            As=bCombo[0]; Bs=bCombo[1]; Cs=bCombo[2];
354            Ds=bCombo[3]; TAs=bCombo[4]; TBs=bCombo[5];
355            String testname = "Test" + testcount++;
356            println("Combinations: " + As + ", " + Bs + ", " + Cs + ", " + Ds +
357                    ", " + TAs + ", " + TBs +
358                    "; see " + testname + ".java");
359            String[] classes = {testname + ".class",
360                                testname + "$Inner.class",
361                                testname + "$1Local1.class",
362                                testname + "$1.class",
363                                testname + "$1$1.class",
364                                testname + "$1$InnerAnon.class"
365            };
366            // Create test source, create and compile File.
367            String sourceString = getSource(srcTemplate, testname,
368                                            As, Bs, Cs, Ds, TAs, TBs);
369            System.out.println(sourceString);
370            try {
371                testFile = writeTestFile(testname+".java", sourceString);
372            }
373            catch (IOException ioe) { ioe.printStackTrace(); }
374            // Compile test source and read classfile.
375            File classFile = null;
376            try {
377                classFile = compile(testFile);
378            }
379            catch (Error err) {
380                System.err.println("FAILED compile. Source:\n" + sourceString);
381                throw err;
382            }
383            String testloc = classFile.getAbsolutePath().substring(
384                   0,classFile.getAbsolutePath().indexOf(classFile.getPath()));
385            for (String clazz : classes) {
386                try {
387                    cf = ClassFile.read(new File(testloc+clazz));
388                }
389                catch (Exception e) { e.printStackTrace();  }
390                // Test for all methods and fields
391                for (Method m: cf.methods) {
392                    test("METHOD", cf, m, null, true);
393                }
394                for (Field f: cf.fields) {
395                    test("FIELD", cf, null, f, true);
396                }
397            }
398        }
399        report();
400        if (tc!=xtc) System.out.println("Test Count: " + tc + " != " +
401                                       "expected: " + xtc);
402    }
403
404
405    String getSrcTemplate(String sTemplate) {
406        List<String> tmpl = null;
407        String sTmpl = "";
408        try {
409            tmpl = Files.readAllLines(new File(testSrc,sTemplate).toPath(),
410                                      Charset.defaultCharset());
411        }
412        catch (IOException ioe) {
413            String error = "FAILED: Test failed to read template" + sTemplate;
414            ioe.printStackTrace();
415            throw new RuntimeException(error);
416        }
417        for (String l : tmpl)
418            sTmpl=sTmpl.concat(l).concat("\n");
419        return sTmpl;
420    }
421
422    // test class template
423    String getSource(String templateName, String testname,
424                     Boolean Arepeats,  Boolean Brepeats,
425                     Boolean Crepeats,  Boolean Drepeats,
426                     Boolean TArepeats, Boolean TBrepeats) {
427        String As  = Arepeats  ? "@A @A":"@A",
428               Bs  = Brepeats  ? "@B @B":"@B",
429               Cs  = Crepeats  ? "@C @C":"@C",
430               Ds  = Drepeats  ? "@D @D":"@D",
431               TAs = TArepeats ? "@TA @TA":"@TA",
432               TBs = TBrepeats ? "@TB @TB":"@TB";
433
434        // split up replace() lines for readability
435        String testsource = getSrcTemplate(templateName).replace("testname",testname);
436        testsource = testsource.replace("_As",As).replace("_Bs",Bs).replace("_Cs",Cs);
437        testsource = testsource.replace("_Ds",Ds).replace("_TAs",TAs).replace("_TBs",TBs);
438        return testsource;
439    }
440}
441