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