Sat, 07 Nov 2020 10:30:02 +0800
Added tag mips-jdk8u275-b01 for changeset eb6ee6a5f2fe
1 /*
2 * Copyright (c) 2003, 2013, 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 */
26 package com.sun.tools.javac.util;
28 import java.util.EnumSet;
29 import java.util.Locale;
30 import java.util.Set;
32 import javax.tools.Diagnostic;
33 import javax.tools.JavaFileObject;
35 import com.sun.tools.javac.api.DiagnosticFormatter;
36 import com.sun.tools.javac.code.Lint.LintCategory;
37 import com.sun.tools.javac.tree.EndPosTable;
38 import com.sun.tools.javac.tree.JCTree;
40 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*;
42 /** An abstraction of a diagnostic message generated by the compiler.
43 *
44 * <p><b>This is NOT part of any supported API.
45 * If you write code that depends on this, you do so at your own risk.
46 * This code and its internal interfaces are subject to change or
47 * deletion without notice.</b>
48 */
49 public class JCDiagnostic implements Diagnostic<JavaFileObject> {
50 /** A factory for creating diagnostic objects. */
51 public static class Factory {
52 /** The context key for the diagnostic factory. */
53 protected static final Context.Key<JCDiagnostic.Factory> diagnosticFactoryKey =
54 new Context.Key<JCDiagnostic.Factory>();
56 /** Get the Factory instance for this context. */
57 public static Factory instance(Context context) {
58 Factory instance = context.get(diagnosticFactoryKey);
59 if (instance == null)
60 instance = new Factory(context);
61 return instance;
62 }
64 DiagnosticFormatter<JCDiagnostic> formatter;
65 final String prefix;
66 final Set<DiagnosticFlag> defaultErrorFlags;
68 /** Create a new diagnostic factory. */
69 protected Factory(Context context) {
70 this(JavacMessages.instance(context), "compiler");
71 context.put(diagnosticFactoryKey, this);
73 final Options options = Options.instance(context);
74 initOptions(options);
75 options.addListener(new Runnable() {
76 public void run() {
77 initOptions(options);
78 }
79 });
80 }
82 private void initOptions(Options options) {
83 if (options.isSet("onlySyntaxErrorsUnrecoverable"))
84 defaultErrorFlags.add(DiagnosticFlag.RECOVERABLE);
85 }
87 /** Create a new diagnostic factory. */
88 public Factory(JavacMessages messages, String prefix) {
89 this.prefix = prefix;
90 this.formatter = new BasicDiagnosticFormatter(messages);
91 defaultErrorFlags = EnumSet.of(DiagnosticFlag.MANDATORY);
92 }
94 /**
95 * Create an error diagnostic.
96 * @param source The source of the compilation unit, if any, in which to report the error.
97 * @param pos The source position at which to report the error.
98 * @param key The key for the localized error message.
99 * @param args Fields of the error message.
100 */
101 public JCDiagnostic error(
102 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
103 return create(ERROR, null, defaultErrorFlags, source, pos, key, args);
104 }
106 /**
107 * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
108 * @param source The source of the compilation unit, if any, in which to report the warning.
109 * @param pos The source position at which to report the warning.
110 * @param key The key for the localized warning message.
111 * @param args Fields of the warning message.
112 * @see MandatoryWarningHandler
113 */
114 public JCDiagnostic mandatoryWarning(
115 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
116 return create(WARNING, null, EnumSet.of(DiagnosticFlag.MANDATORY), source, pos, key, args);
117 }
119 /**
120 * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
121 * @param lc The lint category for the diagnostic
122 * @param source The source of the compilation unit, if any, in which to report the warning.
123 * @param pos The source position at which to report the warning.
124 * @param key The key for the localized warning message.
125 * @param args Fields of the warning message.
126 * @see MandatoryWarningHandler
127 */
128 public JCDiagnostic mandatoryWarning(
129 LintCategory lc,
130 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
131 return create(WARNING, lc, EnumSet.of(DiagnosticFlag.MANDATORY), source, pos, key, args);
132 }
134 /**
135 * Create a warning diagnostic.
136 * @param lc The lint category for the diagnostic
137 * @param key The key for the localized error message.
138 * @param args Fields of the warning message.
139 * @see MandatoryWarningHandler
140 */
141 public JCDiagnostic warning(
142 LintCategory lc, String key, Object... args) {
143 return create(WARNING, lc, EnumSet.noneOf(DiagnosticFlag.class), null, null, key, args);
144 }
146 /**
147 * Create a warning diagnostic.
148 * @param source The source of the compilation unit, if any, in which to report the warning.
149 * @param pos The source position at which to report the warning.
150 * @param key The key for the localized warning message.
151 * @param args Fields of the warning message.
152 */
153 public JCDiagnostic warning(
154 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
155 return create(WARNING, null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
156 }
158 /**
159 * Create a warning diagnostic.
160 * @param lc The lint category for the diagnostic
161 * @param source The source of the compilation unit, if any, in which to report the warning.
162 * @param pos The source position at which to report the warning.
163 * @param key The key for the localized warning message.
164 * @param args Fields of the warning message.
165 * @see MandatoryWarningHandler
166 */
167 public JCDiagnostic warning(
168 LintCategory lc, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
169 return create(WARNING, lc, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
170 }
172 /**
173 * Create a note diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
174 * @param key The key for the localized message.
175 * @param args Fields of the message.
176 * @see MandatoryWarningHandler
177 */
178 public JCDiagnostic mandatoryNote(DiagnosticSource source, String key, Object... args) {
179 return create(NOTE, null, EnumSet.of(DiagnosticFlag.MANDATORY), source, null, key, args);
180 }
182 /**
183 * Create a note diagnostic.
184 * @param key The key for the localized error message.
185 * @param args Fields of the message.
186 */
187 public JCDiagnostic note(String key, Object... args) {
188 return create(NOTE, null, EnumSet.noneOf(DiagnosticFlag.class), null, null, key, args);
189 }
191 /**
192 * Create a note diagnostic.
193 * @param source The source of the compilation unit, if any, in which to report the note.
194 * @param pos The source position at which to report the note.
195 * @param key The key for the localized message.
196 * @param args Fields of the message.
197 */
198 public JCDiagnostic note(
199 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
200 return create(NOTE, null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
201 }
203 /**
204 * Create a fragment diagnostic, for use as an argument in other diagnostics
205 * @param key The key for the localized message.
206 * @param args Fields of the message.
207 */
208 public JCDiagnostic fragment(String key, Object... args) {
209 return create(FRAGMENT, null, EnumSet.noneOf(DiagnosticFlag.class), null, null, key, args);
210 }
212 /**
213 * Create a new diagnostic of the given kind, which is not mandatory and which has
214 * no lint category.
215 * @param kind The diagnostic kind
216 * @param source The source of the compilation unit, if any, in which to report the message.
217 * @param pos The source position at which to report the message.
218 * @param key The key for the localized message.
219 * @param args Fields of the message.
220 */
221 public JCDiagnostic create(
222 DiagnosticType kind, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
223 return create(kind, null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
224 }
226 /**
227 * Create a new diagnostic of the given kind.
228 * @param kind The diagnostic kind
229 * @param lc The lint category, if applicable, or null
230 * @param flags The set of flags for the diagnostic
231 * @param source The source of the compilation unit, if any, in which to report the message.
232 * @param pos The source position at which to report the message.
233 * @param key The key for the localized message.
234 * @param args Fields of the message.
235 */
236 public JCDiagnostic create(
237 DiagnosticType kind, LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
238 return new JCDiagnostic(formatter, kind, lc, flags, source, pos, qualify(kind, key), args);
239 }
241 protected String qualify(DiagnosticType t, String key) {
242 return prefix + "." + t.key + "." + key;
243 }
244 }
248 /**
249 * Create a fragment diagnostic, for use as an argument in other diagnostics
250 * @param key The key for the localized error message.
251 * @param args Fields of the error message.
252 *
253 */
254 @Deprecated
255 public static JCDiagnostic fragment(String key, Object... args) {
256 return new JCDiagnostic(getFragmentFormatter(),
257 FRAGMENT,
258 null,
259 EnumSet.noneOf(DiagnosticFlag.class),
260 null,
261 null,
262 "compiler." + FRAGMENT.key + "." + key,
263 args);
264 }
265 //where
266 @Deprecated
267 public static DiagnosticFormatter<JCDiagnostic> getFragmentFormatter() {
268 if (fragmentFormatter == null) {
269 fragmentFormatter = new BasicDiagnosticFormatter(JavacMessages.getDefaultMessages());
270 }
271 return fragmentFormatter;
272 }
274 /**
275 * A DiagnosticType defines the type of the diagnostic.
276 **/
277 public enum DiagnosticType {
278 /** A fragment of an enclosing diagnostic. */
279 FRAGMENT("misc"),
280 /** A note: similar to, but less serious than, a warning. */
281 NOTE("note"),
282 /** A warning. */
283 WARNING("warn"),
284 /** An error. */
285 ERROR("err");
287 final String key;
289 /** Create a DiagnosticType.
290 * @param key A string used to create the resource key for the diagnostic.
291 */
292 DiagnosticType(String key) {
293 this.key = key;
294 }
295 };
297 /**
298 * A DiagnosticPosition provides information about the positions in a file
299 * that gave rise to a diagnostic. It always defines a "preferred" position
300 * that most accurately defines the location of the diagnostic, it may also
301 * provide a related tree node that spans that location.
302 */
303 public static interface DiagnosticPosition {
304 /** Gets the tree node, if any, to which the diagnostic applies. */
305 JCTree getTree();
306 /** If there is a tree node, get the start position of the tree node.
307 * Otherwise, just returns the same as getPreferredPosition(). */
308 int getStartPosition();
309 /** Get the position within the file that most accurately defines the
310 * location for the diagnostic. */
311 int getPreferredPosition();
312 /** If there is a tree node, and if endPositions are available, get
313 * the end position of the tree node. Otherwise, just returns the
314 * same as getPreferredPosition(). */
315 int getEndPosition(EndPosTable endPosTable);
316 }
318 /**
319 * A DiagnosticPosition that simply identifies a position, but no related
320 * tree node, as the location for a diagnostic. Used for scanner and parser
321 * diagnostics. */
322 public static class SimpleDiagnosticPosition implements DiagnosticPosition {
323 public SimpleDiagnosticPosition(int pos) {
324 this.pos = pos;
325 }
327 public JCTree getTree() {
328 return null;
329 }
331 public int getStartPosition() {
332 return pos;
333 }
335 public int getPreferredPosition() {
336 return pos;
337 }
339 public int getEndPosition(EndPosTable endPosTable) {
340 return pos;
341 }
343 private final int pos;
344 }
346 public enum DiagnosticFlag {
347 MANDATORY,
348 RESOLVE_ERROR,
349 SYNTAX,
350 RECOVERABLE,
351 NON_DEFERRABLE,
352 COMPRESSED
353 }
355 private final DiagnosticType type;
356 private final DiagnosticSource source;
357 private final DiagnosticPosition position;
358 private final String key;
359 protected final Object[] args;
360 private final Set<DiagnosticFlag> flags;
361 private final LintCategory lintCategory;
363 /** source line position (set lazily) */
364 private SourcePosition sourcePosition;
366 /**
367 * This class is used to defer the line/column position fetch logic after diagnostic construction.
368 */
369 class SourcePosition {
371 private final int line;
372 private final int column;
374 SourcePosition() {
375 int n = (position == null ? Position.NOPOS : position.getPreferredPosition());
376 if (n == Position.NOPOS || source == null)
377 line = column = -1;
378 else {
379 line = source.getLineNumber(n);
380 column = source.getColumnNumber(n, true);
381 }
382 }
384 public int getLineNumber() {
385 return line;
386 }
388 public int getColumnNumber() {
389 return column;
390 }
391 }
393 /**
394 * Create a diagnostic object.
395 * @param formatter the formatter to use for the diagnostic
396 * @param dt the type of diagnostic
397 * @param lc the lint category for the diagnostic
398 * @param source the name of the source file, or null if none.
399 * @param pos the character offset within the source file, if given.
400 * @param key a resource key to identify the text of the diagnostic
401 * @param args arguments to be included in the text of the diagnostic
402 */
403 protected JCDiagnostic(DiagnosticFormatter<JCDiagnostic> formatter,
404 DiagnosticType dt,
405 LintCategory lc,
406 Set<DiagnosticFlag> flags,
407 DiagnosticSource source,
408 DiagnosticPosition pos,
409 String key,
410 Object... args) {
411 if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS)
412 throw new IllegalArgumentException();
414 this.defaultFormatter = formatter;
415 this.type = dt;
416 this.lintCategory = lc;
417 this.flags = flags;
418 this.source = source;
419 this.position = pos;
420 this.key = key;
421 this.args = args;
422 }
424 /**
425 * Get the type of this diagnostic.
426 * @return the type of this diagnostic
427 */
428 public DiagnosticType getType() {
429 return type;
430 }
432 /**
433 * Get the subdiagnostic list
434 * @return subdiagnostic list
435 */
436 public List<JCDiagnostic> getSubdiagnostics() {
437 return List.nil();
438 }
440 public boolean isMultiline() {
441 return false;
442 }
444 /**
445 * Check whether or not this diagnostic is required to be shown.
446 * @return true if this diagnostic is required to be shown.
447 */
448 public boolean isMandatory() {
449 return flags.contains(DiagnosticFlag.MANDATORY);
450 }
452 /**
453 * Check whether this diagnostic has an associated lint category.
454 */
455 public boolean hasLintCategory() {
456 return (lintCategory != null);
457 }
459 /**
460 * Get the associated lint category, or null if none.
461 */
462 public LintCategory getLintCategory() {
463 return lintCategory;
464 }
466 /**
467 * Get the name of the source file referred to by this diagnostic.
468 * @return the name of the source referred to with this diagnostic, or null if none
469 */
470 public JavaFileObject getSource() {
471 if (source == null)
472 return null;
473 else
474 return source.getFile();
475 }
477 /**
478 * Get the source referred to by this diagnostic.
479 * @return the source referred to with this diagnostic, or null if none
480 */
481 public DiagnosticSource getDiagnosticSource() {
482 return source;
483 }
485 protected int getIntStartPosition() {
486 return (position == null ? Position.NOPOS : position.getStartPosition());
487 }
489 protected int getIntPosition() {
490 return (position == null ? Position.NOPOS : position.getPreferredPosition());
491 }
493 protected int getIntEndPosition() {
494 return (position == null ? Position.NOPOS : position.getEndPosition(source.getEndPosTable()));
495 }
497 public long getStartPosition() {
498 return getIntStartPosition();
499 }
501 public long getPosition() {
502 return getIntPosition();
503 }
505 public long getEndPosition() {
506 return getIntEndPosition();
507 }
509 public DiagnosticPosition getDiagnosticPosition() {
510 return position;
511 }
513 /**
514 * Get the line number within the source referred to by this diagnostic.
515 * @return the line number within the source referred to by this diagnostic
516 */
517 public long getLineNumber() {
518 if (sourcePosition == null) {
519 sourcePosition = new SourcePosition();
520 }
521 return sourcePosition.getLineNumber();
522 }
524 /**
525 * Get the column number within the line of source referred to by this diagnostic.
526 * @return the column number within the line of source referred to by this diagnostic
527 */
528 public long getColumnNumber() {
529 if (sourcePosition == null) {
530 sourcePosition = new SourcePosition();
531 }
532 return sourcePosition.getColumnNumber();
533 }
535 /**
536 * Get the arguments to be included in the text of the diagnostic.
537 * @return the arguments to be included in the text of the diagnostic
538 */
539 public Object[] getArgs() {
540 return args;
541 }
543 /**
544 * Get the prefix string associated with this type of diagnostic.
545 * @return the prefix string associated with this type of diagnostic
546 */
547 public String getPrefix() {
548 return getPrefix(type);
549 }
551 /**
552 * Get the prefix string associated with a particular type of diagnostic.
553 * @return the prefix string associated with a particular type of diagnostic
554 */
555 public String getPrefix(DiagnosticType dt) {
556 return defaultFormatter.formatKind(this, Locale.getDefault());
557 }
559 /**
560 * Return the standard presentation of this diagnostic.
561 */
562 @Override
563 public String toString() {
564 return defaultFormatter.format(this,Locale.getDefault());
565 }
567 private DiagnosticFormatter<JCDiagnostic> defaultFormatter;
568 @Deprecated
569 private static DiagnosticFormatter<JCDiagnostic> fragmentFormatter;
571 // Methods for javax.tools.Diagnostic
573 public Diagnostic.Kind getKind() {
574 switch (type) {
575 case NOTE:
576 return Diagnostic.Kind.NOTE;
577 case WARNING:
578 return flags.contains(DiagnosticFlag.MANDATORY)
579 ? Diagnostic.Kind.MANDATORY_WARNING
580 : Diagnostic.Kind.WARNING;
581 case ERROR:
582 return Diagnostic.Kind.ERROR;
583 default:
584 return Diagnostic.Kind.OTHER;
585 }
586 }
588 public String getCode() {
589 return key;
590 }
592 public String getMessage(Locale locale) {
593 return defaultFormatter.formatMessage(this, locale);
594 }
596 public void setFlag(DiagnosticFlag flag) {
597 flags.add(flag);
599 if (type == DiagnosticType.ERROR) {
600 switch (flag) {
601 case SYNTAX:
602 flags.remove(DiagnosticFlag.RECOVERABLE);
603 break;
604 case RESOLVE_ERROR:
605 flags.add(DiagnosticFlag.RECOVERABLE);
606 break;
607 }
608 }
609 }
611 public boolean isFlagSet(DiagnosticFlag flag) {
612 return flags.contains(flag);
613 }
615 public static class MultilineDiagnostic extends JCDiagnostic {
617 private final List<JCDiagnostic> subdiagnostics;
619 public MultilineDiagnostic(JCDiagnostic other, List<JCDiagnostic> subdiagnostics) {
620 super(other.defaultFormatter,
621 other.getType(),
622 other.getLintCategory(),
623 other.flags,
624 other.getDiagnosticSource(),
625 other.position,
626 other.getCode(),
627 other.getArgs());
628 this.subdiagnostics = subdiagnostics;
629 }
631 @Override
632 public List<JCDiagnostic> getSubdiagnostics() {
633 return subdiagnostics;
634 }
636 @Override
637 public boolean isMultiline() {
638 return true;
639 }
640 }
641 }