langtools/test/tools/javac/annotations/typeAnnotations/classfile/TestAnonInnerClasses.java
changeset 21010 5ffe0d8a5e24
child 30727 a4dac07f827c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/TestAnonInnerClasses.java	Thu Oct 10 20:12:08 2013 -0400
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8005085 8008762 8008751 8013065 8015323 8015257
+ * @summary Type annotations on anonymous and inner class.
+ *  Six TYPE_USE annotations are repeated(or not); Four combinations create
+ *  four test files, and each results in the test class and 2 anonymous classes.
+ *  Each element of these three classes is checked for expected number of the
+ *  four annotation Attributes. Expected annotation counts depend on type of
+ *  annotation place on type of element (a FIELD&TYPE_USE element on a field
+ *  results in 2). Elements with no annotations expect 0.
+ *  Source template is read in from testanoninner.template
+ *
+ */
+import java.lang.annotation.*;
+import java.io.*;
+import java.util.List;
+import java.util.LinkedList;
+import com.sun.tools.classfile.*;
+import java.nio.file.Files;
+import java.nio.charset.*;
+import java.io.File;
+import java.io.IOException;
+
+
+import java.lang.annotation.*;
+import static java.lang.annotation.RetentionPolicy.*;
+import static java.lang.annotation.ElementType.*;
+
+/*
+ * A source template is read in and testname and annotations are inserted
+ * via replace().
+ */
+public class TestAnonInnerClasses extends ClassfileTestHelper {
+    // tally errors and test cases
+    int errors = 0;
+    int checks = 0;
+    //Note expected test count in case of skips due to bugs.
+    int tc = 0, xtc = 180; // 45 x 4 variations of repeated annotations.
+    File testSrc = new File(System.getProperty("test.src"));
+
+    String[] AnnoAttributes = {
+        Attribute.RuntimeVisibleTypeAnnotations,
+        Attribute.RuntimeInvisibleTypeAnnotations,
+        Attribute.RuntimeVisibleAnnotations,
+        Attribute.RuntimeInvisibleAnnotations
+    };
+
+    // template for source files
+    String srcTemplate = "testanoninner.template";
+
+    // Four test files generated based on combinations of repeating annotations.
+    Boolean As= false, Bs=true, Cs=false, Ds=false, TAs=false,TBs=false;
+    Boolean[][] bRepeat = new Boolean[][]{
+                 /* no repeats    */ {false, false, false, false, false, false},
+                 /* repeat A,C,TA */ {true,  false, true,  false, true,  false},
+                 /* repeat B,D,TB */ {false, true,  false, true,  false, true},
+                 /* repeat all    */ {true,  true,  true,  true,  true,  true}
+    };
+    // Save descriptions of failed test case; does not terminate upon a failure.
+    List<String> failed = new LinkedList<>();
+
+    public static void main(String[] args) throws Exception {
+        new TestAnonInnerClasses().run();
+    }
+
+    // Check annotation counts and make reports sufficiently descriptive to
+    // easily diagnose.
+    void check(String testcase, int vtaX, int itaX, int vaX, int iaX,
+                                int vtaA, int itaA, int vaA, int iaA) {
+
+        String descr = " checking " + testcase+" _TYPE_, expected: " +
+            vtaX + ", " + itaX + ", " + vaX + ", " + iaX + "; actual: " +
+            vtaA + ", " + itaA + ", " + vaA + ", " + iaA;
+        String description;
+        description=descr.replace("_TYPE_","RuntimeVisibleTypeAnnotations");
+        if (vtaX != vtaA) {
+            errors++;
+            failed.add(++checks + " " + testcase + ": (vtaX) " + vtaX +
+                       " != " + vtaA + " (vtaA)");
+            println(checks + " FAIL: " + description);
+        } else {
+            println(++checks + " PASS: " + description);
+        }
+        description=descr.replace("_TYPE_","RuntimeInvisibleTypeAnnotations");
+        if (itaX != itaA) {
+            errors++;
+            failed.add(++checks + " " + testcase + ": (itaX) " + itaX + " != " +
+                       itaA + " (itaA)");
+            println(checks + " FAIL: " + description);
+        } else {
+            println(++checks + " PASS: " + description);
+        }
+        description=descr.replace("_TYPE_","RuntimeVisibleAnnotations");
+        if (vaX != vaA) {
+            errors++;
+            failed.add(++checks + " " + testcase + ": (vaX) " + vaX + " != " +
+                       vaA + " (vaA)");
+            println(checks + " FAIL: " + description);
+        } else {
+            println(++checks + " PASS: " + description);
+        }
+        description=descr.replace("_TYPE_","RuntimeInvisibleAnnotations");
+        if (iaX != iaA) {
+            errors++;
+            failed.add(++checks + " " + testcase + ": (iaX) " + iaX + " != " +
+                       iaA + " (iaA)");
+            println(checks + " FAIL: " + description);
+        } else {
+            println(++checks + " PASS: " + description);
+        }
+        println("");
+    }
+
+    // Print failed cases (if any) and throw exception for fail.
+    void report() {
+        if (errors!=0) {
+            System.err.println("Failed tests: " + errors +
+                               "\nfailed test cases:\n");
+            for (String t: failed) System.err.println("  " + t);
+            throw new RuntimeException("FAIL: There were test failures.");
+        } else
+            System.out.println("PASSED all tests.");
+    }
+
+    void test(String ttype, ClassFile cf, Method m, Field f, boolean visible) {
+        int vtaActual = 0,
+            itaActual = 0,
+            vaActual = 0,
+            iaActual = 0,
+            vtaExp = 0,
+            itaExp = 0,
+            vaExp = 0,
+            iaExp = 0,
+            index = 0,
+            index2 = 0;
+        String memberName = null,
+            testcase = "undefined",
+            testClassName = null;
+        Attribute attr = null,
+            cattr = null;
+        Code_attribute CAttr = null;
+        // Get counts of 4 annotation Attributes on element being checked.
+        for (String AnnoType : AnnoAttributes) {
+            try {
+                switch (ttype) {
+                    case "METHOD":
+                        index = m.attributes.getIndex(cf.constant_pool,
+                                                      AnnoType);
+                        memberName = m.getName(cf.constant_pool);
+                        if (index != -1)
+                            attr = m.attributes.get(index);
+                        //fetch index annotations from code attribute.
+                        index2 = m.attributes.getIndex(cf.constant_pool,
+                                                       Attribute.Code);
+                        if (index2 != -1) {
+                            cattr = m.attributes.get(index2);
+                            assert cattr instanceof Code_attribute;
+                            CAttr = (Code_attribute)cattr;
+                            index2 = CAttr.attributes.getIndex(cf.constant_pool,
+                                                               AnnoType);
+                            if (index2 != -1)
+                                cattr = CAttr.attributes.get(index2);
+                        }
+                        break;
+                    case "FIELD":
+                        index = f.attributes.getIndex(cf.constant_pool,
+                                                      AnnoType);
+                        memberName = f.getName(cf.constant_pool);
+                        if (index != -1)
+                            attr = f.attributes.get(index);
+                        //fetch index annotations from code attribute.
+                        index2 = cf.attributes.getIndex(cf.constant_pool,
+                                                        Attribute.Code);
+                        if (index2!= -1) {
+                            cattr = cf.attributes.get(index2);
+                            assert cattr instanceof Code_attribute;
+                            CAttr = (Code_attribute)cattr;
+                            index2 = CAttr.attributes.getIndex(cf.constant_pool,
+                                                               AnnoType);
+                            if (index2!= -1)
+                                cattr = CAttr.attributes.get(index2);
+                        }
+                        break;
+
+                    default:
+                        memberName = cf.getName();
+                        index = cf.attributes.getIndex(cf.constant_pool,
+                                                       AnnoType);
+                        if (index!= -1) attr = cf.attributes.get(index);
+                        break;
+                }
+            }
+            catch (ConstantPoolException cpe) { cpe.printStackTrace(); }
+            try {
+                testClassName=cf.getName();
+                testcase = ttype + ": " + testClassName + ": " +
+                           memberName + ", ";
+            }
+            catch (ConstantPoolException cpe) { cpe.printStackTrace(); }
+            if (index != -1) {
+                switch (AnnoType) {
+                    case Attribute.RuntimeVisibleTypeAnnotations:
+                        //count RuntimeVisibleTypeAnnotations
+                        RuntimeVisibleTypeAnnotations_attribute RVTAa =
+                                (RuntimeVisibleTypeAnnotations_attribute)attr;
+                        vtaActual += RVTAa.annotations.length;
+                        break;
+                    case Attribute.RuntimeVisibleAnnotations:
+                        //count RuntimeVisibleAnnotations
+                        RuntimeVisibleAnnotations_attribute RVAa =
+                                (RuntimeVisibleAnnotations_attribute)attr;
+                        vaActual += RVAa.annotations.length;
+                        break;
+                    case Attribute.RuntimeInvisibleTypeAnnotations:
+                        //count RuntimeInvisibleTypeAnnotations
+                        RuntimeInvisibleTypeAnnotations_attribute RITAa =
+                                (RuntimeInvisibleTypeAnnotations_attribute)attr;
+                        itaActual += RITAa.annotations.length;
+                        break;
+                    case Attribute.RuntimeInvisibleAnnotations:
+                        //count RuntimeInvisibleAnnotations
+                        RuntimeInvisibleAnnotations_attribute RIAa =
+                                (RuntimeInvisibleAnnotations_attribute)attr;
+                        iaActual += RIAa.annotations.length;
+                        break;
+                }
+            }
+            // annotations from code attribute.
+            if (index2 != -1) {
+                switch (AnnoType) {
+                    case Attribute.RuntimeVisibleTypeAnnotations:
+                        //count RuntimeVisibleTypeAnnotations
+                        RuntimeVisibleTypeAnnotations_attribute RVTAa =
+                                (RuntimeVisibleTypeAnnotations_attribute)cattr;
+                        vtaActual += RVTAa.annotations.length;
+                        break;
+                    case Attribute.RuntimeVisibleAnnotations:
+                        //count RuntimeVisibleAnnotations
+                        RuntimeVisibleAnnotations_attribute RVAa =
+                                (RuntimeVisibleAnnotations_attribute)cattr;
+                        vaActual += RVAa.annotations.length;
+                        break;
+                    case Attribute.RuntimeInvisibleTypeAnnotations:
+                        //count RuntimeInvisibleTypeAnnotations
+                        RuntimeInvisibleTypeAnnotations_attribute RITAa =
+                                (RuntimeInvisibleTypeAnnotations_attribute)cattr;
+                        itaActual += RITAa.annotations.length;
+                        break;
+                    case Attribute.RuntimeInvisibleAnnotations:
+                        //count RuntimeInvisibleAnnotations
+                        RuntimeInvisibleAnnotations_attribute RIAa =
+                                (RuntimeInvisibleAnnotations_attribute)cattr;
+                        iaActual += RIAa.annotations.length;
+                        break;
+                }
+            }
+        }
+
+        switch (memberName) {
+            //METHODs
+            case "test" : vtaExp=4;  itaExp=4;  vaExp=0; iaExp=0; tc++; break;
+            case "mtest": vtaExp=4;  itaExp=4;  vaExp=1; iaExp=1; tc++; break;
+            case "m1":    vtaExp=2;  itaExp=2;  vaExp=1; iaExp=1; tc++; break;
+            case "m2":    vtaExp=4;  itaExp=4;  vaExp=1; iaExp=1; tc++; break;
+            case "m3":    vtaExp=10; itaExp=10; vaExp=1; iaExp=1; tc++; break;
+            case "tm":    vtaExp=6;  itaExp=6;  vaExp=1; iaExp=1; tc++; break;
+            //inner class
+            case "i_m1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "i_m2":  vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
+            case "i_um":  vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
+            //local class
+            case "l_m1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "l_m2":  vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
+            case "l_um":  vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
+            //anon class
+            case "mm_m1": vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "mm_m2": vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
+            case "mm_m3": vtaExp=10; itaExp=10;vaExp=1; iaExp=1; tc++; break;
+            case "mm_tm": vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
+            //InnerAnon class
+            case "ia_m1": vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "ia_m2": vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
+            case "ia_um": vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
+            //FIELDs
+            case "data":   vtaExp = 2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "odata1": vtaExp = 2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "pdata1": vtaExp = 2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "tdata":  vtaExp = 2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "sa1":    vtaExp = 6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
+            //inner class
+            case "i_odata1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "i_pdata1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "i_udata":   vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "i_sa1":     vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
+            case "i_tdata":   vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            //local class
+            case "l_odata1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "l_pdata1":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "l_udata":   vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "l_sa1":     vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
+            case "l_tdata":   vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            //anon class
+            case "mm_odata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "mm_pdata1": vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "mm_sa1":    vtaExp = 6; itaExp=6; vaExp=1; iaExp=1; tc++; break;
+            case "mm_tdata":  vtaExp = 2; itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            // InnerAnon class
+            case "ia_odata1": vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "ia_pdata1": vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "ia_udata":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "ia_sa1":    vtaExp=6;  itaExp=6; vaExp=1; iaExp=1; tc++; break;
+            case "ia_tdata":  vtaExp=2;  itaExp=2; vaExp=1; iaExp=1; tc++; break;
+            case "IA":        vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
+            case "IN":        vtaExp=4;  itaExp=4; vaExp=1; iaExp=1; tc++; break;
+            // default cases are <init>, this$0, this$1, mmtest, atest
+            default:          vtaExp = 0;  itaExp=0; vaExp=0; iaExp=0;    break;
+        }
+        check(testcase,vtaExp,   itaExp,   vaExp,   iaExp,
+                       vtaActual,itaActual,vaActual,iaActual);
+    }
+
+    public void run() {
+        ClassFile cf   = null;
+        InputStream in = null;
+        int testcount  = 1;
+        File testFile  = null;
+        // Generate source, check methods and fields for each combination.
+        for (Boolean[] bCombo : bRepeat) {
+            As=bCombo[0]; Bs=bCombo[1]; Cs=bCombo[2];
+            Ds=bCombo[3]; TAs=bCombo[4]; TBs=bCombo[5];
+            String testname = "Test" + testcount++;
+            println("Combinations: " + As + ", " + Bs + ", " + Cs + ", " + Ds +
+                    ", " + TAs + ", " + TBs +
+                    "; see " + testname + ".java");
+            String[] classes = {testname + ".class",
+                                testname + "$Inner.class",
+                                testname + "$1Local1.class",
+                                testname + "$1.class",
+                                testname + "$1$1.class",
+                                testname + "$1$InnerAnon.class"
+            };
+            // Create test source, create and compile File.
+            String sourceString = getSource(srcTemplate, testname,
+                                            As, Bs, Cs, Ds, TAs, TBs);
+            System.out.println(sourceString);
+            try {
+                testFile = writeTestFile(testname+".java", sourceString);
+            }
+            catch (IOException ioe) { ioe.printStackTrace(); }
+            // Compile test source and read classfile.
+            File classFile = null;
+            try {
+                classFile = compile(testFile);
+            }
+            catch (Error err) {
+                System.err.println("FAILED compile. Source:\n" + sourceString);
+                throw err;
+            }
+            String testloc = classFile.getAbsolutePath().substring(
+                   0,classFile.getAbsolutePath().indexOf(classFile.getPath()));
+            for (String clazz : classes) {
+                try {
+                    cf = ClassFile.read(new File(testloc+clazz));
+                }
+                catch (Exception e) { e.printStackTrace();  }
+                // Test for all methods and fields
+                for (Method m: cf.methods) {
+                    test("METHOD", cf, m, null, true);
+                }
+                for (Field f: cf.fields) {
+                    test("FIELD", cf, null, f, true);
+                }
+            }
+        }
+        report();
+        if (tc!=xtc) System.out.println("Test Count: " + tc + " != " +
+                                       "expected: " + xtc);
+    }
+
+
+    String getSrcTemplate(String sTemplate) {
+        List<String> tmpl = null;
+        String sTmpl = "";
+        try {
+            tmpl = Files.readAllLines(new File(testSrc,sTemplate).toPath(),
+                                      Charset.defaultCharset());
+        }
+        catch (IOException ioe) {
+            String error = "FAILED: Test failed to read template" + sTemplate;
+            ioe.printStackTrace();
+            throw new RuntimeException(error);
+        }
+        for (String l : tmpl)
+            sTmpl=sTmpl.concat(l).concat("\n");
+        return sTmpl;
+    }
+
+    // test class template
+    String getSource(String templateName, String testname,
+                     Boolean Arepeats,  Boolean Brepeats,
+                     Boolean Crepeats,  Boolean Drepeats,
+                     Boolean TArepeats, Boolean TBrepeats) {
+        String As  = Arepeats  ? "@A @A":"@A",
+               Bs  = Brepeats  ? "@B @B":"@B",
+               Cs  = Crepeats  ? "@C @C":"@C",
+               Ds  = Drepeats  ? "@D @D":"@D",
+               TAs = TArepeats ? "@TA @TA":"@TA",
+               TBs = TBrepeats ? "@TB @TB":"@TB";
+
+        // split up replace() lines for readability
+        String testsource = getSrcTemplate(templateName).replace("testname",testname);
+        testsource = testsource.replace("_As",As).replace("_Bs",Bs).replace("_Cs",Cs);
+        testsource = testsource.replace("_Ds",Ds).replace("_TAs",TAs).replace("_TBs",TBs);
+        return testsource;
+    }
+}