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