Thu, 09 Oct 2008 16:19:13 +0100
6731573: diagnostic output should optionally include source line
Summary: Added an -XD option to optionally prints out source lines in error messages
Reviewed-by: jjg
1 /*
2 * Copyright 2003-2008 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
26 package com.sun.tools.javac.util;
28 import java.util.Locale;
29 import java.util.Map;
31 import javax.tools.Diagnostic;
32 import javax.tools.JavaFileObject;
34 import com.sun.tools.javac.api.DiagnosticFormatter;
35 import com.sun.tools.javac.file.JavacFileManager;
36 import com.sun.tools.javac.tree.JCTree;
38 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*;
40 /** An abstraction of a diagnostic message generated by the compiler.
41 *
42 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
43 * you write code that depends on this, you do so at your own risk.
44 * This code and its internal interfaces are subject to change or
45 * deletion without notice.</b>
46 */
47 public class JCDiagnostic implements Diagnostic<JavaFileObject> {
48 /** A factory for creating diagnostic objects. */
49 public static class Factory {
50 /** The context key for the diagnostic factory. */
51 protected static final Context.Key<JCDiagnostic.Factory> diagnosticFactoryKey =
52 new Context.Key<JCDiagnostic.Factory>();
54 /** Get the Factory instance for this context. */
55 public static Factory instance(Context context) {
56 Factory instance = context.get(diagnosticFactoryKey);
57 if (instance == null)
58 instance = new Factory(context);
59 return instance;
60 }
62 DiagnosticFormatter<JCDiagnostic> formatter;
63 final String prefix;
65 /** Create a new diagnostic factory. */
66 protected Factory(Context context) {
67 this(JavacMessages.instance(context), "compiler");
68 context.put(diagnosticFactoryKey, this);
69 }
71 /** Create a new diagnostic factory. */
72 public Factory(JavacMessages messages, String prefix) {
73 this.prefix = prefix;
74 this.formatter = new BasicDiagnosticFormatter(messages);
75 }
77 /**
78 * Create an error diagnostic.
79 * @param source The source of the compilation unit, if any, in which to report the error.
80 * @param pos The source position at which to report the error.
81 * @param key The key for the localized error message.
82 * @param args Fields of the error message.
83 */
84 public JCDiagnostic error(
85 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
86 return new JCDiagnostic(formatter, ERROR, true, source, pos, qualify(ERROR, key), args);
87 }
89 /**
90 * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
91 * @param source The source of the compilation unit, if any, in which to report the warning.
92 * @param pos The source position at which to report the warning.
93 * @param key The key for the localized error message.
94 * @param args Fields of the error message.
95 * @see MandatoryWarningHandler
96 */
97 public JCDiagnostic mandatoryWarning(
98 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
99 return new JCDiagnostic(formatter, WARNING, true, source, pos, qualify(WARNING, key), args);
100 }
102 /**
103 * Create a warning diagnostic.
104 * @param source The source of the compilation unit, if any, in which to report the warning.
105 * @param pos The source position at which to report the warning.
106 * @param key The key for the localized error message.
107 * @param args Fields of the error message.
108 */
109 public JCDiagnostic warning(
110 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
111 return new JCDiagnostic(formatter, WARNING, false, source, pos, qualify(WARNING, key), args);
112 }
114 /**
115 * Create a note diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
116 * @param key The key for the localized error message.
117 * @param args Fields of the error message.
118 * @see MandatoryWarningHandler
119 */
120 public JCDiagnostic mandatoryNote(DiagnosticSource source, String key, Object... args) {
121 return new JCDiagnostic(formatter, NOTE, true, source, null, qualify(NOTE, key), args);
122 }
124 /**
125 * Create a note diagnostic.
126 * @param key The key for the localized error message.
127 * @param args Fields of the error message.
128 */
129 public JCDiagnostic note(String key, Object... args) {
130 return note(null, null, key, args);
131 }
133 /**
134 * Create a note diagnostic.
135 * @param source The source of the compilation unit, if any, in which to report the note.
136 * @param pos The source position at which to report the note.
137 * @param key The key for the localized error message.
138 * @param args Fields of the error message.
139 */
140 public JCDiagnostic note(
141 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
142 return new JCDiagnostic(formatter, NOTE, false, source, pos, qualify(NOTE, key), args);
143 }
145 /**
146 * Create a fragment diagnostic, for use as an argument in other diagnostics
147 * @param key The key for the localized error message.
148 * @param args Fields of the error message.
149 */
150 public JCDiagnostic fragment(String key, Object... args) {
151 return new JCDiagnostic(formatter, FRAGMENT, false, null, null, qualify(FRAGMENT, key), args);
152 }
154 protected String qualify(DiagnosticType t, String key) {
155 return prefix + "." + t.key + "." + key;
156 }
157 }
161 /**
162 * Create a fragment diagnostic, for use as an argument in other diagnostics
163 * @param key The key for the localized error message.
164 * @param args Fields of the error message.
165 *
166 */
167 @Deprecated
168 public static JCDiagnostic fragment(String key, Object... args) {
169 return new JCDiagnostic(getFragmentFormatter(),
170 FRAGMENT,
171 false,
172 null,
173 null,
174 "compiler." + FRAGMENT.key + "." + key,
175 args);
176 }
177 //where
178 @Deprecated
179 public static DiagnosticFormatter<JCDiagnostic> getFragmentFormatter() {
180 if (fragmentFormatter == null) {
181 fragmentFormatter = new BasicDiagnosticFormatter(JavacMessages.getDefaultMessages());
182 }
183 return fragmentFormatter;
184 }
186 /**
187 * A DiagnosticType defines the type of the diagnostic.
188 **/
189 public enum DiagnosticType {
190 /** A fragment of an enclosing diagnostic. */
191 FRAGMENT("misc"),
192 /** A note: similar to, but less serious than, a warning. */
193 NOTE("note"),
194 /** A warning. */
195 WARNING("warn"),
196 /** An error. */
197 ERROR("err");
199 final String key;
201 /** Create a DiagnosticType.
202 * @param key A string used to create the resource key for the diagnostic.
203 */
204 DiagnosticType(String key) {
205 this.key = key;
206 }
207 };
209 /**
210 * A DiagnosticPosition provides information about the positions in a file
211 * that gave rise to a diagnostic. It always defines a "preferred" position
212 * that most accurately defines the location of the diagnostic, it may also
213 * provide a related tree node that spans that location.
214 */
215 public static interface DiagnosticPosition {
216 /** Gets the tree node, if any, to which the diagnostic applies. */
217 JCTree getTree();
218 /** If there is a tree node, get the start position of the tree node.
219 * Otherwise, just returns the same as getPreferredPosition(). */
220 int getStartPosition();
221 /** Get the position within the file that most accurately defines the
222 * location for the diagnostic. */
223 int getPreferredPosition();
224 /** If there is a tree node, and if endPositions are available, get
225 * the end position of the tree node. Otherwise, just returns the
226 * same as getPreferredPosition(). */
227 int getEndPosition(Map<JCTree, Integer> endPosTable);
228 }
230 /**
231 * A DiagnosticPosition that simply identifies a position, but no related
232 * tree node, as the location for a diagnostic. Used for scanner and parser
233 * diagnostics. */
234 public static class SimpleDiagnosticPosition implements DiagnosticPosition {
235 public SimpleDiagnosticPosition(int pos) {
236 this.pos = pos;
237 }
239 public JCTree getTree() {
240 return null;
241 }
243 public int getStartPosition() {
244 return pos;
245 }
247 public int getPreferredPosition() {
248 return pos;
249 }
251 public int getEndPosition(Map<JCTree, Integer> endPosTable) {
252 return pos;
253 }
255 private final int pos;
256 }
258 private final DiagnosticType type;
259 private final DiagnosticSource source;
260 private final DiagnosticPosition position;
261 private final int line;
262 private final int column;
263 private final String key;
264 protected Object[] args;
265 private boolean mandatory;
267 /**
268 * Create a diagnostic object.
269 * @param messages the resource for localized messages
270 * @param dt the type of diagnostic
271 * @param name the name of the source file, or null if none.
272 * @param pos the character offset within the source file, if given.
273 * @param key a resource key to identify the text of the diagnostic
274 * @param args arguments to be included in the text of the diagnostic
275 */
276 protected JCDiagnostic(DiagnosticFormatter<JCDiagnostic> formatter,
277 DiagnosticType dt,
278 boolean mandatory,
279 DiagnosticSource source,
280 DiagnosticPosition pos,
281 String key,
282 Object ... args) {
283 if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS)
284 throw new IllegalArgumentException();
286 this.defaultFormatter = formatter;
287 this.type = dt;
288 this.mandatory = mandatory;
289 this.source = source;
290 this.position = pos;
291 this.key = key;
292 this.args = args;
294 int n = (pos == null ? Position.NOPOS : pos.getPreferredPosition());
295 if (n == Position.NOPOS || source == null)
296 line = column = -1;
297 else {
298 line = source.getLineNumber(n);
299 column = source.getColumnNumber(n, true);
300 }
301 }
303 /**
304 * Get the type of this diagnostic.
305 * @return the type of this diagnostic
306 */
307 public DiagnosticType getType() {
308 return type;
309 }
311 /**
312 * Check whether or not this diagnostic is required to be shown.
313 * @return true if this diagnostic is required to be shown.
314 */
315 public boolean isMandatory() {
316 return mandatory;
317 }
319 /**
320 * Get the name of the source file referred to by this diagnostic.
321 * @return the name of the source referred to with this diagnostic, or null if none
322 */
323 public JavaFileObject getSource() {
324 if (source == null)
325 return null;
326 else
327 return source.getFile();
328 }
330 /**
331 * Get the name of the source file referred to by this diagnostic.
332 * @return the name of the source referred to with this diagnostic, or null if none
333 */
334 public String getSourceName() {
335 JavaFileObject s = getSource();
336 return s == null ? null : JavacFileManager.getJavacFileName(s);
337 }
339 /**
340 * Get the source referred to by this diagnostic.
341 * @return the source referred to with this diagnostic, or null if none
342 */
343 public DiagnosticSource getDiagnosticSource() {
344 return source;
345 }
347 protected int getIntStartPosition() {
348 return (position == null ? Position.NOPOS : position.getStartPosition());
349 }
351 protected int getIntPosition() {
352 return (position == null ? Position.NOPOS : position.getPreferredPosition());
353 }
355 protected int getIntEndPosition() {
356 return (position == null ? Position.NOPOS : position.getEndPosition(source.getEndPosTable()));
357 }
359 public long getStartPosition() {
360 return getIntStartPosition();
361 }
363 public long getPosition() {
364 return getIntPosition();
365 }
367 public long getEndPosition() {
368 return getIntEndPosition();
369 }
371 /**
372 * Get the line number within the source referred to by this diagnostic.
373 * @return the line number within the source referred to by this diagnostic
374 */
375 public long getLineNumber() {
376 return line;
377 }
379 /**
380 * Get the column number within the line of source referred to by this diagnostic.
381 * @return the column number within the line of source referred to by this diagnostic
382 */
383 public long getColumnNumber() {
384 return column;
385 }
387 /**
388 * Get the arguments to be included in the text of the diagnostic.
389 * @return the arguments to be included in the text of the diagnostic
390 */
391 public Object[] getArgs() {
392 return args;
393 }
395 /**
396 * Get the prefix string associated with this type of diagnostic.
397 * @return the prefix string associated with this type of diagnostic
398 */
399 public String getPrefix() {
400 return getPrefix(type);
401 }
403 /**
404 * Get the prefix string associated with a particular type of diagnostic.
405 * @return the prefix string associated with a particular type of diagnostic
406 */
407 public String getPrefix(DiagnosticType dt) {
408 return defaultFormatter.formatKind(this, Locale.getDefault());
409 }
411 /**
412 * Return the standard presentation of this diagnostic.
413 */
414 public String toString() {
415 return defaultFormatter.format(this,Locale.getDefault());
416 }
418 private DiagnosticFormatter<JCDiagnostic> defaultFormatter;
419 @Deprecated
420 private static DiagnosticFormatter<JCDiagnostic> fragmentFormatter;
422 // Methods for javax.tools.Diagnostic
424 public Diagnostic.Kind getKind() {
425 switch (type) {
426 case NOTE:
427 return Diagnostic.Kind.NOTE;
428 case WARNING:
429 return mandatory ? Diagnostic.Kind.MANDATORY_WARNING
430 : Diagnostic.Kind.WARNING;
431 case ERROR:
432 return Diagnostic.Kind.ERROR;
433 default:
434 return Diagnostic.Kind.OTHER;
435 }
436 }
438 public String getCode() {
439 return key;
440 }
442 public String getMessage(Locale locale) {
443 // RFE 6406133: JCDiagnostic.getMessage ignores locale argument
444 return defaultFormatter.formatMessage(this, locale);
445 }
446 }