langtools/test/tools/javac/util/context/T7021650.java
changeset 35669 9ff296647fde
parent 35668 21c2a1c93810
parent 34949 304424bbae03
child 35670 320e424b168c
equal deleted inserted replaced
35668:21c2a1c93810 35669:9ff296647fde
     1 /*
       
     2  * Copyright (c) 2011, 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 7021650
       
    27  * @summary Fix Context issues
       
    28  * @library /tools/javac/lib
       
    29  * @modules jdk.compiler/com.sun.tools.javac.comp
       
    30  *          jdk.compiler/com.sun.tools.javac.file
       
    31  *          jdk.compiler/com.sun.tools.javac.main
       
    32  *          jdk.compiler/com.sun.tools.javac.processing
       
    33  *          jdk.compiler/com.sun.tools.javac.util
       
    34  * @build JavacTestingAbstractProcessor T7021650
       
    35  * @run main T7021650
       
    36  */
       
    37 
       
    38 import java.io.*;
       
    39 import java.net.*;
       
    40 import java.util.*;
       
    41 import javax.annotation.processing.*;
       
    42 import javax.lang.model.element.*;
       
    43 import javax.tools.*;
       
    44 
       
    45 import com.sun.tools.javac.comp.Attr;
       
    46 import com.sun.tools.javac.file.JavacFileManager;
       
    47 import com.sun.tools.javac.main.Main;
       
    48 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
       
    49 import com.sun.tools.javac.util.Context;
       
    50 
       
    51 public class T7021650 extends JavacTestingAbstractProcessor {
       
    52     public static void main(String... args) throws Exception {
       
    53         new T7021650().run();
       
    54     }
       
    55 
       
    56     static File testSrc = new File(System.getProperty("test.src"));
       
    57     static final int MAX_ROUNDS = 3;
       
    58 
       
    59     /**
       
    60      * Perform a compilation with custom factories registered in the context,
       
    61      * and verify that corresponding objects are created in each round.
       
    62      */
       
    63     void run() throws Exception {
       
    64         Counter myDemoCounter = new Counter();
       
    65         Counter myAttrCounter = new Counter();
       
    66 
       
    67         Context context = new Context();
       
    68         // Use a custom file manager which creates classloaders for annotation
       
    69         // processors with a sensible delegation parent, so that all instances
       
    70         // of test classes come from the same class loader. This is important
       
    71         // because the test performs class checks on the instances of classes
       
    72         // found in the context for each round or processing.
       
    73         context.put(JavaFileManager.class, new Context.Factory<JavaFileManager>() {
       
    74             public JavaFileManager make(Context c) {
       
    75                 return new JavacFileManager(c, true, null) {
       
    76                     @Override
       
    77                     protected ClassLoader getClassLoader(URL[] urls) {
       
    78                         return new URLClassLoader(urls, T7021650.class.getClassLoader());
       
    79                     }
       
    80                 };
       
    81             }
       
    82         });
       
    83 
       
    84         MyDemo.preRegister(context, myDemoCounter);
       
    85         MyAttr.preRegister(context, myAttrCounter);
       
    86 
       
    87         String[] args = {
       
    88             "-d", ".",
       
    89             "-processor", T7021650.class.getName(),
       
    90             "-XprintRounds",
       
    91             new File(testSrc, T7021650.class.getName() + ".java").getPath()
       
    92         };
       
    93 
       
    94         compile(context, args);
       
    95 
       
    96         // the services should only be created once in the current scheme:
       
    97         checkEqual("demoCounter", myDemoCounter.count, 1);
       
    98         checkEqual("myAttrCounter", myAttrCounter.count, 1);
       
    99     }
       
   100 
       
   101     void compile(Context context, String... args) throws Exception {
       
   102         StringWriter sw = new StringWriter();
       
   103         PrintWriter pw = new PrintWriter(sw);
       
   104         Main m = new Main("javac", pw);
       
   105         Main.Result res = m.compile(args, context);
       
   106         pw.close();
       
   107         String out = sw.toString();
       
   108         if (!out.isEmpty())
       
   109             System.err.println(out);
       
   110         if (!res.isOK())
       
   111             throw new Exception("compilation failed unexpectedly: result=" + res);
       
   112     }
       
   113 
       
   114     void checkEqual(String label, int found, int expect) throws Exception {
       
   115         if (found != expect)
       
   116             throw new Exception("unexpected value for " + label
       
   117                     + ": expected " + expect
       
   118                     + ": found " + found);
       
   119     }
       
   120 
       
   121     //---------------
       
   122 
       
   123     /*
       
   124      * A custom class unknown to javac but nonetheless registered in the context.
       
   125      */
       
   126     static class Demo {
       
   127         Demo(Context c) {
       
   128             c.put(Demo.class, this);
       
   129         }
       
   130 
       
   131         static Demo instance(Context context) {
       
   132             return context.get(Demo.class);
       
   133         }
       
   134     }
       
   135 
       
   136     static class MyDemo extends Demo {
       
   137         static void preRegister(Context context, final Counter counter) {
       
   138             context.put(Demo.class, new Context.Factory<Demo>() {
       
   139                 public Demo make(Context c) {
       
   140                     counter.count++;
       
   141                     return new MyDemo(c);
       
   142                 }
       
   143             });
       
   144         }
       
   145 
       
   146         MyDemo(Context c) {
       
   147             super(c);
       
   148         }
       
   149     }
       
   150 
       
   151     /**
       
   152      * A custom version of a standard javac component.
       
   153      */
       
   154     static class MyAttr extends Attr {
       
   155         static void preRegister(Context context, final Counter counter) {
       
   156             context.put(attrKey, new Context.Factory<Attr>() {
       
   157                 public Attr make(Context c) {
       
   158                     counter.count++;
       
   159                     return new MyAttr(c);
       
   160                 }
       
   161             });
       
   162         }
       
   163 
       
   164         MyAttr(Context c) {
       
   165             super(c);
       
   166         }
       
   167     }
       
   168 
       
   169     static class Counter {
       
   170         int count;
       
   171     }
       
   172 
       
   173     //---------------
       
   174 
       
   175     int round = 0;
       
   176 
       
   177     @Override
       
   178     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
       
   179         round++;
       
   180 
       
   181         Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
       
   182 
       
   183         // verify items in context as expected
       
   184         check("Demo", Demo.instance(context), MyDemo.class);
       
   185         check("Attr", Attr.instance(context), MyAttr.class);
       
   186 
       
   187         // For a few rounds, generate new source files, so that we can check whether
       
   188         // values in the context are correctly handled in subsequent processing rounds
       
   189         if (round <= MAX_ROUNDS) {
       
   190             String pkg = "p";
       
   191             String currClass = "Gen" + round;
       
   192             String curr = pkg + "." + currClass;
       
   193             String next = (pkg + ".Gen" + (round + 1));
       
   194             StringBuilder text = new StringBuilder();
       
   195             text.append("package ").append(pkg).append(";\n");
       
   196             text.append("public class ").append(currClass).append(" {\n");
       
   197             if (round < MAX_ROUNDS)
       
   198                 text.append("    ").append(next).append(" x;\n");
       
   199             text.append("}\n");
       
   200 
       
   201             try {
       
   202                 JavaFileObject fo = filer.createSourceFile(curr);
       
   203                 Writer out = fo.openWriter();
       
   204                 try {
       
   205                     out.write(text.toString());
       
   206                 } finally {
       
   207                     out.close();
       
   208                 }
       
   209             } catch (IOException e) {
       
   210                 throw new Error(e);
       
   211             }
       
   212         }
       
   213 
       
   214         return true;
       
   215     }
       
   216 
       
   217     void check(String label, Object o, Class<?> clazz) {
       
   218         if (o == null)
       
   219             throw new IllegalStateException(label + ": no item found");
       
   220         if (!clazz.isAssignableFrom(o.getClass()))
       
   221             throw new IllegalStateException(label + ": unexpected class: " + o.getClass());
       
   222     }
       
   223 }