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