CombinationsTargetTest2.java revision 2942:08092deced3f
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 8005877 8004829 8005681 8006734 8006775 8006507
27 * @summary Combinations of Target ElementTypes on (repeated)type annotations.
28 * @modules jdk.jdeps/com.sun.tools.classfile
29 */
30
31import com.sun.tools.classfile.*;
32import java.io.File;
33
34public class CombinationsTargetTest2 extends ClassfileTestHelper {
35
36    // Test count helps identify test case in event of failure.
37    int testcount = 0;
38
39    // Base test case template descriptions;true==annotations in code attribute.
40    enum srce  {
41        src1("(repeating) type annotations on on field in method body",true),
42        src2("(repeating) type annotations on type parameters, bounds and  type arguments", true),
43        src3("(repeating) type annotations on type parameters of class, method return value in method", true),
44        src4("(repeating) type annotations on field in anonymous class", false),
45        src5("(repeating) type annotations on field in anonymous class", false),
46        src6("(repeating) type annotations on void method declaration", false),
47        src7("(repeating) type annotations in use of instanceof", true),
48        src8("(repeating) type annotations in use of instanceof in method", true);
49
50        String description;
51        Boolean local;
52
53        srce(String desc, Boolean b) {
54            this.description = this + ": " +desc;
55            this.local = b;
56        }
57    }
58
59
60    String[] ETypes={"TYPE", "FIELD", "METHOD", "PARAMETER", "CONSTRUCTOR",
61                     "LOCAL_VARIABLE", "ANNOTATION_TYPE", "PACKAGE"};
62
63    // local class tests will have an inner class.
64    Boolean hasInnerClass=false;
65    String innerClassname="";
66
67    public static void main(String[] args) throws Exception {
68        new CombinationsTargetTest2().run();
69    }
70
71    void run() throws Exception {
72        // Determines which repeat and order in source(ABMix).
73        Boolean As= false, BDs=true, ABMix=false;
74        int testrun=0;
75        Boolean [][] bRepeat = new Boolean[][]{{false,false,false},//no repeats
76                                               {true,false,false}, //repeat @A
77                                               {false,true,false}, //repeat @B
78                                               {true,true,false},  //repeat both
79                                               {false,false,true}  //repeat mix
80        };
81
82        for(Boolean[] bCombo : bRepeat) {
83            As=bCombo[0]; BDs=bCombo[1]; ABMix=bCombo[2];
84            for(String et : ETypes) {
85               switch(et) {
86                   case "METHOD":
87                       test( 8, 0, 0, 0, As, BDs, ABMix, "CLASS",   et, ++testrun, srce.src1);
88                       test( 0, 8, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src1);
89                       test( 2, 0, 2, 0, As, BDs, ABMix, "CLASS",   et, ++testrun, srce.src5);
90                       test( 0, 2, 0, 2, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src5);
91                       test( 0, 0, 2, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src6);
92                       test( 0, 0, 0, 2, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src6);
93                       test( 2, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src7);
94                       test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src7);
95                       test( 4, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src8);
96                       test( 0, 4, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src8);
97                       break;
98                   case "FIELD":
99                       test( 8, 0, 0, 0, As, BDs, ABMix, "CLASS",   et, ++testrun, srce.src1);
100                       test( 8, 0, 0, 0, As, BDs, ABMix, "CLASS",   et, ++testrun, srce.src2);
101                       test( 6, 0, 0, 0, As, BDs, ABMix, "CLASS",   et, ++testrun, srce.src3);
102                       test( 2, 0, 2, 0, As, BDs, ABMix, "CLASS",   et, ++testrun, srce.src4);
103                       test( 0, 8, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src1);
104                       test( 0, 8, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src2);
105                       test( 0, 6, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src3);
106                       test( 0, 2, 0, 2, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src4);
107                       break;
108                   default:/*TYPE,PARAMETER,LOCAL_VARIABLE,ANNOTATION_TYPE,PACKAGE*/
109                       test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src4);
110                       test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src5);
111                       break;
112               }
113            }
114        }
115    }
116
117    public void test(int tinv, int tvis, int inv, int vis, Boolean Arepeats,
118                     Boolean BDrepeats, Boolean ABmix, String rtn, String et2,
119                     Integer N, srce source) throws Exception {
120        ++testcount;
121        expected_tvisibles = tvis;
122        expected_tinvisibles = tinv;
123        expected_visibles = vis;
124        expected_invisibles = inv;
125        File testFile = null;
126        String tname="Test" + N.toString();
127        hasInnerClass=false;
128        String testDef = "Test " + testcount + " parameters: tinv=" + tinv +
129                ", tvis=" + tvis + ", inv=" + inv + ", vis=" + vis +
130                ", Arepeats=" + Arepeats + ", BDrepeats=" + BDrepeats +
131                ", ABmix=" + ABmix + ", retention: " + rtn + ", anno2: " +
132                et2 + ", src=" + source + "\n    " + source.description;
133
134        println(testDef);
135        // Create test source and File.
136        String sourceString = sourceString(tname, rtn, et2, Arepeats,
137                                           BDrepeats, ABmix, source);
138        testFile = writeTestFile(tname+".java", sourceString);
139        // Compile test source and read classfile.
140        File classFile = null;
141        try {
142            classFile = compile(testFile);
143        } catch (Error err) {
144            System.err.println("Failed compile. Source:\n" + sourceString);
145            throw err;
146        }
147        //if sourcString() set hasInnerClass it also set innerClassname.
148        if(hasInnerClass) {
149            StringBuffer sb = new StringBuffer(classFile.getAbsolutePath());
150            classFile=new File(sb.insert(sb.lastIndexOf(".class"),innerClassname).toString());
151            println("classfile: " + classFile.getAbsolutePath());
152        }
153        ClassFile cf = ClassFile.read(classFile);
154
155        //Test class,fields and method counts.
156        test(cf);
157
158        for (Field f : cf.fields) {
159            if(source.local)
160                test(cf, f, true);
161            else
162                test(cf,f);
163        }
164        for (Method m: cf.methods) {
165            if(source.local)
166                test(cf, m, true);
167            else
168                test(cf, m);
169        }
170        countAnnotations();
171        if (errors > 0) {
172            System.err.println( testDef );
173            System.err.println( "Source:\n" + sourceString );
174            throw new Exception( errors + " errors found" );
175        }
176        println("Pass");
177    }
178
179    // Source for test cases
180    String sourceString(String testname, String retentn, String annot2,
181                        Boolean Arepeats, Boolean BDrepeats, Boolean ABmix,
182                        srce src) {
183
184        String As = "@A", Bs = "@B", Ds = "@D";
185        if(Arepeats) As = "@A @A";
186        if(BDrepeats) {
187            Bs = "@B @B";
188            Ds = "@D @D";
189        }
190        if(ABmix) { As = "@A @B"; Bs = "@A @B"; Ds = "@D @D"; }
191
192        // Source to check for TYPE_USE and TYPE_PARAMETER annotations.
193        // Source base (annotations) is same for all test cases.
194        String source = new String();
195        String imports = new String("import java.lang.annotation.*; \n" +
196            "import static java.lang.annotation.RetentionPolicy.*; \n" +
197            "import static java.lang.annotation.ElementType.*; \n" +
198            "import java.util.List; \n" +
199            "import java.util.HashMap; \n" +
200            "import java.util.Map; \n\n");
201
202            String sourceBase = new String("@Retention("+retentn+")\n" +
203            "@Target({TYPE_USE,_OTHER_})\n" +
204            "@Repeatable( AC.class )\n" +
205            "@interface A { }\n\n" +
206
207            "@Retention("+retentn+")\n" +
208            "@Target({TYPE_USE,_OTHER_})\n" +
209            "@interface AC { A[] value(); }\n\n" +
210
211            "@Retention("+retentn+")\n" +
212            "@Target({TYPE_USE,_OTHER_})\n" +
213            "@Repeatable( BC.class )\n" +
214            "@interface B { }\n\n" +
215
216            "@Retention("+retentn+")\n" +
217            "@Target({TYPE_USE,_OTHER_})\n" +
218            "@interface BC { B[] value(); } \n\n" +
219
220            "@Retention("+retentn+")\n" +
221            "@Target({TYPE_USE,TYPE_PARAMETER,_OTHER_})\n" +
222            "@Repeatable(DC.class)\n" +
223            "@interface D { }\n\n" +
224
225            "@Retention("+retentn+")\n" +
226            "@Target({TYPE_USE,TYPE_PARAMETER,_OTHER_})\n" +
227            "@interface DC { D[] value(); }\n\n");
228
229        // Test case sources with sample generated source
230        switch(src) {
231            case src1: // (repeating) type annotations on field in method body
232                    /*
233                     * class Test1 {
234                     * Test1(){}
235                     * // type usage in method body
236                     * String test(Test1 this, String param, String ... vararg) {
237                     *     @A @B
238                     *     Object o = new @A @B  String @A @B  [3];
239                     *         return (@A @B  String) null;
240                     * }}
241                      */
242                source = new String(
243                    "// " + src.description + "\n" +
244                    "class " + testname + " {\n" +
245                    "" + testname +"(){} \n" +
246                    "// type usage in method body \n" +
247                    "String test("+testname+" this, " +
248                       "String param, String ... vararg) { \n" +
249                    "    _As_ _Bs_\n    Object o = new _As_ _Bs_  String _As_ _Bs_  [3]; \n" +
250                    "        return (_As_ _Bs_  String) null; \n" +
251                    "} \n" +
252                    "} \n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
253                    "\n\n";
254                    break;
255            case src2: // (repeating) annotations on type parameters, bounds and  type arguments in new statement.
256                    /*
257                     * class Test2<T extends Object> {
258                     *     Map<List<String>, Integer> map =
259                     *         new HashMap<@A @B List<@A @B String>, @A @B Integer>();
260                     *     Map<List<String>, Integer> map2 = new @A @B HashMap<>();
261                     *     String test(Test2<T> this) { return null;}
262                     *     <T> String genericMethod(T t) { return null; }
263                     * }
264                     */
265                source = new String( source +
266                    "// " + src.description + "\n" +
267                    "class " + testname + "<T extends Object> {\n" +
268                    "    Map<List<String>, Integer> map =\n" +
269                    "        new HashMap<_As_ _Bs_ List<_As_ _Bs_ String>, _As_ _Bs_ Integer>();\n" +
270                    "    Map<List<String>, Integer> map2 = new _As_ _Bs_ HashMap<>();\n" +
271                    "    String test(" + testname + "<T> this) { return null;}\n" +
272                    "    <T> String genericMethod(T t) { return null; }\n" +
273                    "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
274                    "\n\n";
275                break;
276            case src3: // (repeating)annotations on type parameters of class, method return value in method.
277                    /*
278                     * class Test3{
279                     *     <E extends Comparable> Map<List<E>, E > foo(E e) {
280                     *         class maptest <E> {
281                     *             Map<List<E>,E> getMap() {
282                     *                 Map<List<E>,E> Em = new HashMap<List<@A @B @D E>,@A @B @D E>();
283                     *                 return Em;
284                     *             }
285                     *         }
286                     *         return new maptest<E>().getMap();
287                     *    }
288                     *    Map<List<String>,String> shm = foo(new String("hello"));
289                     * }
290                     */
291                source = new String( source +
292                    "// " + src.description + "\n" +
293                    "class "+ testname + "{\n" +
294                    "    <E extends Comparable> Map<List<E>, E > foo(E e) {\n" +
295                    "        class maptest <E> {\n" +                  // inner class $1maptest
296                    "            Map<List<E>,E> getMap() { \n" +
297                    "                Map<List<E>,E> Em = new HashMap<List<_As_ _Bs_ _Ds_ E>,_As_ _Bs_ _Ds_ E>();\n" +
298                    "                return Em;\n" +
299                    "            }\n" +
300                    "        }\n" +
301                    "        return new maptest<E>().getMap();\n" +
302                    "   }\n" +
303                    "   Map<List<String>,String> shm = foo(new String(\"hello\"));\n" +
304                    "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs).replace("_Ds_",Ds) +
305                    "\n\n";
306                    hasInnerClass=true;
307                    innerClassname="$1maptest";
308                break;
309            case src4: // (repeating)annotations on field in anonymous class
310                    /*
311                     * class Test95{
312                     *     void mtest( Test95 t){  }
313                     *     public void test() {
314                     *         mtest( new Test95() {
315                     *             @A @A @B @B String data2 = "test";
316                     *         });
317                     *     }
318                     * }
319                     */
320                source = new String( source +
321                    "// " + src.description + "\n" +
322                    "class "+ testname + "{\n" +
323                    "    void mtest( "+ testname + " t){  }\n" +
324                    "    public void test() {\n" +
325                    "        mtest( new "+ testname + "() {\n" +
326                    "            _As_ _Bs_ String data2 = \"test\";\n" +
327                    "        });\n" +
328                    "    }\n" +
329                    "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
330                    "\n\n";
331                    hasInnerClass=true;
332                    innerClassname="$1";
333                break;
334            case src5: // (repeating)annotations on method in anonymous class
335                    /*
336                     * class Test120{
337                     *     void mtest( Test120 t){  }
338                     *     public void test() {
339                     *         mtest( new Test120() {
340                     *             @A @B @A @B String m2(){return null;};
341                     *         });
342                     *     }
343                     */
344                source = new String( source +
345                    "// " + src.description + "\n" +
346                    "class "+ testname + "{\n" +
347                    "    void mtest( "+ testname + " t){  }\n" +
348                    "    public void test() {\n" +
349                    "        mtest( new "+ testname + "() {\n" +
350                    "            _As_ _Bs_ String m2(){return null;};\n" +
351                    "        });\n" +
352                    "    }\n" +
353                    "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
354                    "\n\n";
355                    hasInnerClass=true;
356                    innerClassname="$1";
357                break;
358            case src6: // (repeating)annotations on void method declaration
359                    /*
360                     * class Test95{
361                     *     @A @A @B @B public void test() { };
362                     * }
363                     */
364                source = new String( source +
365                    "// " + src.description + "\n" +
366                    "class "+ testname + "{\n" +
367                    "    _As_ _Bs_ public void test() { }\n" +
368                    "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
369                    "\n\n";
370                    hasInnerClass=false;
371                break;
372            case src7: // (repeating) type annotations in use of instanceof
373                    /*
374                     *   class Test10{
375                     *       String data = "test";
376                     *       boolean dataIsString = ( data instanceof @A @B @A @B String);
377                     *   }
378                     */
379                source = new String( source +
380                    "// " + src.description + "\n" +
381                    "class "+ testname + "{\n" +
382                    "    String data = \"test\";\n" +
383                    "    boolean dataIsString = ( data instanceof _As_ _Bs_ String);\n" +
384                    "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
385                    "\n\n";
386                    hasInnerClass=false;
387                break;
388            case src8: // (repeating) type annotations in use of instanceof
389                    /*
390                     *   class Test20{
391                     *       String data = "test";
392                     *       Boolean isString() {
393                     *           if( data instanceof @A @B @A @B String )
394                     *               return true;
395                     *           else
396                     *               return( data instanceof @A @B @A @B String );
397                     *       }
398                     *   }
399                     */
400                source = new String( source +
401                    "// " + src.description + "\n" +
402                    "class "+ testname + "{\n" +
403                    "    String data = \"test\";\n" +
404                    "    Boolean isString() { \n" +
405                    "        if( data instanceof _As_ _Bs_ String )\n" +
406                    "            return true;\n" +
407                    "        else\n" +
408                    "            return( data instanceof _As_ _Bs_ String );\n" +
409                    "    }\n" +
410                    "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) +
411                    "\n\n";
412                    hasInnerClass=false;
413                break;
414
415        }
416        return imports + source;
417    }
418}
419