test/tools/javac/varargs/warning/Warn5.java

changeset 795
7b99f98b3035
child 892
3e30c95da3c6
equal deleted inserted replaced
794:2f2ead61db06 795:7b99f98b3035
1 /*
2 * Copyright (c) 2010, 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 6993978
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 java.net.URI;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import javax.tools.Diagnostic;
36 import javax.tools.JavaCompiler;
37 import javax.tools.JavaFileObject;
38 import javax.tools.SimpleJavaFileObject;
39 import javax.tools.ToolProvider;
40
41 public class Warn5 {
42
43 enum XlintOption {
44 NONE("none"),
45 ALL("all");
46
47 String opt;
48
49 XlintOption(String opt) {
50 this.opt = opt;
51 }
52
53 String getXlintOption() {
54 return "-Xlint:" + opt;
55 }
56 }
57
58 enum TrustMe {
59 DONT_TRUST(""),
60 TRUST("@java.lang.SafeVarargs");
61
62 String anno;
63
64 TrustMe(String anno) {
65 this.anno = anno;
66 }
67 }
68
69 enum SuppressLevel {
70 NONE,
71 VARARGS;
72
73 String getSuppressAnno() {
74 return this == VARARGS ?
75 "@SuppressWarnings(\"varargs\")" :
76 "";
77 }
78 }
79
80 enum ModifierKind {
81 NONE(""),
82 FINAL("final"),
83 STATIC("static");
84
85 String mod;
86
87 ModifierKind(String mod) {
88 this.mod = mod;
89 }
90 }
91
92 enum MethodKind {
93 METHOD("void m"),
94 CONSTRUCTOR("Test");
95
96
97 String name;
98
99 MethodKind(String name) {
100 this.name = name;
101 }
102 }
103
104 enum SourceLevel {
105 JDK_6("6"),
106 JDK_7("7");
107
108 String sourceKey;
109
110 SourceLevel(String sourceKey) {
111 this.sourceKey = sourceKey;
112 }
113 }
114
115 enum SignatureKind {
116 VARARGS_X("#K <X>#N(X... x)", false, true),
117 VARARGS_STRING("#K #N(String... x)", true, true),
118 ARRAY_X("#K <X>#N(X[] x)", false, false),
119 ARRAY_STRING("#K #N(String[] x)", true, false);
120
121 String stub;
122 boolean isReifiableArg;
123 boolean isVarargs;
124
125 SignatureKind(String stub, boolean isReifiableArg, boolean isVarargs) {
126 this.stub = stub;
127 this.isReifiableArg = isReifiableArg;
128 this.isVarargs = isVarargs;
129 }
130
131 String getSignature(ModifierKind modKind, MethodKind methKind) {
132 return methKind != MethodKind.CONSTRUCTOR ?
133 stub.replace("#K", modKind.mod).replace("#N", methKind.name) :
134 stub.replace("#K", "").replace("#N", methKind.name);
135 }
136 }
137
138 enum BodyKind {
139 ASSIGN("Object o = x;", true),
140 CAST("Object o = (Object)x;", true),
141 METH("test(x);", true),
142 PRINT("System.out.println(x.toString());", false),
143 ARRAY_ASSIGN("Object[] o = x;", true),
144 ARRAY_CAST("Object[] o = (Object[])x;", true),
145 ARRAY_METH("testArr(x);", true);
146
147 String body;
148 boolean hasAliasing;
149
150 BodyKind(String body, boolean hasAliasing) {
151 this.body = body;
152 this.hasAliasing = hasAliasing;
153 }
154 }
155
156 static class JavaSource extends SimpleJavaFileObject {
157
158 String template = "import com.sun.tools.javac.api.*;\n" +
159 "import java.util.List;\n" +
160 "class Test {\n" +
161 " static void test(Object o) {}\n" +
162 " static void testArr(Object[] o) {}\n" +
163 " #T \n #S #M { #B }\n" +
164 "}\n";
165
166 String source;
167
168 public JavaSource(TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind,
169 MethodKind methKind, SignatureKind meth, BodyKind body) {
170 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
171 source = template.replace("#T", trustMe.anno).
172 replace("#S", suppressLevel.getSuppressAnno()).
173 replace("#M", meth.getSignature(modKind, methKind)).
174 replace("#B", body.body);
175 }
176
177 @Override
178 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
179 return source;
180 }
181 }
182
183 public static void main(String... args) throws Exception {
184 for (SourceLevel sourceLevel : SourceLevel.values()) {
185 for (XlintOption xlint : XlintOption.values()) {
186 for (TrustMe trustMe : TrustMe.values()) {
187 for (SuppressLevel suppressLevel : SuppressLevel.values()) {
188 for (ModifierKind modKind : ModifierKind.values()) {
189 for (MethodKind methKind : MethodKind.values()) {
190 for (SignatureKind sig : SignatureKind.values()) {
191 for (BodyKind body : BodyKind.values()) {
192 test(sourceLevel,
193 xlint,
194 trustMe,
195 suppressLevel,
196 modKind,
197 methKind,
198 sig,
199 body);
200 }
201 }
202 }
203 }
204 }
205 }
206 }
207 }
208 }
209
210 static void test(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel,
211 ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) throws Exception {
212 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
213 JavaSource source = new JavaSource(trustMe, suppressLevel, modKind, methKind, sig, body);
214 DiagnosticChecker dc = new DiagnosticChecker();
215 JavacTask ct = (JavacTask)tool.getTask(null, null, dc,
216 Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source));
217 ct.analyze();
218 check(sourceLevel, dc, source, xlint, trustMe,
219 suppressLevel, modKind, methKind, sig, body);
220 }
221
222 static void check(SourceLevel sourceLevel, DiagnosticChecker dc, JavaSource source,
223 XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind,
224 MethodKind methKind, SignatureKind meth, BodyKind body) {
225
226 boolean hasPotentiallyUnsafeBody = sourceLevel == SourceLevel.JDK_7 &&
227 trustMe == TrustMe.TRUST &&
228 suppressLevel != SuppressLevel.VARARGS &&
229 xlint != XlintOption.NONE &&
230 meth.isVarargs && !meth.isReifiableArg && body.hasAliasing &&
231 (methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE));
232
233 boolean hasPotentiallyPollutingDecl = sourceLevel == SourceLevel.JDK_7 &&
234 trustMe == TrustMe.DONT_TRUST &&
235 meth.isVarargs &&
236 !meth.isReifiableArg &&
237 xlint == XlintOption.ALL;
238
239 boolean hasMalformedAnnoInDecl = sourceLevel == SourceLevel.JDK_7 &&
240 trustMe == TrustMe.TRUST &&
241 (!meth.isVarargs ||
242 (modKind == ModifierKind.NONE && methKind == MethodKind.METHOD));
243
244 boolean hasRedundantAnnoInDecl = sourceLevel == SourceLevel.JDK_7 &&
245 trustMe == TrustMe.TRUST &&
246 xlint != XlintOption.NONE &&
247 suppressLevel != SuppressLevel.VARARGS &&
248 (modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) &&
249 meth.isVarargs &&
250 meth.isReifiableArg;
251
252 if (hasPotentiallyUnsafeBody != dc.hasPotentiallyUnsafeBody ||
253 hasPotentiallyPollutingDecl != dc.hasPotentiallyPollutingDecl ||
254 hasMalformedAnnoInDecl != dc.hasMalformedAnnoInDecl ||
255 hasRedundantAnnoInDecl != dc.hasRedundantAnnoInDecl) {
256 throw new Error("invalid diagnostics for source:\n" +
257 source.getCharContent(true) +
258 "\nOptions: " + xlint.getXlintOption() +
259 "\nExpected potentially unsafe body warning: " + hasPotentiallyUnsafeBody +
260 "\nExpected potentially polluting decl warning: " + hasPotentiallyPollutingDecl +
261 "\nExpected malformed anno error: " + hasMalformedAnnoInDecl +
262 "\nExpected redundant anno warning: " + hasRedundantAnnoInDecl +
263 "\nFound potentially unsafe body warning: " + dc.hasPotentiallyUnsafeBody +
264 "\nFound potentially polluting decl warning: " + dc.hasPotentiallyPollutingDecl +
265 "\nFound malformed anno error: " + dc.hasMalformedAnnoInDecl +
266 "\nFound redundant anno warning: " + dc.hasRedundantAnnoInDecl);
267 }
268 }
269
270 static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
271
272 boolean hasPotentiallyUnsafeBody = false;
273 boolean hasPotentiallyPollutingDecl = false;
274 boolean hasMalformedAnnoInDecl = false;
275 boolean hasRedundantAnnoInDecl = false;
276
277 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
278 if (diagnostic.getKind() == Diagnostic.Kind.WARNING) {
279 if (diagnostic.getCode().contains("unsafe.use.varargs.param")) {
280 hasPotentiallyUnsafeBody = true;
281 } else if (diagnostic.getCode().contains("redundant.trustme")) {
282 hasRedundantAnnoInDecl = true;
283 }
284 } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING &&
285 diagnostic.getCode().contains("varargs.non.reifiable.type")) {
286 hasPotentiallyPollutingDecl = true;
287 } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
288 diagnostic.getCode().contains("invalid.trustme")) {
289 hasMalformedAnnoInDecl = true;
290 }
291 }
292 }
293 }

mercurial