--- /dev/null Fri Mar 15 11:47:22 2013 +++ new/test/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest3.java Fri Mar 15 11:47:22 2013 @@ -0,0 +1,547 @@ +/* + * 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 8005681 8008769 8010015 + * @summary Check (repeating)type annotations on lambda usage. + * @run main CombinationsTargetTest3 + */ + +import com.sun.tools.classfile.*; +import java.io.File; +import java.util.Vector; + +public class CombinationsTargetTest3 extends ClassfileTestHelper { + + // Helps identify test case in event of failure. + int testcount = 0; + + // Known failure cases due to open bugs. + Vector skippedTests = new Vector<>(); + void printSkips() { + if(!skippedTests.isEmpty()) { + println(skippedTests.size() + " tests were skipped:"); + for(String t : skippedTests) + println(" " + t); + } + } + + // Test case descriptions and expected annotation counts. + enum srce { + src1("type annotations on lambda expression as method arg.",4,0), + src2("type annotations on new in single line lambda expression",2,0), + src3("type annotations in lambda expression code block",4,0), + src4("type annotations in code block with recursion,cast",2,0), + src5("type annotations in lambda expression code block",4,0), + src6("type annotations on type parm in method reference",4,0), + src7("type annotations on inner class field of lambda expression",2,2), + src8("type annotations in inner class of lambda expression",4,2), + src9("type annotations on static method of interface",4,2); + + String description; + // Expected annotation counts are same for Vis or Invis, but which one + // depends on retention type. + Integer[] exp = { 0, 0 }; + + // If class to test is inner class, this may be set in SourceString() + String innerClassname = null ; + + // If class to test is not main or inner class; set in sourceString() + String altClassName = null; + + srce(String desc, int e1, int e2) { + description = this + ": " +desc; + exp[0]=e1; + exp[1]=e2; + } + } + + // Check for RuntimeInvisible or RuntimeVisible annotations. + String[] RType={"CLASS", "RUNTIME"}; + + // This can be a compile only test. + static boolean compileonly=false; + + // Collect failure for end of test report() + Vector vFailures = new Vector<>(); + + // pass/fail determined after all tests have run. + void report() { + if(vFailures.isEmpty()) { + printSkips(); + println("PASS"); + } else { + System.err.println("FAILED: There were failures:"); + for(String f : vFailures) + System.err.println(f); + throw new RuntimeException("There were failures. See test log."); + } + } + + public static void main(String[] args) throws Exception { + if(args.length>0 && args[0].compareTo("compileonly")==0) + compileonly=true; + new CombinationsTargetTest3().run(); + } + + void run() throws Exception { + // Determines which repeat and order in source(ABMix). + Boolean As= false, BDs=true, ABMix=false; + int testrun=0; + // A repeats and/or B/D repeats, ABMix for order of As and Bs. + Boolean [][] bRepeat = new Boolean[][]{{false,false,false}, //no repeats + {true,false,false}, //repeat @A + {false,true,false}, //repeat @B + {true,true,false}, //repeat both + {false,false,true} //repeat mix + }; + // Added ElementType's. All set; not permuted (so far) for this test + String et = "TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE"; + + // test loop + for(Boolean[] bCombo : bRepeat) { + As=bCombo[0]; BDs=bCombo[1]; ABMix=bCombo[2]; + for(srce src : srce.values()) + for( String rtype : RType ) { + switch( rtype ) { + case "RUNTIME": + test(0,src.exp[0],0,src.exp[1],As, BDs, ABMix, + "RUNTIME", et, ++testrun, src); + break; + case "CLASS": + test(src.exp[0],0,src.exp[1],0,As, BDs, ABMix, + "CLASS", et, ++testrun, src); + break; + } + } + } + report(); + } + + // Filter out skipped cases, compile, pass class file to test method, + // count annotations and asses results. + public void test(int tinv, int tvis, int inv, int vis, Boolean Arepeats, + Boolean BDrepeats, Boolean ABmix, String rtn, String et2, + Integer N, srce source) throws Exception { + ++testcount; + expected_tvisibles = tvis; + expected_tinvisibles = tinv; + expected_visibles = vis; + expected_invisibles = inv; + File testFile = null; + String tname="Test" + N.toString(); + String testDef = "Test " + testcount + " parameters: tinv=" + tinv + + ", tvis=" + tvis + ", inv=" + inv + ", vis=" + vis + + ", Arepeats=" + Arepeats + ", BDrepeats=" + BDrepeats + + ", ABmix=" + ABmix + ", retention: " + rtn + ", anno2: " + + et2 + ", src=" + source; + + // Skip failing cases with bug ID's + //8010015 type-annotations on field of inner class in lambda expression + if(source.equals(srce.src7)) { + skippedTests.add(testDef + + "\n--8010015 type-annotations on field of inner" + + " class in lambda expression."); + return; + } //8005681 repeated type-annotations on new/cast/array in + // inner class in lambda expression." + else if ((source.equals(srce.src2) || source.equals(srce.src4) || + source.equals(srce.src5)) && + (ABmix || (Arepeats && BDrepeats))) { + skippedTests.add(testDef + + "\n--8005681 repeated type-annotations on new/cast/array in" + + " inner class in lambda expression."); + return; + }//8008769 Repeated type-annotations on type parm of local variable + else if (source.equals(srce.src6) && + (ABmix || (Arepeats && BDrepeats))) { + skippedTests.add(testDef + "\n--8008769 Repeated " + + "type-annotations on type parm of local variable"); + return; + } + + println(testDef); + // Create test source and File. + String sourceString = sourceString(tname, rtn, et2, Arepeats, + BDrepeats, ABmix, source); + testFile = writeTestFile(tname+".java", sourceString); + // Compile test source and read classfile. + File classFile = null; + try { + classFile = compile(testFile); + System.out.println("pass compile: " + tname + ".java"); + } catch (Error err) { + System.err.println("fail compile. Source:\n" + sourceString); + throw err; + } + if(!compileonly) { + //check if innerClassname is set + String classdir = classFile.getAbsolutePath(); + if(source.innerClassname != null) { + StringBuffer sb = new StringBuffer(classdir); + classFile=new File(sb.insert(sb.lastIndexOf(".class"), + source.innerClassname).toString()); + source.innerClassname=null; + } else if (source.altClassName != null) { + classdir = classdir.substring(0,classdir.lastIndexOf("Test")); + classFile=new File(classdir.concat(source.altClassName)); + source.innerClassname=null; + } + ClassFile cf = ClassFile.read(classFile); + + println("Testing classfile: " + cf.getName()); + //Test class,fields and method counts. + test(cf); + + for (Field f : cf.fields) { + test(cf, f); + test(cf, f, true); + } + for (Method m: cf.methods) { + test(cf, m); + test(cf, m, true); + } + + countAnnotations(); // sets errors=0 before counting. + if (errors > 0) { + System.err.println( testDef ); + System.err.println( "Source:\n" + sourceString ); + vFailures.add(testDef); + } + } + if(errors==0) println("Pass"); println(""); + } + + /* + * Source definitions for test cases. + * To add a test: + * Add enum to srce(near top of file) with expected annotation counts. + * Add source defintion below. + */ + String sourceString(String testname, String retentn, String annot2, + Boolean Arepeats, Boolean BDrepeats, Boolean ABmix, + srce src) { + + String As = "@A", Bs = "@B", Ds = "@D"; + if(Arepeats) As = "@A @A"; + if(BDrepeats) { + Bs = "@B @B"; + Ds = "@D @D"; + } + if(ABmix) { As = "@A @B"; Bs = "@A @B"; Ds = "@D @D"; } + + // Source to check for TYPE_USE and TYPE_PARAMETER annotations. + // Source base (annotations) is same for all test cases. + String source = new String(); + String imports = new String("import java.lang.annotation.*; \n" + + "import static java.lang.annotation.RetentionPolicy.*; \n" + + "import static java.lang.annotation.ElementType.*; \n" + + "import java.util.List; \n" + + "import java.util.ArrayList;\n\n"); + + String sourceBase = new String( + "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @Repeatable( AC.class ) @interface A { }\n" + + "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @interface AC { A[] value(); } \n" + + "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @Repeatable( BC.class ) @interface B { }\n" + + "@Retention("+retentn+") @Target({TYPE_USE,_OTHER_}) @interface BC { B[] value(); } \n" + + "@Retention("+retentn+") @Target({TYPE_USE,TYPE_PARAMETER,_OTHER_}) @Repeatable(DC.class) @interface D { }\n" + + "@Retention("+retentn+") @Target({TYPE_USE,TYPE_PARAMETER,_OTHER_}) @interface DC { D[] value(); }"); + + // Test case sources with sample generated source + switch(src) { + case src1: //(repeating) type annotations on lambda expressions. + /* + * class Test1 { + * Test1(){} + * interface MapFun { R m( T n); } + * void meth( MapFun mf ) { + * assert( mf.m("four") == 4); + * } + * void test(Integer i) { + * // lambda expression as method arg + * meth( (@A @B String s) -> { @A @B Integer len = s.length(); return len; } ); + * }} + */ + source = new String( source + + "// " + src.description + "\n" + + "class " + testname + " {\n" + + " " + testname +"(){} \n" + + " interface MapFun { R m( T n); }\n\n" + + " void meth( MapFun mf ) {\n" + + " assert( mf.m(\"four\") == 4);\n" + + " }\n\n" + + " void test(Integer i) {\n" + + " // lambda expression as method arg\n" + + " meth( (_As_ _Bs_ String s) -> { _As_ _Bs_ Integer len = s.length(); return len; } );\n" + + "}}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n"; + break; + case src2: //(repeating) type annotations on new in single line lambda expression. + /* + * //case2: (repeating) type annotations on new in single lambda expressions. + * class Test2{ + * interface MapFun { R m( T n); } + * MapFun its; + * void test(Integer i) { + * its = a -> "~"+new @A @B Integer(a).toString()+"~"; + * System.out.println("in: " + i + " out: " + its.m(i)); + * }} + */ + source = new String( source + + "// " + src.description + "\n" + + "class " + testname + "{\n" + + " interface MapFun { R m( T n); }\n" + + " MapFun its;\n" + + " void test(Integer i) {\n" + + " its = a -> \"~\"+new _As_ _Bs_ Integer(a).toString()+\"~\";\n" + + " System.out.println(\"in: \" + i + \" out: \" + its.m(i));\n" + + " }\n" + + "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n"; + break; + case src3: //(repeating) type annotations in lambda expression code block. + /* + * class Test183{ + * interface MapFun { R m( T n); } + * MapFun, String> iLs; + * void testm(Integer i) { + * iLs = l -> { @A @B @A @B String ret = new String(); + * for( @A @B @A @B Integer i2 : l) + * ret=ret.concat(i2.toString() + " "); + * return ret; }; + * List li = new ArrayList<>(); + * for(int j=0; j { R m( T n); }\n" + + " MapFun, String> iLs;\n" + + " void testm(Integer i) {\n" + + " iLs = l -> { _As_ _Bs_ String ret = new String();\n" + + " for( _As_ _Bs_ Integer i2 : l)\n" + + " ret=ret.concat(i2.toString() + \" \");\n" + + " return ret; };\n" + + " List li = new ArrayList<>();\n" + + " for(int j=0; j { R m( T n); } + * MapFun nf; + * void testm(Integer i) { + * nf = j -> { return j == 1 ? 1.0 : (@A @B @A @B Double)(nf.m(j-1) * j); }; + * System.out.println( "nf.m(" + i + "): " + nf.m(i)); + * } + * } + */ + source = new String( source + + "// " + src.description + "\n" + + "class "+ testname + "{\n" + + " interface MapFun { R m( T n); }\n" + + " MapFun nf;\n" + + " void testm(Integer i) {\n" + + " nf = j -> { return j == 1 ? 1.0 : (_As_ _Bs_ Double)(nf.m(j-1) * j); };\n" + + " System.out.println( \"nf.m(\" + i + \"): \" + nf.m(i));\n" + + " }\n" + + " public static void main(String... args) {new " + testname + "().testm(5); }\n" + + "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n"; + break; + case src5: //(repeating) type annotations in lambda expression code block. + /* + * class Test180 { + * interface MapFun { R m( T n); } + * MapFun> iLi; + * void test(Integer i) { + * // type parameter use. + * iLi = n -> { List<@A @B @A @B Integer> LI = new ArrayList<@A @B @A @B Integer>(n); + * for(int nn = n; nn >=0; nn--) LI.add(nn); + * return LI; }; + * List li = iLi.m(i); + * for(Integer k : li) System.out.print(k); + * } + * } + */ + source = new String( source + + "// " + src.description + "\n" + + "class "+ testname + "{\n" + + " interface MapFun { R m( T n); }\n" + + " MapFun> iLi;\n" + + " void test(Integer i) {\n" + + " // type parameter use.\n" + + " iLi = n -> { List<_As_ _Bs_ Integer> LI = new ArrayList<_As_ _Bs_ Integer>(n);\n" + + " for(int nn = n; nn >=0; nn--) LI.add(nn);\n" + + " return LI; };\n" + + " List li = iLi.m(i);\n" + + " for(Integer k : li) System.out.print(k);\n" + + "}\n" + + " public static void main(String... args) {new " + testname + "().test(5); }\n" + + "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs).replace("_Ds_",Ds) + + "\n"; + break; + case src6: //(repeating) type annotations on type parm in method reference. + /* + * class Test240{ + * interface PrintString { void print(String s); } + * public void printArray(Object[] oa, PrintString ps) { + * for(Object o : oa ) ps.print(o.toString()); + * } + * public void test() { + * Integer[] intarray = {1,2,3,4,5}; + * printArray(intarray, @A @B @A @B TPrint::<@A @B @A @B String>print); + * } + * } + * class TPrint { + * public static void print(T t) { System.out.println( t.toString()); } + * } + */ + source = new String( source + + "// " + src.description + "\n" + + "class "+ testname + "{\n" + + " interface PrintString { void print(String s); }\n" + + " public void printArray(Object[] oa, PrintString ps) {\n" + + " for(Object o : oa ) ps.print(o.toString());\n" + + " }\n" + + " public void test() {\n" + + " Integer[] intarray = {1,2,3,4,5};\n" + + " printArray(intarray, _As_ _Bs_ TPrint::<_As_ _Bs_ String>print);\n" + + " }\n" + + " public static void main(String... args) {new " + testname + "().test(); }\n" + + "}\n\n" + + "class TPrint {\n" + + " public static void print(T t) { System.out.println( t.toString()); }\n" + + "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n"; + break; + case src7: //(repeating)type annotations in inner class of lambda expression. + /* + * class Test2{ + * interface MapFun { R m( T n); } + * MapFun,String> cs; + * void test() { + * cs = c -> { + * class innerClass { + * @A @B Class icc = null; + * String getString() { return icc.toString(); } + * } + * return new innerClass().getString(); + * }; + * System.out.println("cs.m : " + cs.m(Integer.class)); + * } + * } + */ + source = new String( source + + "// " + src.description + "\n" + + "class "+ testname + "{\n" + + " interface MapFun { R m( T n); }\n" + + " MapFun,String> cs;\n" + + " void test() {\n" + + " cs = c -> {\n" + + " class innerClass {\n" + + " _As_ _Bs_ Class icc = null;\n" + + " innerClass(Class _c) { icc = _c; }\n" + + " String getString() { return icc.toString(); }\n" + + " }\n" + + " return new innerClass(c).getString();\n" + + " };\n" + + " System.out.println(\"cs.m : \" + cs.m(Integer.class));\n" + + " }\n" + + "\n" + + " public static void main(String... args) {new " + testname + "().test(); }\n" + + "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n"; + src.innerClassname="$1innerClass"; + break; + case src8: //(repeating)type annotations in inner class of lambda expression. + /* + * class Test2{ + * interface MapFun { R m( T n); } + * MapFun,String> cs; + * void test() { + * cs = c -> { + * class innerClass { + * Class icc; + * innerClass(@A @B Class _c) { icc = _c; } + * @A @B String getString() { return icc.toString(); } + * } + * return new innerClass(c).getString(); + * }; + * System.out.println("cs.m : " + cs.m(Integer.class)); + * } + * } + */ + source = new String( source + + "// " + src.description + "\n" + + "class "+ testname + "{\n" + + " interface MapFun { R m( T n); }\n" + + " MapFun,String> cs;\n" + + " void test() {\n" + + " cs = c -> {\n" + + " class innerClass {\n" + + " Class icc;\n" + + " innerClass(_As_ _Bs_ Class _c) { icc = _c; }\n" + + " _As_ _Bs_ String getString() { return icc.toString(); }\n" + + " }\n" + + " return new innerClass(c).getString();\n" + + " };\n" + + " System.out.println(\"cs.m : \" + cs.m(Integer.class));\n" + + " }\n" + + "\n" + + " public static void main(String... args) {new " + testname + "().test(); }\n" + + "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n"; + src.innerClassname="$1innerClass"; + break; + case src9: //(repeating)type annotations on static method of interface + /* + * class Test90{ + * interface I { + * static @A @B @A @B String m() { @A @B @A @B String ret = "I.m"; return ret; } + * } + * } + */ + source = new String( source + + "// " + src.description + "\n" + + "class "+ testname + "{\n" + + " interface I { \n" + + " static _As_ _Bs_ String m() { _As_ _Bs_ String ret = \"I.m\"; return ret; }\n" + + " }\n" + + "}\n\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n"; + src.innerClassname="$I"; + break; + } + return imports + source; + } +}