| 1 | /* | 
| 2 |  * Copyright 1999-2006 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 |  */ | 
| 25 |   | 
| 26 | package com.sun.tools.javac.util; | 
| 27 |   | 
| 28 | import java.io.*; | 
| 29 | import java.nio.CharBuffer; | 
| 30 | import java.util.HashMap; | 
| 31 | import java.util.HashSet; | 
| 32 | import java.util.Map; | 
| 33 | import java.util.Set; | 
| 34 | import javax.tools.DiagnosticListener; | 
| 35 | import javax.tools.JavaFileObject; | 
| 36 | import com.sun.tools.javac.code.Source; | 
| 37 | import com.sun.tools.javac.tree.JCTree; | 
| 38 | import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; | 
| 39 | import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; | 
| 40 | import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition; | 
| 41 | import static com.sun.tools.javac.util.LayoutCharacters.*; | 
| 42 |   | 
| 43 | /** A class for error logs. Reports errors and warnings, and | 
| 44 |  *  keeps track of error numbers and positions. | 
| 45 |  * | 
| 46 |  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If | 
| 47 |  *  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 |  */ | 
| 51 | public class Log { | 
| 52 |     /** The context key for the log. */ | 
| 53 |     public static final Context.Key<Log> logKey | 
| 54 |         = new Context.Key<Log>(); | 
| 55 |   | 
| 56 |     /** The context key for the output PrintWriter. */ | 
| 57 |     public static final Context.Key<PrintWriter> outKey = | 
| 58 |         new Context.Key<PrintWriter>(); | 
| 59 |   | 
| 60 |     //@Deprecated | 
| 61 |     public final PrintWriter errWriter; | 
| 62 |   | 
| 63 |     //@Deprecated | 
| 64 |     public final PrintWriter warnWriter; | 
| 65 |   | 
| 66 |     //@Deprecated | 
| 67 |     public final PrintWriter noticeWriter; | 
| 68 |   | 
| 69 |     /** The maximum number of errors/warnings that are reported. | 
| 70 |      */ | 
| 71 |     public final int MaxErrors; | 
| 72 |     public final int MaxWarnings; | 
| 73 |   | 
| 74 |     /** Whether or not to display the line of source containing a diagnostic. | 
| 75 |      */ | 
| 76 |     private final boolean showSourceLine; | 
| 77 |   | 
| 78 |     /** Switch: prompt user on each error. | 
| 79 |      */ | 
| 80 |     public boolean promptOnError; | 
| 81 |   | 
| 82 |     /** Switch: emit warning messages. | 
| 83 |      */ | 
| 84 |     public boolean emitWarnings; | 
| 85 |   | 
| 86 |     /** Enforce mandatory warnings. | 
| 87 |      */ | 
| 88 |     private boolean enforceMandatoryWarnings; | 
| 89 |   | 
| 90 |     /** Print stack trace on errors? | 
| 91 |      */ | 
| 92 |     public boolean dumpOnError; | 
| 93 |   | 
| 94 |     /** Print multiple errors for same source locations. | 
| 95 |      */ | 
| 96 |     public boolean multipleErrors; | 
| 97 |   | 
| 98 |     /** | 
| 99 |      * Diagnostic listener, if provided through programmatic | 
| 100 |      * interface to javac (JSR 199). | 
| 101 |      */ | 
| 102 |     protected DiagnosticListener<? super JavaFileObject> diagListener; | 
| 103 |     /** | 
| 104 |      * Formatter for diagnostics | 
| 105 |      */ | 
| 106 |     private DiagnosticFormatter diagFormatter; | 
| 107 |   | 
| 108 |     /** | 
| 109 |      * Factory for diagnostics | 
| 110 |      */ | 
| 111 |     private JCDiagnostic.Factory diags; | 
| 112 |   | 
| 113 |   | 
| 114 |     /** Construct a log with given I/O redirections. | 
| 115 |      */ | 
| 116 |     @Deprecated | 
| 117 |     protected Log(Context context, PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter) { | 
| 118 |         context.put(logKey, this); | 
| 119 |         this.errWriter = errWriter; | 
| 120 |         this.warnWriter = warnWriter; | 
| 121 |         this.noticeWriter = noticeWriter; | 
| 122 |   | 
| 123 |         this.diags = JCDiagnostic.Factory.instance(context); | 
| 124 |   | 
| 125 |         Options options = Options.instance(context); | 
| 126 |         this.dumpOnError = options.get("-doe") != null; | 
| 127 |         this.promptOnError = options.get("-prompt") != null; | 
| 128 |         this.emitWarnings = options.get("-Xlint:none") == null; | 
| 129 |         this.MaxErrors = getIntOption(options, "-Xmaxerrs", 100); | 
| 130 |         this.MaxWarnings = getIntOption(options, "-Xmaxwarns", 100); | 
| 131 |         this.showSourceLine = options.get("rawDiagnostics") == null; | 
| 132 |   | 
| 133 |         this.diagFormatter = DiagnosticFormatter.instance(context); | 
| 134 |         @SuppressWarnings("unchecked") // FIXME | 
| 135 |         DiagnosticListener<? super JavaFileObject> diagListener = | 
| 136 |             context.get(DiagnosticListener.class); | 
| 137 |         this.diagListener = diagListener; | 
| 138 |   | 
| 139 |         Source source = Source.instance(context); | 
| 140 |         this.enforceMandatoryWarnings = source.enforceMandatoryWarnings(); | 
| 141 |     } | 
| 142 |     // where | 
| 143 |         private int getIntOption(Options options, String optionName, int defaultValue) { | 
| 144 |             String s = options.get(optionName); | 
| 145 |             try { | 
| 146 |                 if (s != null) return Integer.parseInt(s); | 
| 147 |             } catch (NumberFormatException e) { | 
| 148 |                 // silently ignore ill-formed numbers | 
| 149 |             } | 
| 150 |             return defaultValue; | 
| 151 |         } | 
| 152 |   | 
| 153 |     /** The default writer for diagnostics | 
| 154 |      */ | 
| 155 |     static final PrintWriter defaultWriter(Context context) { | 
| 156 |         PrintWriter result = context.get(outKey); | 
| 157 |         if (result == null) | 
| 158 |             context.put(outKey, result = new PrintWriter(System.err)); | 
| 159 |         return result; | 
| 160 |     } | 
| 161 |   | 
| 162 |     /** Construct a log with default settings. | 
| 163 |      */ | 
| 164 |     protected Log(Context context) { | 
| 165 |         this(context, defaultWriter(context)); | 
| 166 |     } | 
| 167 |   | 
| 168 |     /** Construct a log with all output redirected. | 
| 169 |      */ | 
| 170 |     protected Log(Context context, PrintWriter defaultWriter) { | 
| 171 |         this(context, defaultWriter, defaultWriter, defaultWriter); | 
| 172 |     } | 
| 173 |   | 
| 174 |     /** Get the Log instance for this context. */ | 
| 175 |     public static Log instance(Context context) { | 
| 176 |         Log instance = context.get(logKey); | 
| 177 |         if (instance == null) | 
| 178 |             instance = new Log(context); | 
| 179 |         return instance; | 
| 180 |     } | 
| 181 |   | 
| 182 |     /** The file that's currently translated. | 
| 183 |      */ | 
| 184 |     protected JCDiagnostic.DiagnosticSource source; | 
| 185 |   | 
| 186 |     /** The number of errors encountered so far. | 
| 187 |      */ | 
| 188 |     public int nerrors = 0; | 
| 189 |   | 
| 190 |     /** The number of warnings encountered so far. | 
| 191 |      */ | 
| 192 |     public int nwarnings = 0; | 
| 193 |   | 
| 194 |     /** A set of all errors generated so far. This is used to avoid printing an | 
| 195 |      *  error message more than once. For each error, a pair consisting of the | 
| 196 |      *  source file name and source code position of the error is added to the set. | 
| 197 |      */ | 
| 198 |     private Set<Pair<JavaFileObject, Integer>> recorded = new HashSet<Pair<JavaFileObject,Integer>>(); | 
| 199 |   | 
| 200 |     private Map<JavaFileObject, Map<JCTree, Integer>> endPosTables; | 
| 201 |   | 
| 202 |     /** The buffer containing the file that's currently translated. | 
| 203 |      */ | 
| 204 |     private char[] buf = null; | 
| 205 |   | 
| 206 |     /** The position in the buffer at which last error was reported | 
| 207 |      */ | 
| 208 |     private int bp; | 
| 209 |   | 
| 210 |     /** number of the current source line; first line is 1 | 
| 211 |      */ | 
| 212 |     private int line; | 
| 213 |   | 
| 214 |     /**  buffer index of the first character of the current source line | 
| 215 |      */ | 
| 216 |     private int lineStart; | 
| 217 |   | 
| 218 |     public boolean hasDiagnosticListener() { | 
| 219 |         return diagListener != null; | 
| 220 |     } | 
| 221 |   | 
| 222 |     public void setEndPosTable(JavaFileObject name, Map<JCTree, Integer> table) { | 
| 223 |         if (endPosTables == null) | 
| 224 |             endPosTables = new HashMap<JavaFileObject, Map<JCTree, Integer>>(); | 
| 225 |         endPosTables.put(name, table); | 
| 226 |     } | 
| 227 |   | 
| 228 |     /** Re-assign source, returning previous setting. | 
| 229 |      */ | 
| 230 |     public JavaFileObject useSource(final JavaFileObject name) { | 
| 231 |         JavaFileObject prev = currentSource(); | 
| 232 |         if (name != prev) { | 
| 233 |             source = new JCDiagnostic.DiagnosticSource() { | 
| 234 |                     public JavaFileObject getFile() { | 
| 235 |                         return name; | 
| 236 |                     } | 
| 237 |                     public CharSequence getName() { | 
| 238 |                         return JavacFileManager.getJavacBaseFileName(getFile()); | 
| 239 |                     } | 
| 240 |                     public int getLineNumber(int pos) { | 
| 241 |                         return Log.this.getLineNumber(pos); | 
| 242 |                     } | 
| 243 |                     public int getColumnNumber(int pos) { | 
| 244 |                         return Log.this.getColumnNumber(pos); | 
| 245 |                     } | 
| 246 |                     public Map<JCTree, Integer> getEndPosTable() { | 
| 247 |                         return (endPosTables == null ? null : endPosTables.get(name)); | 
| 248 |                     } | 
| 249 |                 }; | 
| 250 |             buf = null; | 
| 251 |         } | 
| 252 |         return prev; | 
| 253 |     } | 
| 254 |   | 
| 255 |     /** Re-assign source buffer for existing source name. | 
| 256 |      */ | 
| 257 |     protected void setBuf(char[] newBuf) { | 
| 258 |         buf = newBuf; | 
| 259 |         bp = 0; | 
| 260 |         lineStart = 0; | 
| 261 |         line = 1; | 
| 262 |     } | 
| 263 |   | 
| 264 |     protected char[] getBuf() { | 
| 265 |         return buf; | 
| 266 |     } | 
| 267 |   | 
| 268 |     /** Return current source name. | 
| 269 |      */ | 
| 270 |     public JavaFileObject currentSource() { | 
| 271 |         return source == null ? null : source.getFile(); | 
| 272 |     } | 
| 273 |   | 
| 274 |     /** Flush the logs | 
| 275 |      */ | 
| 276 |     public void flush() { | 
| 277 |         errWriter.flush(); | 
| 278 |         warnWriter.flush(); | 
| 279 |         noticeWriter.flush(); | 
| 280 |     } | 
| 281 |   | 
| 282 |     /** Returns true if an error needs to be reported for a given | 
| 283 |      * source name and pos. | 
| 284 |      */ | 
| 285 |     protected boolean shouldReport(JavaFileObject file, int pos) { | 
| 286 |         if (multipleErrors || file == null) | 
| 287 |             return true; | 
| 288 |   | 
| 289 |         Pair<JavaFileObject,Integer> coords = new Pair<JavaFileObject,Integer>(file, pos); | 
| 290 |         boolean shouldReport = !recorded.contains(coords); | 
| 291 |         if (shouldReport) | 
| 292 |             recorded.add(coords); | 
| 293 |         return shouldReport; | 
| 294 |     } | 
| 295 |   | 
| 296 |     /** Prompt user after an error. | 
| 297 |      */ | 
| 298 |     public void prompt() { | 
| 299 |         if (promptOnError) { | 
| 300 |             System.err.println(getLocalizedString("resume.abort")); | 
| 301 |             char ch; | 
| 302 |             try { | 
| 303 |                 while (true) { | 
| 304 |                     switch (System.in.read()) { | 
| 305 |                     case 'a': case 'A': | 
| 306 |                         System.exit(-1); | 
| 307 |                         return; | 
| 308 |                     case 'r': case 'R': | 
| 309 |                         return; | 
| 310 |                     case 'x': case 'X': | 
| 311 |                         throw new AssertionError("user abort"); | 
| 312 |                     default: | 
| 313 |                     } | 
| 314 |                 } | 
| 315 |             } catch (IOException e) {} | 
| 316 |         } | 
| 317 |     } | 
| 318 |   | 
| 319 |     /** Print the faulty source code line and point to the error. | 
| 320 |      *  @param pos   Buffer index of the error position, must be on current line | 
| 321 |      */ | 
| 322 |     private void printErrLine(int pos, PrintWriter writer) { | 
| 323 |         if (!findLine(pos)) | 
| 324 |             return; | 
| 325 |   | 
| 326 |         int lineEnd = lineStart; | 
| 327 |         while (lineEnd < buf.length && buf[lineEnd] != CR && buf[lineEnd] != LF) | 
| 328 |             lineEnd++; | 
| 329 |         if (lineEnd - lineStart == 0) | 
| 330 |             return; | 
| 331 |         printLines(writer, new String(buf, lineStart, lineEnd - lineStart)); | 
| 332 |         for (bp = lineStart; bp < pos; bp++) { | 
| 333 |             writer.print((buf[bp] == '\t') ? "\t" : " "); | 
| 334 |         } | 
| 335 |         writer.println("^"); | 
| 336 |         writer.flush(); | 
| 337 |     } | 
| 338 |   | 
| 339 |     protected static char[] getCharContent(JavaFileObject fileObject) throws IOException { | 
| 340 |         CharSequence cs = fileObject.getCharContent(true); | 
| 341 |         if (cs instanceof CharBuffer) { | 
| 342 |             return JavacFileManager.toArray((CharBuffer)cs); | 
| 343 |         } else { | 
| 344 |             return cs.toString().toCharArray(); | 
| 345 |         } | 
| 346 |     } | 
| 347 |   | 
| 348 |     /** Find the line in the buffer that contains the current position | 
| 349 |      * @param pos      Character offset into the buffer | 
| 350 |      */ | 
| 351 |     private boolean findLine(int pos) { | 
| 352 |         if (pos == Position.NOPOS || currentSource() == null) | 
| 353 |             return false; | 
| 354 |         try { | 
| 355 |             if (buf == null) { | 
| 356 |                 buf = getCharContent(currentSource()); | 
| 357 |                 lineStart = 0; | 
| 358 |                 line = 1; | 
| 359 |             } else if (lineStart > pos) { // messages don't come in order | 
| 360 |                 lineStart = 0; | 
| 361 |                 line = 1; | 
| 362 |             } | 
| 363 |             bp = lineStart; | 
| 364 |             while (bp < buf.length && bp < pos) { | 
| 365 |                 switch (buf[bp++]) { | 
| 366 |                 case CR: | 
| 367 |                     if (bp < buf.length && buf[bp] == LF) bp++; | 
| 368 |                     line++; | 
| 369 |                     lineStart = bp; | 
| 370 |                     break; | 
| 371 |                 case LF: | 
| 372 |                     line++; | 
| 373 |                     lineStart = bp; | 
| 374 |                     break; | 
| 375 |                 } | 
| 376 |             } | 
| 377 |             return bp <= buf.length; | 
| 378 |         } catch (IOException e) { | 
| 379 |             //e.printStackTrace(); | 
| 380 |             // FIXME: include e.getLocalizedMessage() in error message | 
| 381 |             printLines(errWriter, getLocalizedString("source.unavailable")); | 
| 382 |             errWriter.flush(); | 
| 383 |             buf = new char[0]; | 
| 384 |         } | 
| 385 |         return false; | 
| 386 |     } | 
| 387 |   | 
| 388 |     /** Print the text of a message, translating newlines appropriately | 
| 389 |      *  for the platform. | 
| 390 |      */ | 
| 391 |     public static void printLines(PrintWriter writer, String msg) { | 
| 392 |         int nl; | 
| 393 |         while ((nl = msg.indexOf('\n')) != -1) { | 
| 394 |             writer.println(msg.substring(0, nl)); | 
| 395 |             msg = msg.substring(nl+1); | 
| 396 |         } | 
| 397 |         if (msg.length() != 0) writer.println(msg); | 
| 398 |     } | 
| 399 |   | 
| 400 |     /** Report an error, unless another error was already reported at same | 
| 401 |      *  source position. | 
| 402 |      *  @param key    The key for the localized error message. | 
| 403 |      *  @param args   Fields of the error message. | 
| 404 |      */ | 
| 405 |     public void error(String key, Object ... args) { | 
| 406 |         report(diags.error(source, null, key, args)); | 
| 407 |     } | 
| 408 |   | 
| 409 |     /** Report an error, unless another error was already reported at same | 
| 410 |      *  source position. | 
| 411 |      *  @param pos    The source position at which to report the error. | 
| 412 |      *  @param key    The key for the localized error message. | 
| 413 |      *  @param args   Fields of the error message. | 
| 414 |      */ | 
| 415 |     public void error(DiagnosticPosition pos, String key, Object ... args) { | 
| 416 |         report(diags.error(source, pos, key, args)); | 
| 417 |     } | 
| 418 |   | 
| 419 |     /** Report an error, unless another error was already reported at same | 
| 420 |      *  source position. | 
| 421 |      *  @param pos    The source position at which to report the error. | 
| 422 |      *  @param key    The key for the localized error message. | 
| 423 |      *  @param args   Fields of the error message. | 
| 424 |      */ | 
| 425 |     public void error(int pos, String key, Object ... args) { | 
| 426 |         report(diags.error(source, wrap(pos), key, args)); | 
| 427 |     } | 
| 428 |   | 
| 429 |     /** Report a warning, unless suppressed by the  -nowarn option or the | 
| 430 |      *  maximum number of warnings has been reached. | 
| 431 |      *  @param pos    The source position at which to report the warning. | 
| 432 |      *  @param key    The key for the localized warning message. | 
| 433 |      *  @param args   Fields of the warning message. | 
| 434 |      */ | 
| 435 |     public void warning(String key, Object ... args) { | 
| 436 |         report(diags.warning(source, null, key, args)); | 
| 437 |     } | 
| 438 |   | 
| 439 |     /** Report a warning, unless suppressed by the  -nowarn option or the | 
| 440 |      *  maximum number of warnings has been reached. | 
| 441 |      *  @param pos    The source position at which to report the warning. | 
| 442 |      *  @param key    The key for the localized warning message. | 
| 443 |      *  @param args   Fields of the warning message. | 
| 444 |      */ | 
| 445 |     public void warning(DiagnosticPosition pos, String key, Object ... args) { | 
| 446 |         report(diags.warning(source, pos, key, args)); | 
| 447 |     } | 
| 448 |   | 
| 449 |     /** Report a warning, unless suppressed by the  -nowarn option or the | 
| 450 |      *  maximum number of warnings has been reached. | 
| 451 |      *  @param pos    The source position at which to report the warning. | 
| 452 |      *  @param key    The key for the localized warning message. | 
| 453 |      *  @param args   Fields of the warning message. | 
| 454 |      */ | 
| 455 |     public void warning(int pos, String key, Object ... args) { | 
| 456 |         report(diags.warning(source, wrap(pos), key, args)); | 
| 457 |     } | 
| 458 |   | 
| 459 |     /** Report a warning. | 
| 460 |      *  @param pos    The source position at which to report the warning. | 
| 461 |      *  @param key    The key for the localized warning message. | 
| 462 |      *  @param args   Fields of the warning message. | 
| 463 |      */ | 
| 464 |     public void mandatoryWarning(DiagnosticPosition pos, String key, Object ... args) { | 
| 465 |         if (enforceMandatoryWarnings) | 
| 466 |             report(diags.mandatoryWarning(source, pos, key, args)); | 
| 467 |         else | 
| 468 |             report(diags.warning(source, pos, key, args)); | 
| 469 |     } | 
| 470 |   | 
| 471 |     /** Report a warning that cannot be suppressed. | 
| 472 |      *  @param pos    The source position at which to report the warning. | 
| 473 |      *  @param key    The key for the localized warning message. | 
| 474 |      *  @param args   Fields of the warning message. | 
| 475 |      */ | 
| 476 |     public void strictWarning(DiagnosticPosition pos, String key, Object ... args) { | 
| 477 |         writeDiagnostic(diags.warning(source, pos, key, args)); | 
| 478 |         nwarnings++; | 
| 479 |     } | 
| 480 |   | 
| 481 |     /** Provide a non-fatal notification, unless suppressed by the -nowarn option. | 
| 482 |      *  @param key    The key for the localized notification message. | 
| 483 |      *  @param args   Fields of the notification message. | 
| 484 |      */ | 
| 485 |     public void note(String key, Object ... args) { | 
| 486 |         report(diags.note(source, null, key, args)); | 
| 487 |     } | 
| 488 |   | 
| 489 |     /** Provide a non-fatal notification, unless suppressed by the -nowarn option. | 
| 490 |      *  @param key    The key for the localized notification message. | 
| 491 |      *  @param args   Fields of the notification message. | 
| 492 |      */ | 
| 493 |     public void note(DiagnosticPosition pos, String key, Object ... args) { | 
| 494 |         report(diags.note(source, pos, key, args)); | 
| 495 |     } | 
| 496 |   | 
| 497 |     /** Provide a non-fatal notification, unless suppressed by the -nowarn option. | 
| 498 |      *  @param key    The key for the localized notification message. | 
| 499 |      *  @param args   Fields of the notification message. | 
| 500 |      */ | 
| 501 |     public void note(int pos, String key, Object ... args) { | 
| 502 |         report(diags.note(source, wrap(pos), key, args)); | 
| 503 |     } | 
| 504 |   | 
| 505 |     /** Provide a non-fatal notification, unless suppressed by the -nowarn option. | 
| 506 |      *  @param key    The key for the localized notification message. | 
| 507 |      *  @param args   Fields of the notification message. | 
| 508 |      */ | 
| 509 |     public void mandatoryNote(final JavaFileObject file, String key, Object ... args) { | 
| 510 |         JCDiagnostic.DiagnosticSource wrapper = null; | 
| 511 |         if (file != null) { | 
| 512 |             wrapper = new JCDiagnostic.DiagnosticSource() { | 
| 513 |                     public JavaFileObject getFile() { | 
| 514 |                         return file; | 
| 515 |                     } | 
| 516 |                     public CharSequence getName() { | 
| 517 |                         return JavacFileManager.getJavacBaseFileName(getFile()); | 
| 518 |                     } | 
| 519 |                     public int getLineNumber(int pos) { | 
| 520 |                         return Log.this.getLineNumber(pos); | 
| 521 |                     } | 
| 522 |                     public int getColumnNumber(int pos) { | 
| 523 |                         return Log.this.getColumnNumber(pos); | 
| 524 |                     } | 
| 525 |                     public Map<JCTree, Integer> getEndPosTable() { | 
| 526 |                         return (endPosTables == null ? null : endPosTables.get(file)); | 
| 527 |                     } | 
| 528 |                 }; | 
| 529 |         } | 
| 530 |         if (enforceMandatoryWarnings) | 
| 531 |             report(diags.mandatoryNote(wrapper, key, args)); | 
| 532 |         else | 
| 533 |             report(diags.note(wrapper, null, key, args)); | 
| 534 |     } | 
| 535 |   | 
| 536 |     private DiagnosticPosition wrap(int pos) { | 
| 537 |         return (pos == Position.NOPOS ? null : new SimpleDiagnosticPosition(pos)); | 
| 538 |     } | 
| 539 |   | 
| 540 |     /** | 
| 541 |      * Common diagnostic handling. | 
| 542 |      * The diagnostic is counted, and depending on the options and how many diagnostics have been | 
| 543 |      * reported so far, the diagnostic may be handed off to writeDiagnostic. | 
| 544 |      */ | 
| 545 |     public void report(JCDiagnostic diagnostic) { | 
| 546 |         switch (diagnostic.getType()) { | 
| 547 |         case FRAGMENT: | 
| 548 |             throw new IllegalArgumentException(); | 
| 549 |   | 
| 550 |         case NOTE: | 
| 551 |             // Print out notes only when we are permitted to report warnings | 
| 552 |             // Notes are only generated at the end of a compilation, so should be small | 
| 553 |             // in number. | 
| 554 |             if (emitWarnings || diagnostic.isMandatory()) { | 
| 555 |                 writeDiagnostic(diagnostic); | 
| 556 |             } | 
| 557 |             break; | 
| 558 |   | 
| 559 |         case WARNING: | 
| 560 |             if (emitWarnings || diagnostic.isMandatory()) { | 
| 561 |                 if (nwarnings < MaxWarnings) { | 
| 562 |                     writeDiagnostic(diagnostic); | 
| 563 |                     nwarnings++; | 
| 564 |                 } | 
| 565 |             } | 
| 566 |             break; | 
| 567 |   | 
| 568 |         case ERROR: | 
| 569 |             if (nerrors < MaxErrors | 
| 570 |                 && shouldReport(diagnostic.getSource(), diagnostic.getIntPosition())) { | 
| 571 |                 writeDiagnostic(diagnostic); | 
| 572 |                 nerrors++; | 
| 573 |             } | 
| 574 |             break; | 
| 575 |         } | 
| 576 |     } | 
| 577 |   | 
| 578 |     /** | 
| 579 |      * Write out a diagnostic. | 
| 580 |      */ | 
| 581 |     protected void writeDiagnostic(JCDiagnostic diag) { | 
| 582 |         if (diagListener != null) { | 
| 583 |             try { | 
| 584 |                 diagListener.report(diag); | 
| 585 |                 return; | 
| 586 |             } | 
| 587 |             catch (Throwable t) { | 
| 588 |                 throw new ClientCodeException(t); | 
| 589 |             } | 
| 590 |         } | 
| 591 |   | 
| 592 |         PrintWriter writer = getWriterForDiagnosticType(diag.getType()); | 
| 593 |   | 
| 594 |         printLines(writer, diagFormatter.format(diag)); | 
| 595 |         if (showSourceLine) { | 
| 596 |             int pos = diag.getIntPosition(); | 
| 597 |             if (pos != Position.NOPOS) { | 
| 598 |                 JavaFileObject prev = useSource(diag.getSource()); | 
| 599 |                 printErrLine(pos, writer); | 
| 600 |                 useSource(prev); | 
| 601 |             } | 
| 602 |         } | 
| 603 |   | 
| 604 |         if (promptOnError) { | 
| 605 |             switch (diag.getType()) { | 
| 606 |             case ERROR: | 
| 607 |             case WARNING: | 
| 608 |                 prompt(); | 
| 609 |             } | 
| 610 |         } | 
| 611 |   | 
| 612 |         if (dumpOnError) | 
| 613 |             new RuntimeException().printStackTrace(writer); | 
| 614 |   | 
| 615 |         writer.flush(); | 
| 616 |     } | 
| 617 |   | 
| 618 |     @Deprecated | 
| 619 |     protected PrintWriter getWriterForDiagnosticType(DiagnosticType dt) { | 
| 620 |         switch (dt) { | 
| 621 |         case FRAGMENT: | 
| 622 |             throw new IllegalArgumentException(); | 
| 623 |   | 
| 624 |         case NOTE: | 
| 625 |             return noticeWriter; | 
| 626 |   | 
| 627 |         case WARNING: | 
| 628 |             return warnWriter; | 
| 629 |   | 
| 630 |         case ERROR: | 
| 631 |             return errWriter; | 
| 632 |   | 
| 633 |         default: | 
| 634 |             throw new Error(); | 
| 635 |         } | 
| 636 |     } | 
| 637 |   | 
| 638 |     /** Find a localized string in the resource bundle. | 
| 639 |      *  @param key    The key for the localized string. | 
| 640 |      *  @param args   Fields to substitute into the string. | 
| 641 |      */ | 
| 642 |     public static String getLocalizedString(String key, Object ... args) { | 
| 643 |         return Messages.getDefaultLocalizedString("compiler.misc." + key, args); | 
| 644 |     } | 
| 645 |   | 
| 646 | /*************************************************************************** | 
| 647 |  * raw error messages without internationalization; used for experimentation | 
| 648 |  * and quick prototyping | 
| 649 |  ***************************************************************************/ | 
| 650 |   | 
| 651 | /** print an error or warning message: | 
| 652 |  */ | 
| 653 |     private void printRawError(int pos, String msg) { | 
| 654 |         if (!findLine(pos)) { | 
| 655 |             printLines(errWriter, "error: " + msg); | 
| 656 |         } else { | 
| 657 |             JavaFileObject file = currentSource(); | 
| 658 |             if (file != null) | 
| 659 |                 printLines(errWriter, | 
| 660 |                            JavacFileManager.getJavacFileName(file) + ":" + | 
| 661 |                            line + ": " + msg); | 
| 662 |             printErrLine(pos, errWriter); | 
| 663 |         } | 
| 664 |         errWriter.flush(); | 
| 665 |     } | 
| 666 |   | 
| 667 | /** report an error: | 
| 668 |  */ | 
| 669 |     public void rawError(int pos, String msg) { | 
| 670 |         if (nerrors < MaxErrors && shouldReport(currentSource(), pos)) { | 
| 671 |             printRawError(pos, msg); | 
| 672 |             prompt(); | 
| 673 |             nerrors++; | 
| 674 |         } | 
| 675 |         errWriter.flush(); | 
| 676 |     } | 
| 677 |   | 
| 678 | /** report a warning: | 
| 679 |  */ | 
| 680 |     public void rawWarning(int pos, String msg) { | 
| 681 |         if (nwarnings < MaxWarnings && emitWarnings) { | 
| 682 |             printRawError(pos, "warning: " + msg); | 
| 683 |         } | 
| 684 |         prompt(); | 
| 685 |         nwarnings++; | 
| 686 |         errWriter.flush(); | 
| 687 |     } | 
| 688 |   | 
| 689 |     /** Return the one-based line number associated with a given pos | 
| 690 |      * for the current source file.  Zero is returned if no line exists | 
| 691 |      * for the given position. | 
| 692 |      */ | 
| 693 |     protected int getLineNumber(int pos) { | 
| 694 |         if (findLine(pos)) | 
| 695 |             return line; | 
| 696 |         return 0; | 
| 697 |     } | 
| 698 |   | 
| 699 |     /** Return the one-based column number associated with a given pos | 
| 700 |      * for the current source file.  Zero is returned if no column exists | 
| 701 |      * for the given position. | 
| 702 |      */ | 
| 703 |     protected int getColumnNumber(int pos) { | 
| 704 |         if (findLine(pos)) { | 
| 705 |             int column = 0; | 
| 706 |             for (bp = lineStart; bp < pos; bp++) { | 
| 707 |                 if (bp >= buf.length) | 
| 708 |                     return 0; | 
| 709 |                 if (buf[bp] == '\t') | 
| 710 |                     column = (column / TabInc * TabInc) + TabInc; | 
| 711 |                 else | 
| 712 |                     column++; | 
| 713 |             } | 
| 714 |             return column + 1; // positions are one-based | 
| 715 |         } | 
| 716 |         return 0; | 
| 717 |     } | 
| 718 |   | 
| 719 |     public static String format(String fmt, Object... args) { | 
| 720 |         return String.format((java.util.Locale)null, fmt, args); | 
| 721 |     } | 
| 722 |   | 
| 723 | } |