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

changeset 1108
b5d0b8effc85
parent 962
0ff2bbd38f10
child 1482
954541f13717
equal deleted inserted replaced
1103:47147081d5b4 1108:b5d0b8effc85
21 * questions. 21 * questions.
22 */ 22 */
23 23
24 /** 24 /**
25 * @test 25 * @test
26 * @bug 6993978 26 * @bug 6993978 7097436
27 * @summary Project Coin: Annotation to reduce varargs warnings 27 * @summary Project Coin: Annotation to reduce varargs warnings
28 * @author mcimadamore 28 * @author mcimadamore
29 * @run main Warn5 29 * @run main Warn5
30 */ 30 */
31 import com.sun.source.util.JavacTask; 31 import com.sun.source.util.JavacTask;
32 import com.sun.tools.javac.api.JavacTool; 32 import com.sun.tools.javac.api.JavacTool;
33 import java.net.URI; 33 import java.net.URI;
34 import java.util.ArrayList;
35 import java.util.Arrays; 34 import java.util.Arrays;
35 import java.util.EnumSet;
36 import javax.tools.Diagnostic; 36 import javax.tools.Diagnostic;
37 import javax.tools.JavaCompiler; 37 import javax.tools.JavaCompiler;
38 import javax.tools.JavaFileObject; 38 import javax.tools.JavaFileObject;
39 import javax.tools.SimpleJavaFileObject; 39 import javax.tools.SimpleJavaFileObject;
40 import javax.tools.StandardJavaFileManager; 40 import javax.tools.StandardJavaFileManager;
92 } 92 }
93 93
94 enum MethodKind { 94 enum MethodKind {
95 METHOD("void m"), 95 METHOD("void m"),
96 CONSTRUCTOR("Test"); 96 CONSTRUCTOR("Test");
97
98 97
99 String name; 98 String name;
100 99
101 MethodKind(String name) { 100 MethodKind(String name) {
102 this.name = name; 101 this.name = name;
153 this.body = body; 152 this.body = body;
154 this.hasAliasing = hasAliasing; 153 this.hasAliasing = hasAliasing;
155 } 154 }
156 } 155 }
157 156
158 static class JavaSource extends SimpleJavaFileObject { 157 enum WarningKind {
159 158 UNSAFE_BODY,
160 String template = "import com.sun.tools.javac.api.*;\n" + 159 UNSAFE_DECL,
161 "import java.util.List;\n" + 160 MALFORMED_SAFEVARARGS,
162 "class Test {\n" + 161 REDUNDANT_SAFEVARARGS;
163 " static void test(Object o) {}\n" + 162 }
164 " static void testArr(Object[] o) {}\n" + 163
165 " #T \n #S #M { #B }\n" + 164 // Create a single file manager and reuse it for each compile to save time.
166 "}\n"; 165 static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null);
167
168 String source;
169
170 public JavaSource(TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind,
171 MethodKind methKind, SignatureKind meth, BodyKind body) {
172 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
173 source = template.replace("#T", trustMe.anno).
174 replace("#S", suppressLevel.getSuppressAnno()).
175 replace("#M", meth.getSignature(modKind, methKind)).
176 replace("#B", body.body);
177 }
178
179 @Override
180 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
181 return source;
182 }
183 }
184 166
185 public static void main(String... args) throws Exception { 167 public static void main(String... args) throws Exception {
186 for (SourceLevel sourceLevel : SourceLevel.values()) { 168 for (SourceLevel sourceLevel : SourceLevel.values()) {
187 for (XlintOption xlint : XlintOption.values()) { 169 for (XlintOption xlint : XlintOption.values()) {
188 for (TrustMe trustMe : TrustMe.values()) { 170 for (TrustMe trustMe : TrustMe.values()) {
189 for (SuppressLevel suppressLevel : SuppressLevel.values()) { 171 for (SuppressLevel suppressLevel : SuppressLevel.values()) {
190 for (ModifierKind modKind : ModifierKind.values()) { 172 for (ModifierKind modKind : ModifierKind.values()) {
191 for (MethodKind methKind : MethodKind.values()) { 173 for (MethodKind methKind : MethodKind.values()) {
192 for (SignatureKind sig : SignatureKind.values()) { 174 for (SignatureKind sig : SignatureKind.values()) {
193 for (BodyKind body : BodyKind.values()) { 175 for (BodyKind body : BodyKind.values()) {
194 test(sourceLevel, 176 new Warn5(sourceLevel,
195 xlint, 177 xlint,
196 trustMe, 178 trustMe,
197 suppressLevel, 179 suppressLevel,
198 modKind, 180 modKind,
199 methKind, 181 methKind,
200 sig, 182 sig,
201 body); 183 body).test();
202 } 184 }
203 } 185 }
204 } 186 }
205 } 187 }
206 } 188 }
207 } 189 }
208 } 190 }
209 } 191 }
210 } 192 }
211 193
212 // Create a single file manager and reuse it for each compile to save time. 194 final SourceLevel sourceLevel;
213 static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); 195 final XlintOption xlint;
214 196 final TrustMe trustMe;
215 static void test(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, 197 final SuppressLevel suppressLevel;
216 ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) throws Exception { 198 final ModifierKind modKind;
199 final MethodKind methKind;
200 final SignatureKind sig;
201 final BodyKind body;
202 final JavaSource source;
203 final DiagnosticChecker dc;
204
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 }
217
218 void test() throws Exception {
217 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 219 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler();
218 JavaSource source = new JavaSource(trustMe, suppressLevel, modKind, methKind, sig, body);
219 DiagnosticChecker dc = new DiagnosticChecker();
220 JavacTask ct = (JavacTask)tool.getTask(null, fm, dc, 220 JavacTask ct = (JavacTask)tool.getTask(null, fm, dc,
221 Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source)); 221 Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source));
222 ct.analyze(); 222 ct.analyze();
223 check(sourceLevel, dc, source, xlint, trustMe, 223 check();
224 suppressLevel, modKind, methKind, sig, body); 224 }
225 } 225
226 226 void check() {
227 static void check(SourceLevel sourceLevel, DiagnosticChecker dc, JavaSource source, 227
228 XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind, 228 EnumSet<WarningKind> expectedWarnings = EnumSet.noneOf(WarningKind.class);
229 MethodKind methKind, SignatureKind meth, BodyKind body) { 229
230 230 if (sourceLevel == SourceLevel.JDK_7 &&
231 boolean hasPotentiallyUnsafeBody = sourceLevel == SourceLevel.JDK_7 &&
232 trustMe == TrustMe.TRUST && 231 trustMe == TrustMe.TRUST &&
233 suppressLevel != SuppressLevel.VARARGS && 232 suppressLevel != SuppressLevel.VARARGS &&
234 xlint != XlintOption.NONE && 233 xlint != XlintOption.NONE &&
235 meth.isVarargs && !meth.isReifiableArg && body.hasAliasing && 234 sig.isVarargs && !sig.isReifiableArg && body.hasAliasing &&
236 (methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE)); 235 (methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE))) {
237 236 expectedWarnings.add(WarningKind.UNSAFE_BODY);
238 boolean hasPotentiallyPollutingDecl = sourceLevel == SourceLevel.JDK_7 && 237 }
238
239 if (sourceLevel == SourceLevel.JDK_7 &&
239 trustMe == TrustMe.DONT_TRUST && 240 trustMe == TrustMe.DONT_TRUST &&
240 meth.isVarargs && 241 sig.isVarargs &&
241 !meth.isReifiableArg && 242 !sig.isReifiableArg &&
242 xlint == XlintOption.ALL; 243 xlint == XlintOption.ALL) {
243 244 expectedWarnings.add(WarningKind.UNSAFE_DECL);
244 boolean hasMalformedAnnoInDecl = sourceLevel == SourceLevel.JDK_7 && 245 }
246
247 if (sourceLevel == SourceLevel.JDK_7 &&
245 trustMe == TrustMe.TRUST && 248 trustMe == TrustMe.TRUST &&
246 (!meth.isVarargs || 249 (!sig.isVarargs ||
247 (modKind == ModifierKind.NONE && methKind == MethodKind.METHOD)); 250 (modKind == ModifierKind.NONE && methKind == MethodKind.METHOD))) {
248 251 expectedWarnings.add(WarningKind.MALFORMED_SAFEVARARGS);
249 boolean hasRedundantAnnoInDecl = sourceLevel == SourceLevel.JDK_7 && 252 }
253
254 if (sourceLevel == SourceLevel.JDK_7 &&
250 trustMe == TrustMe.TRUST && 255 trustMe == TrustMe.TRUST &&
251 xlint != XlintOption.NONE && 256 xlint != XlintOption.NONE &&
252 suppressLevel != SuppressLevel.VARARGS && 257 suppressLevel != SuppressLevel.VARARGS &&
253 (modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) && 258 (modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) &&
254 meth.isVarargs && 259 sig.isVarargs &&
255 meth.isReifiableArg; 260 sig.isReifiableArg) {
256 261 expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS);
257 if (hasPotentiallyUnsafeBody != dc.hasPotentiallyUnsafeBody || 262 }
258 hasPotentiallyPollutingDecl != dc.hasPotentiallyPollutingDecl || 263
259 hasMalformedAnnoInDecl != dc.hasMalformedAnnoInDecl || 264 if (!expectedWarnings.containsAll(dc.warnings) ||
260 hasRedundantAnnoInDecl != dc.hasRedundantAnnoInDecl) { 265 !dc.warnings.containsAll(expectedWarnings)) {
261 throw new Error("invalid diagnostics for source:\n" + 266 throw new Error("invalid diagnostics for source:\n" +
262 source.getCharContent(true) + 267 source.getCharContent(true) +
263 "\nOptions: " + xlint.getXlintOption() + 268 "\nOptions: " + xlint.getXlintOption() +
264 "\nExpected potentially unsafe body warning: " + hasPotentiallyUnsafeBody + 269 "\nExpected warnings: " + expectedWarnings +
265 "\nExpected potentially polluting decl warning: " + hasPotentiallyPollutingDecl + 270 "\nFound warnings: " + dc.warnings);
266 "\nExpected malformed anno error: " + hasMalformedAnnoInDecl + 271 }
267 "\nExpected redundant anno warning: " + hasRedundantAnnoInDecl + 272 }
268 "\nFound potentially unsafe body warning: " + dc.hasPotentiallyUnsafeBody + 273
269 "\nFound potentially polluting decl warning: " + dc.hasPotentiallyPollutingDecl + 274 class JavaSource extends SimpleJavaFileObject {
270 "\nFound malformed anno error: " + dc.hasMalformedAnnoInDecl + 275
271 "\nFound redundant anno warning: " + dc.hasRedundantAnnoInDecl); 276 String template = "import com.sun.tools.javac.api.*;\n" +
272 } 277 "import java.util.List;\n" +
273 } 278 "class Test {\n" +
274 279 " static void test(Object o) {}\n" +
275 static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> { 280 " static void testArr(Object[] o) {}\n" +
276 281 " #T \n #S #M { #B }\n" +
277 boolean hasPotentiallyUnsafeBody = false; 282 "}\n";
278 boolean hasPotentiallyPollutingDecl = false; 283
279 boolean hasMalformedAnnoInDecl = false; 284 String source;
280 boolean hasRedundantAnnoInDecl = false; 285
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 }
293
294 @Override
295 public CharSequence getCharContent(boolean ignoreEncodingErrors) {
296 return source;
297 }
298 }
299
300 class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
301
302 EnumSet<WarningKind> warnings = EnumSet.noneOf(WarningKind.class);
281 303
282 public void report(Diagnostic<? extends JavaFileObject> diagnostic) { 304 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
283 if (diagnostic.getKind() == Diagnostic.Kind.WARNING) { 305 if (diagnostic.getKind() == Diagnostic.Kind.WARNING) {
284 if (diagnostic.getCode().contains("unsafe.use.varargs.param")) { 306 if (diagnostic.getCode().contains("unsafe.use.varargs.param")) {
285 hasPotentiallyUnsafeBody = true; 307 setWarning(WarningKind.UNSAFE_BODY);
286 } else if (diagnostic.getCode().contains("redundant.trustme")) { 308 } else if (diagnostic.getCode().contains("redundant.trustme")) {
287 hasRedundantAnnoInDecl = true; 309 setWarning(WarningKind.REDUNDANT_SAFEVARARGS);
288 } 310 }
289 } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING && 311 } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING &&
290 diagnostic.getCode().contains("varargs.non.reifiable.type")) { 312 diagnostic.getCode().contains("varargs.non.reifiable.type")) {
291 hasPotentiallyPollutingDecl = true; 313 setWarning(WarningKind.UNSAFE_DECL);
292 } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR && 314 } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR &&
293 diagnostic.getCode().contains("invalid.trustme")) { 315 diagnostic.getCode().contains("invalid.trustme")) {
294 hasMalformedAnnoInDecl = true; 316 setWarning(WarningKind.MALFORMED_SAFEVARARGS);
295 } 317 }
296 } 318 }
319
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 }
325
326 boolean hasWarning(WarningKind wk) {
327 return warnings.contains(wk);
328 }
297 } 329 }
298 } 330 }

mercurial