MakeTypeTest.java revision 3294:9adfb22ff08f
1/*
2 * Copyright (c) 2014, 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     8042239
27 * @summary Verify that TreeMaker.Type(Type) can handle all reasonable types
28 * @library /tools/javac/lib
29 * @modules jdk.compiler/com.sun.tools.javac.api
30 *          jdk.compiler/com.sun.tools.javac.code
31 *          jdk.compiler/com.sun.tools.javac.processing
32 *          jdk.compiler/com.sun.tools.javac.tree
33 *          jdk.compiler/com.sun.tools.javac.util
34 * @build JavacTestingAbstractProcessor MakeTypeTest
35 * @compile/process/ref=MakeTypeTest.out -XDaccessInternalAPI -processor MakeTypeTest MakeTypeTest.java
36 */
37
38import java.lang.annotation.*;
39import java.util.*;
40
41import javax.annotation.processing.RoundEnvironment;
42import javax.lang.model.element.*;
43import javax.lang.model.type.*;
44
45import com.sun.source.tree.*;
46import com.sun.source.util.*;
47import com.sun.tools.javac.api.JavacTrees;
48import com.sun.tools.javac.code.Type;
49import com.sun.tools.javac.code.Type.ClassType;
50import com.sun.tools.javac.processing.JavacProcessingEnvironment;
51import com.sun.tools.javac.tree.JCTree.JCExpression;
52import com.sun.tools.javac.tree.TreeMaker;
53import com.sun.tools.javac.util.*;
54import com.sun.tools.javac.util.List;
55
56public class MakeTypeTest extends JavacTestingAbstractProcessor {
57    @Override
58    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
59        if (!roundEnv.processingOver())
60            return false;
61
62        JavacTask.instance(processingEnv).addTaskListener(new TaskListener() {
63            @Override
64            public void started(TaskEvent e) {
65            }
66            @Override
67            public void finished(TaskEvent e) {
68                if (e.getKind() == TaskEvent.Kind.ANALYZE &&
69                    e.getTypeElement().getQualifiedName().contentEquals("MakeTypeTest")) {
70                    doTest();
71                }
72            }
73        });
74
75        return false;
76    }
77
78    void doTest() {
79        //go through this file, look for @TestType and verify TreeMaker.Type behavior:
80        Context ctx = ((JavacProcessingEnvironment) processingEnv).getContext();
81        JavacTrees trees = JavacTrees.instance(ctx);
82        TypeElement testType = processingEnv.getElementUtils().getTypeElement("MakeTypeTest");
83        TreePath path = trees.getPath(testType);
84
85        Set<TypeKind> unseenTypeKinds = EnumSet.allOf(TypeKind.class);
86
87        new TreePathScanner<Void, Void>() {
88            @Override
89            public Void visitVariable(VariableTree node, Void p) {
90                handleDecl(new TreePath(getCurrentPath(), node.getType()));
91                return super.visitVariable(node, p);
92            }
93
94            @Override
95            public Void visitMethod(MethodTree node, Void p) {
96                if (node.getReturnType() != null)
97                    handleDecl(new TreePath(getCurrentPath(), node.getReturnType()));
98                return super.visitMethod(node, p);
99            }
100
101            @Override
102            public Void visitTypeParameter(TypeParameterTree node, Void p) {
103                TypeVariable type = (TypeVariable) trees.getTypeMirror(getCurrentPath());
104                TreePath aBoundPath = new TreePath(getCurrentPath(), node.getBounds().get(0));
105                handleDecl(aBoundPath, (Type) type.getUpperBound());
106                return super.visitTypeParameter(node, p);
107            }
108
109            void handleDecl(TreePath typePath) {
110                handleDecl(typePath, (Type) trees.getTypeMirror(typePath));
111            }
112
113            void handleDecl(TreePath typePath, Type type) {
114                Element decl = trees.getElement(typePath.getParentPath());
115                TestType testType = decl.getAnnotation(TestType.class);
116
117                if (testType == null) return ;
118
119                if (testType.nested() >= 0) {
120                    ClassType ct = (ClassType) type;
121                    type = ct.getTypeArguments().get(testType.nested());
122                }
123
124                JCExpression typeExpr = TreeMaker.instance(ctx).Type(type);
125
126                if (!typeExpr.getKind().equals(testType.expectedKind())) {
127                    throw new IllegalStateException("was=" + typeExpr + ", kind=" +
128                            typeExpr.getKind() + "; expected kind: " +
129                            testType.expectedKind() + "; type=" + type);
130                }
131                unseenTypeKinds.remove(type.getKind());
132            }
133
134        }.scan(path, null);
135
136        unseenTypeKinds.removeAll(Arrays.asList(TypeKind.NONE, TypeKind.NULL, TypeKind.ERROR,
137                TypeKind.PACKAGE, TypeKind.EXECUTABLE, TypeKind.OTHER, TypeKind.MODULE));
138
139        if (!unseenTypeKinds.isEmpty())
140            throw new IllegalStateException("Unhandled types=" + unseenTypeKinds);
141
142        System.err.println("done.");
143    }
144
145    //the following defines the Types that should be passed into TreeMaker.Type and
146    //the expected resulting Tree kind:
147
148    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
149    boolean f1;
150    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
151    byte f2;
152    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
153    char f3;
154    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
155    double f4;
156    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
157    float f5;
158    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
159    int f6;
160    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
161    long f7;
162    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
163    short f8;
164    @TestType(expectedKind=Tree.Kind.PARAMETERIZED_TYPE)
165    List<? extends String> f9;
166    @TestType(expectedKind=Tree.Kind.ARRAY_TYPE)
167    int[] fa;
168    @TestType(expectedKind=Tree.Kind.EXTENDS_WILDCARD, nested = 0)
169    List<? extends String> fb;
170    @TestType(expectedKind=Tree.Kind.SUPER_WILDCARD, nested = 0)
171    List<? super String> fc;
172    @TestType(expectedKind=Tree.Kind.UNBOUNDED_WILDCARD, nested = 0)
173    List<?> fd;
174
175    @TestType(expectedKind=Tree.Kind.PRIMITIVE_TYPE)
176    void voidMethod() {
177        try {
178            voidMethod();
179        } catch (@TestType(expectedKind=Tree.Kind.UNION_TYPE) NullPointerException |
180                                                              IllegalStateException ex) {
181        }
182    }
183
184    class WithTypeParam<@TestType(expectedKind=Tree.Kind.INTERSECTION_TYPE)
185                        T extends CharSequence & Runnable> {
186        @TestType(expectedKind=Tree.Kind.IDENTIFIER)
187        T voidMethod() {
188            return null;
189        }
190    }
191
192}
193
194//TreeMaker.Type will be tested for the type the element annotated by this annotation
195@Target({ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD,
196         ElementType.PARAMETER, ElementType.TYPE_PARAMETER})
197@interface TestType {
198    //the expected Tree kind of the Tree that will be returned from TreeMaker.Type for the type
199    public Tree.Kind expectedKind();
200    //if >=0, the current type will be interpreted as a ClassType and the type to test will be
201    //the given type argument:
202    public int nested() default -1;
203}
204