JCDiagnostic.java revision 2776:aa568700edd1
1246091Sdelphij/* 2246074Sgabor * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 3246074Sgabor * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4246074Sgabor * 5246074Sgabor * This code is free software; you can redistribute it and/or modify it 6246074Sgabor * under the terms of the GNU General Public License version 2 only, as 7246074Sgabor * published by the Free Software Foundation. Oracle designates this 8246074Sgabor * particular file as subject to the "Classpath" exception as provided 9246074Sgabor * by Oracle in the LICENSE file that accompanied this code. 10246074Sgabor * 11246074Sgabor * This code is distributed in the hope that it will be useful, but WITHOUT 12246074Sgabor * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13246074Sgabor * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14246074Sgabor * version 2 for more details (a copy is included in the LICENSE file that 15246074Sgabor * accompanied this code). 16246074Sgabor * 17246074Sgabor * You should have received a copy of the GNU General Public License version 18246074Sgabor * 2 along with this work; if not, write to the Free Software Foundation, 19246074Sgabor * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20246074Sgabor * 21246074Sgabor * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22246074Sgabor * or visit www.oracle.com if you need additional information or have any 23246074Sgabor * questions. 24246074Sgabor */ 25246074Sgabor 26246074Sgaborpackage com.sun.tools.javac.util; 27246091Sdelphij 28246091Sdelphijimport java.util.EnumSet; 29246074Sgaborimport java.util.Locale; 30246074Sgaborimport java.util.Set; 31246074Sgaborimport java.util.stream.Stream; 32246074Sgabor 33246074Sgaborimport javax.tools.Diagnostic; 34246074Sgaborimport javax.tools.JavaFileObject; 35246074Sgabor 36246074Sgaborimport com.sun.tools.javac.api.DiagnosticFormatter; 37246074Sgaborimport com.sun.tools.javac.code.Lint.LintCategory; 38246074Sgaborimport com.sun.tools.javac.tree.EndPosTable; 39246074Sgaborimport com.sun.tools.javac.tree.JCTree; 40246074Sgaborimport com.sun.tools.javac.util.DefinedBy.Api; 41246074Sgabor 42246074Sgaborimport static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*; 43246074Sgabor 44246074Sgabor/** An abstraction of a diagnostic message generated by the compiler. 45246074Sgabor * 46246074Sgabor * <p><b>This is NOT part of any supported API. 47246074Sgabor * If you write code that depends on this, you do so at your own risk. 48246074Sgabor * This code and its internal interfaces are subject to change or 49246074Sgabor * deletion without notice.</b> 50246074Sgabor */ 51246074Sgaborpublic class JCDiagnostic implements Diagnostic<JavaFileObject> { 52246074Sgabor /** A factory for creating diagnostic objects. */ 53246074Sgabor public static class Factory { 54246074Sgabor /** The context key for the diagnostic factory. */ 55246074Sgabor protected static final Context.Key<JCDiagnostic.Factory> diagnosticFactoryKey = new Context.Key<>(); 56246074Sgabor 57246074Sgabor /** Get the Factory instance for this context. */ 58246074Sgabor public static Factory instance(Context context) { 59246074Sgabor Factory instance = context.get(diagnosticFactoryKey); 60246074Sgabor if (instance == null) 61246074Sgabor instance = new Factory(context); 62246074Sgabor return instance; 63246074Sgabor } 64246074Sgabor 65246074Sgabor DiagnosticFormatter<JCDiagnostic> formatter; 66246074Sgabor final String prefix; 67246074Sgabor final Set<DiagnosticFlag> defaultErrorFlags; 68246074Sgabor 69246074Sgabor /** Create a new diagnostic factory. */ 70246074Sgabor protected Factory(Context context) { 71246074Sgabor this(JavacMessages.instance(context), "compiler"); 72246074Sgabor context.put(diagnosticFactoryKey, this); 73246074Sgabor 74246074Sgabor final Options options = Options.instance(context); 75246074Sgabor initOptions(options); 76246074Sgabor options.addListener(new Runnable() { 77246074Sgabor public void run() { 78246074Sgabor initOptions(options); 79246074Sgabor } 80246074Sgabor }); 81246074Sgabor } 82246074Sgabor 83246074Sgabor private void initOptions(Options options) { 84246074Sgabor if (options.isSet("onlySyntaxErrorsUnrecoverable")) 85246074Sgabor defaultErrorFlags.add(DiagnosticFlag.RECOVERABLE); 86246074Sgabor } 87246074Sgabor 88246074Sgabor /** Create a new diagnostic factory. */ 89246074Sgabor public Factory(JavacMessages messages, String prefix) { 90246074Sgabor this.prefix = prefix; 91246074Sgabor this.formatter = new BasicDiagnosticFormatter(messages); 92246074Sgabor defaultErrorFlags = EnumSet.of(DiagnosticFlag.MANDATORY); 93246074Sgabor } 94246074Sgabor 95246074Sgabor /** 96246074Sgabor * Create an error diagnostic 97246074Sgabor * @param source The source of the compilation unit, if any, in which to report the error. 98246074Sgabor * @param pos The source position at which to report the error. 99246074Sgabor * @param key The key for the localized error message. 100246074Sgabor * @param args Fields of the error message. 101246074Sgabor */ 102246074Sgabor public JCDiagnostic error( 103246074Sgabor DiagnosticFlag flag, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 104252636Sobrien return error(flag, source, pos, errorKey(key, args)); 105246074Sgabor } 106246074Sgabor 107246074Sgabor /** 108246074Sgabor * Create an error diagnostic 109246074Sgabor * @param source The source of the compilation unit, if any, in which to report the error. 110252636Sobrien * @param pos The source position at which to report the error. 111252636Sobrien * @param errorKey The key for the localized error message. 112252636Sobrien */ 113252636Sobrien public JCDiagnostic error( 114252636Sobrien DiagnosticFlag flag, DiagnosticSource source, DiagnosticPosition pos, Error errorKey) { 115246074Sgabor JCDiagnostic diag = create(null, defaultErrorFlags, source, pos, errorKey); 116246074Sgabor if (flag != null) { 117246074Sgabor diag.setFlag(flag); 118246074Sgabor } 119246074Sgabor return diag; 120246074Sgabor } 121246074Sgabor 122246074Sgabor /** 123246074Sgabor * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options. 124246074Sgabor * @param lc The lint category for the diagnostic 125246074Sgabor * @param source The source of the compilation unit, if any, in which to report the warning. 126246074Sgabor * @param pos The source position at which to report the warning. 127246074Sgabor * @param key The key for the localized warning message. 128246074Sgabor * @param args Fields of the warning message. 129246074Sgabor * @see MandatoryWarningHandler 130246074Sgabor */ 131246074Sgabor public JCDiagnostic mandatoryWarning( 132246074Sgabor LintCategory lc, 133246074Sgabor DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 134246074Sgabor return mandatoryWarning(lc, source, pos, warningKey(key, args)); 135246074Sgabor } 136246074Sgabor 137246074Sgabor /** 138246074Sgabor * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options. 139246074Sgabor * @param lc The lint category for the diagnostic 140246074Sgabor * @param source The source of the compilation unit, if any, in which to report the warning. 141246074Sgabor * @param pos The source position at which to report the warning. 142246074Sgabor * @param warningKey The key for the localized warning message. 143246074Sgabor * @see MandatoryWarningHandler 144246074Sgabor */ 145246074Sgabor public JCDiagnostic mandatoryWarning( 146246074Sgabor LintCategory lc, 147246074Sgabor DiagnosticSource source, DiagnosticPosition pos, Warning warningKey) { 148246074Sgabor return create(lc, EnumSet.of(DiagnosticFlag.MANDATORY), source, pos, warningKey); 149246074Sgabor } 150246074Sgabor 151246074Sgabor /** 152246074Sgabor * Create a warning diagnostic. 153246074Sgabor * @param lc The lint category for the diagnostic 154246074Sgabor * @param source The source of the compilation unit, if any, in which to report the warning. 155246074Sgabor * @param pos The source position at which to report the warning. 156246074Sgabor * @param key The key for the localized error message. 157246074Sgabor * @param args Fields of the warning message. 158246074Sgabor * @see MandatoryWarningHandler 159246074Sgabor */ 160246074Sgabor public JCDiagnostic warning( 161246074Sgabor LintCategory lc, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 162246074Sgabor return warning(lc, source, pos, warningKey(key, args)); 163246074Sgabor } 164246074Sgabor 165246074Sgabor /** 166246074Sgabor * Create a warning diagnostic. 167246074Sgabor * @param lc The lint category for the diagnostic 168246074Sgabor * @param source The source of the compilation unit, if any, in which to report the warning. 169246074Sgabor * @param pos The source position at which to report the warning. 170246074Sgabor * @param warningKey The key for the localized warning message. 171246074Sgabor * @see MandatoryWarningHandler 172246074Sgabor */ 173246074Sgabor public JCDiagnostic warning( 174246074Sgabor LintCategory lc, DiagnosticSource source, DiagnosticPosition pos, Warning warningKey) { 175246074Sgabor return create(lc, EnumSet.noneOf(DiagnosticFlag.class), source, pos, warningKey); 176246074Sgabor } 177246074Sgabor 178246074Sgabor /** 179246074Sgabor * Create a note diagnostic that will not be hidden by the -nowarn or -Xlint:none options. 180246074Sgabor * @param source The source of the compilation unit, if any, in which to report the warning. 181246074Sgabor * @param key The key for the localized warning message. 182246074Sgabor * @param args Fields of the warning message. 183246074Sgabor * @see MandatoryWarningHandler 184246074Sgabor */ 185246074Sgabor public JCDiagnostic mandatoryNote(DiagnosticSource source, String key, Object... args) { 186246074Sgabor return mandatoryNote(source, noteKey(key, args)); 187246074Sgabor } 188246074Sgabor 189246074Sgabor /** 190246074Sgabor * Create a note diagnostic that will not be hidden by the -nowarn or -Xlint:none options. 191246074Sgabor * @param noteKey The key for the localized note message. 192246074Sgabor * @see MandatoryWarningHandler 193246074Sgabor */ 194246074Sgabor public JCDiagnostic mandatoryNote(DiagnosticSource source, Note noteKey) { 195246074Sgabor return create(null, EnumSet.of(DiagnosticFlag.MANDATORY), source, null, noteKey); 196246074Sgabor } 197246074Sgabor 198246074Sgabor /** 199246074Sgabor * Create a note diagnostic. 200246074Sgabor * @param key The key for the localized error message. 201246074Sgabor * @param args Fields of the message. 202246074Sgabor */ 203246074Sgabor public JCDiagnostic note( 204246074Sgabor DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 205246074Sgabor return note(source, pos, noteKey(key, args)); 206246074Sgabor } 207246074Sgabor 208246074Sgabor /** 209246074Sgabor * Create a note diagnostic. 210246074Sgabor * @param source The source of the compilation unit, if any, in which to report the note. 211246074Sgabor * @param pos The source position at which to report the note. 212246074Sgabor * @param noteKey The key for the localized note message. 213246074Sgabor */ 214246074Sgabor public JCDiagnostic note( 215246074Sgabor DiagnosticSource source, DiagnosticPosition pos, Note noteKey) { 216246074Sgabor return create(null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, noteKey); 217246074Sgabor } 218246074Sgabor 219246074Sgabor /** 220246074Sgabor * Create a fragment diagnostic, for use as an argument in other diagnostics 221246074Sgabor * @param key The key for the localized message. 222246074Sgabor * @param args Fields of the message. 223246074Sgabor */ 224246074Sgabor public JCDiagnostic fragment(String key, Object... args) { 225246074Sgabor return fragment(fragmentKey(key, args)); 226246074Sgabor } 227246074Sgabor 228246074Sgabor /** 229246074Sgabor * Create a fragment diagnostic, for use as an argument in other diagnostics 230246074Sgabor * @param fragmentKey The key for the localized subdiagnostic message. 231246074Sgabor */ 232246074Sgabor public JCDiagnostic fragment(Fragment fragmentKey) { 233246074Sgabor return create(null, EnumSet.noneOf(DiagnosticFlag.class), null, null, fragmentKey); 234246074Sgabor } 235246074Sgabor 236246074Sgabor /** 237246074Sgabor * Create a new diagnostic of the given kind, which is not mandatory and which has 238246074Sgabor * no lint category. 239246074Sgabor * @param kind The diagnostic kind 240246074Sgabor * @param source The source of the compilation unit, if any, in which to report the message. 241246074Sgabor * @param pos The source position at which to report the message. 242246074Sgabor * @param key The key for the localized message. 243246074Sgabor * @param args Fields of the message. 244246074Sgabor */ 245246074Sgabor public JCDiagnostic create( 246246074Sgabor DiagnosticType kind, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 247246074Sgabor return create(null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, DiagnosticInfo.of(kind, prefix, key, args)); 248246074Sgabor } 249246074Sgabor 250246074Sgabor /** 251246074Sgabor * Create a new diagnostic of the given kind, which is not mandatory and which has 252246074Sgabor * no lint category. 253246074Sgabor * @param source The source of the compilation unit, if any, in which to report the message. 254246074Sgabor * @param pos The source position at which to report the message. 255246074Sgabor * @param diagnosticInfo The key for the localized message. 256246074Sgabor */ 257246074Sgabor public JCDiagnostic create( 258246074Sgabor DiagnosticSource source, DiagnosticPosition pos, DiagnosticInfo diagnosticInfo) { 259246074Sgabor return create(null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, diagnosticInfo); 260246074Sgabor } 261246074Sgabor 262246074Sgabor /** 263246074Sgabor * Create a new diagnostic of the given kind. 264246074Sgabor * @param kind The diagnostic kind 265246074Sgabor * @param lc The lint category, if applicable, or null 266246074Sgabor * @param flags The set of flags for the diagnostic 267246074Sgabor * @param source The source of the compilation unit, if any, in which to report the message. 268246074Sgabor * @param pos The source position at which to report the message. 269246074Sgabor * @param key The key for the localized message. 270246074Sgabor * @param args Fields of the message. 271246074Sgabor */ 272246074Sgabor public JCDiagnostic create(DiagnosticType kind, 273246074Sgabor LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { 274246074Sgabor return create(lc, flags, source, pos, DiagnosticInfo.of(kind, prefix, key, args)); 275246074Sgabor } 276246074Sgabor 277246074Sgabor /** 278246074Sgabor * Create a new diagnostic with given key. 279246074Sgabor * @param lc The lint category, if applicable, or null 280246074Sgabor * @param flags The set of flags for the diagnostic 281246074Sgabor * @param source The source of the compilation unit, if any, in which to report the message. 282246074Sgabor * @param pos The source position at which to report the message. 283246074Sgabor * @param diagnosticInfo The key for the localized message. 284246074Sgabor */ 285246074Sgabor public JCDiagnostic create( 286246074Sgabor LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, DiagnosticInfo diagnosticInfo) { 287246074Sgabor return new JCDiagnostic(formatter, normalize(diagnosticInfo), lc, flags, source, pos); 288246074Sgabor } 289246074Sgabor //where 290246074Sgabor DiagnosticInfo normalize(DiagnosticInfo diagnosticInfo) { 291246074Sgabor //replace all nested FragmentKey with full-blown JCDiagnostic objects 292246074Sgabor return DiagnosticInfo.of(diagnosticInfo.type, diagnosticInfo.prefix, diagnosticInfo.code, 293246074Sgabor Stream.of(diagnosticInfo.args).map(o -> { 294246074Sgabor return (o instanceof Fragment) ? 295246074Sgabor fragment((Fragment)o) : o; 296246074Sgabor }).toArray()); 297246074Sgabor } 298246074Sgabor 299246074Sgabor /** 300246074Sgabor * Create a new error key. 301246074Sgabor */ 302246074Sgabor Error errorKey(String code, Object... args) { 303246074Sgabor return (Error)DiagnosticInfo.of(ERROR, prefix, code, args); 304246074Sgabor } 305246074Sgabor 306246074Sgabor /** 307246074Sgabor * Create a new warning key. 308246074Sgabor */ 309246074Sgabor Warning warningKey(String code, Object... args) { 310246074Sgabor return (Warning)DiagnosticInfo.of(WARNING, prefix, code, args); 311246074Sgabor } 312246074Sgabor 313246074Sgabor /** 314246074Sgabor * Create a new note key. 315246074Sgabor */ 316246074Sgabor Note noteKey(String code, Object... args) { 317246074Sgabor return (Note)DiagnosticInfo.of(NOTE, prefix, code, args); 318246074Sgabor } 319246074Sgabor 320246074Sgabor /** 321246074Sgabor * Create a new fragment key. 322246074Sgabor */ 323246074Sgabor Fragment fragmentKey(String code, Object... args) { 324246074Sgabor return (Fragment)DiagnosticInfo.of(FRAGMENT, prefix, code, args); 325246074Sgabor } 326246074Sgabor } 327246074Sgabor 328246074Sgabor 329246074Sgabor 330246074Sgabor /** 331246074Sgabor * Create a fragment diagnostic, for use as an argument in other diagnostics 332246074Sgabor * @param key The key for the localized error message. 333246074Sgabor * @param args Fields of the error message. 334246074Sgabor * 335246074Sgabor */ 336246074Sgabor @Deprecated 337246074Sgabor public static JCDiagnostic fragment(String key, Object... args) { 338246074Sgabor return new JCDiagnostic(getFragmentFormatter(), 339246074Sgabor DiagnosticInfo.of(FRAGMENT, 340246074Sgabor "compiler", 341246074Sgabor key, 342246074Sgabor args), 343246074Sgabor null, 344246074Sgabor EnumSet.noneOf(DiagnosticFlag.class), 345246074Sgabor null, 346246074Sgabor null); 347246074Sgabor } 348246074Sgabor //where 349246074Sgabor @Deprecated 350246074Sgabor public static DiagnosticFormatter<JCDiagnostic> getFragmentFormatter() { 351246074Sgabor if (fragmentFormatter == null) { 352246074Sgabor fragmentFormatter = new BasicDiagnosticFormatter(JavacMessages.getDefaultMessages()); 353246074Sgabor } 354246074Sgabor return fragmentFormatter; 355246074Sgabor } 356246074Sgabor 357246074Sgabor /** 358246074Sgabor * A DiagnosticType defines the type of the diagnostic. 359246074Sgabor **/ 360246074Sgabor public enum DiagnosticType { 361246074Sgabor /** A fragment of an enclosing diagnostic. */ 362246074Sgabor FRAGMENT("misc"), 363246074Sgabor /** A note: similar to, but less serious than, a warning. */ 364246074Sgabor NOTE("note"), 365246074Sgabor /** A warning. */ 366246074Sgabor WARNING("warn"), 367246074Sgabor /** An error. */ 368246074Sgabor ERROR("err"); 369246074Sgabor 370246074Sgabor final String key; 371246074Sgabor 372246074Sgabor /** Create a DiagnosticType. 373246074Sgabor * @param key A string used to create the resource key for the diagnostic. 374246074Sgabor */ 375246074Sgabor DiagnosticType(String key) { 376246074Sgabor this.key = key; 377246074Sgabor } 378246074Sgabor } 379246074Sgabor 380246074Sgabor /** 381246074Sgabor * A DiagnosticPosition provides information about the positions in a file 382246074Sgabor * that gave rise to a diagnostic. It always defines a "preferred" position 383246074Sgabor * that most accurately defines the location of the diagnostic, it may also 384246074Sgabor * provide a related tree node that spans that location. 385246074Sgabor */ 386246074Sgabor public static interface DiagnosticPosition { 387246074Sgabor /** Gets the tree node, if any, to which the diagnostic applies. */ 388246074Sgabor JCTree getTree(); 389246074Sgabor /** If there is a tree node, get the start position of the tree node. 390246074Sgabor * Otherwise, just returns the same as getPreferredPosition(). */ 391246074Sgabor int getStartPosition(); 392246074Sgabor /** Get the position within the file that most accurately defines the 393246074Sgabor * location for the diagnostic. */ 394246074Sgabor int getPreferredPosition(); 395246074Sgabor /** If there is a tree node, and if endPositions are available, get 396246074Sgabor * the end position of the tree node. Otherwise, just returns the 397246074Sgabor * same as getPreferredPosition(). */ 398246074Sgabor int getEndPosition(EndPosTable endPosTable); 399246074Sgabor } 400246074Sgabor 401246074Sgabor /** 402246074Sgabor * A DiagnosticPosition that simply identifies a position, but no related 403246074Sgabor * tree node, as the location for a diagnostic. Used for scanner and parser 404246074Sgabor * diagnostics. */ 405246074Sgabor public static class SimpleDiagnosticPosition implements DiagnosticPosition { 406246074Sgabor public SimpleDiagnosticPosition(int pos) { 407246074Sgabor this.pos = pos; 408246074Sgabor } 409246074Sgabor 410246074Sgabor public JCTree getTree() { 411246074Sgabor return null; 412246074Sgabor } 413246074Sgabor 414246074Sgabor public int getStartPosition() { 415246074Sgabor return pos; 416246074Sgabor } 417246074Sgabor 418246074Sgabor public int getPreferredPosition() { 419246074Sgabor return pos; 420246074Sgabor } 421246074Sgabor 422246074Sgabor public int getEndPosition(EndPosTable endPosTable) { 423246074Sgabor return pos; 424246074Sgabor } 425246074Sgabor 426246074Sgabor private final int pos; 427246074Sgabor } 428246074Sgabor 429246074Sgabor public enum DiagnosticFlag { 430246074Sgabor MANDATORY, 431246074Sgabor RESOLVE_ERROR, 432246074Sgabor SYNTAX, 433246074Sgabor RECOVERABLE, 434246074Sgabor NON_DEFERRABLE, 435246074Sgabor COMPRESSED 436246074Sgabor } 437246074Sgabor 438246074Sgabor private final DiagnosticSource source; 439246074Sgabor private final DiagnosticPosition position; 440246074Sgabor private final DiagnosticInfo diagnosticInfo; 441246074Sgabor private final Set<DiagnosticFlag> flags; 442246074Sgabor private final LintCategory lintCategory; 443246074Sgabor 444246074Sgabor /** source line position (set lazily) */ 445246074Sgabor private SourcePosition sourcePosition; 446246074Sgabor 447246074Sgabor /** 448246074Sgabor * This class is used to defer the line/column position fetch logic after diagnostic construction. 449246074Sgabor */ 450246074Sgabor class SourcePosition { 451246074Sgabor 452246074Sgabor private final int line; 453246074Sgabor private final int column; 454246074Sgabor 455246074Sgabor SourcePosition() { 456246074Sgabor int n = (position == null ? Position.NOPOS : position.getPreferredPosition()); 457246074Sgabor if (n == Position.NOPOS || source == null) 458246074Sgabor line = column = -1; 459246074Sgabor else { 460246074Sgabor line = source.getLineNumber(n); 461246074Sgabor column = source.getColumnNumber(n, true); 462246074Sgabor } 463246074Sgabor } 464246074Sgabor 465246074Sgabor public int getLineNumber() { 466246074Sgabor return line; 467246074Sgabor } 468246074Sgabor 469246074Sgabor public int getColumnNumber() { 470246074Sgabor return column; 471246074Sgabor } 472246074Sgabor } 473246074Sgabor 474246074Sgabor /** 475246074Sgabor * A diagnostic key object encapsulates basic properties of a diagnostic, such as the resource key, 476246074Sgabor * the arguments and the kind associated with the diagnostic object. Diagnostic keys can be either 477246074Sgabor * created programmatically (by using the supplied factory method) or obtained through build-time 478246074Sgabor * generated factory methods. 479246074Sgabor */ 480246074Sgabor public static abstract class DiagnosticInfo { 481246074Sgabor 482246074Sgabor /** The diagnostic kind (i.e. error). */ 483246074Sgabor DiagnosticType type; 484246074Sgabor 485246074Sgabor /** The diagnostic prefix (i.e. 'javac'); used to compute full resource key. */ 486246074Sgabor String prefix; 487246074Sgabor 488246074Sgabor /** The diagnostic code (i.e. 'cannot.resolve.sym'); together with {@code prefix} it forms 489246074Sgabor * the full resource key. */ 490246074Sgabor String code; 491246074Sgabor 492246074Sgabor /** The diagnostic arguments. */ 493246074Sgabor Object[] args; 494246074Sgabor 495246074Sgabor private DiagnosticInfo(DiagnosticType type, String prefix, String code, Object... args) { 496246074Sgabor this.type = type; 497246074Sgabor this.prefix = prefix; 498246074Sgabor this.code = code; 499246074Sgabor this.args = args; 500246074Sgabor } 501246074Sgabor 502246074Sgabor /** 503246074Sgabor * Compute the resource key. 504246074Sgabor */ 505246074Sgabor public String key() { 506246074Sgabor return prefix + "." + type.key + "." + code; 507246074Sgabor } 508246074Sgabor 509246074Sgabor /** 510246074Sgabor * Static factory method; build a custom diagnostic key using given kind, prefix, code and args. 511246074Sgabor */ 512246074Sgabor public static DiagnosticInfo of(DiagnosticType type, String prefix, String code, Object... args) { 513246074Sgabor switch (type) { 514246074Sgabor case ERROR: 515246074Sgabor return new Error(prefix, code, args); 516246074Sgabor case WARNING: 517246074Sgabor return new Warning(prefix, code, args); 518246074Sgabor case NOTE: 519246074Sgabor return new Note(prefix, code, args); 520246074Sgabor case FRAGMENT: 521246074Sgabor return new Fragment(prefix, code, args); 522246074Sgabor default: 523246074Sgabor Assert.error("Wrong diagnostic type: " + type); 524246074Sgabor return null; 525246074Sgabor } 526246074Sgabor } 527246074Sgabor 528246074Sgabor } 529246074Sgabor 530246074Sgabor /** 531246074Sgabor * Class representing error diagnostic keys. 532246074Sgabor */ 533246074Sgabor public static final class Error extends DiagnosticInfo { 534246074Sgabor public Error(String prefix, String key, Object... args) { 535246074Sgabor super(DiagnosticType.ERROR, prefix, key, args); 536246074Sgabor } 537246074Sgabor } 538246074Sgabor 539246074Sgabor /** 540246074Sgabor * Class representing warning diagnostic keys. 541246074Sgabor */ 542246074Sgabor public static final class Warning extends DiagnosticInfo { 543246074Sgabor public Warning(String prefix, String key, Object... args) { 544246074Sgabor super(DiagnosticType.WARNING, prefix, key, args); 545246074Sgabor } 546246074Sgabor } 547246074Sgabor 548246074Sgabor /** 549246074Sgabor * Class representing note diagnostic keys. 550246074Sgabor */ 551246074Sgabor public static final class Note extends DiagnosticInfo { 552246074Sgabor public Note(String prefix, String key, Object... args) { 553246074Sgabor super(DiagnosticType.NOTE, prefix, key, args); 554246074Sgabor } 555246074Sgabor } 556246074Sgabor 557246074Sgabor /** 558246074Sgabor * Class representing fragment diagnostic keys. 559246074Sgabor */ 560246074Sgabor public static final class Fragment extends DiagnosticInfo { 561246074Sgabor public Fragment(String prefix, String key, Object... args) { 562246074Sgabor super(DiagnosticType.FRAGMENT, prefix, key, args); 563246074Sgabor } 564246074Sgabor } 565246074Sgabor 566246074Sgabor /** 567246074Sgabor * Create a diagnostic object. 568246074Sgabor * @param formatter the formatter to use for the diagnostic 569246074Sgabor * @param diagnosticInfo the diagnostic key 570246074Sgabor * @param lc the lint category for the diagnostic 571246074Sgabor * @param source the name of the source file, or null if none. 572246074Sgabor * @param pos the character offset within the source file, if given. 573246074Sgabor */ 574246074Sgabor protected JCDiagnostic(DiagnosticFormatter<JCDiagnostic> formatter, 575246074Sgabor DiagnosticInfo diagnosticInfo, 576246074Sgabor LintCategory lc, 577246074Sgabor Set<DiagnosticFlag> flags, 578246074Sgabor DiagnosticSource source, 579246074Sgabor DiagnosticPosition pos) { 580246074Sgabor if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS) 581246074Sgabor throw new IllegalArgumentException(); 582246074Sgabor 583246074Sgabor this.defaultFormatter = formatter; 584246074Sgabor this.diagnosticInfo = diagnosticInfo; 585246074Sgabor this.lintCategory = lc; 586246074Sgabor this.flags = flags; 587246074Sgabor this.source = source; 588246074Sgabor this.position = pos; 589246074Sgabor } 590246074Sgabor 591246074Sgabor /** 592246074Sgabor * Get the type of this diagnostic. 593246074Sgabor * @return the type of this diagnostic 594246074Sgabor */ 595246074Sgabor public DiagnosticType getType() { 596246074Sgabor return diagnosticInfo.type; 597246074Sgabor } 598246074Sgabor 599246074Sgabor /** 600246074Sgabor * Get the subdiagnostic list 601246074Sgabor * @return subdiagnostic list 602246074Sgabor */ 603246074Sgabor public List<JCDiagnostic> getSubdiagnostics() { 604246074Sgabor return List.nil(); 605246074Sgabor } 606246074Sgabor 607246074Sgabor public boolean isMultiline() { 608246074Sgabor return false; 609246074Sgabor } 610246074Sgabor 611246074Sgabor /** 612246074Sgabor * Check whether or not this diagnostic is required to be shown. 613246074Sgabor * @return true if this diagnostic is required to be shown. 614246074Sgabor */ 615246074Sgabor public boolean isMandatory() { 616246074Sgabor return flags.contains(DiagnosticFlag.MANDATORY); 617246074Sgabor } 618246074Sgabor 619246074Sgabor /** 620246074Sgabor * Check whether this diagnostic has an associated lint category. 621246074Sgabor */ 622246074Sgabor public boolean hasLintCategory() { 623246074Sgabor return (lintCategory != null); 624246074Sgabor } 625246074Sgabor 626246074Sgabor /** 627246074Sgabor * Get the associated lint category, or null if none. 628246074Sgabor */ 629246074Sgabor public LintCategory getLintCategory() { 630246074Sgabor return lintCategory; 631246074Sgabor } 632246074Sgabor 633246074Sgabor /** 634246074Sgabor * Get the name of the source file referred to by this diagnostic. 635246074Sgabor * @return the name of the source referred to with this diagnostic, or null if none 636246074Sgabor */ 637246074Sgabor @DefinedBy(Api.COMPILER) 638246074Sgabor public JavaFileObject getSource() { 639246074Sgabor if (source == null) 640246074Sgabor return null; 641246074Sgabor else 642246074Sgabor return source.getFile(); 643246074Sgabor } 644246074Sgabor 645246074Sgabor /** 646246074Sgabor * Get the source referred to by this diagnostic. 647246074Sgabor * @return the source referred to with this diagnostic, or null if none 648246074Sgabor */ 649246074Sgabor public DiagnosticSource getDiagnosticSource() { 650246074Sgabor return source; 651246074Sgabor } 652246074Sgabor 653246074Sgabor protected int getIntStartPosition() { 654246074Sgabor return (position == null ? Position.NOPOS : position.getStartPosition()); 655246074Sgabor } 656246074Sgabor 657246074Sgabor protected int getIntPosition() { 658246074Sgabor return (position == null ? Position.NOPOS : position.getPreferredPosition()); 659246074Sgabor } 660246074Sgabor 661246074Sgabor protected int getIntEndPosition() { 662246074Sgabor return (position == null ? Position.NOPOS : position.getEndPosition(source.getEndPosTable())); 663246074Sgabor } 664246074Sgabor 665246074Sgabor @DefinedBy(Api.COMPILER) 666246074Sgabor public long getStartPosition() { 667246074Sgabor return getIntStartPosition(); 668246074Sgabor } 669246074Sgabor 670246074Sgabor @DefinedBy(Api.COMPILER) 671246074Sgabor public long getPosition() { 672246074Sgabor return getIntPosition(); 673246074Sgabor } 674246074Sgabor 675246074Sgabor @DefinedBy(Api.COMPILER) 676246074Sgabor public long getEndPosition() { 677246074Sgabor return getIntEndPosition(); 678246074Sgabor } 679246074Sgabor 680246074Sgabor public DiagnosticPosition getDiagnosticPosition() { 681246074Sgabor return position; 682246074Sgabor } 683246074Sgabor 684246074Sgabor /** 685246074Sgabor * Get the line number within the source referred to by this diagnostic. 686246074Sgabor * @return the line number within the source referred to by this diagnostic 687246074Sgabor */ 688246074Sgabor @DefinedBy(Api.COMPILER) 689246074Sgabor public long getLineNumber() { 690246074Sgabor if (sourcePosition == null) { 691246074Sgabor sourcePosition = new SourcePosition(); 692246074Sgabor } 693246074Sgabor return sourcePosition.getLineNumber(); 694246074Sgabor } 695246074Sgabor 696246074Sgabor /** 697246074Sgabor * Get the column number within the line of source referred to by this diagnostic. 698246074Sgabor * @return the column number within the line of source referred to by this diagnostic 699246074Sgabor */ 700246074Sgabor @DefinedBy(Api.COMPILER) 701246074Sgabor public long getColumnNumber() { 702246074Sgabor if (sourcePosition == null) { 703246074Sgabor sourcePosition = new SourcePosition(); 704246074Sgabor } 705246074Sgabor return sourcePosition.getColumnNumber(); 706246074Sgabor } 707246074Sgabor 708246074Sgabor /** 709246074Sgabor * Get the arguments to be included in the text of the diagnostic. 710246074Sgabor * @return the arguments to be included in the text of the diagnostic 711246074Sgabor */ 712246074Sgabor public Object[] getArgs() { 713246074Sgabor return diagnosticInfo.args; 714246074Sgabor } 715246074Sgabor 716246074Sgabor /** 717246074Sgabor * Get the prefix string associated with this type of diagnostic. 718246074Sgabor * @return the prefix string associated with this type of diagnostic 719246074Sgabor */ 720246074Sgabor public String getPrefix() { 721246074Sgabor return getPrefix(diagnosticInfo.type); 722246074Sgabor } 723246074Sgabor 724246074Sgabor /** 725246074Sgabor * Get the prefix string associated with a particular type of diagnostic. 726246074Sgabor * @return the prefix string associated with a particular type of diagnostic 727246074Sgabor */ 728246074Sgabor public String getPrefix(DiagnosticType dt) { 729246074Sgabor return defaultFormatter.formatKind(this, Locale.getDefault()); 730246074Sgabor } 731246074Sgabor 732246074Sgabor /** 733246074Sgabor * Return the standard presentation of this diagnostic. 734246074Sgabor */ 735246074Sgabor @Override 736246074Sgabor public String toString() { 737246074Sgabor return defaultFormatter.format(this, Locale.getDefault()); 738246074Sgabor } 739246074Sgabor 740246074Sgabor private DiagnosticFormatter<JCDiagnostic> defaultFormatter; 741246074Sgabor @Deprecated 742246074Sgabor private static DiagnosticFormatter<JCDiagnostic> fragmentFormatter; 743246074Sgabor 744246074Sgabor // Methods for javax.tools.Diagnostic 745246074Sgabor 746246074Sgabor @DefinedBy(Api.COMPILER) 747246074Sgabor public Diagnostic.Kind getKind() { 748246074Sgabor switch (diagnosticInfo.type) { 749246074Sgabor case NOTE: 750246074Sgabor return Diagnostic.Kind.NOTE; 751246074Sgabor case WARNING: 752246074Sgabor return flags.contains(DiagnosticFlag.MANDATORY) 753246074Sgabor ? Diagnostic.Kind.MANDATORY_WARNING 754246074Sgabor : Diagnostic.Kind.WARNING; 755246074Sgabor case ERROR: 756246074Sgabor return Diagnostic.Kind.ERROR; 757246074Sgabor default: 758246074Sgabor return Diagnostic.Kind.OTHER; 759246074Sgabor } 760246074Sgabor } 761246074Sgabor 762246074Sgabor @DefinedBy(Api.COMPILER) 763246074Sgabor public String getCode() { 764246074Sgabor return diagnosticInfo.key(); 765246074Sgabor } 766246074Sgabor 767246074Sgabor @DefinedBy(Api.COMPILER) 768246074Sgabor public String getMessage(Locale locale) { 769246074Sgabor return defaultFormatter.formatMessage(this, locale); 770246074Sgabor } 771246074Sgabor 772246074Sgabor public void setFlag(DiagnosticFlag flag) { 773246074Sgabor flags.add(flag); 774246074Sgabor 775246074Sgabor if (diagnosticInfo.type == DiagnosticType.ERROR) { 776246074Sgabor switch (flag) { 777246074Sgabor case SYNTAX: 778246074Sgabor flags.remove(DiagnosticFlag.RECOVERABLE); 779246074Sgabor break; 780246074Sgabor case RESOLVE_ERROR: 781246074Sgabor flags.add(DiagnosticFlag.RECOVERABLE); 782246074Sgabor break; 783246074Sgabor } 784246074Sgabor } 785246074Sgabor } 786246074Sgabor 787246074Sgabor public boolean isFlagSet(DiagnosticFlag flag) { 788246074Sgabor return flags.contains(flag); 789246074Sgabor } 790246074Sgabor 791246074Sgabor public static class MultilineDiagnostic extends JCDiagnostic { 792246074Sgabor 793246074Sgabor private final List<JCDiagnostic> subdiagnostics; 794246074Sgabor 795246074Sgabor public MultilineDiagnostic(JCDiagnostic other, List<JCDiagnostic> subdiagnostics) { 796246074Sgabor super(other.defaultFormatter, 797246074Sgabor other.diagnosticInfo, 798246074Sgabor other.getLintCategory(), 799246074Sgabor other.flags, 800246074Sgabor other.getDiagnosticSource(), 801246074Sgabor other.position); 802246074Sgabor this.subdiagnostics = subdiagnostics; 803246074Sgabor } 804246074Sgabor 805246074Sgabor @Override 806246074Sgabor public List<JCDiagnostic> getSubdiagnostics() { 807246074Sgabor return subdiagnostics; 808246074Sgabor } 809246074Sgabor 810246074Sgabor @Override 811246074Sgabor public boolean isMultiline() { 812246074Sgabor return true; 813246074Sgabor } 814246074Sgabor } 815246074Sgabor} 816246074Sgabor