--- /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;
+ }
+}