8267204: Expose access to underlying streams in Reporter
Reviewed-by: prappo
This commit is contained in:
parent
76b54a1995
commit
6ff978ac16
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,41 +25,124 @@
|
||||
|
||||
package jdk.javadoc.doclet;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Locale;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.FileObject;
|
||||
|
||||
import com.sun.source.util.DocTreePath;
|
||||
|
||||
/**
|
||||
* This interface provides error, warning and notice reporting.
|
||||
* Interface for reporting diagnostics and other messages.
|
||||
*
|
||||
* <p>Diagnostics consist of a {@link Diagnostic.Kind diagnostic kind} and a message,
|
||||
* and may additionally be associated with an {@link Element element},
|
||||
* a {@link DocTreePath tree node} in a documentation comment,
|
||||
* or an arbitrary position in a given {@link FileObject file}.
|
||||
* Other messages may be written directly to one of two streams that are informally
|
||||
* for use by "standard output" and "diagnostic output", where "standard output"
|
||||
* means the output that is the expected result of executing some operation,
|
||||
* such as the command-line help that is generated when using a {@code --help} option,
|
||||
* and "diagnostic output" refers to any errors, warnings and other output that is
|
||||
* a side-effect of executing the operation.
|
||||
*
|
||||
* <p>The exact manner in which diagnostics are output is unspecified and depends
|
||||
* on the enclosing context. For example:
|
||||
* <ul>
|
||||
* <li>The {@link javax.tools.DocumentationTool} API allows a client to specify a
|
||||
* {@link javax.tools.DiagnosticListener} to which diagnostics will be
|
||||
* {@link javax.tools.DiagnosticListener#report reported}. If no listener is specified,
|
||||
* diagnostics will be written to a given stream, or to {@code System.err} if no such
|
||||
* stream is provided.
|
||||
* <li>The {@link java.util.spi.ToolProvider} API allows a client to specify
|
||||
* the streams to be used for reporting standard and diagnostic output.
|
||||
* </ul>
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public interface Reporter {
|
||||
|
||||
/**
|
||||
* Print error message and increment error count.
|
||||
* Prints a diagnostic message.
|
||||
*
|
||||
* @param kind specify the diagnostic kind
|
||||
* @param msg message to print
|
||||
* @param kind the kind of diagnostic
|
||||
* @param message the message to be printed
|
||||
*/
|
||||
void print(Diagnostic.Kind kind, String msg);
|
||||
void print(Diagnostic.Kind kind, String message);
|
||||
|
||||
/**
|
||||
* Print an error message and increment error count.
|
||||
* Prints a diagnostic message related to a tree node in a documentation comment.
|
||||
*
|
||||
* @param kind specify the diagnostic kind
|
||||
* @param path the DocTreePath of item where the error occurs
|
||||
* @param msg message to print
|
||||
* @param kind the kind of diagnostic
|
||||
* @param path the path for the tree node
|
||||
* @param message the message to be printed
|
||||
*/
|
||||
void print(Diagnostic.Kind kind, DocTreePath path, String msg);
|
||||
void print(Diagnostic.Kind kind, DocTreePath path, String message);
|
||||
|
||||
/**
|
||||
* Print an error message and increment error count.
|
||||
* Prints a diagnostic message related to an element.
|
||||
*
|
||||
* @param kind specify the diagnostic kind
|
||||
* @param e the Element for which the error occurs
|
||||
* @param msg message to print
|
||||
* @param kind the kind of diagnostic
|
||||
* @param element the element
|
||||
* @param message the message to be printed
|
||||
*/
|
||||
void print(Diagnostic.Kind kind, Element e, String msg);
|
||||
void print(Diagnostic.Kind kind, Element element, String message);
|
||||
|
||||
/**
|
||||
* Prints a diagnostic message related to a position within a range of characters in a file.
|
||||
* The positions are all 0-based character offsets from the beginning of content of the file.
|
||||
* The positions should satisfy the relation {@code start <= pos <= end}.
|
||||
*
|
||||
* @param kind the kind of diagnostic
|
||||
* @param file the file
|
||||
* @param start the beginning of the enclosing range
|
||||
* @param pos the position
|
||||
* @param end the end of the enclosing range
|
||||
* @param message the message to be printed
|
||||
*
|
||||
* @since 17
|
||||
*/
|
||||
void print(Diagnostic.Kind kind, FileObject file, int start, int pos, int end, String message);
|
||||
|
||||
/**
|
||||
* Returns a writer that can be used to write non-diagnostic output,
|
||||
* or {@code null} if no such writer is available.
|
||||
*
|
||||
* @apiNote
|
||||
* The value may or may not be the same as that returned by {@link #getDiagnosticWriter()}.
|
||||
*
|
||||
* @implSpec
|
||||
* This implementation returns {@code null}.
|
||||
* The implementation provided by the {@code javadoc} tool to
|
||||
* {@link Doclet#init(Locale, Reporter) initialize} a doclet
|
||||
* always returns a non-{@code null} value.
|
||||
*
|
||||
* @return the writer
|
||||
* @since 17
|
||||
*/
|
||||
default PrintWriter getStandardWriter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a writer that can be used to write diagnostic output,
|
||||
* or {@code null} if no such writer is available.
|
||||
*
|
||||
* @apiNote
|
||||
* The value may or may not be the same as that returned by {@link #getStandardWriter()}.
|
||||
*
|
||||
* @implSpec
|
||||
* This implementation returns {@code null}.
|
||||
* The implementation provided by the {@code javadoc} tool to
|
||||
* {@link Doclet#init(Locale, Reporter) initialize} a doclet
|
||||
* always returns a non-{@code null} value.
|
||||
*
|
||||
* @return the writer
|
||||
* @since 17
|
||||
*/
|
||||
default PrintWriter getDiagnosticWriter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,6 +26,7 @@ package jdk.javadoc.internal.doclets.toolkit;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.FileObject;
|
||||
|
||||
import com.sun.source.util.DocTreePath;
|
||||
import jdk.javadoc.doclet.Reporter;
|
||||
@ -76,8 +77,8 @@ public class Messages {
|
||||
/**
|
||||
* Reports an error message to the doclet's reporter.
|
||||
*
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message.
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message
|
||||
*/
|
||||
public void error(String key, Object... args) {
|
||||
report(ERROR, resources.getText(key, args));
|
||||
@ -86,22 +87,35 @@ public class Messages {
|
||||
/**
|
||||
* Reports an error message to the doclet's reporter.
|
||||
*
|
||||
* @param path a path identifying the position to be included with
|
||||
* the message
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message.
|
||||
* @param path a path identifying the position to be included with the message
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message
|
||||
*/
|
||||
public void error(DocTreePath path, String key, Object... args) {
|
||||
report(ERROR, path, resources.getText(key, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports an error message to the doclet's reporter.
|
||||
*
|
||||
* @param fo the file object to be associated with the message
|
||||
* @param start the start of a range of characters to be associated with the message
|
||||
* @param pos the position to be associated with the message
|
||||
* @param end the end of a range of characters to be associated with the message
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message
|
||||
*/
|
||||
public void error(FileObject fo, int start, int pos, int end, String key, Object... args) {
|
||||
report(ERROR, fo, start, pos, end, resources.getText(key, args));
|
||||
}
|
||||
|
||||
// ***** Warnings *****
|
||||
|
||||
/**
|
||||
* Reports a warning message to the doclet's reporter.
|
||||
*
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message.
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message
|
||||
*/
|
||||
public void warning(String key, Object... args) {
|
||||
report(WARNING, resources.getText(key, args));
|
||||
@ -110,10 +124,9 @@ public class Messages {
|
||||
/**
|
||||
* Reports a warning message to the doclet's reporter.
|
||||
*
|
||||
* @param path a path identifying the position to be included with
|
||||
* the message
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message.
|
||||
* @param path a path identifying the position to be included with the message
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message
|
||||
*/
|
||||
public void warning(DocTreePath path, String key, Object... args) {
|
||||
if (configuration.showMessage(path, key)) {
|
||||
@ -124,10 +137,9 @@ public class Messages {
|
||||
/**
|
||||
* Reports a warning message to the doclet's reporter.
|
||||
*
|
||||
* @param e an element identifying the declaration whose position should
|
||||
* to be included with the message
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message.
|
||||
* @param e an element identifying the position to be included with the message
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message
|
||||
*/
|
||||
public void warning(Element e, String key, Object... args) {
|
||||
if (configuration.showMessage(e, key)) {
|
||||
@ -135,17 +147,33 @@ public class Messages {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a warning message to the doclet's reporter.
|
||||
*
|
||||
* @param fo the file object to be associated with the message
|
||||
* @param start the start of a range of characters to be associated with the message
|
||||
* @param pos the position to be associated with the message
|
||||
* @param end the end of a range of characters to be associated with the message
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message
|
||||
*/
|
||||
public void warning(FileObject fo, int start, int pos, int end, String key, Object... args) {
|
||||
report(WARNING, fo, start, pos, end, resources.getText(key, args));
|
||||
}
|
||||
|
||||
// ***** Notices *****
|
||||
|
||||
/**
|
||||
* Reports an informational notice to the doclet's reporter.
|
||||
* The message is written directly to the reporter's diagnostic stream.
|
||||
*
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message.
|
||||
* @param key the name of a resource containing the message to be printed
|
||||
* @param args optional arguments to be replaced in the message
|
||||
*/
|
||||
public void notice(String key, Object... args) {
|
||||
if (!configuration.getOptions().quiet()) {
|
||||
report(NOTE, resources.getText(key, args));
|
||||
// Note: we do not use report(NOTE, ...) which would prefix the output with "Note:"
|
||||
reporter.getDiagnosticWriter().println(resources.getText(key, args));
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,4 +190,8 @@ public class Messages {
|
||||
private void report(Diagnostic.Kind k, Element e, String msg) {
|
||||
reporter.print(k, e, msg);
|
||||
}
|
||||
|
||||
private void report(Diagnostic.Kind k, FileObject fo, int start, int pos, int end, String msg) {
|
||||
reporter.print(k, fo, start, pos, end, msg);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package jdk.javadoc.internal.tool;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
@ -36,8 +37,12 @@ import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.NestingKind;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.ForwardingFileObject;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import jdk.javadoc.doclet.Reporter;
|
||||
@ -157,17 +162,25 @@ public class Messager extends Log implements Reporter {
|
||||
private final JavacMessages messages;
|
||||
private final JCDiagnostic.Factory javadocDiags;
|
||||
|
||||
/** The default writer for notes. */
|
||||
private static final PrintWriter defaultOutWriter = new PrintWriter(System.out);
|
||||
/** The default writer for errors and warnings. */
|
||||
private static final PrintWriter defaultErrWriter = new PrintWriter(System.err);
|
||||
private static PrintWriter createPrintWriter(PrintStream ps, boolean autoflush) {
|
||||
return new PrintWriter(ps, autoflush) {
|
||||
// avoid closing system streams
|
||||
@Override
|
||||
public void close() {
|
||||
super.flush();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param programName Name of the program (for error messages).
|
||||
*/
|
||||
public Messager(Context context, String programName) {
|
||||
this(context, programName, defaultOutWriter, defaultErrWriter);
|
||||
// use the current values of System.out, System.err, in case they have been redirected
|
||||
this(context, programName,
|
||||
createPrintWriter(System.out, false),
|
||||
createPrintWriter(System.err, true));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,9 +189,8 @@ public class Messager extends Log implements Reporter {
|
||||
* @param outWriter Stream for notices etc.
|
||||
* @param errWriter Stream for errors and warnings
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public Messager(Context context, String programName, PrintWriter outWriter, PrintWriter errWriter) {
|
||||
super(context, errWriter, errWriter, outWriter);
|
||||
super(context, outWriter, errWriter);
|
||||
messages = JavacMessages.instance(context);
|
||||
messages.add(locale -> ResourceBundle.getBundle("jdk.javadoc.internal.tool.resources.javadoc",
|
||||
locale));
|
||||
@ -197,6 +209,16 @@ public class Messager extends Log implements Reporter {
|
||||
};
|
||||
}
|
||||
|
||||
@Override // Reporter
|
||||
public PrintWriter getStandardWriter() {
|
||||
return getWriter(Log.WriterKind.STDOUT);
|
||||
}
|
||||
|
||||
@Override // Reporter
|
||||
public PrintWriter getDiagnosticWriter() {
|
||||
return getWriter(Log.WriterKind.STDERR);
|
||||
}
|
||||
|
||||
public void setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
@ -234,6 +256,51 @@ public class Messager extends Log implements Reporter {
|
||||
report(dt, flags, ds, dp, message);
|
||||
}
|
||||
|
||||
@Override // Reporter
|
||||
public void print(Kind kind, FileObject file, int start, int pos, int end, String message) throws IllegalArgumentException {
|
||||
DiagnosticType dt = getDiagnosticType(kind);
|
||||
Set<DiagnosticFlag> flags = getDiagnosticFlags(kind);
|
||||
// Although not required to do so, it is the case that any file object returned from the
|
||||
// javac impl of JavaFileManager will return an object that implements JavaFileObject.
|
||||
// See PathFileObject, which provides the primary impls of (Java)FileObject.
|
||||
JavaFileObject fo = file instanceof JavaFileObject _fo ? _fo : new WrappingJavaFileObject(file);
|
||||
DiagnosticSource ds = new DiagnosticSource(fo, this);
|
||||
DiagnosticPosition dp = createDiagnosticPosition(null, start, pos, end);
|
||||
report(dt, flags, ds, dp, message);
|
||||
}
|
||||
|
||||
private class WrappingJavaFileObject
|
||||
extends ForwardingFileObject<FileObject> implements JavaFileObject {
|
||||
|
||||
WrappingJavaFileObject(FileObject fo) {
|
||||
super(fo);
|
||||
assert !(fo instanceof JavaFileObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Kind getKind() {
|
||||
String name = fileObject.getName();
|
||||
return name.endsWith(Kind.HTML.extension)
|
||||
? JavaFileObject.Kind.HTML
|
||||
: JavaFileObject.Kind.OTHER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNameCompatible(String simpleName, Kind kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NestingKind getNestingKind() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Modifier getAccessLevel() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints an error message.
|
||||
*
|
||||
@ -332,46 +399,22 @@ public class Messager extends Log implements Reporter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a "notice" message.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
public void printNotice(String message) {
|
||||
report(DiagnosticType.NOTE, null, null, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a "notice" message for a given documentation tree node.
|
||||
*
|
||||
* @param path the path for the documentation tree node
|
||||
* @param message the message
|
||||
*/
|
||||
public void printNotice(DocTreePath path, String message) {
|
||||
DiagnosticSource ds = getDiagnosticSource(path);
|
||||
DiagnosticPosition dp = getDiagnosticPosition(path);
|
||||
report(DiagnosticType.NOTE, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a "notice" message for a given element.
|
||||
*
|
||||
* @param element the element
|
||||
* @param message the message
|
||||
*/
|
||||
public void printNotice(Element element, String message) {
|
||||
DiagnosticSource ds = getDiagnosticSource(element);
|
||||
DiagnosticPosition dp = getDiagnosticPosition(element);
|
||||
report(DiagnosticType.NOTE, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a "notice" message.
|
||||
* Prints a "notice" message to the standard writer.
|
||||
*
|
||||
* @param key the resource key for the message
|
||||
* @param args the arguments for the message
|
||||
*/
|
||||
public void notice(String key, Object... args) {
|
||||
printNotice(getText(key, args));
|
||||
public void noticeUsingKey(String key, Object... args) {
|
||||
printRawLines(getStandardWriter(), getText(key, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a "notice" message to the standard writer.
|
||||
*
|
||||
* @param message the message
|
||||
*/
|
||||
public void notice(String message) {
|
||||
printRawLines(getStandardWriter(), message);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -389,16 +432,21 @@ public class Messager extends Log implements Reporter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the error and warning counts, if any.
|
||||
* Prints the error and warning counts, if any, to the diagnostic writer.
|
||||
*/
|
||||
public void printErrorWarningCounts() {
|
||||
if (nerrors > 0) {
|
||||
notice((nerrors > 1) ? "main.errors" : "main.error",
|
||||
"" + nerrors);
|
||||
}
|
||||
if (nwarnings > 0) {
|
||||
notice((nwarnings > 1) ? "main.warnings" : "main.warning",
|
||||
"" + nwarnings);
|
||||
printCount(nerrors, "main.error", "main.errors");
|
||||
printCount(nwarnings, "main.warning", "main.warnings");
|
||||
}
|
||||
|
||||
private void printCount(int count, String singleKey, String pluralKey) {
|
||||
if (count > 0) {
|
||||
String message = getText(count > 1 ? pluralKey : singleKey, count);
|
||||
if (diagListener != null) {
|
||||
report(DiagnosticType.NOTE, null, null, message);
|
||||
} else {
|
||||
printRawLines(getDiagnosticWriter(), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -446,9 +494,10 @@ public class Messager extends Log implements Reporter {
|
||||
*
|
||||
* {@code Log} reports all notes with a "Note:" prefix. That's not good for the
|
||||
* standard doclet, which uses notes to report the various "progress" messages,
|
||||
* such as "Generating class ...". Therefore, for now, we detect and report those
|
||||
* messages directly. (A better solution would be to expose access to the output
|
||||
* and error streams via {@code Reporter}).
|
||||
* such as "Generating class ...". They can be written directly to the diagnostic
|
||||
* writer, but that bypasses low-level checks about whether to suppress notes,
|
||||
* and bypasses the diagnostic listener for API clients.
|
||||
* Overall, it's an over-constrained problem with no obvious good solution.
|
||||
*
|
||||
* Note: there is an intentional difference in behavior between the diagnostic source
|
||||
* being set to {@code null} (no source intended) and {@code NO_SOURCE} (no source available).
|
||||
@ -459,12 +508,7 @@ public class Messager extends Log implements Reporter {
|
||||
* @param message the message
|
||||
*/
|
||||
private void report(DiagnosticType dt, Set<DiagnosticFlag> flags, DiagnosticSource ds, DiagnosticPosition dp, String message) {
|
||||
if (dt == DiagnosticType.NOTE && ds == null && !hasDiagnosticListener()) {
|
||||
printRawLines(WriterKind.STDOUT, message);
|
||||
getWriter(WriterKind.STDOUT).flush();
|
||||
} else {
|
||||
report(javadocDiags.create(dt, null, flags, ds, dp, "message", message));
|
||||
}
|
||||
report(javadocDiags.create(dt, null, flags, ds, dp, "message", message));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -195,7 +195,7 @@ public class Start {
|
||||
}
|
||||
|
||||
private void showUsage(String headerKey, ToolOption.Kind kind, String footerKey) {
|
||||
messager.notice(headerKey);
|
||||
messager.noticeUsingKey(headerKey);
|
||||
showToolOptions(kind);
|
||||
|
||||
// let doclet print usage information
|
||||
@ -205,11 +205,11 @@ public class Start {
|
||||
: Option.Kind.STANDARD);
|
||||
}
|
||||
if (footerKey != null)
|
||||
messager.notice(footerKey);
|
||||
messager.noticeUsingKey(footerKey);
|
||||
}
|
||||
|
||||
private void showVersion(String labelKey, String value) {
|
||||
messager.notice(labelKey, messager.programName, value);
|
||||
messager.noticeUsingKey(labelKey, messager.programName, value);
|
||||
}
|
||||
|
||||
private void showToolOptions(ToolOption.Kind kind) {
|
||||
@ -252,7 +252,7 @@ public class Start {
|
||||
if (options.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
messager.notice("main.doclet.usage.header", name);
|
||||
messager.noticeUsingKey("main.doclet.usage.header", name);
|
||||
|
||||
Comparator<Doclet.Option> comp = new Comparator<Doclet.Option>() {
|
||||
final Collator collator = Collator.getInstance(Locale.US);
|
||||
@ -307,22 +307,22 @@ public class Start {
|
||||
if (synopses.length() < DEFAULT_SYNOPSIS_WIDTH
|
||||
&& !description.contains("\n")
|
||||
&& (SMALL_INDENT.length() + DEFAULT_SYNOPSIS_WIDTH + 1 + description.length() <= DEFAULT_MAX_LINE_LENGTH)) {
|
||||
messager.printNotice(String.format(COMPACT_FORMAT, synopses, description));
|
||||
messager.notice(String.format(COMPACT_FORMAT, synopses, description));
|
||||
return;
|
||||
}
|
||||
|
||||
// If option synopses fit on a single line of reasonable length, show that;
|
||||
// otherwise, show 1 per line
|
||||
if (synopses.length() <= DEFAULT_MAX_LINE_LENGTH) {
|
||||
messager.printNotice(SMALL_INDENT + synopses);
|
||||
messager.notice(SMALL_INDENT + synopses);
|
||||
} else {
|
||||
for (String name: names) {
|
||||
messager.printNotice(SMALL_INDENT + name + parameters);
|
||||
messager.notice(SMALL_INDENT + name + parameters);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, show the description
|
||||
messager.printNotice(LARGE_INDENT + description.replace("\n", "\n" + LARGE_INDENT));
|
||||
messager.notice(LARGE_INDENT + description.replace("\n", "\n" + LARGE_INDENT));
|
||||
}
|
||||
|
||||
|
||||
@ -560,7 +560,7 @@ public class Start {
|
||||
// We're done.
|
||||
if (options.verbose()) {
|
||||
long elapsedMillis = (System.nanoTime() - startNanos) / 1_000_000;
|
||||
messager.notice("main.done_in", Long.toString(elapsedMillis));
|
||||
messager.noticeUsingKey("main.done_in", Long.toString(elapsedMillis));
|
||||
}
|
||||
|
||||
return returnStatus;
|
||||
|
@ -199,7 +199,7 @@ public class ToolEnvironment {
|
||||
if (quiet) {
|
||||
return;
|
||||
}
|
||||
messager.notice(key);
|
||||
messager.noticeUsingKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -212,7 +212,7 @@ public class ToolEnvironment {
|
||||
if (quiet) {
|
||||
return;
|
||||
}
|
||||
messager.notice(key, a1);
|
||||
messager.noticeUsingKey(key, a1);
|
||||
}
|
||||
|
||||
TreePath getTreePath(JCCompilationUnit tree) {
|
||||
|
@ -70,7 +70,7 @@ public class TestDiagsLineCaret extends JavadocTester {
|
||||
error: This is a error
|
||||
warning: This is a warning
|
||||
warning: This is a mandatory_warning
|
||||
This is a note
|
||||
Note: This is a note
|
||||
MyClass.java:5: error: This is a error for MyClass
|
||||
public class MyClass { }
|
||||
^
|
||||
|
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8267204
|
||||
* @summary Expose access to underlying streams in Reporter
|
||||
* @library /tools/lib ../../lib
|
||||
* @modules jdk.javadoc/jdk.javadoc.internal.tool
|
||||
* @build toolbox.ToolBox javadoc.tester.*
|
||||
* @run main TestReporterStreams
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
import com.sun.source.doctree.DocCommentTree;
|
||||
import com.sun.source.doctree.SinceTree;
|
||||
import com.sun.source.tree.CompilationUnitTree;
|
||||
import com.sun.source.util.DocSourcePositions;
|
||||
import com.sun.source.util.DocTreePath;
|
||||
import com.sun.source.util.DocTrees;
|
||||
import com.sun.source.util.TreePath;
|
||||
import javadoc.tester.JavadocTester;
|
||||
import jdk.javadoc.doclet.Doclet;
|
||||
import jdk.javadoc.doclet.DocletEnvironment;
|
||||
import jdk.javadoc.doclet.Reporter;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
public class TestReporterStreams extends JavadocTester {
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
TestReporterStreams tester = new TestReporterStreams();
|
||||
tester.runTests(m -> new Object[]{Path.of(m.getName())});
|
||||
}
|
||||
|
||||
ToolBox tb = new ToolBox();
|
||||
|
||||
TestReporterStreams() throws IOException {
|
||||
tb.writeJavaFiles(Path.of("."), """
|
||||
/**
|
||||
* Comment.
|
||||
* @since 0
|
||||
*/
|
||||
public class C { }""");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the entry point used by the DocumentationTool API and JavadocTester, in which
|
||||
* all output is written to a single specified writer.
|
||||
*/
|
||||
@Test
|
||||
public void testSingleStream(Path base) throws IOException {
|
||||
test(base, false, Output.OUT, Output.OUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the entry point used by the launcher, in which output is written to
|
||||
* writers that wrap {@code System.out} and {@code System.err}.
|
||||
*/
|
||||
@Test
|
||||
public void testStandardStreams(Path base) throws IOException {
|
||||
test(base, true, Output.STDOUT, Output.STDERR);
|
||||
}
|
||||
|
||||
void test(Path base, boolean useStdStreams, Output stdOut, Output stdErr) throws IOException {
|
||||
String testClasses = System.getProperty("test.classes");
|
||||
|
||||
setOutputDirectoryCheck(DirectoryCheck.NONE);
|
||||
setUseStandardStreams(useStdStreams);
|
||||
javadoc("-docletpath", testClasses,
|
||||
"-doclet", MyDoclet.class.getName(),
|
||||
"C.java" // avoid using a directory, to avoid path separator issues in expected output
|
||||
);
|
||||
checkExit(Exit.ERROR);
|
||||
checkOutput(stdOut, true,
|
||||
"Writing to the standard writer");
|
||||
checkOutput(stdErr, true,
|
||||
"Writing to the diagnostic writer");
|
||||
checkOutput(stdErr, true,
|
||||
"""
|
||||
error: This is a ERROR with no position
|
||||
C.java:5: error: This is a ERROR for an element
|
||||
public class C { }
|
||||
^
|
||||
C.java:2: error: This is a ERROR for a doc tree path
|
||||
* Comment.
|
||||
^
|
||||
C.java:3: error: This is a ERROR for a file position
|
||||
* @since 0
|
||||
^
|
||||
warning: This is a WARNING with no position
|
||||
C.java:5: warning: This is a WARNING for an element
|
||||
public class C { }
|
||||
^
|
||||
C.java:2: warning: This is a WARNING for a doc tree path
|
||||
* Comment.
|
||||
^
|
||||
C.java:3: warning: This is a WARNING for a file position
|
||||
* @since 0
|
||||
^
|
||||
warning: This is a MANDATORY_WARNING with no position
|
||||
C.java:5: warning: This is a MANDATORY_WARNING for an element
|
||||
public class C { }
|
||||
^
|
||||
C.java:2: warning: This is a MANDATORY_WARNING for a doc tree path
|
||||
* Comment.
|
||||
^
|
||||
C.java:3: warning: This is a MANDATORY_WARNING for a file position
|
||||
* @since 0
|
||||
^
|
||||
Note: This is a NOTE with no position
|
||||
C.java:5: Note: This is a NOTE for an element
|
||||
public class C { }
|
||||
^
|
||||
C.java:2: Note: This is a NOTE for a doc tree path
|
||||
* Comment.
|
||||
^
|
||||
C.java:3: Note: This is a NOTE for a file position
|
||||
* @since 0
|
||||
^
|
||||
""");
|
||||
}
|
||||
|
||||
public static class MyDoclet implements Doclet {
|
||||
private Locale locale;
|
||||
private Reporter reporter;
|
||||
|
||||
@Override
|
||||
public void init(Locale locale, Reporter reporter) {
|
||||
this.locale = locale;
|
||||
this.reporter = reporter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "MyDoclet";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<? extends Option> getSupportedOptions() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latestSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean run(DocletEnvironment environment) {
|
||||
// Write directly to the given streams
|
||||
reporter.getStandardWriter().println("Writing to the standard writer");
|
||||
reporter.getDiagnosticWriter().println("Writing to the diagnostic writer");
|
||||
|
||||
// the following is little more than a null check for the locale
|
||||
reporter.print(Diagnostic.Kind.NOTE, "The locale is " + locale.getDisplayName());
|
||||
|
||||
// Write different kinds of diagnostics using the different overloads
|
||||
// for printing diagnostics
|
||||
Set<? extends Element> specElems = environment.getSpecifiedElements();
|
||||
Element e = specElems.iterator().next();
|
||||
|
||||
DocTrees trees = environment.getDocTrees();
|
||||
TreePath tp = trees.getPath(e);
|
||||
DocCommentTree dct = trees.getDocCommentTree(e);
|
||||
DocTreePath dtp = new DocTreePath(tp, dct);
|
||||
|
||||
CompilationUnitTree cut = tp.getCompilationUnit();
|
||||
JavaFileObject fo = cut.getSourceFile();
|
||||
SinceTree st = (SinceTree) dct.getBlockTags().get(0);
|
||||
DocSourcePositions sp = trees.getSourcePositions();
|
||||
int start = (int) sp.getStartPosition(cut, dct, st);
|
||||
int pos = (int) sp.getStartPosition(cut, dct, st.getBody().get(0));
|
||||
int end = (int) sp.getEndPosition(cut, dct, st);
|
||||
|
||||
for (Diagnostic.Kind k : Diagnostic.Kind.values()) {
|
||||
if (k == Diagnostic.Kind.OTHER) {
|
||||
continue;
|
||||
}
|
||||
|
||||
reporter.print(k, "This is a " + k + " with no position");
|
||||
reporter.print(k, e, "This is a " + k + " for an element");
|
||||
reporter.print(k, dtp, "This is a " + k + " for a doc tree path");
|
||||
reporter.print(k, fo, start, pos, end, "This is a " + k + " for a file position");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -236,6 +236,7 @@ public abstract class JavadocTester {
|
||||
private boolean automaticCheckAccessibility = true;
|
||||
private boolean automaticCheckLinks = true;
|
||||
private boolean automaticCheckUniqueOUT = true;
|
||||
private boolean useStandardStreams = false;
|
||||
|
||||
/** The current subtest number. Incremented when checking(...) is called. */
|
||||
private int numTestsRun = 0;
|
||||
@ -338,7 +339,7 @@ public abstract class JavadocTester {
|
||||
cs = charsetArg;
|
||||
}
|
||||
} else {
|
||||
cs = docencodingArg;
|
||||
cs = docencodingArg;
|
||||
}
|
||||
try {
|
||||
charset = Charset.forName(cs);
|
||||
@ -351,7 +352,7 @@ public abstract class JavadocTester {
|
||||
|
||||
outputDirectoryCheck.check(outputDir);
|
||||
|
||||
// This is the sole stream used by javadoc
|
||||
// This is the sole stream normally used by javadoc
|
||||
WriterOutput outOut = new WriterOutput();
|
||||
|
||||
// These are to catch output to System.out and System.err,
|
||||
@ -360,7 +361,9 @@ public abstract class JavadocTester {
|
||||
StreamOutput sysErr = new StreamOutput(System.err, System::setErr);
|
||||
|
||||
try {
|
||||
exitCode = jdk.javadoc.internal.tool.Main.execute(args, outOut.pw);
|
||||
exitCode = useStandardStreams
|
||||
? jdk.javadoc.internal.tool.Main.execute(args) // use sysOut, sysErr
|
||||
: jdk.javadoc.internal.tool.Main.execute(args, outOut.pw); // default
|
||||
} finally {
|
||||
outputMap.put(Output.STDOUT, sysOut.close());
|
||||
outputMap.put(Output.STDERR, sysErr.close());
|
||||
@ -418,6 +421,16 @@ public abstract class JavadocTester {
|
||||
automaticCheckUniqueOUT = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to use standard output streams (stdout and stderr)
|
||||
* instead of a single temporary stream.
|
||||
* Tests using standard streams should generally take care to avoid
|
||||
* conflicting use of stdout and stderr.
|
||||
*/
|
||||
public void setUseStandardStreams(boolean b) {
|
||||
useStandardStreams = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* The exit codes returned by the javadoc tool.
|
||||
* @see jdk.javadoc.internal.tool.Main.Result
|
||||
@ -1105,4 +1118,4 @@ public abstract class JavadocTester {
|
||||
|
||||
// Support classes for checkLinks
|
||||
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -109,8 +109,8 @@ public class EnsureNewOldDoclet extends TestRunner {
|
||||
setArgs("-classpath", ".", // insulates us from ambient classpath
|
||||
testSrc.toString());
|
||||
Task.Result tr = task.run(Task.Expect.SUCCESS);
|
||||
List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
|
||||
checkOutput(testName, out, NEW_HEADER);
|
||||
List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
|
||||
checkOutput(testName, err, NEW_HEADER);
|
||||
}
|
||||
|
||||
// input: new doclet and new taglet
|
||||
@ -128,8 +128,8 @@ public class EnsureNewOldDoclet extends TestRunner {
|
||||
Task.Result tr = task.run(Task.Expect.SUCCESS);
|
||||
List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
|
||||
List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
|
||||
checkOutput(testName, out, NEW_HEADER);
|
||||
checkOutput(testName, out, NEW_TAGLET_MARKER);
|
||||
checkOutput(testName, err, NEW_HEADER);
|
||||
checkOutput(testName, err, NEW_TAGLET_MARKER);
|
||||
}
|
||||
|
||||
void setArgs(String... args) {
|
||||
|
@ -54,9 +54,8 @@ public class GetTask_DiagListenerTest extends APITest {
|
||||
/**
|
||||
* Verify that a diagnostic listener can be specified.
|
||||
* Note that messages from the tool and doclet are imperfectly modeled
|
||||
* because the DocErrorReporter API works in terms of localized strings
|
||||
* and file:line positions. Therefore, messages reported via DocErrorReporter
|
||||
* and simply wrapped and passed through.
|
||||
* because the Reporter API works in terms of localized strings.
|
||||
* Therefore, messages reported via Reporter are simply wrapped and passed through.
|
||||
*/
|
||||
@Test
|
||||
public void testDiagListener() throws Exception {
|
||||
@ -77,7 +76,6 @@ public class GetTask_DiagListenerTest extends APITest {
|
||||
diagCodes.add(d.getCode());
|
||||
}
|
||||
List<String> expect = Arrays.asList(
|
||||
"javadoc.note.message", // Loading source file
|
||||
"compiler.err.expected4", // class, interface, enum, or record expected
|
||||
"javadoc.note.message"); // 1 error
|
||||
if (!diagCodes.equals(expect))
|
||||
|
Loading…
Reference in New Issue
Block a user