src/share/classes/com/sun/tools/javac/util/JCDiagnostic.java

Sat, 01 Dec 2007 00:00:00 +0000

author
duke
date
Sat, 01 Dec 2007 00:00:00 +0000
changeset 1
9a66ca7c79fa
child 50
b9bcea8bbe24
permissions
-rw-r--r--

Initial load

duke@1 1 /*
duke@1 2 * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
duke@1 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@1 4 *
duke@1 5 * This code is free software; you can redistribute it and/or modify it
duke@1 6 * under the terms of the GNU General Public License version 2 only, as
duke@1 7 * published by the Free Software Foundation. Sun designates this
duke@1 8 * particular file as subject to the "Classpath" exception as provided
duke@1 9 * by Sun in the LICENSE file that accompanied this code.
duke@1 10 *
duke@1 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@1 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@1 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@1 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@1 15 * accompanied this code).
duke@1 16 *
duke@1 17 * You should have received a copy of the GNU General Public License version
duke@1 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@1 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@1 20 *
duke@1 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@1 22 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@1 23 * have any questions.
duke@1 24 */
duke@1 25
duke@1 26 package com.sun.tools.javac.util;
duke@1 27
duke@1 28 import java.net.URI;
duke@1 29 import java.text.MessageFormat;
duke@1 30 import java.util.Locale;
duke@1 31 import java.util.Map;
duke@1 32 import java.util.MissingResourceException;
duke@1 33 import java.util.ResourceBundle;
duke@1 34
duke@1 35 import javax.tools.Diagnostic;
duke@1 36 import javax.tools.FileObject;
duke@1 37 import javax.tools.JavaFileObject;
duke@1 38
duke@1 39 import com.sun.tools.javac.tree.JCTree;
duke@1 40
duke@1 41 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*;
duke@1 42
duke@1 43 /** An abstraction of a diagnostic message generated by the compiler.
duke@1 44 *
duke@1 45 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
duke@1 46 * you write code that depends on this, you do so at your own risk.
duke@1 47 * This code and its internal interfaces are subject to change or
duke@1 48 * deletion without notice.</b>
duke@1 49 */
duke@1 50 public class JCDiagnostic implements Diagnostic<JavaFileObject> {
duke@1 51 /** A factory for creating diagnostic objects. */
duke@1 52 public static class Factory {
duke@1 53 /** The context key for the diagnostic factory. */
duke@1 54 protected static final Context.Key<JCDiagnostic.Factory> diagnosticFactoryKey =
duke@1 55 new Context.Key<JCDiagnostic.Factory>();
duke@1 56
duke@1 57 /** Get the Factory instance for this context. */
duke@1 58 public static Factory instance(Context context) {
duke@1 59 Factory instance = context.get(diagnosticFactoryKey);
duke@1 60 if (instance == null)
duke@1 61 instance = new Factory(context);
duke@1 62 return instance;
duke@1 63 }
duke@1 64
duke@1 65 final Messages messages;
duke@1 66 final String prefix;
duke@1 67
duke@1 68 /** Create a new diagnostic factory. */
duke@1 69 protected Factory(Context context) {
duke@1 70 context.put(diagnosticFactoryKey, this);
duke@1 71 messages = Messages.instance(context);
duke@1 72 prefix = "compiler";
duke@1 73 }
duke@1 74
duke@1 75 /** Create a new diagnostic factory. */
duke@1 76 public Factory(Messages messages, String prefix) {
duke@1 77 this.messages = messages;
duke@1 78 this.prefix = prefix;
duke@1 79 }
duke@1 80
duke@1 81 /**
duke@1 82 * Create an error diagnostic.
duke@1 83 * @param source The source of the compilation unit, if any, in which to report the error.
duke@1 84 * @param pos The source position at which to report the error.
duke@1 85 * @param key The key for the localized error message.
duke@1 86 * @param args Fields of the error message.
duke@1 87 */
duke@1 88 public JCDiagnostic error(
duke@1 89 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
duke@1 90 return new JCDiagnostic(messages, ERROR, true, source, pos, qualify(ERROR, key), args);
duke@1 91 }
duke@1 92
duke@1 93 /**
duke@1 94 * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
duke@1 95 * @param source The source of the compilation unit, if any, in which to report the warning.
duke@1 96 * @param pos The source position at which to report the warning.
duke@1 97 * @param key The key for the localized error message.
duke@1 98 * @param args Fields of the error message.
duke@1 99 * @see MandatoryWarningHandler
duke@1 100 */
duke@1 101 public JCDiagnostic mandatoryWarning(
duke@1 102 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
duke@1 103 return new JCDiagnostic(messages, WARNING, true, source, pos, qualify(WARNING, key), args);
duke@1 104 }
duke@1 105
duke@1 106 /**
duke@1 107 * Create a warning diagnostic.
duke@1 108 * @param source The source of the compilation unit, if any, in which to report the warning.
duke@1 109 * @param pos The source position at which to report the warning.
duke@1 110 * @param key The key for the localized error message.
duke@1 111 * @param args Fields of the error message.
duke@1 112 */
duke@1 113 public JCDiagnostic warning(
duke@1 114 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
duke@1 115 return new JCDiagnostic(messages, WARNING, false, source, pos, qualify(WARNING, key), args);
duke@1 116 }
duke@1 117
duke@1 118 /**
duke@1 119 * Create a note diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
duke@1 120 * @param key The key for the localized error message.
duke@1 121 * @param args Fields of the error message.
duke@1 122 * @see MandatoryWarningHandler
duke@1 123 */
duke@1 124 public JCDiagnostic mandatoryNote(DiagnosticSource source, String key, Object... args) {
duke@1 125 return new JCDiagnostic(messages, NOTE, true, source, null, qualify(NOTE, key), args);
duke@1 126 }
duke@1 127
duke@1 128 /**
duke@1 129 * Create a note diagnostic.
duke@1 130 * @param key The key for the localized error message.
duke@1 131 * @param args Fields of the error message.
duke@1 132 */
duke@1 133 public JCDiagnostic note(String key, Object... args) {
duke@1 134 return note(null, null, key, args);
duke@1 135 }
duke@1 136
duke@1 137 /**
duke@1 138 * Create a note diagnostic.
duke@1 139 * @param source The source of the compilation unit, if any, in which to report the note.
duke@1 140 * @param pos The source position at which to report the note.
duke@1 141 * @param key The key for the localized error message.
duke@1 142 * @param args Fields of the error message.
duke@1 143 */
duke@1 144 public JCDiagnostic note(
duke@1 145 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
duke@1 146 return new JCDiagnostic(messages, NOTE, false, source, pos, qualify(NOTE, key), args);
duke@1 147 }
duke@1 148
duke@1 149 /**
duke@1 150 * Create a fragment diagnostic, for use as an argument in other diagnostics
duke@1 151 * @param key The key for the localized error message.
duke@1 152 * @param args Fields of the error message.
duke@1 153 */
duke@1 154 public JCDiagnostic fragment(String key, Object... args) {
duke@1 155 return new JCDiagnostic(messages, FRAGMENT, false, null, null, qualify(FRAGMENT, key), args);
duke@1 156 }
duke@1 157
duke@1 158 protected String qualify(DiagnosticType t, String key) {
duke@1 159 return prefix + "." + t.key + "." + key;
duke@1 160 }
duke@1 161 }
duke@1 162
duke@1 163
duke@1 164
duke@1 165 /**
duke@1 166 * Create a fragment diagnostic, for use as an argument in other diagnostics
duke@1 167 * @param key The key for the localized error message.
duke@1 168 * @param args Fields of the error message.
duke@1 169 */
duke@1 170 // should be deprecated
duke@1 171 public static JCDiagnostic fragment(String key, Object... args) {
duke@1 172 return new JCDiagnostic(Messages.getDefaultMessages(),
duke@1 173 FRAGMENT,
duke@1 174 false,
duke@1 175 null,
duke@1 176 null,
duke@1 177 "compiler." + FRAGMENT.key + "." + key,
duke@1 178 args);
duke@1 179 }
duke@1 180
duke@1 181 /**
duke@1 182 * A simple abstraction of a source file, as needed for use in a diagnostic message.
duke@1 183 */
duke@1 184 // Note: This class may be superceded by a more general abstraction
duke@1 185 public interface DiagnosticSource {
duke@1 186 JavaFileObject getFile();
duke@1 187 CharSequence getName();
duke@1 188 int getLineNumber(int pos);
duke@1 189 int getColumnNumber(int pos);
duke@1 190 Map<JCTree, Integer> getEndPosTable();
duke@1 191 };
duke@1 192
duke@1 193 /**
duke@1 194 * A DiagnosticType defines the type of the diagnostic.
duke@1 195 **/
duke@1 196 public enum DiagnosticType {
duke@1 197 /** A fragment of an enclosing diagnostic. */
duke@1 198 FRAGMENT("misc"),
duke@1 199 /** A note: similar to, but less serious than, a warning. */
duke@1 200 NOTE("note"),
duke@1 201 /** A warning. */
duke@1 202 WARNING("warn"),
duke@1 203 /** An error. */
duke@1 204 ERROR("err");
duke@1 205
duke@1 206 final String key;
duke@1 207
duke@1 208 /** Create a DiagnosticType.
duke@1 209 * @param key A string used to create the resource key for the diagnostic.
duke@1 210 */
duke@1 211 DiagnosticType(String key) {
duke@1 212 this.key = key;
duke@1 213 }
duke@1 214 };
duke@1 215
duke@1 216 /**
duke@1 217 * A DiagnosticPosition provides information about the positions in a file
duke@1 218 * that gave rise to a diagnostic. It always defines a "preferred" position
duke@1 219 * that most accurately defines the location of the diagnostic, it may also
duke@1 220 * provide a related tree node that spans that location.
duke@1 221 */
duke@1 222 public static interface DiagnosticPosition {
duke@1 223 /** Gets the tree node, if any, to which the diagnostic applies. */
duke@1 224 JCTree getTree();
duke@1 225 /** If there is a tree node, get the start position of the tree node.
duke@1 226 * Otherwise, just returns the same as getPreferredPosition(). */
duke@1 227 int getStartPosition();
duke@1 228 /** Get the position within the file that most accurately defines the
duke@1 229 * location for the diagnostic. */
duke@1 230 int getPreferredPosition();
duke@1 231 /** If there is a tree node, and if endPositions are available, get
duke@1 232 * the end position of the tree node. Otherwise, just returns the
duke@1 233 * same as getPreferredPosition(). */
duke@1 234 int getEndPosition(Map<JCTree, Integer> endPosTable);
duke@1 235 }
duke@1 236
duke@1 237 /**
duke@1 238 * A DiagnosticPosition that simply identifies a position, but no related
duke@1 239 * tree node, as the location for a diagnostic. Used for scanner and parser
duke@1 240 * diagnostics. */
duke@1 241 public static class SimpleDiagnosticPosition implements DiagnosticPosition {
duke@1 242 public SimpleDiagnosticPosition(int pos) {
duke@1 243 this.pos = pos;
duke@1 244 }
duke@1 245
duke@1 246 public JCTree getTree() {
duke@1 247 return null;
duke@1 248 }
duke@1 249
duke@1 250 public int getStartPosition() {
duke@1 251 return pos;
duke@1 252 }
duke@1 253
duke@1 254 public int getPreferredPosition() {
duke@1 255 return pos;
duke@1 256 }
duke@1 257
duke@1 258 public int getEndPosition(Map<JCTree, Integer> endPosTable) {
duke@1 259 return pos;
duke@1 260 }
duke@1 261
duke@1 262 private final int pos;
duke@1 263 }
duke@1 264
duke@1 265 private final Messages messages;
duke@1 266 private final DiagnosticType type;
duke@1 267 private final DiagnosticSource source;
duke@1 268 private final DiagnosticPosition position;
duke@1 269 private final int line;
duke@1 270 private final int column;
duke@1 271 private final String key;
duke@1 272 private final Object[] args;
duke@1 273 private boolean mandatory;
duke@1 274
duke@1 275 /**
duke@1 276 * Create a diagnostic object.
duke@1 277 * @param messages the resource for localized messages
duke@1 278 * @param dt the type of diagnostic
duke@1 279 * @param name the name of the source file, or null if none.
duke@1 280 * @param pos the character offset within the source file, if given.
duke@1 281 * @param key a resource key to identify the text of the diagnostic
duke@1 282 * @param args arguments to be included in the text of the diagnostic
duke@1 283 */
duke@1 284 protected JCDiagnostic(Messages messages,
duke@1 285 DiagnosticType dt,
duke@1 286 boolean mandatory,
duke@1 287 DiagnosticSource source,
duke@1 288 DiagnosticPosition pos,
duke@1 289 String key,
duke@1 290 Object ... args) {
duke@1 291 if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS)
duke@1 292 throw new IllegalArgumentException();
duke@1 293
duke@1 294 this.messages = messages;
duke@1 295 this.type = dt;
duke@1 296 this.mandatory = mandatory;
duke@1 297 this.source = source;
duke@1 298 this.position = pos;
duke@1 299 this.key = key;
duke@1 300 this.args = args;
duke@1 301
duke@1 302 int n = (pos == null ? Position.NOPOS : pos.getPreferredPosition());
duke@1 303 if (n == Position.NOPOS || source == null)
duke@1 304 line = column = -1;
duke@1 305 else {
duke@1 306 line = source.getLineNumber(n);
duke@1 307 column = source.getColumnNumber(n);
duke@1 308 }
duke@1 309 }
duke@1 310
duke@1 311 /**
duke@1 312 * Get the type of this diagnostic.
duke@1 313 * @return the type of this diagnostic
duke@1 314 */
duke@1 315 public DiagnosticType getType() {
duke@1 316 return type;
duke@1 317 }
duke@1 318
duke@1 319 /**
duke@1 320 * Check whether or not this diagnostic is required to be shown.
duke@1 321 * @return true if this diagnostic is required to be shown.
duke@1 322 */
duke@1 323 public boolean isMandatory() {
duke@1 324 return mandatory;
duke@1 325 }
duke@1 326
duke@1 327 /**
duke@1 328 * Get the name of the source file referred to by this diagnostic.
duke@1 329 * @return the name of the source referred to with this diagnostic, or null if none
duke@1 330 */
duke@1 331 public JavaFileObject getSource() {
duke@1 332 if (source == null)
duke@1 333 return null;
duke@1 334 else
duke@1 335 return source.getFile();
duke@1 336 }
duke@1 337
duke@1 338 /**
duke@1 339 * Get the name of the source file referred to by this diagnostic.
duke@1 340 * @return the name of the source referred to with this diagnostic, or null if none
duke@1 341 */
duke@1 342 public String getSourceName() {
duke@1 343 JavaFileObject s = getSource();
duke@1 344 return s == null ? null : JavacFileManager.getJavacFileName(s);
duke@1 345 }
duke@1 346
duke@1 347 /**
duke@1 348 * Get the source referred to by this diagnostic.
duke@1 349 * @return the source referred to with this diagnostic, or null if none
duke@1 350 */
duke@1 351 public DiagnosticSource getDiagnosticSource() {
duke@1 352 return source;
duke@1 353 }
duke@1 354
duke@1 355 protected int getIntStartPosition() {
duke@1 356 return (position == null ? Position.NOPOS : position.getStartPosition());
duke@1 357 }
duke@1 358
duke@1 359 protected int getIntPosition() {
duke@1 360 return (position == null ? Position.NOPOS : position.getPreferredPosition());
duke@1 361 }
duke@1 362
duke@1 363 protected int getIntEndPosition() {
duke@1 364 return (position == null ? Position.NOPOS : position.getEndPosition(source.getEndPosTable()));
duke@1 365 }
duke@1 366
duke@1 367 public long getStartPosition() {
duke@1 368 return getIntStartPosition();
duke@1 369 }
duke@1 370
duke@1 371 public long getPosition() {
duke@1 372 return getIntPosition();
duke@1 373 }
duke@1 374
duke@1 375 public long getEndPosition() {
duke@1 376 return getIntEndPosition();
duke@1 377 }
duke@1 378
duke@1 379 /**
duke@1 380 * Get the line number within the source referred to by this diagnostic.
duke@1 381 * @return the line number within the source referred to by this diagnostic
duke@1 382 */
duke@1 383 public long getLineNumber() {
duke@1 384 return line;
duke@1 385 }
duke@1 386
duke@1 387 /**
duke@1 388 * Get the column number within the line of source referred to by this diagnostic.
duke@1 389 * @return the column number within the line of source referred to by this diagnostic
duke@1 390 */
duke@1 391 public long getColumnNumber() {
duke@1 392 return column;
duke@1 393 }
duke@1 394
duke@1 395 /**
duke@1 396 * Get the arguments to be included in the text of the diagnostic.
duke@1 397 * @return the arguments to be included in the text of the diagnostic
duke@1 398 */
duke@1 399 public Object[] getArgs() {
duke@1 400 return args;
duke@1 401 }
duke@1 402
duke@1 403 /**
duke@1 404 * Get the prefix string associated with this type of diagnostic.
duke@1 405 * @return the prefix string associated with this type of diagnostic
duke@1 406 */
duke@1 407 public String getPrefix() {
duke@1 408 return getPrefix(type);
duke@1 409 }
duke@1 410
duke@1 411 /**
duke@1 412 * Get the prefix string associated with a particular type of diagnostic.
duke@1 413 * @return the prefix string associated with a particular type of diagnostic
duke@1 414 */
duke@1 415 public String getPrefix(DiagnosticType dt) {
duke@1 416 switch (dt) {
duke@1 417 case FRAGMENT: return "";
duke@1 418 case NOTE: return getLocalizedString("compiler.note.note");
duke@1 419 case WARNING: return getLocalizedString("compiler.warn.warning");
duke@1 420 case ERROR: return getLocalizedString("compiler.err.error");
duke@1 421 default:
duke@1 422 throw new AssertionError("Unknown diagnostic type: " + dt);
duke@1 423 }
duke@1 424 }
duke@1 425
duke@1 426 /**
duke@1 427 * Return the standard presentation of this diagnostic.
duke@1 428 */
duke@1 429 public String toString() {
duke@1 430 if (defaultFormatter == null) {
duke@1 431 defaultFormatter =
duke@1 432 new DiagnosticFormatter();
duke@1 433 }
duke@1 434 return defaultFormatter.format(this);
duke@1 435 }
duke@1 436
duke@1 437 private static DiagnosticFormatter defaultFormatter;
duke@1 438
duke@1 439 private static final String messageBundleName =
duke@1 440 "com.sun.tools.javac.resources.compiler";
duke@1 441
duke@1 442 private String getLocalizedString(String key, Object... args) {
duke@1 443 String[] strings = new String[args.length];
duke@1 444 for (int i = 0; i < strings.length; i++) {
duke@1 445 Object arg = args[i];
duke@1 446 if (arg == null)
duke@1 447 strings[i] = null;
duke@1 448 else if (arg instanceof JCDiagnostic)
duke@1 449 strings[i] = ((JCDiagnostic) arg).getMessage(null);
duke@1 450 else
duke@1 451 strings[i] = arg.toString();
duke@1 452 }
duke@1 453
duke@1 454 return messages.getLocalizedString(key, (Object[]) strings);
duke@1 455 }
duke@1 456
duke@1 457 // Methods for javax.tools.Diagnostic
duke@1 458
duke@1 459 public Diagnostic.Kind getKind() {
duke@1 460 switch (type) {
duke@1 461 case NOTE:
duke@1 462 return Diagnostic.Kind.NOTE;
duke@1 463 case WARNING:
duke@1 464 return mandatory ? Diagnostic.Kind.MANDATORY_WARNING
duke@1 465 : Diagnostic.Kind.WARNING;
duke@1 466 case ERROR:
duke@1 467 return Diagnostic.Kind.ERROR;
duke@1 468 default:
duke@1 469 return Diagnostic.Kind.OTHER;
duke@1 470 }
duke@1 471 }
duke@1 472
duke@1 473 public String getCode() {
duke@1 474 return key;
duke@1 475 }
duke@1 476
duke@1 477 public String getMessage(Locale locale) {
duke@1 478 // RFE 6406133: JCDiagnostic.getMessage ignores locale argument
duke@1 479 return getLocalizedString(key, args);
duke@1 480 }
duke@1 481
duke@1 482 }

mercurial