Mon, 24 Oct 2011 13:00:30 +0100
7098660: Write better overload resolution/inference tests
Summary: Add overload/inference debug diagnostics - added test harness using annotations to check outcome of overload resolution/inference
Reviewed-by: jjg
1 /*
2 * Copyright (c) 2010, 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 */
24 /**
25 * @test
26 * @bug 6993978 7097436
27 * @summary Project Coin: Annotation to reduce varargs warnings
28 * @author mcimadamore
29 * @run main Warn5
30 */
31 import com.sun.source.util.JavacTask;
32 import com.sun.tools.javac.api.JavacTool;
33 import java.net.URI;
34 import java.util.Arrays;
35 import java.util.EnumSet;
36 import javax.tools.Diagnostic;
37 import javax.tools.JavaCompiler;
38 import javax.tools.JavaFileObject;
39 import javax.tools.SimpleJavaFileObject;
40 import javax.tools.StandardJavaFileManager;
41 import javax.tools.ToolProvider;
43 public class Warn5 {
45 enum XlintOption {
46 NONE("none"),
47 ALL("all");
49 String opt;
51 XlintOption(String opt) {
52 this.opt = opt;
53 }
55 String getXlintOption() {
56 return "-Xlint:" + opt;
57 }
58 }
60 enum TrustMe {
61 DONT_TRUST(""),
62 TRUST("@java.lang.SafeVarargs");
64 String anno;
66 TrustMe(String anno) {
67 this.anno = anno;
68 }
69 }
71 enum SuppressLevel {
72 NONE,
73 VARARGS;
75 String getSuppressAnno() {
76 return this == VARARGS ?
77 "@SuppressWarnings(\"varargs\")" :
78 "";
79 }
80 }
82 enum ModifierKind {
83 NONE(""),
84 FINAL("final"),
85 STATIC("static");
87 String mod;
89 ModifierKind(String mod) {
90 this.mod = mod;
91 }
92 }
94 enum MethodKind {
95 METHOD("void m"),
96 CONSTRUCTOR("Test");
98 String name;
100 MethodKind(String name) {
101 this.name = name;
102 }
103 }
105 enum SourceLevel {
106 JDK_6("6"),
107 JDK_7("7");
109 String sourceKey;
111 SourceLevel(String sourceKey) {
112 this.sourceKey = sourceKey;
113 }
114 }
116 enum SignatureKind {
117 VARARGS_X("#K <X>#N(X... x)", false, true),
118 VARARGS_STRING("#K #N(String... x)", true, true),
119 ARRAY_X("#K <X>#N(X[] x)", false, false),
120 ARRAY_STRING("#K #N(String[] x)", true, false);
122 String stub;
123 boolean isReifiableArg;
124 boolean isVarargs;
126 SignatureKind(String stub, boolean isReifiableArg, boolean isVarargs) {
127 this.stub = stub;
128 this.isReifiableArg = isReifiableArg;
129 this.isVarargs = isVarargs;
130 }
132 String getSignature(ModifierKind modKind, MethodKind methKind) {
133 return methKind != MethodKind.CONSTRUCTOR ?
134 stub.replace("#K", modKind.mod).replace("#N", methKind.name) :
135 stub.replace("#K", "").replace("#N", methKind.name);
136 }
137 }
139 enum BodyKind {
140 ASSIGN("Object o = x;", true),
141 CAST("Object o = (Object)x;", true),
142 METH("test(x);", true),
143 PRINT("System.out.println(x.toString());", false),
144 ARRAY_ASSIGN("Object[] o = x;", true),
145 ARRAY_CAST("Object[] o = (Object[])x;", true),
146 ARRAY_METH("testArr(x);", true);
148 String body;
149 boolean hasAliasing;
151 BodyKind(String body, boolean hasAliasing) {
152 this.body = body;
153 this.hasAliasing = hasAliasing;
154 }
155 }
157 enum WarningKind {
158 UNSAFE_BODY,
159 UNSAFE_DECL,
160 MALFORMED_SAFEVARARGS,
161 REDUNDANT_SAFEVARARGS;
162 }
164 // Create a single file manager and reuse it for each compile to save time.
165 static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
167 public static void main(String... args) throws Exception {
168 for (SourceLevel sourceLevel : SourceLevel.values()) {
169 for (XlintOption xlint : XlintOption.values()) {
170 for (TrustMe trustMe : TrustMe.values()) {
171 for (SuppressLevel suppressLevel : SuppressLevel.values()) {
172 for (ModifierKind modKind : ModifierKind.values()) {
173 for (MethodKind methKind : MethodKind.values()) {
174 for (SignatureKind sig : SignatureKind.values()) {
175 for (BodyKind body : BodyKind.values()) {
176 new Warn5(sourceLevel,
177 xlint,
178 trustMe,
179 suppressLevel,
180 modKind,
181 methKind,
182 sig,
183 body).test();
184 }
185 }
186 }
187 }
188 }
189 }
190 }
191 }
192 }
194 final SourceLevel sourceLevel;
195 final XlintOption xlint;
196 final TrustMe trustMe;
197 final SuppressLevel suppressLevel;
198 final ModifierKind modKind;
199 final MethodKind methKind;
200 final SignatureKind sig;
201 final BodyKind body;
202 final JavaSource source;
203 final DiagnosticChecker dc;
205 public Warn5(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) {
206 this.sourceLevel = sourceLevel;
207 this.xlint = xlint;
208 this.trustMe = trustMe;
209 this.suppressLevel = suppressLevel;
210 this.modKind = modKind;
211 this.methKind = methKind;
212 this.sig = sig;
213 this.body = body;
214 this.source = new JavaSource();
215 this.dc = new DiagnosticChecker();
216 }
218 void test() throws Exception {
219 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
220 JavacTask ct = (JavacTask)tool.getTask(null, fm, dc,
221 Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source));
222 ct.analyze();
223 check();
224 }
226 void check() {
228 EnumSet<WarningKind> expectedWarnings = EnumSet.noneOf(WarningKind.class);
230 if (sourceLevel == SourceLevel.JDK_7 &&
231 trustMe == TrustMe.TRUST &&
232 suppressLevel != SuppressLevel.VARARGS &&
233 xlint != XlintOption.NONE &&
234 sig.isVarargs && !sig.isReifiableArg && body.hasAliasing &&
235 (methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE))) {
236 expectedWarnings.add(WarningKind.UNSAFE_BODY);
237 }
239 if (sourceLevel == SourceLevel.JDK_7 &&
240 trustMe == TrustMe.DONT_TRUST &&
241 sig.isVarargs &&
242 !sig.isReifiableArg &&
243 xlint == XlintOption.ALL) {
244 expectedWarnings.add(WarningKind.UNSAFE_DECL);
245 }
247 if (sourceLevel == SourceLevel.JDK_7 &&
248 trustMe == TrustMe.TRUST &&
249 (!sig.isVarargs ||
250 (modKind == ModifierKind.NONE && methKind == MethodKind.METHOD))) {
251 expectedWarnings.add(WarningKind.MALFORMED_SAFEVARARGS);
252 }
254 if (sourceLevel == SourceLevel.JDK_7 &&
255 trustMe == TrustMe.TRUST &&
256 xlint != XlintOption.NONE &&
257 suppressLevel != SuppressLevel.VARARGS &&
258 (modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) &&
259 sig.isVarargs &&
260 sig.isReifiableArg) {
261 expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS);
262 }
264 if (!expectedWarnings.containsAll(dc.warnings) ||
265 !dc.warnings.containsAll(expectedWarnings)) {
266 throw new Error("invalid diagnostics for source:\n" +
267 source.getCharContent(true) +
268 "\nOptions: " + xlint.getXlintOption() +
269 "\nExpected warnings: " + expectedWarnings +
270 "\nFound warnings: " + dc.warnings);
271 }
272 }
274 class JavaSource extends SimpleJavaFileObject {
276 String template = "import com.sun.tools.javac.api.*;\n" +
277 "import java.util.List;\n" +
278 "class Test {\n" +
279 " static void test(Object o) {}\n" +
280 " static void testArr(Object[] o) {}\n" +
281 " #T \n #S #M { #B }\n" +
282 "}\n";
284 String source;
286 public JavaSource() {
287 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
288 source = template.replace("#T", trustMe.anno).
289 replace("#S", suppressLevel.getSuppressAnno()).
290 replace("#M", sig.getSignature(modKind, methKind)).
291 replace("#B", body.body);
292 }
294 @Override
295 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
296 return source;
297 }
298 }
300 class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
302 EnumSet<WarningKind> warnings = EnumSet.noneOf(WarningKind.class);
304 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
305 if (diagnostic.getKind() == Diagnostic.Kind.WARNING) {
306 if (diagnostic.getCode().contains("unsafe.use.varargs.param")) {
307 setWarning(WarningKind.UNSAFE_BODY);
308 } else if (diagnostic.getCode().contains("redundant.trustme")) {
309 setWarning(WarningKind.REDUNDANT_SAFEVARARGS);
310 }
311 } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING &&
312 diagnostic.getCode().contains("varargs.non.reifiable.type")) {
313 setWarning(WarningKind.UNSAFE_DECL);
314 } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
315 diagnostic.getCode().contains("invalid.trustme")) {
316 setWarning(WarningKind.MALFORMED_SAFEVARARGS);
317 }
318 }
320 void setWarning(WarningKind wk) {
321 if (!warnings.add(wk)) {
322 throw new AssertionError("Duplicate warning of kind " + wk + " in source:\n" + source);
323 }
324 }
326 boolean hasWarning(WarningKind wk) {
327 return warnings.contains(wk);
328 }
329 }
330 }