Messager.java revision 3827:44bdefe64114
1156230Smux/* 2156230Smux * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. 3156230Smux * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4156230Smux * 5156230Smux * This code is free software; you can redistribute it and/or modify it 6156230Smux * under the terms of the GNU General Public License version 2 only, as 7156230Smux * published by the Free Software Foundation. Oracle designates this 8156230Smux * particular file as subject to the "Classpath" exception as provided 9156230Smux * by Oracle in the LICENSE file that accompanied this code. 10156230Smux * 11156230Smux * This code is distributed in the hope that it will be useful, but WITHOUT 12156230Smux * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13156230Smux * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14156230Smux * version 2 for more details (a copy is included in the LICENSE file that 15156230Smux * accompanied this code). 16156230Smux * 17156230Smux * You should have received a copy of the GNU General Public License version 18156230Smux * 2 along with this work; if not, write to the Free Software Foundation, 19156230Smux * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20156230Smux * 21156230Smux * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22156230Smux * or visit www.oracle.com if you need additional information or have any 23156230Smux * questions. 24156230Smux */ 25156230Smux 26156230Smuxpackage jdk.javadoc.internal.tool; 27156230Smux 28156230Smux 29156230Smuximport java.io.PrintWriter; 30156230Smuximport java.util.Locale; 31156230Smuximport java.util.ResourceBundle; 32156230Smux 33156230Smuximport javax.lang.model.element.Element; 34156230Smuximport javax.tools.Diagnostic.Kind; 35156230Smux 36156230Smuximport com.sun.tools.javac.util.Context.Factory; 37156230Smuximport jdk.javadoc.doclet.Reporter; 38156230Smuximport com.sun.source.tree.CompilationUnitTree; 39156230Smuximport com.sun.source.util.DocSourcePositions; 40156230Smuximport com.sun.source.util.DocTreePath; 41156230Smuximport com.sun.source.util.TreePath; 42156230Smuximport com.sun.tools.javac.api.JavacTrees; 43156230Smuximport com.sun.tools.javac.tree.JCTree; 44156230Smuximport com.sun.tools.javac.util.Context; 45156230Smuximport com.sun.tools.javac.util.JCDiagnostic; 46156230Smuximport com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; 47156230Smuximport com.sun.tools.javac.util.JavacMessages; 48156230Smuximport com.sun.tools.javac.util.Log; 49156230Smux 50156230Smux/** 51156230Smux * Utility for integrating with javadoc tools and for localization. 52156230Smux * Handle resources, access to error and warning counts and 53156230Smux * message formatting. 54156230Smux * 55156230Smux * <p><b>This is NOT part of any supported API. 56156230Smux * If you write code that depends on this, you do so at your own risk. 57156230Smux * This code and its internal interfaces are subject to change or 58156230Smux * deletion without notice.</b> 59156230Smux * 60156230Smux * @see java.util.ResourceBundle 61156230Smux * @see java.text.MessageFormat 62156230Smux * @author Neal Gafter (rewrite) 63156230Smux */ 64156230Smuxpublic class Messager extends Log implements Reporter { 65156230Smux final Context context; 66156230Smux 67156230Smux /** Get the current messager, which is also the compiler log. */ 68156230Smux public static Messager instance0(Context context) { 69156230Smux Log instance = context.get(logKey); 70156230Smux if (instance == null || !(instance instanceof Messager)) 71156230Smux throw new InternalError("no messager instance!"); 72156230Smux return (Messager)instance; 73156230Smux } 74156230Smux 75156230Smux public static void preRegister(Context context, 76156230Smux final String programName) { 77156230Smux context.put(logKey, (Factory<Log>)c -> new Messager(c, programName)); 78156230Smux } 79156230Smux 80156230Smux public static void preRegister(Context context, final String programName, 81156230Smux final PrintWriter outWriter, final PrintWriter errWriter) { 82156230Smux context.put(logKey, (Factory<Log>)c -> new Messager(c, programName, outWriter, errWriter)); 83156230Smux } 84156230Smux 85156230Smux @Override 86156230Smux public void print(Kind kind, String msg) { 87156230Smux switch (kind) { 88156230Smux case ERROR: 89156701Smux printError(msg); 90156230Smux return; 91156230Smux case WARNING: 92156230Smux case MANDATORY_WARNING: 93156230Smux printWarning(msg); 94156230Smux return; 95156230Smux default: 96156230Smux printNotice(msg); 97156230Smux return; 98156230Smux } 99156230Smux } 100156230Smux 101156230Smux @Override 102156230Smux public void print(Kind kind, DocTreePath path, String msg) { 103156230Smux switch (kind) { 104156230Smux case ERROR: 105156701Smux printError(path, msg); 106156230Smux return; 107156230Smux case WARNING: 108156230Smux case MANDATORY_WARNING: 109156230Smux printWarning(path, msg); 110156230Smux return; 111203368Slulf default: 112156230Smux printWarning(path, msg); 113156230Smux return; 114156230Smux } 115156230Smux } 116156230Smux 117156230Smux @Override 118156230Smux public void print(Kind kind, Element e, String msg) { 119156230Smux switch (kind) { 120156230Smux case ERROR: 121156230Smux printError(e, msg); 122156230Smux return; 123156230Smux case WARNING: 124156230Smux case MANDATORY_WARNING: 125156230Smux printWarning(e, msg); 126156230Smux return; 127156230Smux 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) { 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