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