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