1 /*
   2  * Copyright (c) 2011, 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     7029150
  27  * @summary Test support for union types
  28  * @library ../../../lib
  29  */
  30 
  31 import java.net.URI;
  32 import java.util.*;
  33 import javax.annotation.processing.*;
  34 import javax.lang.model.element.*;
  35 import javax.lang.model.type.*;
  36 import javax.lang.model.util.*;
  37 import javax.tools.*;
  38 
  39 import com.sun.source.tree.*;
  40 import com.sun.source.util.*;
  41 
  42 
  43 public class TestUnionType extends JavacTestingAbstractProcessor {
  44     enum TestKind {
  45         SingleType("E1", "E1",
  46                 "VariableTree: E1 e",
  47                 "VariableTree: elem EXCEPTION_PARAMETER e",
  48                 "VariableTree: elem.type DECLARED",
  49                 "VariableTree: elem.type.elem CLASS E1",
  50                 "VariableTree: type DECLARED",
  51                 "VariableTree: type.elem CLASS E1",
  52                 "VariableTree: type.elem.type DECLARED"),
  53 
  54         ValidTypes("E1, E2", "E1 | E2",
  55                 "VariableTree: E1 | E2 e",
  56                 "VariableTree: elem EXCEPTION_PARAMETER e",
  57                 "VariableTree: elem.type UNION Test.E1,Test.E2",
  58                 "VariableTree: elem.type.elem null",
  59                 "VariableTree: type UNION Test.E1,Test.E2",
  60                 "VariableTree: type.elem null"),
  61 
  62         InvalidTypes("E1, E2", "E1 | EMissing",
  63                 "VariableTree: E1 | EMissing e",
  64                 "VariableTree: elem EXCEPTION_PARAMETER e",
  65                 "VariableTree: elem.type UNION Test.E1,EMissing",
  66                 "VariableTree: elem.type.elem null",
  67                 "VariableTree: type UNION Test.E1,EMissing",
  68                 "VariableTree: type.elem null"),
  69 
  70         Uncaught("E1", "E1 | E2",
  71                 "VariableTree: E1 | E2 e",
  72                 "VariableTree: elem EXCEPTION_PARAMETER e",
  73                 "VariableTree: elem.type UNION Test.E1,Test.E2",
  74                 "VariableTree: elem.type.elem null",
  75                 "VariableTree: type UNION Test.E1,Test.E2",
  76                 "VariableTree: type.elem null");
  77 
  78         TestKind(String throwsTypes, String catchTypes, String... gold) {
  79             this.throwsTypes = throwsTypes;
  80             this.catchTypes = catchTypes;
  81             this.gold = Arrays.asList(gold);
  82         }
  83 
  84         final String throwsTypes;
  85         final String catchTypes;
  86         final List<String> gold;
  87     }
  88 
  89     static class TestFileObject extends SimpleJavaFileObject {
  90         public static final String template =
  91                   "class Test {\n"
  92                 + "    class E1 extends Exception { }\n"
  93                 + "    class E2 extends Exception { }\n"
  94                 + "    void doSomething() throws #T { }\n"
  95                 + "    void test() {\n"
  96                 + "        try {\n"
  97                 + "            doSomething();\n"
  98                 + "        } catch (#C e) {\n"
  99                 + "        }\n"
 100                 + "    }\n"
 101                 + "}\n";
 102 
 103         public TestFileObject(TestKind tk) {
 104             super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
 105             this.tk = tk;
 106         }
 107 
 108         @Override
 109         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
 110             return template
 111                     .replace("#T", tk.throwsTypes)
 112                     .replace("#C", tk.catchTypes);
 113         }
 114         final TestKind tk;
 115     }
 116 
 117     public static void main(String... args) throws Exception {
 118         JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
 119         List<String> options = Arrays.asList("-proc:only");
 120         for (TestKind tk: TestKind.values()) {
 121             System.err.println("Test: " + tk);
 122             TestUnionType p = new TestUnionType();
 123             JavaFileObject fo = new TestFileObject(tk);
 124             JavaCompiler.CompilationTask task = comp.getTask(null, null, null, options, null, Arrays.asList(fo));
 125             task.setProcessors(Arrays.asList(p));
 126             boolean ok = task.call();
 127             System.err.println("compilation " + (ok ? "passed" : "failed"));
 128             if (!ok)
 129                 throw new Exception("compilation failed unexpectedly");
 130             if (!p.log.equals(tk.gold)) {
 131                 System.err.println("Expected output:");
 132                 for (String g: tk.gold)
 133                     System.err.println(g);
 134                 throw new Exception("unexpected output from test");
 135             }
 136             System.err.println();
 137         }
 138     }
 139 
 140     Trees trees;
 141     List<String> log;
 142 
 143     @Override
 144     public void init(ProcessingEnvironment env) {
 145         super.init(env);
 146         trees = Trees.instance(env);
 147         log = new ArrayList<String>();
 148     }
 149 
 150     @Override
 151     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
 152         if (!roundEnv.processingOver()) {
 153             for (Element e: roundEnv.getRootElements()) {
 154                 scan(trees.getPath(e));
 155             }
 156         }
 157         return true;
 158     }
 159 
 160     void scan(TreePath path) {
 161         new Scanner().scan(path, null);
 162     }
 163 
 164     class Scanner extends TreePathScanner<Void,Void> {
 165         @Override
 166         public Void visitVariable(VariableTree tree, Void ignore) {
 167             TreePath p = getCurrentPath();
 168             Element e = trees.getElement(p);
 169             if (e.getKind() == ElementKind.EXCEPTION_PARAMETER) {
 170                 log("VariableTree: " + tree);
 171                 log("VariableTree: elem " + print(e));
 172                 log("VariableTree: elem.type " + print(e.asType()));
 173                 log("VariableTree: elem.type.elem " + print(types.asElement(e.asType())));
 174                 TypeMirror tm = trees.getTypeMirror(p);
 175                 log("VariableTree: type " + print(tm));
 176                 log("VariableTree: type.elem " + print(types.asElement(tm)));
 177                 if (types.asElement(tm) != null)
 178                     log("VariableTree: type.elem.type " + print(types.asElement(tm).asType()));
 179             }
 180             return super.visitVariable(tree, null);
 181         }
 182 
 183         String print(TypeMirror tm) {
 184             return (tm == null) ? null : new TypePrinter().visit(tm);
 185         }
 186 
 187         String print(Element e) {
 188             return (e == null) ? null : (e.getKind() + " " + e.getSimpleName());
 189         }
 190 
 191         void log(String msg) {
 192             System.err.println(msg);
 193             log.add(msg);
 194         }
 195     }
 196 
 197     class TypePrinter extends SimpleTypeVisitor7<String, Void> {
 198         @Override
 199         protected String defaultAction(TypeMirror tm, Void ignore) {
 200             return String.valueOf(tm.getKind());
 201         }
 202 
 203         @Override
 204         public String visitUnion(UnionType t, Void ignore) {
 205             return (t.getKind() + " " + t.getAlternatives());
 206         }
 207     }
 208 }