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