JCDiagnostic.java revision 3591:8382e92dd1f9
1/* 2 * Copyright (c) 2003, 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. 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.util.EnumSet; 29import java.util.Locale; 30import java.util.Set; 31import java.util.stream.Stream; 32 33import javax.tools.Diagnostic; 34import javax.tools.JavaFileObject; 35 36import com.sun.tools.javac.api.DiagnosticFormatter; 37import com.sun.tools.javac.code.Lint.LintCategory; 38import com.sun.tools.javac.tree.EndPosTable; 39import com.sun.tools.javac.tree.JCTree; 40import com.sun.tools.javac.util.DefinedBy.Api; 41 42import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*; 43 44/** An abstraction of a diagnostic message generated by the compiler. 45 * 46 * <p><b>This is NOT part of any supported API. 47 * If you write code that depends on this, you do so at your own risk. 48 * This code and its internal interfaces are subject to change or 49 * deletion without notice.</b> 50 */ 51public class JCDiagnostic implements Diagnostic<JavaFileObject> { 52 /** A factory for creating diagnostic objects. */ 53 public static class Factory { 54 /** The context key for the diagnostic factory. */ 55 protected static final Context.Key<JCDiagnostic.Factory> diagnosticFactoryKey = new Context.Key<>(); 56 57 /** Get the Factory instance for this context. */ 58 public static Factory instance(Context context) { 59 Factory instance = context.get(diagnosticFactoryKey); 60 if (instance == null) 61 instance = new Factory(context); 62 return instance; 63 } 64 65 DiagnosticFormatter<JCDiagnostic> formatter; 66 final String prefix; 67 final Set<DiagnosticFlag> defaultErrorFlags; 68 69 /** Create a new diagnostic factory. */ 70 protected Factory(Context context) { 71 this(JavacMessages.instance(context), "compiler"); 72 context.put(diagnosticFactoryKey, this); 73 74 final Options options = Options.instance(context); 75 initOptions(options); 76 options.addListener(new Runnable() { 77 public void run() { 78 initOptions(options); 79 } 80 }); 81 } 82 83 private void initOptions(Options options) { 84 if (options.isSet("onlySyntaxErrorsUnrecoverable")) 85 defaultErrorFlags.add(DiagnosticFlag.RECOVERABLE); 86 } 87 88 /** Create a new diagnostic factory. */ 89 public Factory(JavacMessages messages, String prefix) { 90 this.prefix = prefix; 91 this.formatter = new BasicDiagnosticFormatter(messages); 92 defaultErrorFlags = EnumSet.of(DiagnosticFlag.MANDATORY); 93 } 94 95 /** 96 * Create an error diagnostic 97 * @param source The source of the compilation unit, if any, in which to report the error. 98 * @param pos The source position at which to report the error. 99 * @param key The key for the localized error message. 100 * @param args Fields of the error message. 101 */ 102 public JCDiagnostic error( 103 DiagnosticFlag flag, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 104 return error(flag, source, pos, errorKey(key, args)); 105 } 106 107 /** 108 * Create an error diagnostic 109 * @param source The source of the compilation unit, if any, in which to report the error. 110 * @param pos The source position at which to report the error. 111 * @param errorKey The key for the localized error message. 112 */ 113 public JCDiagnostic error( 114 DiagnosticFlag flag, DiagnosticSource source, DiagnosticPosition pos, Error errorKey) { 115 JCDiagnostic diag = create(null, EnumSet.copyOf(defaultErrorFlags), source, pos, errorKey); 116 if (flag != null) { 117 diag.setFlag(flag); 118 } 119 return diag; 120 } 121 122 /** 123 * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options. 124 * @param lc The lint category for the diagnostic 125 * @param source The source of the compilation unit, if any, in which to report the warning. 126 * @param pos The source position at which to report the warning. 127 * @param key The key for the localized warning message. 128 * @param args Fields of the warning message. 129 * @see MandatoryWarningHandler 130 */ 131 public JCDiagnostic mandatoryWarning( 132 LintCategory lc, 133 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 134 return mandatoryWarning(lc, source, pos, warningKey(key, args)); 135 } 136 137 /** 138 * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options. 139 * @param lc The lint category for the diagnostic 140 * @param source The source of the compilation unit, if any, in which to report the warning. 141 * @param pos The source position at which to report the warning. 142 * @param warningKey The key for the localized warning message. 143 * @see MandatoryWarningHandler 144 */ 145 public JCDiagnostic mandatoryWarning( 146 LintCategory lc, 147 DiagnosticSource source, DiagnosticPosition pos, Warning warningKey) { 148 return create(lc, EnumSet.of(DiagnosticFlag.MANDATORY), source, pos, warningKey); 149 } 150 151 /** 152 * Create a warning diagnostic. 153 * @param lc The lint category for the diagnostic 154 * @param source The source of the compilation unit, if any, in which to report the warning. 155 * @param pos The source position at which to report the warning. 156 * @param key The key for the localized error message. 157 * @param args Fields of the warning message. 158 * @see MandatoryWarningHandler 159 */ 160 public JCDiagnostic warning( 161 LintCategory lc, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 162 return warning(lc, source, pos, warningKey(key, args)); 163 } 164 165 /** 166 * Create a warning diagnostic. 167 * @param lc The lint category for the diagnostic 168 * @param source The source of the compilation unit, if any, in which to report the warning. 169 * @param pos The source position at which to report the warning. 170 * @param warningKey The key for the localized warning message. 171 * @see MandatoryWarningHandler 172 */ 173 public JCDiagnostic warning( 174 LintCategory lc, DiagnosticSource source, DiagnosticPosition pos, Warning warningKey) { 175 return create(lc, EnumSet.noneOf(DiagnosticFlag.class), source, pos, warningKey); 176 } 177 178 /** 179 * Create a note diagnostic that will not be hidden by the -nowarn or -Xlint:none options. 180 * @param source The source of the compilation unit, if any, in which to report the warning. 181 * @param key The key for the localized warning message. 182 * @param args Fields of the warning message. 183 * @see MandatoryWarningHandler 184 */ 185 public JCDiagnostic mandatoryNote(DiagnosticSource source, String key, Object... args) { 186 return mandatoryNote(source, noteKey(key, args)); 187 } 188 189 /** 190 * Create a note diagnostic that will not be hidden by the -nowarn or -Xlint:none options. 191 * @param noteKey The key for the localized note message. 192 * @see MandatoryWarningHandler 193 */ 194 public JCDiagnostic mandatoryNote(DiagnosticSource source, Note noteKey) { 195 return create(null, EnumSet.of(DiagnosticFlag.MANDATORY), source, null, noteKey); 196 } 197 198 /** 199 * Create a note diagnostic. 200 * @param key The key for the localized error message. 201 * @param args Fields of the message. 202 */ 203 public JCDiagnostic note( 204 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 205 return note(source, pos, noteKey(key, args)); 206 } 207 208 /** 209 * Create a note diagnostic. 210 * @param source The source of the compilation unit, if any, in which to report the note. 211 * @param pos The source position at which to report the note. 212 * @param noteKey The key for the localized note message. 213 */ 214 public JCDiagnostic note( 215 DiagnosticSource source, DiagnosticPosition pos, Note noteKey) { 216 return create(null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, noteKey); 217 } 218 219 /** 220 * Create a fragment diagnostic, for use as an argument in other diagnostics 221 * @param key The key for the localized message. 222 * @param args Fields of the message. 223 */ 224 public JCDiagnostic fragment(String key, Object... args) { 225 return fragment(fragmentKey(key, args)); 226 } 227 228 /** 229 * Create a fragment diagnostic, for use as an argument in other diagnostics 230 * @param fragmentKey The key for the localized subdiagnostic message. 231 */ 232 public JCDiagnostic fragment(Fragment fragmentKey) { 233 return create(null, EnumSet.noneOf(DiagnosticFlag.class), null, null, fragmentKey); 234 } 235 236 /** 237 * Create a new diagnostic of the given kind, which is not mandatory and which has 238 * no lint category. 239 * @param kind The diagnostic kind 240 * @param source The source of the compilation unit, if any, in which to report the message. 241 * @param pos The source position at which to report the message. 242 * @param key The key for the localized message. 243 * @param args Fields of the message. 244 */ 245 public JCDiagnostic create( 246 DiagnosticType kind, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 247 return create(null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, DiagnosticInfo.of(kind, prefix, key, args)); 248 } 249 250 /** 251 * Create a new diagnostic of the given kind, which is not mandatory and which has 252 * no lint category. 253 * @param source The source of the compilation unit, if any, in which to report the message. 254 * @param pos The source position at which to report the message. 255 * @param diagnosticInfo The key for the localized message. 256 */ 257 public JCDiagnostic create( 258 DiagnosticSource source, DiagnosticPosition pos, DiagnosticInfo diagnosticInfo) { 259 return create(null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, diagnosticInfo); 260 } 261 262 /** 263 * Create a new diagnostic of the given kind. 264 * @param kind The diagnostic kind 265 * @param lc The lint category, if applicable, or null 266 * @param flags The set of flags for the diagnostic 267 * @param source The source of the compilation unit, if any, in which to report the message. 268 * @param pos The source position at which to report the message. 269 * @param key The key for the localized message. 270 * @param args Fields of the message. 271 */ 272 public JCDiagnostic create(DiagnosticType kind, 273 LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 274 return create(lc, flags, source, pos, DiagnosticInfo.of(kind, prefix, key, args)); 275 } 276 277 /** 278 * Create a new diagnostic with given key. 279 * @param lc The lint category, if applicable, or null 280 * @param flags The set of flags for the diagnostic 281 * @param source The source of the compilation unit, if any, in which to report the message. 282 * @param pos The source position at which to report the message. 283 * @param diagnosticInfo The key for the localized message. 284 */ 285 public JCDiagnostic create( 286 LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, DiagnosticInfo diagnosticInfo) { 287 return new JCDiagnostic(formatter, normalize(diagnosticInfo), lc, flags, source, pos); 288 } 289 //where 290 DiagnosticInfo normalize(DiagnosticInfo diagnosticInfo) { 291 //replace all nested FragmentKey with full-blown JCDiagnostic objects 292 return DiagnosticInfo.of(diagnosticInfo.type, diagnosticInfo.prefix, diagnosticInfo.code, 293 Stream.of(diagnosticInfo.args).map(o -> { 294 return (o instanceof Fragment) ? 295 fragment((Fragment)o) : o; 296 }).toArray()); 297 } 298 299 /** 300 * Create a new error key. 301 */ 302 Error errorKey(String code, Object... args) { 303 return (Error)DiagnosticInfo.of(ERROR, prefix, code, args); 304 } 305 306 /** 307 * Create a new warning key. 308 */ 309 Warning warningKey(String code, Object... args) { 310 return (Warning)DiagnosticInfo.of(WARNING, prefix, code, args); 311 } 312 313 /** 314 * Create a new note key. 315 */ 316 Note noteKey(String code, Object... args) { 317 return (Note)DiagnosticInfo.of(NOTE, prefix, code, args); 318 } 319 320 /** 321 * Create a new fragment key. 322 */ 323 Fragment fragmentKey(String code, Object... args) { 324 return (Fragment)DiagnosticInfo.of(FRAGMENT, prefix, code, args); 325 } 326 } 327 328 329 330 /** 331 * Create a fragment diagnostic, for use as an argument in other diagnostics 332 * @param key The key for the localized error message. 333 * @param args Fields of the error message. 334 * 335 */ 336 @Deprecated 337 public static JCDiagnostic fragment(String key, Object... args) { 338 return new JCDiagnostic(getFragmentFormatter(), 339 DiagnosticInfo.of(FRAGMENT, 340 "compiler", 341 key, 342 args), 343 null, 344 EnumSet.noneOf(DiagnosticFlag.class), 345 null, 346 null); 347 } 348 //where 349 @Deprecated 350 public static DiagnosticFormatter<JCDiagnostic> getFragmentFormatter() { 351 if (fragmentFormatter == null) { 352 fragmentFormatter = new BasicDiagnosticFormatter(JavacMessages.getDefaultMessages()); 353 } 354 return fragmentFormatter; 355 } 356 357 /** 358 * A DiagnosticType defines the type of the diagnostic. 359 **/ 360 public enum DiagnosticType { 361 /** A fragment of an enclosing diagnostic. */ 362 FRAGMENT("misc"), 363 /** A note: similar to, but less serious than, a warning. */ 364 NOTE("note"), 365 /** A warning. */ 366 WARNING("warn"), 367 /** An error. */ 368 ERROR("err"); 369 370 final String key; 371 372 /** Create a DiagnosticType. 373 * @param key A string used to create the resource key for the diagnostic. 374 */ 375 DiagnosticType(String key) { 376 this.key = key; 377 } 378 } 379 380 /** 381 * A DiagnosticPosition provides information about the positions in a file 382 * that gave rise to a diagnostic. It always defines a "preferred" position 383 * that most accurately defines the location of the diagnostic, it may also 384 * provide a related tree node that spans that location. 385 */ 386 public static interface DiagnosticPosition { 387 /** Gets the tree node, if any, to which the diagnostic applies. */ 388 JCTree getTree(); 389 /** If there is a tree node, get the start position of the tree node. 390 * Otherwise, just returns the same as getPreferredPosition(). */ 391 int getStartPosition(); 392 /** Get the position within the file that most accurately defines the 393 * location for the diagnostic. */ 394 int getPreferredPosition(); 395 /** If there is a tree node, and if endPositions are available, get 396 * the end position of the tree node. Otherwise, just returns the 397 * same as getPreferredPosition(). */ 398 int getEndPosition(EndPosTable endPosTable); 399 } 400 401 /** 402 * A DiagnosticPosition that simply identifies a position, but no related 403 * tree node, as the location for a diagnostic. Used for scanner and parser 404 * diagnostics. */ 405 public static class SimpleDiagnosticPosition implements DiagnosticPosition { 406 public SimpleDiagnosticPosition(int pos) { 407 this.pos = pos; 408 } 409 410 public JCTree getTree() { 411 return null; 412 } 413 414 public int getStartPosition() { 415 return pos; 416 } 417 418 public int getPreferredPosition() { 419 return pos; 420 } 421 422 public int getEndPosition(EndPosTable endPosTable) { 423 return pos; 424 } 425 426 private final int pos; 427 } 428 429 public enum DiagnosticFlag { 430 MANDATORY, 431 RESOLVE_ERROR, 432 SYNTAX, 433 RECOVERABLE, 434 NON_DEFERRABLE, 435 COMPRESSED, 436 /** Print multiple errors for same source locations. 437 */ 438 MULTIPLE, 439 /** Flag for not-supported-in-source-X errors. 440 */ 441 SOURCE_LEVEL; 442 } 443 444 private final DiagnosticSource source; 445 private final DiagnosticPosition position; 446 private final DiagnosticInfo diagnosticInfo; 447 private final Set<DiagnosticFlag> flags; 448 private final LintCategory lintCategory; 449 450 /** source line position (set lazily) */ 451 private SourcePosition sourcePosition; 452 453 /** 454 * This class is used to defer the line/column position fetch logic after diagnostic construction. 455 */ 456 class SourcePosition { 457 458 private final int line; 459 private final int column; 460 461 SourcePosition() { 462 int n = (position == null ? Position.NOPOS : position.getPreferredPosition()); 463 if (n == Position.NOPOS || source == null) 464 line = column = -1; 465 else { 466 line = source.getLineNumber(n); 467 column = source.getColumnNumber(n, true); 468 } 469 } 470 471 public int getLineNumber() { 472 return line; 473 } 474 475 public int getColumnNumber() { 476 return column; 477 } 478 } 479 480 /** 481 * A diagnostic key object encapsulates basic properties of a diagnostic, such as the resource key, 482 * the arguments and the kind associated with the diagnostic object. Diagnostic keys can be either 483 * created programmatically (by using the supplied factory method) or obtained through build-time 484 * generated factory methods. 485 */ 486 public static abstract class DiagnosticInfo { 487 488 /** The diagnostic kind (i.e. error). */ 489 DiagnosticType type; 490 491 /** The diagnostic prefix (i.e. 'javac'); used to compute full resource key. */ 492 String prefix; 493 494 /** The diagnostic code (i.e. 'cannot.resolve.sym'); together with {@code prefix} it forms 495 * the full resource key. */ 496 String code; 497 498 /** The diagnostic arguments. */ 499 Object[] args; 500 501 private DiagnosticInfo(DiagnosticType type, String prefix, String code, Object... args) { 502 this.type = type; 503 this.prefix = prefix; 504 this.code = code; 505 this.args = args; 506 } 507 508 /** 509 * Compute the resource key. 510 */ 511 public String key() { 512 return prefix + "." + type.key + "." + code; 513 } 514 515 /** 516 * Static factory method; build a custom diagnostic key using given kind, prefix, code and args. 517 */ 518 public static DiagnosticInfo of(DiagnosticType type, String prefix, String code, Object... args) { 519 switch (type) { 520 case ERROR: 521 return new Error(prefix, code, args); 522 case WARNING: 523 return new Warning(prefix, code, args); 524 case NOTE: 525 return new Note(prefix, code, args); 526 case FRAGMENT: 527 return new Fragment(prefix, code, args); 528 default: 529 Assert.error("Wrong diagnostic type: " + type); 530 return null; 531 } 532 } 533 534 } 535 536 /** 537 * Class representing error diagnostic keys. 538 */ 539 public static final class Error extends DiagnosticInfo { 540 public Error(String prefix, String key, Object... args) { 541 super(DiagnosticType.ERROR, prefix, key, args); 542 } 543 } 544 545 /** 546 * Class representing warning diagnostic keys. 547 */ 548 public static final class Warning extends DiagnosticInfo { 549 public Warning(String prefix, String key, Object... args) { 550 super(DiagnosticType.WARNING, prefix, key, args); 551 } 552 } 553 554 /** 555 * Class representing note diagnostic keys. 556 */ 557 public static final class Note extends DiagnosticInfo { 558 public Note(String prefix, String key, Object... args) { 559 super(DiagnosticType.NOTE, prefix, key, args); 560 } 561 } 562 563 /** 564 * Class representing fragment diagnostic keys. 565 */ 566 public static final class Fragment extends DiagnosticInfo { 567 public Fragment(String prefix, String key, Object... args) { 568 super(DiagnosticType.FRAGMENT, prefix, key, args); 569 } 570 } 571 572 /** 573 * Create a diagnostic object. 574 * @param formatter the formatter to use for the diagnostic 575 * @param diagnosticInfo the diagnostic key 576 * @param lc the lint category for the diagnostic 577 * @param source the name of the source file, or null if none. 578 * @param pos the character offset within the source file, if given. 579 */ 580 protected JCDiagnostic(DiagnosticFormatter<JCDiagnostic> formatter, 581 DiagnosticInfo diagnosticInfo, 582 LintCategory lc, 583 Set<DiagnosticFlag> flags, 584 DiagnosticSource source, 585 DiagnosticPosition pos) { 586 if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS) 587 throw new IllegalArgumentException(); 588 589 this.defaultFormatter = formatter; 590 this.diagnosticInfo = diagnosticInfo; 591 this.lintCategory = lc; 592 this.flags = flags; 593 this.source = source; 594 this.position = pos; 595 } 596 597 /** 598 * Get the type of this diagnostic. 599 * @return the type of this diagnostic 600 */ 601 public DiagnosticType getType() { 602 return diagnosticInfo.type; 603 } 604 605 /** 606 * Get the subdiagnostic list 607 * @return subdiagnostic list 608 */ 609 public List<JCDiagnostic> getSubdiagnostics() { 610 return List.nil(); 611 } 612 613 public boolean isMultiline() { 614 return false; 615 } 616 617 /** 618 * Check whether or not this diagnostic is required to be shown. 619 * @return true if this diagnostic is required to be shown. 620 */ 621 public boolean isMandatory() { 622 return flags.contains(DiagnosticFlag.MANDATORY); 623 } 624 625 /** 626 * Check whether this diagnostic has an associated lint category. 627 */ 628 public boolean hasLintCategory() { 629 return (lintCategory != null); 630 } 631 632 /** 633 * Get the associated lint category, or null if none. 634 */ 635 public LintCategory getLintCategory() { 636 return lintCategory; 637 } 638 639 /** 640 * Get the name of the source file referred to by this diagnostic. 641 * @return the name of the source referred to with this diagnostic, or null if none 642 */ 643 @DefinedBy(Api.COMPILER) 644 public JavaFileObject getSource() { 645 if (source == null) 646 return null; 647 else 648 return source.getFile(); 649 } 650 651 /** 652 * Get the source referred to by this diagnostic. 653 * @return the source referred to with this diagnostic, or null if none 654 */ 655 public DiagnosticSource getDiagnosticSource() { 656 return source; 657 } 658 659 protected int getIntStartPosition() { 660 return (position == null ? Position.NOPOS : position.getStartPosition()); 661 } 662 663 protected int getIntPosition() { 664 return (position == null ? Position.NOPOS : position.getPreferredPosition()); 665 } 666 667 protected int getIntEndPosition() { 668 return (position == null ? Position.NOPOS : position.getEndPosition(source.getEndPosTable())); 669 } 670 671 @DefinedBy(Api.COMPILER) 672 public long getStartPosition() { 673 return getIntStartPosition(); 674 } 675 676 @DefinedBy(Api.COMPILER) 677 public long getPosition() { 678 return getIntPosition(); 679 } 680 681 @DefinedBy(Api.COMPILER) 682 public long getEndPosition() { 683 return getIntEndPosition(); 684 } 685 686 public DiagnosticPosition getDiagnosticPosition() { 687 return position; 688 } 689 690 /** 691 * Get the line number within the source referred to by this diagnostic. 692 * @return the line number within the source referred to by this diagnostic 693 */ 694 @DefinedBy(Api.COMPILER) 695 public long getLineNumber() { 696 if (sourcePosition == null) { 697 sourcePosition = new SourcePosition(); 698 } 699 return sourcePosition.getLineNumber(); 700 } 701 702 /** 703 * Get the column number within the line of source referred to by this diagnostic. 704 * @return the column number within the line of source referred to by this diagnostic 705 */ 706 @DefinedBy(Api.COMPILER) 707 public long getColumnNumber() { 708 if (sourcePosition == null) { 709 sourcePosition = new SourcePosition(); 710 } 711 return sourcePosition.getColumnNumber(); 712 } 713 714 /** 715 * Get the arguments to be included in the text of the diagnostic. 716 * @return the arguments to be included in the text of the diagnostic 717 */ 718 public Object[] getArgs() { 719 return diagnosticInfo.args; 720 } 721 722 /** 723 * Get the prefix string associated with this type of diagnostic. 724 * @return the prefix string associated with this type of diagnostic 725 */ 726 public String getPrefix() { 727 return getPrefix(diagnosticInfo.type); 728 } 729 730 /** 731 * Get the prefix string associated with a particular type of diagnostic. 732 * @return the prefix string associated with a particular type of diagnostic 733 */ 734 public String getPrefix(DiagnosticType dt) { 735 return defaultFormatter.formatKind(this, Locale.getDefault()); 736 } 737 738 /** 739 * Return the standard presentation of this diagnostic. 740 */ 741 @Override 742 public String toString() { 743 return defaultFormatter.format(this, Locale.getDefault()); 744 } 745 746 private DiagnosticFormatter<JCDiagnostic> defaultFormatter; 747 @Deprecated 748 private static DiagnosticFormatter<JCDiagnostic> fragmentFormatter; 749 750 // Methods for javax.tools.Diagnostic 751 752 @DefinedBy(Api.COMPILER) 753 public Diagnostic.Kind getKind() { 754 switch (diagnosticInfo.type) { 755 case NOTE: 756 return Diagnostic.Kind.NOTE; 757 case WARNING: 758 return flags.contains(DiagnosticFlag.MANDATORY) 759 ? Diagnostic.Kind.MANDATORY_WARNING 760 : Diagnostic.Kind.WARNING; 761 case ERROR: 762 return Diagnostic.Kind.ERROR; 763 default: 764 return Diagnostic.Kind.OTHER; 765 } 766 } 767 768 @DefinedBy(Api.COMPILER) 769 public String getCode() { 770 return diagnosticInfo.key(); 771 } 772 773 @DefinedBy(Api.COMPILER) 774 public String getMessage(Locale locale) { 775 return defaultFormatter.formatMessage(this, locale); 776 } 777 778 public void setFlag(DiagnosticFlag flag) { 779 flags.add(flag); 780 781 if (diagnosticInfo.type == DiagnosticType.ERROR) { 782 switch (flag) { 783 case SYNTAX: 784 flags.remove(DiagnosticFlag.RECOVERABLE); 785 break; 786 case RESOLVE_ERROR: 787 flags.add(DiagnosticFlag.RECOVERABLE); 788 break; 789 } 790 } 791 } 792 793 public boolean isFlagSet(DiagnosticFlag flag) { 794 return flags.contains(flag); 795 } 796 797 public static class MultilineDiagnostic extends JCDiagnostic { 798 799 private final List<JCDiagnostic> subdiagnostics; 800 801 public MultilineDiagnostic(JCDiagnostic other, List<JCDiagnostic> subdiagnostics) { 802 super(other.defaultFormatter, 803 other.diagnosticInfo, 804 other.getLintCategory(), 805 other.flags, 806 other.getDiagnosticSource(), 807 other.position); 808 this.subdiagnostics = subdiagnostics; 809 } 810 811 @Override 812 public List<JCDiagnostic> getSubdiagnostics() { 813 return subdiagnostics; 814 } 815 816 @Override 817 public boolean isMultiline() { 818 return true; 819 } 820 } 821} 822