1 /* 2 * Copyright (c) 2003, 2018, 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 26 package com.sun.tools.javac.util; 27 28 import java.util.EnumSet; 29 import java.util.Locale; 30 import java.util.Set; 31 import java.util.stream.Stream; 32 33 import javax.tools.Diagnostic; 34 import javax.tools.JavaFileObject; 35 36 import com.sun.tools.javac.api.DiagnosticFormatter; 37 import com.sun.tools.javac.code.Lint.LintCategory; 38 import com.sun.tools.javac.tree.EndPosTable; 39 import com.sun.tools.javac.tree.JCTree; 40 import com.sun.tools.javac.util.DefinedBy.Api; 41 42 import 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 */ 51 public 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. */ instance(Context 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. */ Factory(Context context)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 initOptions(Options options)79 private void initOptions(Options options) { 80 if (options.isSet("onlySyntaxErrorsUnrecoverable")) 81 defaultErrorFlags.add(DiagnosticFlag.RECOVERABLE); 82 } 83 84 /** Create a new diagnostic factory. */ Factory(JavacMessages messages, String prefix)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 */ error( DiagnosticFlag flag, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args)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 */ error( DiagnosticFlag flag, DiagnosticSource source, DiagnosticPosition pos, Error errorKey)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 */ mandatoryWarning( LintCategory lc, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args)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 */ mandatoryWarning( LintCategory lc, DiagnosticSource source, DiagnosticPosition pos, Warning warningKey)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 */ warning( LintCategory lc, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args)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 */ warning( LintCategory lc, DiagnosticSource source, DiagnosticPosition pos, Warning warningKey)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 */ mandatoryNote(DiagnosticSource source, String key, Object... args)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 */ mandatoryNote(DiagnosticSource source, Note noteKey)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 */ note( DiagnosticSource source, DiagnosticPosition pos, String key, Object... args)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 */ note( DiagnosticSource source, DiagnosticPosition pos, Note noteKey)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 */ fragment(String key, Object... args)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 */ fragment(Fragment fragmentKey)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 */ create( DiagnosticType kind, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args)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 */ create( DiagnosticSource source, DiagnosticPosition pos, DiagnosticInfo diagnosticInfo)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 */ create(DiagnosticType kind, LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args)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 */ create( LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, DiagnosticInfo diagnosticInfo)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 normalize(DiagnosticInfo diagnosticInfo)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 */ errorKey(String code, Object... args)298 public 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 */ warningKey(String code, Object... args)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 */ noteKey(String code, Object... args)312 public 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 */ fragmentKey(String code, Object... args)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 fragment(String key, Object... args)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 getFragmentFormatter()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 */ DiagnosticType(String key)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. */ getTree()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(). */ getStartPosition()387 int getStartPosition(); 388 /** Get the position within the file that most accurately defines the 389 * location for the diagnostic. */ getPreferredPosition()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(). */ getEndPosition(EndPosTable endPosTable)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 { SimpleDiagnosticPosition(int pos)402 public SimpleDiagnosticPosition(int pos) { 403 this.pos = pos; 404 } 405 getTree()406 public JCTree getTree() { 407 return null; 408 } 409 getStartPosition()410 public int getStartPosition() { 411 return pos; 412 } 413 getPreferredPosition()414 public int getPreferredPosition() { 415 return pos; 416 } 417 getEndPosition(EndPosTable endPosTable)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 /** Flag for diagnostics that were reported through API methods. 433 */ 434 API, 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 SourcePosition()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 getLineNumber()467 public int getLineNumber() { 468 return line; 469 } 470 getColumnNumber()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 DiagnosticInfo(DiagnosticType type, String prefix, String code, Object... args)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 */ key()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 */ of(DiagnosticType type, String prefix, String code, Object... args)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 * Returns the code for this diagnostic info, provided mainly for backward compatibility 532 */ getCode()533 public String getCode() { 534 return code; 535 } 536 537 /** 538 * Returns the arguments for this diagnostic info, provided mainly for backward compatibility 539 */ getArgs()540 public Object[] getArgs() { 541 return args; 542 } 543 setArgs(Object[] args)544 public void setArgs(Object[] args) { 545 this.args = args; 546 } 547 } 548 549 /** 550 * Class representing error diagnostic keys. 551 */ 552 public static final class Error extends DiagnosticInfo { Error(String prefix, String key, Object... args)553 public Error(String prefix, String key, Object... args) { 554 super(DiagnosticType.ERROR, prefix, key, args); 555 } 556 } 557 558 /** 559 * Class representing warning diagnostic keys. 560 */ 561 public static final class Warning extends DiagnosticInfo { Warning(String prefix, String key, Object... args)562 public Warning(String prefix, String key, Object... args) { 563 super(DiagnosticType.WARNING, prefix, key, args); 564 } 565 } 566 567 /** 568 * Class representing note diagnostic keys. 569 */ 570 public static final class Note extends DiagnosticInfo { Note(String prefix, String key, Object... args)571 public Note(String prefix, String key, Object... args) { 572 super(DiagnosticType.NOTE, prefix, key, args); 573 } 574 } 575 576 /** 577 * Class representing fragment diagnostic keys. 578 */ 579 public static final class Fragment extends DiagnosticInfo { Fragment(String prefix, String key, Object... args)580 public Fragment(String prefix, String key, Object... args) { 581 super(DiagnosticType.FRAGMENT, prefix, key, args); 582 } 583 } 584 585 /** 586 * Create a diagnostic object. 587 * @param formatter the formatter to use for the diagnostic 588 * @param diagnosticInfo the diagnostic key 589 * @param lc the lint category for the diagnostic 590 * @param source the name of the source file, or null if none. 591 * @param pos the character offset within the source file, if given. 592 */ JCDiagnostic(DiagnosticFormatter<JCDiagnostic> formatter, DiagnosticInfo diagnosticInfo, LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos)593 protected JCDiagnostic(DiagnosticFormatter<JCDiagnostic> formatter, 594 DiagnosticInfo diagnosticInfo, 595 LintCategory lc, 596 Set<DiagnosticFlag> flags, 597 DiagnosticSource source, 598 DiagnosticPosition pos) { 599 if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS) 600 throw new IllegalArgumentException(); 601 602 this.defaultFormatter = formatter; 603 this.diagnosticInfo = diagnosticInfo; 604 this.lintCategory = lc; 605 this.flags = flags; 606 this.source = source; 607 this.position = pos; 608 } 609 610 /** 611 * Get the type of this diagnostic. 612 * @return the type of this diagnostic 613 */ getType()614 public DiagnosticType getType() { 615 return diagnosticInfo.type; 616 } 617 618 /** 619 * Get the subdiagnostic list 620 * @return subdiagnostic list 621 */ getSubdiagnostics()622 public List<JCDiagnostic> getSubdiagnostics() { 623 return List.nil(); 624 } 625 isMultiline()626 public boolean isMultiline() { 627 return false; 628 } 629 630 /** 631 * Check whether or not this diagnostic is required to be shown. 632 * @return true if this diagnostic is required to be shown. 633 */ isMandatory()634 public boolean isMandatory() { 635 return flags.contains(DiagnosticFlag.MANDATORY); 636 } 637 638 /** 639 * Check whether this diagnostic has an associated lint category. 640 */ hasLintCategory()641 public boolean hasLintCategory() { 642 return (lintCategory != null); 643 } 644 645 /** 646 * Get the associated lint category, or null if none. 647 */ getLintCategory()648 public LintCategory getLintCategory() { 649 return lintCategory; 650 } 651 652 /** 653 * Get the name of the source file referred to by this diagnostic. 654 * @return the name of the source referred to with this diagnostic, or null if none 655 */ 656 @DefinedBy(Api.COMPILER) getSource()657 public JavaFileObject getSource() { 658 if (source == null) 659 return null; 660 else 661 return source.getFile(); 662 } 663 664 /** 665 * Get the source referred to by this diagnostic. 666 * @return the source referred to with this diagnostic, or null if none 667 */ getDiagnosticSource()668 public DiagnosticSource getDiagnosticSource() { 669 return source; 670 } 671 getIntStartPosition()672 protected int getIntStartPosition() { 673 return (position == null ? Position.NOPOS : position.getStartPosition()); 674 } 675 getIntPosition()676 protected int getIntPosition() { 677 return (position == null ? Position.NOPOS : position.getPreferredPosition()); 678 } 679 getIntEndPosition()680 protected int getIntEndPosition() { 681 return (position == null ? Position.NOPOS : position.getEndPosition(source.getEndPosTable())); 682 } 683 684 @DefinedBy(Api.COMPILER) getStartPosition()685 public long getStartPosition() { 686 return getIntStartPosition(); 687 } 688 689 @DefinedBy(Api.COMPILER) getPosition()690 public long getPosition() { 691 return getIntPosition(); 692 } 693 694 @DefinedBy(Api.COMPILER) getEndPosition()695 public long getEndPosition() { 696 return getIntEndPosition(); 697 } 698 getDiagnosticPosition()699 public DiagnosticPosition getDiagnosticPosition() { 700 return position; 701 } 702 703 /** 704 * Get the line number within the source referred to by this diagnostic. 705 * @return the line number within the source referred to by this diagnostic 706 */ 707 @DefinedBy(Api.COMPILER) getLineNumber()708 public long getLineNumber() { 709 if (sourcePosition == null) { 710 sourcePosition = new SourcePosition(); 711 } 712 return sourcePosition.getLineNumber(); 713 } 714 715 /** 716 * Get the column number within the line of source referred to by this diagnostic. 717 * @return the column number within the line of source referred to by this diagnostic 718 */ 719 @DefinedBy(Api.COMPILER) getColumnNumber()720 public long getColumnNumber() { 721 if (sourcePosition == null) { 722 sourcePosition = new SourcePosition(); 723 } 724 return sourcePosition.getColumnNumber(); 725 } 726 727 /** 728 * Get the arguments to be included in the text of the diagnostic. 729 * @return the arguments to be included in the text of the diagnostic 730 */ getArgs()731 public Object[] getArgs() { 732 return diagnosticInfo.args; 733 } 734 735 /** 736 * Get the prefix string associated with this type of diagnostic. 737 * @return the prefix string associated with this type of diagnostic 738 */ getPrefix()739 public String getPrefix() { 740 return getPrefix(diagnosticInfo.type); 741 } 742 743 /** 744 * Get the prefix string associated with a particular type of diagnostic. 745 * @return the prefix string associated with a particular type of diagnostic 746 */ getPrefix(DiagnosticType dt)747 public String getPrefix(DiagnosticType dt) { 748 return defaultFormatter.formatKind(this, Locale.getDefault()); 749 } 750 751 /** 752 * Return the standard presentation of this diagnostic. 753 */ 754 @Override toString()755 public String toString() { 756 return defaultFormatter.format(this, Locale.getDefault()); 757 } 758 759 private DiagnosticFormatter<JCDiagnostic> defaultFormatter; 760 @Deprecated 761 private static DiagnosticFormatter<JCDiagnostic> fragmentFormatter; 762 763 // Methods for javax.tools.Diagnostic 764 765 @DefinedBy(Api.COMPILER) getKind()766 public Diagnostic.Kind getKind() { 767 switch (diagnosticInfo.type) { 768 case NOTE: 769 return Diagnostic.Kind.NOTE; 770 case WARNING: 771 return flags.contains(DiagnosticFlag.MANDATORY) 772 ? Diagnostic.Kind.MANDATORY_WARNING 773 : Diagnostic.Kind.WARNING; 774 case ERROR: 775 return Diagnostic.Kind.ERROR; 776 default: 777 return Diagnostic.Kind.OTHER; 778 } 779 } 780 781 @DefinedBy(Api.COMPILER) getCode()782 public String getCode() { 783 return diagnosticInfo.key(); 784 } 785 786 @DefinedBy(Api.COMPILER) getMessage(Locale locale)787 public String getMessage(Locale locale) { 788 return defaultFormatter.formatMessage(this, locale); 789 } 790 setFlag(DiagnosticFlag flag)791 public void setFlag(DiagnosticFlag flag) { 792 flags.add(flag); 793 794 if (diagnosticInfo.type == DiagnosticType.ERROR) { 795 switch (flag) { 796 case SYNTAX: 797 flags.remove(DiagnosticFlag.RECOVERABLE); 798 break; 799 case RESOLVE_ERROR: 800 flags.add(DiagnosticFlag.RECOVERABLE); 801 break; 802 } 803 } 804 } 805 isFlagSet(DiagnosticFlag flag)806 public boolean isFlagSet(DiagnosticFlag flag) { 807 return flags.contains(flag); 808 } 809 810 public static class MultilineDiagnostic extends JCDiagnostic { 811 812 private final List<JCDiagnostic> subdiagnostics; 813 MultilineDiagnostic(JCDiagnostic other, List<JCDiagnostic> subdiagnostics)814 public MultilineDiagnostic(JCDiagnostic other, List<JCDiagnostic> subdiagnostics) { 815 super(other.defaultFormatter, 816 other.diagnosticInfo, 817 other.getLintCategory(), 818 other.flags, 819 other.getDiagnosticSource(), 820 other.position); 821 this.subdiagnostics = subdiagnostics; 822 } 823 824 @Override getSubdiagnostics()825 public List<JCDiagnostic> getSubdiagnostics() { 826 return subdiagnostics; 827 } 828 829 @Override isMultiline()830 public boolean isMultiline() { 831 return true; 832 } 833 } 834 } 835