|
1 /* |
|
2 * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
21 * have any questions. |
|
22 */ |
|
23 |
|
24 /** |
|
25 * @test |
|
26 * @bug 6769027 |
|
27 * @summary Source line should be displayed immediately after the first diagnostic line |
|
28 * @author Maurizio Cimadamore |
|
29 * @run main/othervm T6769027 |
|
30 */ |
|
31 import java.net.URI; |
|
32 import java.util.regex.Matcher; |
|
33 import javax.tools.*; |
|
34 import com.sun.tools.javac.util.*; |
|
35 |
|
36 public class T6769027 { |
|
37 |
|
38 enum OutputKind { |
|
39 RAW("rawDiagnostics","rawDiagnostics"), |
|
40 BASIC("",""); |
|
41 |
|
42 String key; |
|
43 String value; |
|
44 |
|
45 void init(Options opts) { |
|
46 opts.put(key, value); |
|
47 } |
|
48 |
|
49 OutputKind(String key, String value) { |
|
50 this.key = key; |
|
51 this.value = value; |
|
52 } |
|
53 } |
|
54 |
|
55 enum CaretKind { |
|
56 DEFAULT("", ""), |
|
57 SHOW("showCaret","true"), |
|
58 HIDE("showCaret","false"); |
|
59 |
|
60 String key; |
|
61 String value; |
|
62 |
|
63 void init(Options opts) { |
|
64 opts.put(key, value); |
|
65 } |
|
66 |
|
67 CaretKind(String key, String value) { |
|
68 this.key = key; |
|
69 this.value = value; |
|
70 } |
|
71 |
|
72 boolean isEnabled() { |
|
73 return this == DEFAULT || this == SHOW; |
|
74 } |
|
75 } |
|
76 |
|
77 enum SourceLineKind { |
|
78 DEFAULT("", ""), |
|
79 AFTER_SUMMARY("sourcePosition", "top"), |
|
80 BOTTOM("sourcePosition", "bottom"); |
|
81 |
|
82 String key; |
|
83 String value; |
|
84 |
|
85 void init(Options opts) { |
|
86 opts.put(key, value); |
|
87 } |
|
88 |
|
89 SourceLineKind(String key, String value) { |
|
90 this.key = key; |
|
91 this.value = value; |
|
92 } |
|
93 |
|
94 boolean isAfterSummary() { |
|
95 return this == DEFAULT || this == AFTER_SUMMARY; |
|
96 } |
|
97 } |
|
98 |
|
99 enum XDiagsSource { |
|
100 DEFAULT(""), |
|
101 SOURCE("source"), |
|
102 NO_SOURCE("-source"); |
|
103 |
|
104 String flag; |
|
105 |
|
106 void init(Options opts) { |
|
107 if (this != DEFAULT) { |
|
108 String flags = opts.get("diags"); |
|
109 flags = flags == null ? flag : flags + "," + flag; |
|
110 opts.put("diags", flags); |
|
111 } |
|
112 } |
|
113 |
|
114 XDiagsSource(String flag) { |
|
115 this.flag = flag; |
|
116 } |
|
117 |
|
118 String getOutput(CaretKind caretKind, IndentKind indent, OutputKind outKind) { |
|
119 String spaces = (outKind == OutputKind.BASIC) ? indent.string : ""; |
|
120 return "\n" + spaces + "This is a source line" + |
|
121 (caretKind.isEnabled() ? "\n" + spaces + " ^" : ""); |
|
122 } |
|
123 } |
|
124 |
|
125 enum XDiagsCompact { |
|
126 DEFAULT(""), |
|
127 COMPACT("short"), |
|
128 NO_COMPACT("-short"); |
|
129 |
|
130 String flag; |
|
131 |
|
132 void init(Options opts) { |
|
133 if (this != DEFAULT) { |
|
134 String flags = opts.get("diags"); |
|
135 flags = flags == null ? flag : flags + "," + flag; |
|
136 opts.put("diags", flags); |
|
137 } |
|
138 } |
|
139 |
|
140 XDiagsCompact(String flag) { |
|
141 this.flag = flag; |
|
142 } |
|
143 } |
|
144 |
|
145 enum ErrorKind { |
|
146 SINGLE("single", |
|
147 "compiler.err.single: Hello!", |
|
148 "KXThis is a test error message Hello!"), |
|
149 DOUBLE("double", |
|
150 "compiler.err.double: Hello!", |
|
151 "KXThis is a test error message.\n" + |
|
152 "KXYThis is another line of the above error message Hello!"); |
|
153 |
|
154 String key; |
|
155 String rawOutput; |
|
156 String nonRawOutput; |
|
157 |
|
158 String key() { |
|
159 return key; |
|
160 } |
|
161 |
|
162 ErrorKind(String key, String rawOutput, String nonRawOutput) { |
|
163 this.key = key; |
|
164 this.rawOutput = rawOutput; |
|
165 this.nonRawOutput = nonRawOutput; |
|
166 } |
|
167 |
|
168 String getOutput(OutputKind outKind, IndentKind summaryIndent, IndentKind detailsIndent) { |
|
169 return outKind == OutputKind.RAW ? |
|
170 rawOutput : |
|
171 nonRawOutput.replace("X", summaryIndent.string).replace("Y", detailsIndent.string).replace("K", ""); |
|
172 } |
|
173 |
|
174 String getOutput(OutputKind outKind, IndentKind summaryIndent, IndentKind detailsIndent, String indent) { |
|
175 return outKind == OutputKind.RAW ? |
|
176 rawOutput : |
|
177 nonRawOutput.replace("X", summaryIndent.string).replace("Y", detailsIndent.string).replace("K", indent); |
|
178 } |
|
179 } |
|
180 |
|
181 enum MultilineKind { |
|
182 NONE(0), |
|
183 DOUBLE(1), |
|
184 NESTED(2), |
|
185 DOUBLE_NESTED(3); |
|
186 |
|
187 static String[][] rawTemplates = { |
|
188 {"", ",{(E),(E)}", ",{(E,{(E)})}", ",{(E,{(E)}),(E,{(E)})}"}, //ENABLED |
|
189 {"", "", "", "",""}, //DISABLED |
|
190 {"", ",{(E)}", ",{(E,{(E)})}", ",{(E,{(E)})}"}, //LIMIT_LENGTH |
|
191 {"", ",{(E),(E)}", ",{(E)}", ",{(E),(E)}"}, //LIMIT_DEPTH |
|
192 {"", ",{(E)}", ",{(E)}", ",{(E)}"}}; //LIMIT_BOTH |
|
193 |
|
194 static String[][] basicTemplates = { |
|
195 {"", "\nE\nE", "\nE\nQ", "\nE\nQ\nE\nQ"}, //ENABLED |
|
196 {"", "", "", "",""}, //DISABLED |
|
197 {"", "\nE", "\nE\nQ", "\nE\nQ"}, //LIMIT_LENGTH |
|
198 {"", "\nE\nE", "\nE", "\nE\nE"}, //LIMIT_DEPTH |
|
199 {"", "\nE", "\nE", "\nE"}}; //LIMIT_BOTH |
|
200 |
|
201 |
|
202 int index; |
|
203 |
|
204 MultilineKind (int index) { |
|
205 this.index = index; |
|
206 } |
|
207 |
|
208 boolean isDouble() { |
|
209 return this == DOUBLE || this == DOUBLE_NESTED; |
|
210 } |
|
211 |
|
212 boolean isNested() { |
|
213 return this == NESTED || this == DOUBLE_NESTED; |
|
214 } |
|
215 |
|
216 String getOutput(OutputKind outKind, ErrorKind errKind, MultilinePolicy policy, |
|
217 IndentKind summaryIndent, IndentKind detailsIndent, IndentKind multiIndent) { |
|
218 String constIndent = (errKind == ErrorKind.DOUBLE) ? |
|
219 summaryIndent.string + detailsIndent.string : |
|
220 summaryIndent.string; |
|
221 constIndent += multiIndent.string; |
|
222 |
|
223 String errMsg1 = errKind.getOutput(outKind, summaryIndent, detailsIndent, constIndent); |
|
224 String errMsg2 = errKind.getOutput(outKind, summaryIndent, detailsIndent, constIndent + constIndent); |
|
225 |
|
226 errMsg1 = errMsg1.replaceAll("compiler.err", "compiler.misc"); |
|
227 errMsg1 = errMsg1.replaceAll("error message", "subdiagnostic"); |
|
228 errMsg2 = errMsg2.replaceAll("compiler.err", "compiler.misc"); |
|
229 errMsg2 = errMsg2.replaceAll("error message", "subdiagnostic"); |
|
230 |
|
231 String template = outKind == OutputKind.RAW ? |
|
232 rawTemplates[policy.index][index] : |
|
233 basicTemplates[policy.index][index]; |
|
234 |
|
235 template = template.replaceAll("E", errMsg1); |
|
236 return template.replaceAll("Q", errMsg2); |
|
237 } |
|
238 } |
|
239 |
|
240 enum MultilinePolicy { |
|
241 ENABLED(0, "multilinePolicy", "enabled"), |
|
242 DISABLED(1, "multilinePolicy", "disabled"), |
|
243 LIMIT_LENGTH(2, "multilinePolicy", "limit:1:*"), |
|
244 LIMIT_DEPTH(3, "multilinePolicy", "limit:*:1"), |
|
245 LIMIT_BOTH(4, "multilinePolicy", "limit:1:1"); |
|
246 |
|
247 String name; |
|
248 String value; |
|
249 int index; |
|
250 |
|
251 MultilinePolicy(int index, String name, String value) { |
|
252 this.name = name; |
|
253 this.value = value; |
|
254 this.index = index; |
|
255 } |
|
256 |
|
257 void init(Options options) { |
|
258 options.put(name, value); |
|
259 } |
|
260 } |
|
261 |
|
262 enum PositionKind { |
|
263 NOPOS(Position.NOPOS, "- ", "error: "), |
|
264 POS(5, "/Test.java:1:6: ", "myfo:/Test.java:1: "); |
|
265 |
|
266 int pos; |
|
267 String rawOutput; |
|
268 String nonRawOutput; |
|
269 |
|
270 PositionKind(int pos, String rawOutput, String nonRawOutput) { |
|
271 this.pos = pos; |
|
272 this.rawOutput = rawOutput; |
|
273 this.nonRawOutput = nonRawOutput; |
|
274 } |
|
275 |
|
276 JCDiagnostic.DiagnosticPosition pos() { |
|
277 return new JCDiagnostic.SimpleDiagnosticPosition(pos); |
|
278 } |
|
279 |
|
280 String getOutput(OutputKind outputKind) { |
|
281 return outputKind == OutputKind.RAW ? |
|
282 rawOutput : |
|
283 nonRawOutput; |
|
284 } |
|
285 } |
|
286 |
|
287 static class MyFileObject extends SimpleJavaFileObject { |
|
288 private String text; |
|
289 public MyFileObject(String text) { |
|
290 super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); |
|
291 this.text = text; |
|
292 } |
|
293 @Override |
|
294 public CharSequence getCharContent(boolean ignoreEncodingErrors) { |
|
295 return text; |
|
296 } |
|
297 } |
|
298 |
|
299 enum IndentKind { |
|
300 NONE(""), |
|
301 CUSTOM(" "); |
|
302 |
|
303 String string; |
|
304 |
|
305 IndentKind(String indent) { |
|
306 string = indent; |
|
307 } |
|
308 } |
|
309 |
|
310 class MyLog extends Log { |
|
311 MyLog(Context ctx) { |
|
312 super(ctx); |
|
313 } |
|
314 |
|
315 @Override |
|
316 protected java.io.PrintWriter getWriterForDiagnosticType(JCDiagnostic.DiagnosticType dt) { |
|
317 return new java.io.PrintWriter(System.out); |
|
318 } |
|
319 |
|
320 @Override |
|
321 protected boolean shouldReport(JavaFileObject jfo, int pos) { |
|
322 return true; |
|
323 } |
|
324 } |
|
325 |
|
326 int nerrors = 0; |
|
327 |
|
328 void exec(OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind, |
|
329 MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource, |
|
330 XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind, |
|
331 IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent, |
|
332 IndentKind subdiagsIndent) { |
|
333 Context ctx = new Context(); |
|
334 Options options = Options.instance(ctx); |
|
335 outputKind.init(options); |
|
336 multiPolicy.init(options); |
|
337 xdiagsSource.init(options); |
|
338 xdiagsCompact.init(options); |
|
339 caretKind.init(options); |
|
340 sourceLineKind.init(options); |
|
341 String indentString = ""; |
|
342 indentString = (summaryIndent == IndentKind.CUSTOM) ? "3" : "0"; |
|
343 indentString += (detailsIndent == IndentKind.CUSTOM) ? "|3" : "|0"; |
|
344 indentString += (sourceIndent == IndentKind.CUSTOM) ? "|3" : "|0"; |
|
345 indentString += (subdiagsIndent == IndentKind.CUSTOM) ? "|3" : "|0"; |
|
346 options.put("diagsIndentation", indentString); |
|
347 MyLog log = new MyLog(ctx); |
|
348 JavacMessages messages = JavacMessages.instance(ctx); |
|
349 messages.add("tester"); |
|
350 JCDiagnostic.Factory diags = JCDiagnostic.Factory.instance(ctx); |
|
351 log.useSource(new MyFileObject("This is a source line")); |
|
352 JCDiagnostic d = diags.error(log.currentSource(), |
|
353 posKind.pos(), |
|
354 errorKind.key(), "Hello!"); |
|
355 if (multiKind != MultilineKind.NONE) { |
|
356 JCDiagnostic sub = diags.fragment(errorKind.key(), "Hello!"); |
|
357 if (multiKind.isNested()) |
|
358 sub = new JCDiagnostic.MultilineDiagnostic(sub, List.of(sub)); |
|
359 List<JCDiagnostic> subdiags = multiKind.isDouble() ? |
|
360 List.of(sub, sub) : |
|
361 List.of(sub); |
|
362 d = new JCDiagnostic.MultilineDiagnostic(d, subdiags); |
|
363 } |
|
364 String diag = log.getDiagnosticFormatter().format(d, messages.getCurrentLocale()); |
|
365 checkOutput(diag, |
|
366 outputKind, |
|
367 errorKind, |
|
368 multiKind, |
|
369 multiPolicy, |
|
370 posKind, |
|
371 xdiagsSource, |
|
372 xdiagsCompact, |
|
373 caretKind, |
|
374 sourceLineKind, |
|
375 summaryIndent, |
|
376 detailsIndent, |
|
377 sourceIndent, |
|
378 subdiagsIndent); |
|
379 } |
|
380 |
|
381 void test() { |
|
382 for (OutputKind outputKind : OutputKind.values()) { |
|
383 for (ErrorKind errKind : ErrorKind.values()) { |
|
384 for (MultilineKind multiKind : MultilineKind.values()) { |
|
385 for (MultilinePolicy multiPolicy : MultilinePolicy.values()) { |
|
386 for (PositionKind posKind : PositionKind.values()) { |
|
387 for (XDiagsSource xdiagsSource : XDiagsSource.values()) { |
|
388 for (XDiagsCompact xdiagsCompact : XDiagsCompact.values()) { |
|
389 for (CaretKind caretKind : CaretKind.values()) { |
|
390 for (SourceLineKind sourceLineKind : SourceLineKind.values()) { |
|
391 for (IndentKind summaryIndent : IndentKind.values()) { |
|
392 for (IndentKind detailsIndent : IndentKind.values()) { |
|
393 for (IndentKind sourceIndent : IndentKind.values()) { |
|
394 for (IndentKind subdiagsIndent : IndentKind.values()) { |
|
395 exec(outputKind, |
|
396 errKind, |
|
397 multiKind, |
|
398 multiPolicy, |
|
399 posKind, |
|
400 xdiagsSource, |
|
401 xdiagsCompact, |
|
402 caretKind, |
|
403 sourceLineKind, |
|
404 summaryIndent, |
|
405 detailsIndent, |
|
406 sourceIndent, |
|
407 subdiagsIndent); |
|
408 } |
|
409 } |
|
410 } |
|
411 } |
|
412 } |
|
413 } |
|
414 } |
|
415 } |
|
416 } |
|
417 } |
|
418 } |
|
419 } |
|
420 } |
|
421 if (nerrors != 0) |
|
422 throw new AssertionError(nerrors + " errors found"); |
|
423 } |
|
424 |
|
425 void printInfo(String msg, OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind, |
|
426 MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource, |
|
427 XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind, |
|
428 IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent, |
|
429 IndentKind subdiagsIndent, String errorLine) { |
|
430 String sep = "*********************************************************"; |
|
431 String desc = "raw=" + outputKind + " pos=" + posKind + " key=" + errorKind.key() + |
|
432 " multiline=" + multiKind +" multiPolicy=" + multiPolicy.value + |
|
433 " diags= " + java.util.Arrays.asList(xdiagsSource.flag, xdiagsCompact.flag) + |
|
434 " caret=" + caretKind + " sourcePosition=" + sourceLineKind + |
|
435 " summaryIndent=" + summaryIndent + " detailsIndent=" + detailsIndent + |
|
436 " sourceIndent=" + sourceIndent + " subdiagsIndent=" + subdiagsIndent; |
|
437 System.out.println(sep); |
|
438 System.out.println(desc); |
|
439 System.out.println(sep); |
|
440 System.out.println(msg); |
|
441 System.out.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine); |
|
442 } |
|
443 |
|
444 void checkOutput(String msg, OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind, |
|
445 MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource, |
|
446 XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind, |
|
447 IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent, |
|
448 IndentKind subdiagsIndent) { |
|
449 boolean shouldPrintSource = posKind == PositionKind.POS && |
|
450 xdiagsSource != XDiagsSource.NO_SOURCE && |
|
451 (xdiagsSource == XDiagsSource.SOURCE || |
|
452 outputKind == OutputKind.BASIC); |
|
453 String errorLine = posKind.getOutput(outputKind) + |
|
454 errorKind.getOutput(outputKind, summaryIndent, detailsIndent); |
|
455 if (xdiagsCompact != XDiagsCompact.COMPACT) |
|
456 errorLine += multiKind.getOutput(outputKind, errorKind, multiPolicy, summaryIndent, detailsIndent, subdiagsIndent); |
|
457 String[] lines = errorLine.split("\n"); |
|
458 if (xdiagsCompact == XDiagsCompact.COMPACT) { |
|
459 errorLine = lines[0]; |
|
460 lines = new String[] {errorLine}; |
|
461 } |
|
462 if (shouldPrintSource) { |
|
463 if (sourceLineKind.isAfterSummary()) { |
|
464 String sep = "\n"; |
|
465 if (lines.length == 1) { |
|
466 errorLine += "\n"; |
|
467 sep = ""; |
|
468 } |
|
469 errorLine = errorLine.replaceFirst("\n", |
|
470 Matcher.quoteReplacement(xdiagsSource.getOutput(caretKind, sourceIndent, outputKind) + sep)); |
|
471 } |
|
472 else |
|
473 errorLine += xdiagsSource.getOutput(caretKind, sourceIndent, outputKind); |
|
474 } |
|
475 |
|
476 if (!msg.equals(errorLine)) { |
|
477 printInfo(msg, |
|
478 outputKind, |
|
479 errorKind, |
|
480 multiKind, |
|
481 multiPolicy, |
|
482 posKind, |
|
483 xdiagsSource, |
|
484 xdiagsCompact, |
|
485 caretKind, |
|
486 sourceLineKind, |
|
487 summaryIndent, |
|
488 detailsIndent, |
|
489 sourceIndent, |
|
490 subdiagsIndent, |
|
491 errorLine); |
|
492 nerrors++; |
|
493 } |
|
494 } |
|
495 |
|
496 public static void main(String... args) throws Exception { |
|
497 new T6769027().test(); |
|
498 } |
|
499 } |