Log.java revision 3591:8382e92dd1f9
1/* 2 * Copyright (c) 1999, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.tools.javac.util; 27 28import java.io.*; 29import java.util.Arrays; 30import java.util.EnumMap; 31import java.util.EnumSet; 32import java.util.HashSet; 33import java.util.Map; 34import java.util.Queue; 35import java.util.Set; 36 37import javax.tools.DiagnosticListener; 38import javax.tools.JavaFileObject; 39 40import com.sun.tools.javac.api.DiagnosticFormatter; 41import com.sun.tools.javac.main.Main; 42import com.sun.tools.javac.main.Option; 43import com.sun.tools.javac.tree.EndPosTable; 44import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; 45import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 46import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; 47 48import static com.sun.tools.javac.main.Option.*; 49 50/** A class for error logs. Reports errors and warnings, and 51 * keeps track of error numbers and positions. 52 * 53 * <p><b>This is NOT part of any supported API. 54 * If you write code that depends on this, you do so at your own risk. 55 * This code and its internal interfaces are subject to change or 56 * deletion without notice.</b> 57 */ 58public class Log extends AbstractLog { 59 /** The context key for the log. */ 60 public static final Context.Key<Log> logKey = new Context.Key<>(); 61 62 /** The context key for the standard output PrintWriter. */ 63 public static final Context.Key<PrintWriter> outKey = new Context.Key<>(); 64 65 /** The context key for the diagnostic PrintWriter. */ 66 public static final Context.Key<PrintWriter> errKey = new Context.Key<>(); 67 68 /* TODO: Should unify this with prefix handling in JCDiagnostic.Factory. */ 69 public enum PrefixKind { 70 JAVAC("javac."), 71 COMPILER_MISC("compiler.misc."); 72 PrefixKind(String v) { 73 value = v; 74 } 75 public String key(String k) { 76 return value + k; 77 } 78 final String value; 79 } 80 81 /** 82 * DiagnosticHandler's provide the initial handling for diagnostics. 83 * When a diagnostic handler is created and has been initialized, it 84 * should install itself as the current diagnostic handler. When a 85 * client has finished using a handler, the client should call 86 * {@code log.removeDiagnosticHandler();} 87 * 88 * Note that javax.tools.DiagnosticListener (if set) is called later in the 89 * diagnostic pipeline. 90 */ 91 public static abstract class DiagnosticHandler { 92 /** 93 * The previously installed diagnostic handler. 94 */ 95 protected DiagnosticHandler prev; 96 97 /** 98 * Install this diagnostic handler as the current one, 99 * recording the previous one. 100 */ 101 protected void install(Log log) { 102 prev = log.diagnosticHandler; 103 log.diagnosticHandler = this; 104 } 105 106 /** 107 * Handle a diagnostic. 108 */ 109 public abstract void report(JCDiagnostic diag); 110 } 111 112 /** 113 * A DiagnosticHandler that discards all diagnostics. 114 */ 115 public static class DiscardDiagnosticHandler extends DiagnosticHandler { 116 public DiscardDiagnosticHandler(Log log) { 117 install(log); 118 } 119 120 @Override 121 public void report(JCDiagnostic diag) { } 122 } 123 124 /** 125 * A DiagnosticHandler that can defer some or all diagnostics, 126 * by buffering them for later examination and/or reporting. 127 * If a diagnostic is not deferred, or is subsequently reported 128 * with reportAllDiagnostics(), it will be reported to the previously 129 * active diagnostic handler. 130 */ 131 public static class DeferredDiagnosticHandler extends DiagnosticHandler { 132 private Queue<JCDiagnostic> deferred = new ListBuffer<>(); 133 private final Filter<JCDiagnostic> filter; 134 135 public DeferredDiagnosticHandler(Log log) { 136 this(log, null); 137 } 138 139 public DeferredDiagnosticHandler(Log log, Filter<JCDiagnostic> filter) { 140 this.filter = filter; 141 install(log); 142 } 143 144 @Override 145 public void report(JCDiagnostic diag) { 146 if (!diag.isFlagSet(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE) && 147 (filter == null || filter.accepts(diag))) { 148 deferred.add(diag); 149 } else { 150 prev.report(diag); 151 } 152 } 153 154 public Queue<JCDiagnostic> getDiagnostics() { 155 return deferred; 156 } 157 158 /** Report all deferred diagnostics. */ 159 public void reportDeferredDiagnostics() { 160 reportDeferredDiagnostics(EnumSet.allOf(JCDiagnostic.Kind.class)); 161 } 162 163 /** Report selected deferred diagnostics. */ 164 public void reportDeferredDiagnostics(Set<JCDiagnostic.Kind> kinds) { 165 JCDiagnostic d; 166 while ((d = deferred.poll()) != null) { 167 if (kinds.contains(d.getKind())) 168 prev.report(d); 169 } 170 deferred = null; // prevent accidental ongoing use 171 } 172 } 173 174 public enum WriterKind { NOTICE, WARNING, ERROR, STDOUT, STDERR } 175 176 private final Map<WriterKind, PrintWriter> writers; 177 178 /** The maximum number of errors/warnings that are reported. 179 */ 180 protected int MaxErrors; 181 protected int MaxWarnings; 182 183 /** Switch: prompt user on each error. 184 */ 185 public boolean promptOnError; 186 187 /** Switch: emit warning messages. 188 */ 189 public boolean emitWarnings; 190 191 /** Switch: suppress note messages. 192 */ 193 public boolean suppressNotes; 194 195 /** Print stack trace on errors? 196 */ 197 public boolean dumpOnError; 198 199 /** 200 * Diagnostic listener, if provided through programmatic 201 * interface to javac (JSR 199). 202 */ 203 protected DiagnosticListener<? super JavaFileObject> diagListener; 204 205 /** 206 * Formatter for diagnostics. 207 */ 208 private DiagnosticFormatter<JCDiagnostic> diagFormatter; 209 210 /** 211 * Keys for expected diagnostics. 212 */ 213 public Set<String> expectDiagKeys; 214 215 /** 216 * Set to true if a compressed diagnostic is reported 217 */ 218 public boolean compressedOutput; 219 220 /** 221 * JavacMessages object used for localization. 222 */ 223 private JavacMessages messages; 224 225 /** 226 * Handler for initial dispatch of diagnostics. 227 */ 228 private DiagnosticHandler diagnosticHandler; 229 230 /** Get the Log instance for this context. */ 231 public static Log instance(Context context) { 232 Log instance = context.get(logKey); 233 if (instance == null) 234 instance = new Log(context); 235 return instance; 236 } 237 238 /** 239 * Register a Context.Factory to create a Log. 240 */ 241 public static void preRegister(Context context, PrintWriter w) { 242 context.put(Log.class, (Context.Factory<Log>) (c -> new Log(c, w))); 243 } 244 245 /** 246 * Construct a log with default settings. 247 * If no streams are set in the context, the log will be initialized to use 248 * System.out for normal output, and System.err for all diagnostic output. 249 * If one stream is set in the context, with either Log.outKey or Log.errKey, 250 * it will be used for all output. 251 * Otherwise, the log will be initialized to use both streams found in the context. 252 */ 253 protected Log(Context context) { 254 this(context, initWriters(context)); 255 } 256 257 /** 258 * Initialize a map of writers based on values found in the context 259 * @param context the context in which to find writers to use 260 * @return a map of writers 261 */ 262 private static Map<WriterKind, PrintWriter> initWriters(Context context) { 263 PrintWriter out = context.get(outKey); 264 PrintWriter err = context.get(errKey); 265 if (out == null && err == null) { 266 out = new PrintWriter(System.out, true); 267 err = new PrintWriter(System.err, true); 268 return initWriters(out, err); 269 } else if (out == null || err == null) { 270 PrintWriter pw = (out != null) ? out : err; 271 return initWriters(pw, pw); 272 } else { 273 return initWriters(out, err); 274 } 275 } 276 277 /** 278 * Construct a log with all output sent to a single output stream. 279 */ 280 protected Log(Context context, PrintWriter writer) { 281 this(context, initWriters(writer, writer)); 282 } 283 284 /** 285 * Construct a log. 286 * The log will be initialized to use stdOut for normal output, and stdErr 287 * for all diagnostic output. 288 */ 289 protected Log(Context context, PrintWriter out, PrintWriter err) { 290 this(context, initWriters(out, err)); 291 } 292 293 /** 294 * Initialize a writer map for a stream for normal output, and a stream for diagnostics. 295 * @param out a stream to be used for normal output 296 * @param err a stream to be used for diagnostic messages, such as errors, warnings, etc 297 * @return a map of writers 298 */ 299 private static Map<WriterKind, PrintWriter> initWriters(PrintWriter out, PrintWriter err) { 300 Map<WriterKind, PrintWriter> writers = new EnumMap<>(WriterKind.class); 301 writers.put(WriterKind.ERROR, err); 302 writers.put(WriterKind.WARNING, err); 303 writers.put(WriterKind.NOTICE, err); 304 305 writers.put(WriterKind.STDOUT, out); 306 writers.put(WriterKind.STDERR, err); 307 308 return writers; 309 } 310 311 /** 312 * Construct a log with given I/O redirections. 313 * @deprecated 314 * This constructor is provided to support the supported but now-deprecated javadoc entry point 315 * com.sun.tools.javadoc.Main.execute(String programName, 316 * PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter, 317 * String defaultDocletClassName, String... args) 318 */ 319 @Deprecated 320 protected Log(Context context, PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter) { 321 this(context, initWriters(errWriter, warnWriter, noticeWriter)); 322 } 323 324 /** 325 * Initialize a writer map with different streams for different types of diagnostics. 326 * @param errWriter a stream for writing error messages 327 * @param warnWriter a stream for writing warning messages 328 * @param noticeWriter a stream for writing notice messages 329 * @return a map of writers 330 * @deprecated This method exists to support a supported but now deprecated javadoc entry point. 331 */ 332 @Deprecated 333 private static Map<WriterKind, PrintWriter> initWriters(PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter) { 334 Map<WriterKind, PrintWriter> writers = new EnumMap<>(WriterKind.class); 335 writers.put(WriterKind.ERROR, errWriter); 336 writers.put(WriterKind.WARNING, warnWriter); 337 writers.put(WriterKind.NOTICE, noticeWriter); 338 339 writers.put(WriterKind.STDOUT, noticeWriter); 340 writers.put(WriterKind.STDERR, errWriter); 341 342 return writers; 343 } 344 345 /** 346 * Creates a log. 347 * @param context the context in which the log should be registered 348 * @param writers a map of writers that can be accessed by the kind of writer required 349 */ 350 private Log(Context context, Map<WriterKind, PrintWriter> writers) { 351 super(JCDiagnostic.Factory.instance(context)); 352 context.put(logKey, this); 353 this.writers = writers; 354 355 @SuppressWarnings("unchecked") // FIXME 356 DiagnosticListener<? super JavaFileObject> dl = 357 context.get(DiagnosticListener.class); 358 this.diagListener = dl; 359 360 diagnosticHandler = new DefaultDiagnosticHandler(); 361 362 messages = JavacMessages.instance(context); 363 messages.add(Main.javacBundleName); 364 365 final Options options = Options.instance(context); 366 initOptions(options); 367 options.addListener(new Runnable() { 368 @Override 369 public void run() { 370 initOptions(options); 371 } 372 }); 373 } 374 // where 375 private void initOptions(Options options) { 376 this.dumpOnError = options.isSet(DOE); 377 this.promptOnError = options.isSet(PROMPT); 378 this.emitWarnings = options.isUnset(XLINT_CUSTOM, "none"); 379 this.suppressNotes = options.isSet("suppressNotes"); 380 this.MaxErrors = getIntOption(options, XMAXERRS, getDefaultMaxErrors()); 381 this.MaxWarnings = getIntOption(options, XMAXWARNS, getDefaultMaxWarnings()); 382 383 boolean rawDiagnostics = options.isSet("rawDiagnostics"); 384 this.diagFormatter = rawDiagnostics ? new RawDiagnosticFormatter(options) : 385 new BasicDiagnosticFormatter(options, messages); 386 387 String ek = options.get("expectKeys"); 388 if (ek != null) 389 expectDiagKeys = new HashSet<>(Arrays.asList(ek.split(", *"))); 390 } 391 392 private int getIntOption(Options options, Option option, int defaultValue) { 393 String s = options.get(option); 394 try { 395 if (s != null) { 396 int n = Integer.parseInt(s); 397 return (n <= 0 ? Integer.MAX_VALUE : n); 398 } 399 } catch (NumberFormatException e) { 400 // silently ignore ill-formed numbers 401 } 402 return defaultValue; 403 } 404 405 /** Default value for -Xmaxerrs. 406 */ 407 protected int getDefaultMaxErrors() { 408 return 100; 409 } 410 411 /** Default value for -Xmaxwarns. 412 */ 413 protected int getDefaultMaxWarnings() { 414 return 100; 415 } 416 417 /** The number of errors encountered so far. 418 */ 419 public int nerrors = 0; 420 421 /** The number of warnings encountered so far. 422 */ 423 public int nwarnings = 0; 424 425 /** A set of all errors generated so far. This is used to avoid printing an 426 * error message more than once. For each error, a pair consisting of the 427 * source file name and source code position of the error is added to the set. 428 */ 429 protected Set<Pair<JavaFileObject, Integer>> recorded = new HashSet<>(); 430 431 /** A set of "not-supported-in-source-X" errors produced so far. This is used to only generate 432 * one such error per file. 433 */ 434 protected Set<Pair<JavaFileObject, String>> recordedSourceLevelErrors = new HashSet<>(); 435 436 public boolean hasDiagnosticListener() { 437 return diagListener != null; 438 } 439 440 public void setEndPosTable(JavaFileObject name, EndPosTable endPosTable) { 441 Assert.checkNonNull(name); 442 getSource(name).setEndPosTable(endPosTable); 443 } 444 445 /** Return current sourcefile. 446 */ 447 public JavaFileObject currentSourceFile() { 448 return source == null ? null : source.getFile(); 449 } 450 451 /** Get the current diagnostic formatter. 452 */ 453 public DiagnosticFormatter<JCDiagnostic> getDiagnosticFormatter() { 454 return diagFormatter; 455 } 456 457 /** Set the current diagnostic formatter. 458 */ 459 public void setDiagnosticFormatter(DiagnosticFormatter<JCDiagnostic> diagFormatter) { 460 this.diagFormatter = diagFormatter; 461 } 462 463 public PrintWriter getWriter(WriterKind kind) { 464 return writers.get(kind); 465 } 466 467 public void setWriter(WriterKind kind, PrintWriter pw) { 468 Assert.checkNonNull(pw); 469 writers.put(kind, pw); 470 } 471 472 public void setWriters(PrintWriter pw) { 473 Assert.checkNonNull(pw); 474 for (WriterKind k: WriterKind.values()) 475 writers.put(k, pw); 476 } 477 478 /** 479 * Replace the specified diagnostic handler with the 480 * handler that was current at the time this handler was created. 481 * The given handler must be the currently installed handler; 482 * it must be specified explicitly for clarity and consistency checking. 483 */ 484 public void popDiagnosticHandler(DiagnosticHandler h) { 485 Assert.check(diagnosticHandler == h); 486 diagnosticHandler = h.prev; 487 } 488 489 /** Flush the logs 490 */ 491 public void flush() { 492 for (PrintWriter pw: writers.values()) { 493 pw.flush(); 494 } 495 } 496 497 public void flush(WriterKind kind) { 498 getWriter(kind).flush(); 499 } 500 501 /** Returns true if an error needs to be reported for a given 502 * source name and pos. 503 */ 504 protected boolean shouldReport(JavaFileObject file, int pos) { 505 if (file == null) 506 return true; 507 508 Pair<JavaFileObject,Integer> coords = new Pair<>(file, pos); 509 boolean shouldReport = !recorded.contains(coords); 510 if (shouldReport) 511 recorded.add(coords); 512 return shouldReport; 513 } 514 515 /** Returns true if a diagnostics needs to be reported. 516 */ 517 private boolean shouldReport(JCDiagnostic d) { 518 JavaFileObject file = d.getSource(); 519 520 if (file == null) 521 return true; 522 523 if (!shouldReport(file, d.getIntPosition())) 524 return false; 525 526 if (!d.isFlagSet(DiagnosticFlag.SOURCE_LEVEL)) 527 return true; 528 529 Pair<JavaFileObject, String> coords = new Pair<>(file, d.getCode()); 530 boolean shouldReport = !recordedSourceLevelErrors.contains(coords); 531 if (shouldReport) 532 recordedSourceLevelErrors.add(coords); 533 return shouldReport; 534 } 535 536 /** Prompt user after an error. 537 */ 538 public void prompt() { 539 if (promptOnError) { 540 System.err.println(localize("resume.abort")); 541 try { 542 while (true) { 543 switch (System.in.read()) { 544 case 'a': case 'A': 545 System.exit(-1); 546 return; 547 case 'r': case 'R': 548 return; 549 case 'x': case 'X': 550 throw new AssertionError("user abort"); 551 default: 552 } 553 } 554 } catch (IOException e) {} 555 } 556 } 557 558 /** Print the faulty source code line and point to the error. 559 * @param pos Buffer index of the error position, must be on current line 560 */ 561 private void printErrLine(int pos, PrintWriter writer) { 562 String line = (source == null ? null : source.getLine(pos)); 563 if (line == null) 564 return; 565 int col = source.getColumnNumber(pos, false); 566 567 printRawLines(writer, line); 568 for (int i = 0; i < col - 1; i++) { 569 writer.print((line.charAt(i) == '\t') ? "\t" : " "); 570 } 571 writer.println("^"); 572 writer.flush(); 573 } 574 575 public void printNewline() { 576 PrintWriter noticeWriter = writers.get(WriterKind.NOTICE); 577 noticeWriter.println(); 578 } 579 580 public void printNewline(WriterKind wk) { 581 getWriter(wk).println(); 582 } 583 584 public void printLines(String key, Object... args) { 585 PrintWriter noticeWriter = writers.get(WriterKind.NOTICE); 586 printRawLines(noticeWriter, localize(key, args)); 587 } 588 589 public void printLines(PrefixKind pk, String key, Object... args) { 590 PrintWriter noticeWriter = writers.get(WriterKind.NOTICE); 591 printRawLines(noticeWriter, localize(pk, key, args)); 592 } 593 594 public void printLines(WriterKind wk, String key, Object... args) { 595 printRawLines(getWriter(wk), localize(key, args)); 596 } 597 598 public void printLines(WriterKind wk, PrefixKind pk, String key, Object... args) { 599 printRawLines(getWriter(wk), localize(pk, key, args)); 600 } 601 602 /** Print the text of a message, translating newlines appropriately 603 * for the platform. 604 */ 605 public void printRawLines(String msg) { 606 PrintWriter noticeWriter = writers.get(WriterKind.NOTICE); 607 printRawLines(noticeWriter, msg); 608 } 609 610 /** Print the text of a message, translating newlines appropriately 611 * for the platform. 612 */ 613 public void printRawLines(WriterKind kind, String msg) { 614 printRawLines(getWriter(kind), msg); 615 } 616 617 /** Print the text of a message, translating newlines appropriately 618 * for the platform. 619 */ 620 public static void printRawLines(PrintWriter writer, String msg) { 621 int nl; 622 while ((nl = msg.indexOf('\n')) != -1) { 623 writer.println(msg.substring(0, nl)); 624 msg = msg.substring(nl+1); 625 } 626 if (msg.length() != 0) writer.println(msg); 627 } 628 629 /** 630 * Print the localized text of a "verbose" message to the 631 * noticeWriter stream. 632 */ 633 public void printVerbose(String key, Object... args) { 634 PrintWriter noticeWriter = writers.get(WriterKind.NOTICE); 635 printRawLines(noticeWriter, localize("verbose." + key, args)); 636 } 637 638 @Override 639 protected void directError(String key, Object... args) { 640 PrintWriter errWriter = writers.get(WriterKind.ERROR); 641 printRawLines(errWriter, localize(key, args)); 642 errWriter.flush(); 643 } 644 645 /** Report a warning that cannot be suppressed. 646 * @param pos The source position at which to report the warning. 647 * @param key The key for the localized warning message. 648 * @param args Fields of the warning message. 649 */ 650 public void strictWarning(DiagnosticPosition pos, String key, Object ... args) { 651 writeDiagnostic(diags.warning(null, source, pos, key, args)); 652 nwarnings++; 653 } 654 655 /** 656 * Primary method to report a diagnostic. 657 * @param diagnostic 658 */ 659 @Override 660 public void report(JCDiagnostic diagnostic) { 661 diagnosticHandler.report(diagnostic); 662 } 663 664 /** 665 * Common diagnostic handling. 666 * The diagnostic is counted, and depending on the options and how many diagnostics have been 667 * reported so far, the diagnostic may be handed off to writeDiagnostic. 668 */ 669 private class DefaultDiagnosticHandler extends DiagnosticHandler { 670 @Override 671 public void report(JCDiagnostic diagnostic) { 672 if (expectDiagKeys != null) 673 expectDiagKeys.remove(diagnostic.getCode()); 674 675 switch (diagnostic.getType()) { 676 case FRAGMENT: 677 throw new IllegalArgumentException(); 678 679 case NOTE: 680 // Print out notes only when we are permitted to report warnings 681 // Notes are only generated at the end of a compilation, so should be small 682 // in number. 683 if ((emitWarnings || diagnostic.isMandatory()) && !suppressNotes) { 684 writeDiagnostic(diagnostic); 685 } 686 break; 687 688 case WARNING: 689 if (emitWarnings || diagnostic.isMandatory()) { 690 if (nwarnings < MaxWarnings) { 691 writeDiagnostic(diagnostic); 692 nwarnings++; 693 } 694 } 695 break; 696 697 case ERROR: 698 if (nerrors < MaxErrors && 699 (diagnostic.isFlagSet(DiagnosticFlag.MULTIPLE) || 700 shouldReport(diagnostic))) { 701 writeDiagnostic(diagnostic); 702 nerrors++; 703 } 704 break; 705 } 706 if (diagnostic.isFlagSet(JCDiagnostic.DiagnosticFlag.COMPRESSED)) { 707 compressedOutput = true; 708 } 709 } 710 } 711 712 /** 713 * Write out a diagnostic. 714 */ 715 protected void writeDiagnostic(JCDiagnostic diag) { 716 if (diagListener != null) { 717 diagListener.report(diag); 718 return; 719 } 720 721 PrintWriter writer = getWriterForDiagnosticType(diag.getType()); 722 723 printRawLines(writer, diagFormatter.format(diag, messages.getCurrentLocale())); 724 725 if (promptOnError) { 726 switch (diag.getType()) { 727 case ERROR: 728 case WARNING: 729 prompt(); 730 } 731 } 732 733 if (dumpOnError) 734 new RuntimeException().printStackTrace(writer); 735 736 writer.flush(); 737 } 738 739 @Deprecated 740 protected PrintWriter getWriterForDiagnosticType(DiagnosticType dt) { 741 switch (dt) { 742 case FRAGMENT: 743 throw new IllegalArgumentException(); 744 745 case NOTE: 746 return writers.get(WriterKind.NOTICE); 747 748 case WARNING: 749 return writers.get(WriterKind.WARNING); 750 751 case ERROR: 752 return writers.get(WriterKind.ERROR); 753 754 default: 755 throw new Error(); 756 } 757 } 758 759 /** Find a localized string in the resource bundle. 760 * Because this method is static, it ignores the locale. 761 * Use localize(key, args) when possible. 762 * @param key The key for the localized string. 763 * @param args Fields to substitute into the string. 764 */ 765 public static String getLocalizedString(String key, Object ... args) { 766 return JavacMessages.getDefaultLocalizedString(PrefixKind.COMPILER_MISC.key(key), args); 767 } 768 769 /** Find a localized string in the resource bundle. 770 * @param key The key for the localized string. 771 * @param args Fields to substitute into the string. 772 */ 773 public String localize(String key, Object... args) { 774 return localize(PrefixKind.COMPILER_MISC, key, args); 775 } 776 777 public String localize(JCDiagnostic.DiagnosticInfo diagInfo) { 778 if (useRawMessages) { 779 return diagInfo.key(); 780 } else { 781 return messages.getLocalizedString(diagInfo.key(), diagInfo.args); 782 } 783 } 784 785 /** Find a localized string in the resource bundle. 786 * @param key The key for the localized string. 787 * @param args Fields to substitute into the string. 788 */ 789 public String localize(PrefixKind pk, String key, Object... args) { 790 if (useRawMessages) 791 return pk.key(key); 792 else 793 return messages.getLocalizedString(pk.key(key), args); 794 } 795 // where 796 // backdoor hook for testing, should transition to use -XDrawDiagnostics 797 private static boolean useRawMessages = false; 798 799/*************************************************************************** 800 * raw error messages without internationalization; used for experimentation 801 * and quick prototyping 802 ***************************************************************************/ 803 804 /** print an error or warning message: 805 */ 806 private void printRawDiag(PrintWriter pw, String prefix, int pos, String msg) { 807 if (source == null || pos == Position.NOPOS) { 808 printRawLines(pw, prefix + msg); 809 } else { 810 int line = source.getLineNumber(pos); 811 JavaFileObject file = source.getFile(); 812 if (file != null) 813 printRawLines(pw, 814 file.getName() + ":" + 815 line + ": " + msg); 816 printErrLine(pos, pw); 817 } 818 pw.flush(); 819 } 820 821 /** report an error: 822 */ 823 public void rawError(int pos, String msg) { 824 PrintWriter errWriter = writers.get(WriterKind.ERROR); 825 if (nerrors < MaxErrors && shouldReport(currentSourceFile(), pos)) { 826 printRawDiag(errWriter, "error: ", pos, msg); 827 prompt(); 828 nerrors++; 829 } 830 errWriter.flush(); 831 } 832 833 /** report a warning: 834 */ 835 public void rawWarning(int pos, String msg) { 836 PrintWriter warnWriter = writers.get(WriterKind.ERROR); 837 if (nwarnings < MaxWarnings && emitWarnings) { 838 printRawDiag(warnWriter, "warning: ", pos, msg); 839 } 840 prompt(); 841 nwarnings++; 842 warnWriter.flush(); 843 } 844 845 public static String format(String fmt, Object... args) { 846 return String.format((java.util.Locale)null, fmt, args); 847 } 848 849} 850