Messager.java revision 3233:b5d08bc0d224
1/* 2 * Copyright (c) 1997, 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 jdk.javadoc.internal.tool; 27 28 29import java.io.PrintWriter; 30import java.util.Locale; 31import java.util.ResourceBundle; 32 33import javax.lang.model.element.Element; 34import javax.tools.Diagnostic.Kind; 35 36import jdk.javadoc.doclet.Reporter; 37import com.sun.source.tree.CompilationUnitTree; 38import com.sun.source.util.DocSourcePositions; 39import com.sun.source.util.DocTreePath; 40import com.sun.source.util.TreePath; 41import com.sun.tools.javac.api.JavacTrees; 42import com.sun.tools.javac.tree.JCTree; 43import com.sun.tools.javac.util.Context; 44import com.sun.tools.javac.util.JCDiagnostic; 45import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; 46import com.sun.tools.javac.util.JavacMessages; 47import com.sun.tools.javac.util.Log; 48 49/** 50 * Utility for integrating with javadoc tools and for localization. 51 * Handle Resources. Access to error and warning counts. 52 * Message formatting. 53 * <br> 54 * Also provides implementation for DocErrorReporter. 55 * 56 * <p><b>This is NOT part of any supported API. 57 * If you write code that depends on this, you do so at your own risk. 58 * This code and its internal interfaces are subject to change or 59 * deletion without notice.</b> 60 * 61 * @see java.util.ResourceBundle 62 * @see java.text.MessageFormat 63 * @author Neal Gafter (rewrite) 64 */ 65public class Messager extends Log implements Reporter { 66 final Context context; 67 68 /** Get the current messager, which is also the compiler log. */ 69 public static Messager instance0(Context context) { 70 Log instance = context.get(logKey); 71 if (instance == null || !(instance instanceof Messager)) 72 throw new InternalError("no messager instance!"); 73 return (Messager)instance; 74 } 75 76 public static void preRegister(Context context, 77 final String programName) { 78 context.put(logKey, new Context.Factory<Log>() { 79 public Log make(Context c) { 80 return new Messager(c, programName); 81 } 82 }); 83 } 84 85 public static void preRegister(Context context, final String programName, 86 final PrintWriter outWriter, final PrintWriter errWriter) { 87 context.put(logKey, new Context.Factory<Log>() { 88 public Log make(Context c) { 89 return new Messager(c, programName, outWriter, errWriter); 90 } 91 }); 92 } 93 94 @Override 95 public void print(Kind kind, String msg) { 96 switch (kind) { 97 case ERROR: 98 printError(msg); 99 return; 100 case WARNING: 101 case MANDATORY_WARNING: 102 printWarning(msg); 103 return; 104 default: 105 printNotice(msg); 106 return; 107 } 108 } 109 110 @Override 111 public void print(Kind kind, DocTreePath path, String msg) { 112 switch (kind) { 113 case ERROR: 114 printError(path, msg); 115 return; 116 case WARNING: 117 case MANDATORY_WARNING: 118 printWarning(path, msg); 119 return; 120 default: 121 printWarning(path, msg); 122 return; 123 } 124 } 125 126 @Override 127 public void print(Kind kind, Element e, String msg) { 128 switch (kind) { 129 case ERROR: 130 printError(e, msg); 131 return; 132 case WARNING: 133 case MANDATORY_WARNING: 134 printWarning(e, msg); 135 return; 136 default: 137 printWarning(e, msg); 138 return; 139 } 140 } 141 142 public class ExitJavadoc extends Error { 143 private static final long serialVersionUID = 0; 144 } 145 146 final String programName; 147 148 private Locale locale; 149 private final JavacMessages messages; 150 private final JCDiagnostic.Factory javadocDiags; 151 152 /** The default writer for diagnostics 153 */ 154 static final PrintWriter defaultOutWriter = new PrintWriter(System.out); 155 static final PrintWriter defaultErrWriter = new PrintWriter(System.err); 156 157 /** 158 * Constructor 159 * @param programName Name of the program (for error messages). 160 */ 161 public Messager(Context context, String programName) { 162 this(context, programName, defaultOutWriter, defaultErrWriter); 163 } 164 165 /** 166 * Constructor 167 * @param programName Name of the program (for error messages). 168 * @param outWriter Stream for notices etc. 169 * @param errWriter Stream for errors and warnings 170 */ 171 @SuppressWarnings("deprecation") 172 public Messager(Context context, String programName, PrintWriter outWriter, PrintWriter errWriter) { 173 super(context, errWriter, errWriter, outWriter); 174 messages = JavacMessages.instance(context); 175 messages.add(locale -> ResourceBundle.getBundle("jdk.javadoc.internal.tool.resources.javadoc", 176 locale)); 177 javadocDiags = new JCDiagnostic.Factory(messages, "javadoc"); 178 this.programName = programName; 179 this.context = context; 180 locale = Locale.getDefault(); 181 } 182 183 public void setLocale(Locale locale) { 184 this.locale = locale; 185 } 186 187 /** 188 * get and format message string from resource 189 * 190 * @param key selects message from resource 191 * @param args arguments for the message 192 */ 193 String getText(String key, Object... args) { 194 return messages.getLocalizedString(locale, key, args); 195 } 196 197 private String getDiagSource(DocTreePath path) { 198 if (path == null) { 199 return programName; 200 } 201 JavacTrees trees = JavacTrees.instance(context); 202 DocSourcePositions sourcePositions = trees.getSourcePositions(); 203 CompilationUnitTree cu = path.getTreePath().getCompilationUnit(); 204 long spos = sourcePositions.getStartPosition(cu, path.getDocComment(), path.getLeaf()); 205 long lineNumber = cu.getLineMap().getLineNumber(spos); 206 String fname = cu.getSourceFile().getName(); 207 String posString = fname + ":" + lineNumber; 208 return posString; 209 } 210 211 private String getDiagSource(Element e) { 212 if (e == null) { 213 return programName; 214 } 215 JavacTrees trees = JavacTrees.instance(context); 216 TreePath path = trees.getPath(e); 217 DocSourcePositions sourcePositions = trees.getSourcePositions(); 218 JCTree tree = trees.getTree(e); 219 CompilationUnitTree cu = path.getCompilationUnit(); 220 long spos = sourcePositions.getStartPosition(cu, tree); 221 long lineNumber = cu.getLineMap().getLineNumber(spos); 222 String fname = cu.getSourceFile().getName(); 223 String posString = fname + ":" + lineNumber; 224 return posString; 225 } 226 227 /** 228 * Print error message, increment error count. 229 * Part of DocErrorReporter. 230 * 231 * @param msg message to print 232 */ 233 public void printError(String msg) { 234 printError((DocTreePath)null, msg); 235 } 236 237 public void printError(DocTreePath path, String msg) { 238 String prefix = getDiagSource(path); 239 if (diagListener != null) { 240 report(DiagnosticType.ERROR, prefix, msg); 241 return; 242 } 243 incrementErrorCount(prefix, msg); 244 } 245 246 public void printError(Element e, String msg) { 247 String prefix = getDiagSource(e); 248 if (diagListener != null) { 249 report(DiagnosticType.ERROR, prefix, msg); 250 return; 251 } 252 incrementErrorCount(prefix, msg); 253 } 254 255 private void incrementErrorCount(String prefix, String msg) { 256 if (nerrors < MaxErrors) { 257 errWriter.println(prefix + ": " + getText("javadoc.error") + " - " + msg); 258 errWriter.flush(); 259 prompt(); 260 nerrors++; 261 } 262 } 263 264 /** 265 * Print warning message, increment warning count. 266 * Part of DocErrorReporter. 267 * 268 * @param msg message to print 269 */ 270 public void printWarning(String msg) { 271 printWarning((DocTreePath)null, msg); 272 } 273 274 public void printWarning(DocTreePath path, String msg) { 275 String prefix = getDiagSource(path); 276 if (diagListener != null) { 277 report(DiagnosticType.WARNING, prefix, msg); 278 return; 279 } 280 incrementWarningCount(prefix, msg); 281 } 282 283 public void printWarning(Element e, String msg) { 284 String prefix = getDiagSource(e); 285 if (diagListener != null) { 286 report(DiagnosticType.WARNING, prefix, msg); 287 return; 288 } 289 incrementWarningCount(prefix, msg); 290 } 291 292 private void incrementWarningCount(String prefix, String msg) { 293 if (nwarnings < MaxWarnings) { 294 warnWriter.println(prefix + ": " + getText("javadoc.warning") + " - " + msg); 295 warnWriter.flush(); 296 nwarnings++; 297 } 298 } 299 300 /** 301 * Print a message. 302 * Part of DocErrorReporter. 303 * 304 * @param msg message to print 305 */ 306 public void printNotice(String msg) { 307 printNotice((DocTreePath)null, msg); 308 } 309 310 public void printNotice(DocTreePath path, String msg) { 311 String prefix = getDiagSource(path); 312 if (diagListener != null) { 313 report(DiagnosticType.NOTE, null, prefix + ": " + msg); 314 return; 315 } 316 317 if (path == null) { 318 noticeWriter.println(msg); 319 } else { 320 noticeWriter.println(prefix + ": " + msg); 321 } 322 noticeWriter.flush(); 323 } 324 325 public void printNotice(Element e, String msg) { 326 String pos = getDiagSource(e); 327 if (diagListener != null) { 328 report(DiagnosticType.NOTE, pos, msg); 329 return; 330 } 331 332 if (e == null) { 333 noticeWriter.println(msg); 334 } else { 335 noticeWriter.println(pos + ": " + msg); 336 } 337 noticeWriter.flush(); 338 } 339 340 /** 341 * Print error message, increment error count. 342 * 343 * @param key selects message from resource 344 */ 345 public void error(Element e, String key, Object... args) { 346 printError(e, getText(key, args)); 347 } 348 349 /** 350 * Print error message, increment error count. 351 * 352 * @param key selects message from resource 353 */ 354 public void error(DocTreePath path, String key, Object... args) { 355 printError(path, getText(key, args)); 356 } 357 358 public void error(String key, Object... args) { 359 printError((Element)null, getText(key, args)); 360 } 361 362 public void warning(String key, Object... args) { 363 printWarning((Element)null, getText(key, args)); 364 } 365 366 /** 367 * Print warning message, increment warning count. 368 * 369 * @param key selects message from resource 370 */ 371 public void warning(Element e, String key, Object... args) { 372 printWarning(e, getText(key, args)); 373 } 374 375 /** 376 * Print warning message, increment warning count. 377 * 378 * @param key selects message from resource 379 */ 380 public void warning(DocTreePath path, String key, Object... args) { 381 printWarning(path, getText(key, args)); 382 } 383 384 /** 385 * Print a message. 386 * 387 * @param key selects message from resource 388 */ 389 public void notice(String key, Object... args) { 390 printNotice(getText(key, args)); 391 } 392 393 /** 394 * Return total number of errors, including those recorded 395 * in the compilation log. 396 */ 397 public int nerrors() { return nerrors; } 398 399 /** 400 * Return total number of warnings, including those recorded 401 * in the compilation log. 402 */ 403 public int nwarnings() { return nwarnings; } 404 405 /** 406 * Print exit message. 407 */ 408 public void exitNotice() { 409 if (nerrors > 0) { 410 notice((nerrors > 1) ? "main.errors" : "main.error", 411 "" + nerrors); 412 } 413 if (nwarnings > 0) { 414 notice((nwarnings > 1) ? "main.warnings" : "main.warning", 415 "" + nwarnings); 416 } 417 } 418 419 /** 420 * Force program exit, e.g., from a fatal error. 421 * <p> 422 * TODO: This method does not really belong here. 423 */ 424 public void exit() { 425 throw new ExitJavadoc(); 426 } 427 428 private void report(DiagnosticType type, String pos, String msg) { 429 switch (type) { 430 case ERROR: 431 case WARNING: 432 Object prefix = (pos == null) ? programName : pos; 433 report(javadocDiags.create(type, null, null, "msg", prefix, msg)); 434 break; 435 436 case NOTE: 437 String key = (pos == null) ? "msg" : "pos.msg"; 438 report(javadocDiags.create(type, null, null, key, pos, msg)); 439 break; 440 441 default: 442 throw new IllegalArgumentException(type.toString()); 443 } 444 } 445} 446