Messager.java revision 3896:8e4dbcb99277
1311118Sdim/* 2311118Sdim * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3311118Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4311118Sdim * 5311118Sdim * This code is free software; you can redistribute it and/or modify it 6311118Sdim * under the terms of the GNU General Public License version 2 only, as 7311118Sdim * published by the Free Software Foundation. Oracle designates this 8311118Sdim * particular file as subject to the "Classpath" exception as provided 9311118Sdim * by Oracle in the LICENSE file that accompanied this code. 10311118Sdim * 11311118Sdim * This code is distributed in the hope that it will be useful, but WITHOUT 12311118Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13311118Sdim * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14311118Sdim * version 2 for more details (a copy is included in the LICENSE file that 15311118Sdim * accompanied this code). 16311118Sdim * 17311118Sdim * You should have received a copy of the GNU General Public License version 18311118Sdim * 2 along with this work; if not, write to the Free Software Foundation, 19311118Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20311118Sdim * 21311118Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22311118Sdim * or visit www.oracle.com if you need additional information or have any 23311118Sdim * questions. 24311118Sdim */ 25311118Sdim 26311118Sdimpackage jdk.javadoc.internal.tool; 27311118Sdim 28311118Sdim 29311118Sdimimport java.io.PrintWriter; 30311118Sdimimport java.util.Locale; 31311118Sdimimport java.util.ResourceBundle; 32311118Sdim 33311118Sdimimport javax.lang.model.element.Element; 34311118Sdimimport javax.tools.Diagnostic.Kind; 35311118Sdim 36311118Sdimimport com.sun.tools.javac.util.Context.Factory; 37311118Sdimimport jdk.javadoc.doclet.Reporter; 38311118Sdimimport com.sun.source.tree.CompilationUnitTree; 39311118Sdimimport com.sun.source.util.DocSourcePositions; 40311118Sdimimport com.sun.source.util.DocTreePath; 41311118Sdimimport com.sun.source.util.TreePath; 42311118Sdimimport com.sun.tools.javac.api.JavacTrees; 43311118Sdimimport com.sun.tools.javac.tree.JCTree; 44311118Sdimimport com.sun.tools.javac.util.Context; 45311118Sdimimport com.sun.tools.javac.util.JCDiagnostic; 46import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; 47import com.sun.tools.javac.util.JavacMessages; 48import com.sun.tools.javac.util.Log; 49 50/** 51 * Utility for integrating with javadoc tools and for localization. 52 * Handle resources, access to error and warning counts and 53 * message formatting. 54 * 55 * <p><b>This is NOT part of any supported API. 56 * If you write code that depends on this, you do so at your own risk. 57 * This code and its internal interfaces are subject to change or 58 * deletion without notice.</b> 59 * 60 * @see java.util.ResourceBundle 61 * @see java.text.MessageFormat 62 * @author Neal Gafter (rewrite) 63 */ 64public class Messager extends Log implements Reporter { 65 final Context context; 66 67 /** Get the current messager, which is also the compiler log. */ 68 public static Messager instance0(Context context) { 69 Log instance = context.get(logKey); 70 if (instance == null || !(instance instanceof Messager)) 71 throw new InternalError("no messager instance!"); 72 return (Messager)instance; 73 } 74 75 public static void preRegister(Context context, 76 final String programName) { 77 context.put(logKey, (Factory<Log>)c -> new Messager(c, programName)); 78 } 79 80 public static void preRegister(Context context, final String programName, 81 final PrintWriter outWriter, final PrintWriter errWriter) { 82 context.put(logKey, (Factory<Log>)c -> new Messager(c, programName, outWriter, errWriter)); 83 } 84 85 @Override 86 public void print(Kind kind, String msg) { 87 switch (kind) { 88 case ERROR: 89 printError(msg); 90 return; 91 case WARNING: 92 case MANDATORY_WARNING: 93 printWarning(msg); 94 return; 95 default: 96 printNotice(msg); 97 return; 98 } 99 } 100 101 @Override 102 public void print(Kind kind, DocTreePath path, String msg) { 103 switch (kind) { 104 case ERROR: 105 printError(path, msg); 106 return; 107 case WARNING: 108 case MANDATORY_WARNING: 109 printWarning(path, msg); 110 return; 111 default: 112 printWarning(path, msg); 113 return; 114 } 115 } 116 117 @Override 118 public void print(Kind kind, Element e, String msg) { 119 switch (kind) { 120 case ERROR: 121 printError(e, msg); 122 return; 123 case WARNING: 124 case MANDATORY_WARNING: 125 printWarning(e, msg); 126 return; 127 default: 128 printWarning(e, msg); 129 return; 130 } 131 } 132 133 final String programName; 134 135 private Locale locale; 136 private final JavacMessages messages; 137 private final JCDiagnostic.Factory javadocDiags; 138 139 /** The default writer for diagnostics 140 */ 141 static final PrintWriter defaultOutWriter = new PrintWriter(System.out); 142 static final PrintWriter defaultErrWriter = new PrintWriter(System.err); 143 144 /** 145 * Constructor 146 * @param programName Name of the program (for error messages). 147 */ 148 public Messager(Context context, String programName) { 149 this(context, programName, defaultOutWriter, defaultErrWriter); 150 } 151 152 /** 153 * Constructor 154 * @param programName Name of the program (for error messages). 155 * @param outWriter Stream for notices etc. 156 * @param errWriter Stream for errors and warnings 157 */ 158 @SuppressWarnings("deprecation") 159 public Messager(Context context, String programName, PrintWriter outWriter, PrintWriter errWriter) { 160 super(context, errWriter, errWriter, outWriter); 161 messages = JavacMessages.instance(context); 162 messages.add(locale -> ResourceBundle.getBundle("jdk.javadoc.internal.tool.resources.javadoc", 163 locale)); 164 javadocDiags = new JCDiagnostic.Factory(messages, "javadoc"); 165 this.programName = programName; 166 this.context = context; 167 locale = Locale.getDefault(); 168 } 169 170 public void setLocale(Locale locale) { 171 this.locale = locale; 172 } 173 174 /** 175 * get and format message string from resource 176 * 177 * @param key selects message from resource 178 * @param args arguments for the message 179 */ 180 String getText(String key, Object... args) { 181 return messages.getLocalizedString(locale, key, args); 182 } 183 184 private String getDiagSource(DocTreePath path) { 185 if (path == null || path.getTreePath() == null) { 186 return programName; 187 } 188 JavacTrees trees = JavacTrees.instance(context); 189 DocSourcePositions sourcePositions = trees.getSourcePositions(); 190 CompilationUnitTree cu = path.getTreePath().getCompilationUnit(); 191 long spos = sourcePositions.getStartPosition(cu, path.getDocComment(), path.getLeaf()); 192 long lineNumber = cu.getLineMap().getLineNumber(spos); 193 String fname = cu.getSourceFile().getName(); 194 String posString = fname + ":" + lineNumber; 195 return posString; 196 } 197 198 private String getDiagSource(Element e) { 199 if (e == null) { 200 return programName; 201 } 202 JavacTrees trees = JavacTrees.instance(context); 203 TreePath path = trees.getPath(e); 204 DocSourcePositions sourcePositions = trees.getSourcePositions(); 205 JCTree tree = trees.getTree(e); 206 CompilationUnitTree cu = path.getCompilationUnit(); 207 long spos = sourcePositions.getStartPosition(cu, tree); 208 long lineNumber = cu.getLineMap().getLineNumber(spos); 209 String fname = cu.getSourceFile().getName(); 210 String posString = fname + ":" + lineNumber; 211 return posString; 212 } 213 214 /** 215 * Print error message, increment error count. 216 * Part of DocErrorReporter. 217 * 218 * @param msg message to print 219 */ 220 public void printError(String msg) { 221 printError((DocTreePath)null, msg); 222 } 223 224 public void printError(DocTreePath path, String msg) { 225 String prefix = getDiagSource(path); 226 if (diagListener != null) { 227 report(DiagnosticType.ERROR, prefix, msg); 228 return; 229 } 230 printError(prefix, msg); 231 } 232 233 public void printError(Element e, String msg) { 234 String prefix = getDiagSource(e); 235 if (diagListener != null) { 236 report(DiagnosticType.ERROR, prefix, msg); 237 return; 238 } 239 printError(prefix, msg); 240 } 241 242 public void printErrorUsingKey(String key, Object... args) { 243 printError((Element)null, getText(key, args)); 244 } 245 246 // print the error and increment count 247 private void printError(String prefix, String msg) { 248 if (nerrors < MaxErrors) { 249 PrintWriter errWriter = getWriter(WriterKind.ERROR); 250 printRawLines(errWriter, prefix + ": " + getText("javadoc.error") + " - " + msg); 251 errWriter.flush(); 252 prompt(); 253 nerrors++; 254 } 255 } 256 257 /** 258 * Print warning message, increment warning count. 259 * Part of DocErrorReporter. 260 * 261 * @param msg message to print 262 */ 263 public void printWarning(String msg) { 264 printWarning((DocTreePath)null, msg); 265 } 266 267 public void printWarningUsingKey(String key, Object... args) { 268 printWarning((Element)null, getText(key, args)); 269 } 270 271 public void printWarning(Element e, String key, Object... args) { 272 printWarning(getText(key, args)); 273 } 274 275 public void printWarning(DocTreePath path, String msg) { 276 String prefix = getDiagSource(path); 277 if (diagListener != null) { 278 report(DiagnosticType.WARNING, prefix, msg); 279 return; 280 } 281 printWarning(prefix, msg); 282 } 283 284 public void printWarning(Element e, String msg) { 285 String prefix = getDiagSource(e); 286 if (diagListener != null) { 287 report(DiagnosticType.WARNING, prefix, msg); 288 return; 289 } 290 printWarning(prefix, msg); 291 } 292 293 // print the warning and increment count 294 private void printWarning(String prefix, String msg) { 295 if (nwarnings < MaxWarnings) { 296 PrintWriter warnWriter = getWriter(WriterKind.WARNING); 297 printRawLines(warnWriter, prefix + ": " + getText("javadoc.warning") + " - " + msg); 298 warnWriter.flush(); 299 nwarnings++; 300 } 301 } 302 303 /** 304 * Print a message. 305 * Part of DocErrorReporter. 306 * 307 * @param msg message to print 308 */ 309 public void printNotice(String msg) { 310 printNotice((DocTreePath)null, msg); 311 } 312 313 public void printNotice(DocTreePath path, String msg) { 314 String prefix = getDiagSource(path); 315 if (diagListener != null) { 316 report(DiagnosticType.NOTE, null, prefix + ": " + msg); 317 return; 318 } 319 320 PrintWriter noticeWriter = getWriter(WriterKind.NOTICE); 321 if (path == null) { 322 printRawLines(noticeWriter, msg); 323 } else { 324 printRawLines(noticeWriter, prefix + ": " + msg); 325 } 326 noticeWriter.flush(); 327 } 328 329 public void printNotice(Element e, String msg) { 330 String pos = getDiagSource(e); 331 if (diagListener != null) { 332 report(DiagnosticType.NOTE, pos, msg); 333 return; 334 } 335 336 PrintWriter noticeWriter = getWriter(WriterKind.NOTICE); 337 if (e == null) { 338 printRawLines(noticeWriter, msg); 339 } else { 340 printRawLines(noticeWriter, pos + ": " + msg); 341 } 342 noticeWriter.flush(); 343 } 344 345 /** 346 * Print a message. 347 * 348 * @param key selects message from resource 349 */ 350 public void notice(String key, Object... args) { 351 printNotice(getText(key, args)); 352 } 353 354 /** 355 * Returns true if errors have been recorded. 356 */ 357 public boolean hasErrors() { 358 return nerrors != 0; 359 } 360 361 /** 362 * Returns true if warnings have been recorded. 363 */ 364 public boolean hasWarnings() { 365 return nwarnings != 0; 366 } 367 368 /** 369 * Print exit message. 370 */ 371 public void printErrorWarningCounts() { 372 if (nerrors > 0) { 373 notice((nerrors > 1) ? "main.errors" : "main.error", 374 "" + nerrors); 375 } 376 if (nwarnings > 0) { 377 notice((nwarnings > 1) ? "main.warnings" : "main.warning", 378 "" + nwarnings); 379 } 380 } 381 382 private void report(DiagnosticType type, String pos, String msg) { 383 switch (type) { 384 case ERROR: 385 case WARNING: 386 Object prefix = (pos == null) ? programName : pos; 387 report(javadocDiags.create(type, null, null, "msg", prefix, msg)); 388 break; 389 390 case NOTE: 391 String key = (pos == null) ? "msg" : "pos.msg"; 392 report(javadocDiags.create(type, null, null, key, pos, msg)); 393 break; 394 395 default: 396 throw new IllegalArgumentException(type.toString()); 397 } 398 } 399} 400