8267126: javadoc should show "line and caret" for diagnostics.

Reviewed-by: prappo
This commit is contained in:
Jonathan Gibbons 2021-05-25 01:33:13 +00:00
parent 461a3feebe
commit b4d4884c03
37 changed files with 839 additions and 313 deletions

View File

@ -60,6 +60,7 @@ import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.util.Names;
import com.sun.tools.javac.util.Options;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
import jdk.javadoc.internal.tool.ToolEnvironment;
@ -536,4 +537,21 @@ public class WorkArounds {
return (sym.flags() & Flags.PREVIEW_REFLECTIVE) != 0;
}
/**
* Returns whether or not to permit dynamically loaded components to access
* part of the javadoc internal API. The flag is the same (hidden) compiler
* option that allows javac plugins and annotation processors to access
* javac internal API.
*
* As with all workarounds, it is better to consider updating the public API,
* rather than relying on undocumented features like this, that may be withdrawn
* at any time, without notice.
*
* @return true if access is permitted to internal API
*/
public boolean accessInternalAPI() {
Options compilerOptions = Options.instance(toolEnv.context);
return compilerOptions.isSet("accessInternalAPI");
}
}

View File

@ -185,6 +185,8 @@ public class TagletManager {
private final String tagletPath;
private final BaseConfiguration configuration;
/**
* Constructs a new {@code TagletManager}.
*
@ -197,6 +199,7 @@ public class TagletManager {
standardTagsLowercase = new HashSet<>();
unseenCustomTags = new HashSet<>();
allTaglets = new LinkedHashMap<>();
this.configuration = configuration;
BaseOptions options = configuration.getOptions();
this.nosince = options.noSince();
this.showversion = options.showVersion();
@ -250,6 +253,15 @@ public class TagletManager {
try {
ClassLoader tagClassLoader;
tagClassLoader = fileManager.getClassLoader(TAGLET_PATH);
if (configuration.workArounds.accessInternalAPI()) {
Module thisModule = getClass().getModule();
Module tagletLoaderUnnamedModule = tagClassLoader.getUnnamedModule();
List<String> pkgs = List.of(
"jdk.javadoc.doclet",
"jdk.javadoc.internal.doclets.toolkit",
"jdk.javadoc.internal.doclets.formats.html");
pkgs.forEach(p -> thisModule.addOpens(p, tagletLoaderUnnamedModule));
}
Class<? extends jdk.javadoc.doclet.Taglet> customTagClass =
tagClassLoader.loadClass(classname).asSubclass(jdk.javadoc.doclet.Taglet.class);
jdk.javadoc.doclet.Taglet instance = customTagClass.getConstructor().newInstance();

View File

@ -93,6 +93,7 @@ import javax.tools.JavaFileManager;
import javax.tools.JavaFileManager.Location;
import javax.tools.StandardLocation;
import com.sun.source.doctree.BlockTagTree;
import com.sun.source.doctree.DeprecatedTree;
import com.sun.source.doctree.DocCommentTree;
import com.sun.source.doctree.DocTree;
@ -2632,10 +2633,10 @@ public class Utils {
public List<? extends DocTree> getBlockTags(Element element, Taglet taglet) {
return getBlockTags(element, t -> {
if (taglet instanceof BaseTaglet bt) {
return bt.accepts(t);
} else if (t instanceof UnknownBlockTagTree tree) {
return tree.getTagName().equals(taglet.getName());
if (taglet instanceof BaseTaglet baseTaglet) {
return baseTaglet.accepts(t);
} else if (t instanceof BlockTagTree blockTagTree) {
return blockTagTree.getTagName().equals(taglet.getName());
} else {
return false;
}

View File

@ -567,7 +567,7 @@ public class ElementsTable {
if (!isMandated(mdle, rd) && onlyTransitive == rd.isTransitive()) {
if (!haveModuleSources(dep)) {
if (!warnedNoSources.contains(dep)) {
messager.printWarning(dep, "main.module_source_not_found", dep.getQualifiedName());
messager.printWarningUsingKey(dep, "main.module_source_not_found", dep.getQualifiedName());
warnedNoSources.add(dep);
}
}

View File

@ -25,32 +25,90 @@
package jdk.javadoc.internal.tool;
import java.io.PrintWriter;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import javax.lang.model.element.Element;
import javax.tools.Diagnostic;
import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.util.Context.Factory;
import jdk.javadoc.doclet.Reporter;
import com.sun.tools.javac.tree.EndPosTable;
import com.sun.tools.javac.util.Context.Factory;
import com.sun.tools.javac.util.DiagnosticSource;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.util.DocSourcePositions;
import com.sun.source.util.DocTreePath;
import com.sun.source.util.TreePath;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
import com.sun.tools.javac.util.JavacMessages;
import com.sun.tools.javac.util.Log;
/**
* Utility for integrating with javadoc tools and for localization.
* Handle resources, access to error and warning counts and
* message formatting.
* Class for reporting diagnostics and other messages.
*
* The class leverages the javac support for reporting diagnostics, for stylistic consistency
* of diagnostic messages and to avoid code duplication.
*
* The class is a subtype of javac's Log, and is primarily an adapter between
* javadoc method signatures and the underlying javac methods. Within this class,
* the methods call down to a core {@code report} method which hands off to
* a similar method in the superclass ({@code Log.report}, which takes care
* of reporting the diagnostic (unless it has been suppressed), displaying
* the source line and a caret to indicate the position of the issue (if appropriate),
* counting errors and warnings, and so on.
*
* In general, the underlying javac layer is more powerful, whereas the javadoc methods are
* constrained by the public {@link jdk.javadoc.doclet.Doclet} API.
*
* In the underlying javac layer, the following abstractions are used:
* <ul>
* <li>{@code DiagnosticType} -- error, warning, note, etc.
* <li>{@code DiagnosticSource} -- a file object and a cache of its content
* <li>{@code DiagnosticPosition} -- a tuple of values (start, pos, end) for the position of a diagnostic
* <li>{@code DiagnosticFlag} -- additional flags related to the diagnostic
* </ul>
*
* The javadoc layer is defined by the methods on {@code Doclet.Reporter}, and by
* assorted methods defined in this class for use by the javadoc tool.
* The primary data types are:
* <ul>
* <li>{@code Diagnostic.Kind} -- maps to {@code DiagnosticType} and {@code Set<DiagnosticFlag>}
* <li>{@code Element} -- maps to {@code DiagnosticSource} and {@code DiagnosticPosition}
* <li>{@code DocTreePath} -- maps to {@code DiagnosticSource} and {@code DiagnosticPosition}
* </ul>
*
* The reporting methods in the javac layer primarily take pre-localized (key, args) pairs,
* while the methods in the javadoc layer, especially the {@code Reporter} interface, take
* localized strings. To accommodate this, "wrapper" resources are used, whose value is {@code {0}},
* to pass the localized string down to javac. A side-effect is that clients using a
* {@code DiagnosticListener} with a {@code DocumentationTask} cannot access the original resource
* key for the localized message.
* Given the limitations of the API, it is not possible to do any better.
* The javac Annotation Processing API has the same problem.
*
* There is a slight disparity between javac's use of streams and javadoc's use of streams.
* javac reports <b>all</b> diagnostics to the "error" stream, and provides a separate
* "output" stream for expected output, such as command-line help or the output from options
* like {@code -Xprint}. javadoc API, and {@code Reporter} in particular, does not specify
* the use of streams, and provides no support for identifying or specifying streams. JDK-8267204.
* The current implementation/workaround is to write errors and warnings to the "error"
* stream and notes to the "output" stream.
*
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
@ -61,7 +119,19 @@ import com.sun.tools.javac.util.Log;
* @see java.text.MessageFormat
*/
public class Messager extends Log implements Reporter {
final Context context;
/** The overall context for the documentation run. */
private final Context context;
/** The tool environment, providing access to the tool's utility classes and tables. */
private ToolEnvironment toolEnv;
/** The utility class to access the positions of items in doc comments. */
private DocSourcePositions sourcePositions;
/**
* A memory-sensitive cache of recently used {@code DiagnosticSource} objects.
*/
private final LinkedHashMap<JavaFileObject, SoftReference<DiagnosticSource>> diagSourceCache;
/** Get the current messager, which is also the compiler log. */
public static Messager instance0(Context context) {
@ -81,66 +151,16 @@ public class Messager extends Log implements Reporter {
context.put(logKey, (Factory<Log>)c -> new Messager(c, programName, outWriter, errWriter));
}
@Override
public void print(Kind kind, String msg) {
switch (kind) {
case ERROR:
printError(msg);
return;
case WARNING:
case MANDATORY_WARNING:
printWarning(msg);
return;
default:
printNotice(msg);
return;
}
}
@Override
public void print(Kind kind, DocTreePath path, String msg) {
switch (kind) {
case ERROR:
printError(path, msg);
return;
case WARNING:
case MANDATORY_WARNING:
printWarning(path, msg);
return;
default:
printWarning(path, msg);
return;
}
}
@Override
public void print(Kind kind, Element e, String msg) {
switch (kind) {
case ERROR:
printError(e, msg);
return;
case WARNING:
case MANDATORY_WARNING:
printWarning(e, msg);
return;
case NOTE:
printNotice(e, msg);
return;
default:
throw new IllegalArgumentException(String.format("unexpected option %s", kind));
}
}
final String programName;
private Locale locale;
private final JavacMessages messages;
private final JCDiagnostic.Factory javadocDiags;
/** The default writer for diagnostics
*/
static final PrintWriter defaultOutWriter = new PrintWriter(System.out);
static final PrintWriter defaultErrWriter = new PrintWriter(System.err);
/** 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);
/**
* Constructor
@ -166,6 +186,15 @@ public class Messager extends Log implements Reporter {
this.programName = programName;
this.context = context;
locale = Locale.getDefault();
diagSourceCache = new LinkedHashMap<>() {
private static final int MAX_ENTRIES = 5;
@Override
protected boolean removeEldestEntry(Map.Entry<JavaFileObject, SoftReference<DiagnosticSource>> eldest) {
return size() > MAX_ENTRIES;
}
};
}
public void setLocale(Locale locale) {
@ -173,183 +202,173 @@ public class Messager extends Log implements Reporter {
}
/**
* get and format message string from resource
* Returns the localized string from the tool's resource bundles.
*
* @param key selects message from resource
* @param args arguments for the message
* @param key the resource key
* @param args arguments for the resource
*/
String getText(String key, Object... args) {
return messages.getLocalizedString(locale, key, args);
}
private String getDiagSource(DocTreePath path) {
if (path == null || path.getTreePath() == null) {
return programName;
}
JavacTrees trees = JavacTrees.instance(context);
DocSourcePositions sourcePositions = trees.getSourcePositions();
CompilationUnitTree cu = path.getTreePath().getCompilationUnit();
long spos = sourcePositions.getStartPosition(cu, path.getDocComment(), path.getLeaf());
long lineNumber = cu.getLineMap().getLineNumber(spos);
String fname = cu.getSourceFile().getName();
String posString = fname + ":" + lineNumber;
return posString;
@Override // Reporter
public void print(Kind kind, String message) {
report(kind, null, null, message);
}
private String getDiagSource(Element e) {
if (e == null) {
return programName;
}
JavacTrees trees = JavacTrees.instance(context);
TreePath path = trees.getPath(e);
if (path == null) {
return programName;
}
DocSourcePositions sourcePositions = trees.getSourcePositions();
JCTree tree = trees.getTree(e);
CompilationUnitTree cu = path.getCompilationUnit();
long spos = sourcePositions.getStartPosition(cu, tree);
long lineNumber = cu.getLineMap().getLineNumber(spos);
String fname = cu.getSourceFile().getName();
String posString = fname + ":" + lineNumber;
return posString;
@Override // Reporter
public void print(Diagnostic.Kind kind, DocTreePath path, String message) {
DiagnosticType dt = getDiagnosticType(kind);
Set<DiagnosticFlag> flags = getDiagnosticFlags(kind);
DiagnosticSource ds = getDiagnosticSource(path);
DiagnosticPosition dp = getDiagnosticPosition(path);
report(dt, flags, ds, dp, message);
}
@Override // Reporter
public void print(Kind kind, Element element, String message) {
DiagnosticType dt = getDiagnosticType(kind);
Set<DiagnosticFlag> flags = getDiagnosticFlags(kind);
DiagnosticSource ds = getDiagnosticSource(element);
DiagnosticPosition dp = getDiagnosticPosition(element);
report(dt, flags, ds, dp, message);
}
/**
* Print error message, increment error count.
* Part of DocErrorReporter.
* Prints an error message.
*
* @param msg message to print
* @param message the message
*/
public void printError(String msg) {
printError((DocTreePath)null, msg);
public void printError(String message) {
report(DiagnosticType.ERROR,null, null, message);
}
public void printError(DocTreePath path, String msg) {
String prefix = getDiagSource(path);
if (diagListener != null) {
report(DiagnosticType.ERROR, prefix, msg);
return;
}
printError(prefix, msg);
/**
* Prints an error message for a given documentation tree node.
*
* @param path the path for the documentation tree node
* @param message the message
*/
public void printError(DocTreePath path, String message) {
DiagnosticSource ds = getDiagnosticSource(path);
DiagnosticPosition dp = getDiagnosticPosition(path);
report(DiagnosticType.ERROR, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
}
public void printError(Element e, String msg) {
String prefix = getDiagSource(e);
if (diagListener != null) {
report(DiagnosticType.ERROR, prefix, msg);
return;
}
printError(prefix, msg);
/**
* Prints an error message for a given element.
*
* @param element the element
* @param message the message
*/
public void printError(Element element, String message) {
DiagnosticSource ds = getDiagnosticSource(element);
DiagnosticPosition dp = getDiagnosticPosition(element);
report(DiagnosticType.ERROR, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
}
/**
* Prints an error message.
*
* @param key the resource key for the message
* @param args the arguments for the message
*/
public void printErrorUsingKey(String key, Object... args) {
printError((Element)null, getText(key, args));
}
// print the error and increment count
private void printError(String prefix, String msg) {
if (nerrors < MaxErrors) {
PrintWriter errWriter = getWriter(WriterKind.ERROR);
printRawLines(errWriter, prefix + ": " + getText("javadoc.error") + " - " + msg);
errWriter.flush();
prompt();
nerrors++;
}
printError(getText(key, args));
}
/**
* Print warning message, increment warning count.
* Part of DocErrorReporter.
* Prints a warning message.
*
* @param msg message to print
* @param message the message
*/
public void printWarning(String msg) {
printWarning((DocTreePath)null, msg);
public void printWarning(String message) {
report(DiagnosticType.WARNING, null, null, message);
}
/**
* Prints a warning message for a given documentation tree node.
*
* @param path the path for the documentation tree node
* @param message the message
*/
public void printWarning(DocTreePath path, String message) {
DiagnosticSource ds = getDiagnosticSource(path);
DiagnosticPosition dp = getDiagnosticPosition(path);
report(DiagnosticType.WARNING, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
}
/**
* Prints a warning message for a given element.
*
* @param element the element
* @param message the message
*/
public void printWarning(Element element, String message) {
DiagnosticSource ds = getDiagnosticSource(element);
DiagnosticPosition dp = getDiagnosticPosition(element);
report(DiagnosticType.WARNING, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
}
/**
* Prints a warning message.
*
* @param key the resource key for the message
* @param args the arguments for the message
*/
public void printWarningUsingKey(String key, Object... args) {
printWarning((Element)null, getText(key, args));
}
public void printWarning(Element e, String key, Object... args) {
printWarning(getText(key, args));
}
public void printWarning(DocTreePath path, String msg) {
String prefix = getDiagSource(path);
if (diagListener != null) {
report(DiagnosticType.WARNING, prefix, msg);
return;
}
printWarning(prefix, msg);
}
public void printWarning(Element e, String msg) {
String prefix = getDiagSource(e);
if (diagListener != null) {
report(DiagnosticType.WARNING, prefix, msg);
return;
}
printWarning(prefix, msg);
}
// print the warning and increment count
private void printWarning(String prefix, String msg) {
if (nwarnings < MaxWarnings) {
PrintWriter warnWriter = getWriter(WriterKind.WARNING);
printRawLines(warnWriter, prefix + ": " + getText("javadoc.warning") + " - " + msg);
warnWriter.flush();
nwarnings++;
}
}
/**
* Print a message.
* Part of DocErrorReporter.
* Prints a warning message for an element.
*
* @param msg message to print
* @param element the element
* @param key the resource key for the message
* @param args the arguments for the message
*/
public void printNotice(String msg) {
printNotice((DocTreePath)null, msg);
}
public void printNotice(DocTreePath path, String msg) {
String prefix = getDiagSource(path);
if (diagListener != null) {
report(DiagnosticType.NOTE, null, prefix + ": " + msg);
return;
}
PrintWriter noticeWriter = getWriter(WriterKind.NOTICE);
if (path == null) {
printRawLines(noticeWriter, msg);
} else {
printRawLines(noticeWriter, prefix + ": " + msg);
}
noticeWriter.flush();
}
public void printNotice(Element e, String msg) {
String pos = getDiagSource(e);
if (diagListener != null) {
report(DiagnosticType.NOTE, pos, msg);
return;
}
PrintWriter noticeWriter = getWriter(WriterKind.NOTICE);
if (e == null) {
printRawLines(noticeWriter, msg);
} else {
printRawLines(noticeWriter, pos + ": " + msg);
}
noticeWriter.flush();
public void printWarningUsingKey(Element element, String key, Object... args) {
printWarning(element, getText(key, args));
}
/**
* Print a message.
* Prints a "notice" message.
*
* @param key selects message from resource
* @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.
*
* @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));
@ -370,7 +389,7 @@ public class Messager extends Log implements Reporter {
}
/**
* Print exit message.
* Prints the error and warning counts, if any.
*/
public void printErrorWarningCounts() {
if (nerrors > 0) {
@ -383,21 +402,237 @@ public class Messager extends Log implements Reporter {
}
}
private void report(DiagnosticType type, String pos, String msg) {
switch (type) {
case ERROR:
case WARNING:
Object prefix = (pos == null) ? programName : pos;
report(javadocDiags.create(type, null, null, "msg", prefix, msg));
break;
/**
* Reports a diagnostic message.
*
* @param kind the kind of diagnostic
* @param ds the diagnostic source
* @param dp the diagnostic position
* @param message the message
*/
private void report(Diagnostic.Kind kind, DiagnosticSource ds, DiagnosticPosition dp, String message) {
report(getDiagnosticType(kind), getDiagnosticFlags(kind), ds, dp, message);
}
case NOTE:
String key = (pos == null) ? "msg" : "pos.msg";
report(javadocDiags.create(type, null, null, key, pos, msg));
break;
/**
* Reports a diagnostic message.
*
* @param dt the diagnostic type
* @param ds the diagnostic source
* @param dp the diagnostic position
* @param message the message
*/
private void report(DiagnosticType dt, DiagnosticSource ds, DiagnosticPosition dp, String message) {
report(dt, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
}
default:
throw new IllegalArgumentException(type.toString());
/**
* Reports a diagnostic message, with diagnostic flags.
* For javadoc, the only flag that is used is {@code MANDATORY_WARNING}, and only
* because in principle the public API supports it via {@code Kind.MANDATORY_WARNING}.
* javadoc itself does generate mandatory warnings.
*
* This is the primary low-level wrapper around the underlying {@code Log.report}.
* Because we already have a localized message, we use wrapper resources (just {@code {0}})
* to wrap the string. The current behavior is one wrapper per diagnostic type.
* We could improve this by subtyping {@code DiagnosticInfo} to modify the resource key used.
*
* {@code Log} reports all diagnostics to the corresponding writer, which defaults
* to the "error" stream, when using the two-stream constructor. That doesn't work
* for javadoc, which has historically written notes to the "output" stream, because
* the public API used by doclets does not provide for more detailed control.
* Therefore, for now, javadoc continues to use the (deprecated) three-stream
* constructor, with the {@code NOTE} stream set to the "output" stream.
*
* {@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}).
*
* 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).
*
* @param dt the diagnostic type
* @param ds the diagnostic source
* @param dp the diagnostic position
* @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));
}
}
/**
* Returns a diagnostic position for a documentation tree node.
*
* @param path the path for the documentation tree node
* @return the diagnostic position
*/
private DiagnosticPosition getDiagnosticPosition(DocTreePath path) {
DocSourcePositions posns = getSourcePositions();
CompilationUnitTree compUnit = path.getTreePath().getCompilationUnit();
int start = (int) posns.getStartPosition(compUnit, path.getDocComment(), path.getLeaf());
int end = (int) posns.getEndPosition(compUnit, path.getDocComment(), path.getLeaf());
return createDiagnosticPosition(null, start, start, end);
}
/**
* Returns a diagnostic position for an element, or {@code null} if the source
* file is not available.
*
* @param element the element
* @return the diagnostic position
*/
private DiagnosticPosition getDiagnosticPosition(Element element) {
ToolEnvironment toolEnv = getToolEnv();
DocSourcePositions posns = getSourcePositions();
TreePath tp = toolEnv.elementToTreePath.get(element);
if (tp == null) {
return null;
}
CompilationUnitTree compUnit = tp.getCompilationUnit();
JCTree tree = (JCTree) tp.getLeaf();
int start = (int) posns.getStartPosition(compUnit, tree);
int pos = tree.getPreferredPosition();
int end = (int) posns.getEndPosition(compUnit, tree);
return createDiagnosticPosition(tree, start, pos, end);
}
/**
* Creates a diagnostic position.
*
* @param tree the tree node, or null if no tree is applicable
* @param start the start position
* @param pos the "preferred" position: this is used to position the caret in messages
* @param end the end position
* @return the diagnostic position
*/
private DiagnosticPosition createDiagnosticPosition(JCTree tree, int start, int pos, int end) {
return new DiagnosticPosition() {
@Override
public JCTree getTree() {
return tree;
}
@Override
public int getStartPosition() {
return start;
}
@Override
public int getPreferredPosition() {
return pos;
}
@Override
public int getEndPosition(EndPosTable endPosTable) {
return end;
}
};
}
/**
* Returns the diagnostic type for a diagnostic kind.
*
* @param kind the diagnostic kind
* @return the diagnostic type
*/
private DiagnosticType getDiagnosticType(Diagnostic.Kind kind) {
return switch (kind) {
case ERROR -> DiagnosticType.ERROR;
case WARNING, MANDATORY_WARNING -> DiagnosticType.WARNING;
case NOTE -> DiagnosticType.NOTE;
case OTHER -> DiagnosticType.FRAGMENT;
};
}
/**
* Returns the diagnostic flags for a diagnostic kind.
* A diagnostic kind of {@code MANDATORY_WARNING} requires the {@code MANDATORY} flag.
*
* @param kind the diagnostic kind
* @return the flags
*/
private Set<DiagnosticFlag> getDiagnosticFlags(Diagnostic.Kind kind) {
return kind == Kind.MANDATORY_WARNING
? EnumSet.of(DiagnosticFlag.MANDATORY)
: EnumSet.noneOf(DiagnosticFlag.class);
}
/**
* Returns the diagnostic source for an documentation tree node.
*
* @param path the path for the documentation tree node
* @return the diagnostic source
*/
private DiagnosticSource getDiagnosticSource(DocTreePath path) {
return getDiagnosticSource(path.getTreePath().getCompilationUnit().getSourceFile());
}
/**
* Returns the diagnostic source for an element, or {@code NO_SOURCE} if the
* source file is not known (for example, if the element was read from a class file).
*
* @param element the element
* @return the diagnostic source
*/
private DiagnosticSource getDiagnosticSource(Element element) {
TreePath tp = getToolEnv().elementToTreePath.get(element);
return tp == null ? DiagnosticSource.NO_SOURCE
: getDiagnosticSource(tp.getCompilationUnit().getSourceFile());
}
/**
* Returns the diagnostic source for a file object.
*
* {@code DiagnosticSource} objects are moderately expensive because they maintain
* an internal copy of the content, to provide the line map.
* Therefore, we keep a small memory-sensitive cache of recently used objects.
*
* @param fo the file object
* @return the diagnostic source
*/
private DiagnosticSource getDiagnosticSource(JavaFileObject fo) {
Reference<DiagnosticSource> ref = diagSourceCache.get(fo);
DiagnosticSource ds = ref == null ? null : ref.get();
if (ds == null) {
ds = new DiagnosticSource(fo, this);
diagSourceCache.put(fo, new SoftReference<>(ds));
}
return ds;
}
/**
* Returns the object for computing source positions.
*
* The value is determined lazily because the tool environment is computed lazily.
*
* @return the object for computing source positions
*/
private DocSourcePositions getSourcePositions() {
if (sourcePositions == null) {
sourcePositions = getToolEnv().docTrees.getSourcePositions();
}
return sourcePositions;
}
/**
* Returns the tool environment.
*
* The value is determined lazily, because creating it eagerly disrupts
* the overall initialization of objects in the context.
*
* @return the tool environment
*/
private ToolEnvironment getToolEnv() {
if (toolEnv == null) {
toolEnv = ToolEnvironment.instance(context);
}
return toolEnv;
}
}

View File

@ -327,13 +327,7 @@ public class Start {
/**
* Main program - external wrapper. In order to maintain backward
* CLI compatibility, the execution is dispatched to the appropriate
* Start mechanism, depending on the doclet variant.
*
* The doclet tests are performed in the begin method, further on,
* this is to minimize argument processing and most importantly the impact
* of class loader creation, needed to detect the doclet class variants.
* Main program - external wrapper.
*/
@SuppressWarnings("deprecation")
Result begin(String... argv) {
@ -398,11 +392,19 @@ public class Start {
try {
result = parseAndExecute(options, fileObjects);
} catch (com.sun.tools.javac.main.Option.InvalidValueException e) {
messager.printError(e.getMessage());
// The detail message from javac already includes a localized "error: " prefix,
// so print the message directly.
// It would be even better to rethrow this as IllegalArgumentException
// when invoked via the API.
// See javac Arguments.error(InvalidValueException) for an example
messager.printRawLines(e.getMessage());
Throwable t = e.getCause();
dumpStack(t == null ? e : t);
return ERROR;
} catch (OptionException oe) {
// It would be even better to rethrow this as IllegalArgumentException
// when invoked via the API.
// See javac Arguments.error(InvalidValueException) for an example
if (oe.message != null)
messager.printError(oe.message);

View File

@ -88,17 +88,15 @@ public class ToolEnvironment {
/** Predefined symbols known to the compiler. */
public final Symtab syms;
/** Referenced directly in RootDocImpl. */
/** JavaDoc's subtype of the compiler's class finder */
private final ClassFinder finder;
/** Javadoc's own version of the compiler's enter phase. */
/** Javadoc's subtype of the compiler's enter phase. */
final Enter enter;
/** The name table. */
private Names names;
final Symbol externalizableSym;
/** If true, prevent printing of any notifications. */
boolean quiet = false;
@ -144,7 +142,6 @@ public class ToolEnvironment {
finder = JavadocClassFinder.instance(context);
enter = JavadocEnter.instance(context);
names = Names.instance(context);
externalizableSym = syms.enterClass(syms.java_base, names.fromString("java.io.Externalizable"));
chk = Check.instance(context);
types = com.sun.tools.javac.code.Types.instance(context);
fileManager = context.get(JavaFileManager.class);

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 1997, 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
@ -309,12 +309,16 @@ for duplicates. Include error messages and the following diagnostic in your repo
main.not_a_doclet=\
Class {0} is not a valid doclet.\n\
Note: As of JDK 13, the com.sun.javadoc API is no longer supported.
javadoc.class_not_found=Class {0} not found.
javadoc.error=error
javadoc.warning=warning
javadoc.error.msg={0}: error - {1}
javadoc.warning.msg={0}: warning - {1}
javadoc.note.msg = {1}
javadoc.note.pos.msg= {0}: {1}
javadoc.version={0} {1}
javadoc.fullversion={0} full version "{1}"
javadoc.err.message={0}
javadoc.warn.message={0}
javadoc.note.message={0}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -94,7 +94,7 @@ public class TestCharsetDocencodingOptions extends JavadocTester {
checkExit(Exit.ERROR);
checkOutput(Output.OUT, true,
"javadoc: error - Option -charset conflicts with -docencoding");
"error: Option -charset conflicts with -docencoding");
}
@Test

View File

@ -0,0 +1,145 @@
/*
* 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.
*/
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import javax.lang.model.element.Element;
import javax.tools.Diagnostic;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.EntityTree;
import com.sun.source.util.DocTreePath;
import com.sun.source.util.DocTreePathScanner;
import com.sun.source.util.DocTrees;
import com.sun.source.util.TreePath;
import jdk.javadoc.doclet.Doclet;
import jdk.javadoc.doclet.DocletEnvironment;
import jdk.javadoc.doclet.Reporter;
import jdk.javadoc.doclet.StandardDoclet;
import jdk.javadoc.doclet.Taglet;
/**
* A taglet that writes messages to the doclet's reporter.
*/
public class MyTaglet implements Taglet {
private DocletEnvironment docEnv;
private Reporter reporter;
@Override
public void init(DocletEnvironment env, Doclet doclet) {
Taglet.super.init(env, doclet);
docEnv = env;
// The following should be as simple as
// reporter = ((StandardDoclet) doclet).getReporter();
// JDK-8267176
try {
StandardDoclet sd = (StandardDoclet) doclet;
Field htmlDocletField = sd.getClass().getDeclaredField("htmlDoclet");
htmlDocletField.setAccessible(true);
Object htmlDoclet = htmlDocletField.get(sd);
Method getConfigurationMethod = htmlDoclet.getClass().getDeclaredMethod("getConfiguration");
Object config = getConfigurationMethod.invoke(htmlDoclet);
Method getReporterMethod = config.getClass().getMethod(("getReporter"));
reporter = (Reporter) getReporterMethod.invoke(config);
} catch (ReflectiveOperationException e) {
throw new IllegalStateException(e);
}
}
@Override
public Set<Location> getAllowedLocations() {
return EnumSet.allOf(Location.class);
}
@Override
public boolean isInlineTag() {
return false;
}
@Override
public boolean isBlockTag() {
return true;
}
/**
* Refines an existing tag ({@code @since} that provides a {@code List<DocTree>},
* so that we can better test positions within the tree node. The alternative,
* defining a new tag, would use {@code UnknownBlockTagTree} which just provides
* a single {@code Doc Tree}.
*
* @return the name of the tag supported by this taglet
*/
@Override
public String getName() {
return "since";
}
@Override
public String toString(List<? extends DocTree> tags, Element element) {
List<Diagnostic.Kind> kinds = Arrays.stream(Diagnostic.Kind.values())
.filter(k -> k != Diagnostic.Kind.OTHER)
.toList();
for (Diagnostic.Kind k : kinds) {
String message = "This is a " + k.toString().toLowerCase(Locale.ROOT);
reporter.print(k, message);
}
for (Diagnostic.Kind k : kinds) {
String message = "This is a " + k.toString().toLowerCase(Locale.ROOT) + " for " + element;
reporter.print(k, element, message);
}
DocTreePathScanner<Void, Diagnostic.Kind> s = new DocTreePathScanner<>() {
@Override
public Void scan(DocTree tree, Diagnostic.Kind k) {
return super.scan(tree, k);
}
@Override
public Void visitEntity(EntityTree node, Diagnostic.Kind k) {
if (node.getName().contentEquals("#x1f955")) {
String message = "This is a " + k.toString().toLowerCase(Locale.ROOT)
+ ": this is not a caret";
reporter.print(k, getCurrentPath(), message);
}
return super.visitEntity(node, k);
}
};
DocTrees trees = docEnv.getDocTrees();
TreePath tp = trees.getPath(element);
DocTreePath root = new DocTreePath(tp, trees.getDocCommentTree(element));
for (Diagnostic.Kind k : kinds) {
tags.forEach(t -> s.scan(new DocTreePath(root, t), k));
}
return "<b>mytaglet output</b>";
}
}

View File

@ -0,0 +1,104 @@
/*
* 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 8267126
* @summary javadoc should show "line and caret" for diagnostics
* @library /tools/lib ../../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
* @build javadoc.tester.* MyTaglet
* @run main TestDiagsLineCaret
*/
import java.io.IOException;
import java.nio.file.Path;
import javadoc.tester.JavadocTester;
import toolbox.ToolBox;
public class TestDiagsLineCaret extends JavadocTester {
public static void main(String... args) throws Exception {
TestDiagsLineCaret tester = new TestDiagsLineCaret();
tester.runTests();
}
ToolBox tb = new ToolBox();
@Test
public void testDiags() throws IOException {
tb.writeJavaFiles(Path.of("."), """
/**
* First sentence.
* @since def &#x1f955; ghi
*/
public class MyClass { }
""");
String testClasses = System.getProperty("test.classes");
javadoc("-d", "out",
"-XDaccessInternalAPI",
"-tagletpath", testClasses,
"-taglet", "MyTaglet",
"MyClass.java");
checkExit(Exit.ERROR);
checkOutput(Output.OUT, true,
"""
error: This is a error
warning: This is a warning
warning: This is a mandatory_warning
This is a note
MyClass.java:5: error: This is a error for MyClass
public class MyClass { }
^
MyClass.java:5: warning: This is a warning for MyClass
public class MyClass { }
^
MyClass.java:5: warning: This is a mandatory_warning for MyClass
public class MyClass { }
^
MyClass.java:5: Note: This is a note for MyClass
public class MyClass { }
^
MyClass.java:3: error: This is a error: this is not a caret
* @since def &#x1f955; ghi
^
MyClass.java:3: warning: This is a warning: this is not a caret
* @since def &#x1f955; ghi
^
MyClass.java:3: warning: This is a mandatory_warning: this is not a caret
* @since def &#x1f955; ghi
^
MyClass.java:3: Note: This is a note: this is not a caret
* @since def &#x1f955; ghi
^
""",
"""
3 errors
6 warnings
""");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
@ -171,7 +171,7 @@ public class TestDocFiles extends JavadocTester {
} else {
// be careful handing file separator characters in the message
checkOutput(Output.OUT, true,
"warning - File " + f + " not copied: invalid name");
"warning: File " + f + " not copied: invalid name");
}
}
}

View File

@ -374,7 +374,7 @@ public class TestJavaFX extends JavadocTester {
checkExit(Exit.OK);
// make sure the doclet indeed emits the warning
checkOutput(Output.OUT, true, "C.java:0: warning - invalid usage of tag <");
checkOutput(Output.OUT, true, "C.java:31: warning: invalid usage of tag <");
}
/*
@ -419,6 +419,7 @@ public class TestJavaFX extends JavadocTester {
javadoc("-d", "out5",
"--javafx",
"--disable-javafx-strict-checks",
"--no-platform-links",
"-Xdoclint:all",
"--source-path", "src5",
"pkg");

View File

@ -247,7 +247,7 @@ public class TestRedirectLinks extends JavadocTester {
// 3: The original URL is still used in the generated docs, to avoid assuming
// that all the other files at that link have been redirected as well.
checkOutput(Output.OUT, true,
"javadoc: warning - URL " + oldURL + "/element-list was redirected to " + newURL + "/element-list");
"warning: URL " + oldURL + "/element-list was redirected to " + newURL + "/element-list");
checkOutput("mC/p5/C5.html", true,
"extends <a href=\"" + oldURL + """
/mA/p1/C1.html" title="class or interface in p1" class="external-link">C1</a>""");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -112,6 +112,7 @@ public class TestMissingComment extends JavadocTester {
javadoc("-d", base.resolve("api").toString(),
"-Xdoclint:missing",
"--no-platform-links",
src.resolve("C.java").toString());
checkExit(Exit.OK);
checkOutput(Output.OUT, true,

View File

@ -196,9 +196,9 @@ public class TestNewLanguageFeatures extends JavadocTester {
checkOutput(Output.OUT, true,
// Bad type parameter warnings.
"""
warning - @param argument "<BadClassTypeParam>" is not the name of a type parameter.""",
warning: @param argument "<BadClassTypeParam>" is not the name of a type parameter.""",
"""
warning - @param argument "<BadMethodTypeParam>" is not the name of a type parameter.""");
warning: @param argument "<BadMethodTypeParam>" is not the name of a type parameter.""");
// Signature of subclass that has type parameters.
checkOutput("pkg/TypeParameterSubClass.html", true,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 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
@ -59,7 +59,7 @@ public class TestNoFrames extends JavadocTester {
checkOutput(Output.OUT, true,
"""
javadoc: warning - The --no-frames option is no longer required and may be removed
in a future release.""");
warning: The --no-frames option is no longer required and may be removed
in a future release.""");
}
}

View File

@ -161,7 +161,7 @@ public class TestOptions extends JavadocTester {
checkExit(Exit.ERROR);
checkOutput(Output.OUT, true,
"javadoc: error - File not found:",
"error: File not found:",
"custom-stylesheet-1.css");
}
@ -174,7 +174,7 @@ public class TestOptions extends JavadocTester {
checkExit(Exit.ERROR);
checkOutput(Output.OUT, true,
"javadoc: error - File not found:",
"error: File not found:",
"additional-stylesheet-4.css");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -69,7 +69,7 @@ public class TestReturnTag extends JavadocTester {
checkExit(Exit.OK);
checkOutput(Output.OUT, true,
"warning - @return tag cannot be used in method with void return type.");
"warning: @return tag cannot be used in method with void return type.");
}
@Test

View File

@ -673,10 +673,10 @@ public class TestSearch extends JavadocTester {
void checkInvalidUsageIndexTag() {
checkOutput(Output.OUT, true,
"AnotherClass.java:29: warning - invalid usage of tag {@index",
"AnotherClass.java:39: warning - invalid usage of tag {@index",
"AnotherClass.java:34: warning - invalid usage of tag {@index",
"AnotherClass.java:68: warning - invalid usage of tag {@index");
"AnotherClass.java:29: warning: invalid usage of tag {@index",
"AnotherClass.java:39: warning: invalid usage of tag {@index",
"AnotherClass.java:34: warning: invalid usage of tag {@index",
"AnotherClass.java:68: warning: invalid usage of tag {@index");
}
void checkJqueryAndImageFiles(boolean expectedOutput) {

View File

@ -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
@ -51,7 +51,7 @@ public class TestTagInheritence extends JavadocTester {
//Test bad inheritDoc tag warning.
checkOutput(Output.OUT, true,
"warning - @inheritDoc used but testBadInheritDocTag() "
"warning: @inheritDoc used but testBadInheritDocTag() "
+ "does not override or implement any method.");
//Test valid usage of inheritDoc tag.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -52,10 +52,10 @@ public class TestTagMisuse extends JavadocTester {
checkExit(Exit.OK);
checkOutput(Output.OUT, true,
"warning - Tag @param cannot be used in field documentation.",
"warning - Tag @throws cannot be used in field documentation.",
"warning - Tag @return cannot be used in constructor documentation."
/* DCerroneous, "warning - Tag @throws cannot be used in inline documentation."*/);
"warning: Tag @param cannot be used in field documentation.",
"warning: Tag @throws cannot be used in field documentation.",
"warning: Tag @return cannot be used in constructor documentation."
/* DCerroneous, "warning: Tag @throws cannot be used in inline documentation."*/);
checkOutput(Output.OUT, false, "DocletAbortException");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -152,14 +152,14 @@ public class TestValueTag extends JavadocTester {
checkExit(Exit.OK);
checkOutput(Output.OUT, true,
// Test @value warning printed when used with non-constant.
"warning - @value tag (which references nonConstant) "
"warning: @value tag (which references nonConstant) "
+ "can only be used in constants.",
"warning - @value tag (which references NULL) "
"warning: @value tag (which references NULL) "
+ "can only be used in constants.",
"warning - @value tag (which references TEST_12_ERROR) "
"warning: @value tag (which references TEST_12_ERROR) "
+ "can only be used in constants.",
// Test warning printed for bad reference.
"warning - {@value UnknownClass#unknownConstant}"
"warning: {@value UnknownClass#unknownConstant}"
+ " (referenced by @value tag) is an unknown reference."
);
checkForException();

View File

@ -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
@ -50,10 +50,10 @@ public class TestWarnBadParamNames extends JavadocTester {
checkOutput(Output.OUT, true,
"""
warning - @param argument "int" is not a parameter name.""",
warning: @param argument "int" is not a parameter name.""",
"""
warning - @param argument "IDontExist" is not a parameter name.""",
warning: @param argument "IDontExist" is not a parameter name.""",
"""
warning - Parameter "arg" is documented more than once.""");
warning: Parameter "arg" is documented more than once.""");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 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
@ -80,7 +80,7 @@ public class Test {
System.err.println("Errors:\n" + errOut);
check(errOut, "Errors.java", expectErrs);
check(errOut, " warning ", expectWarns); // requires -locale en_US
check(errOut, " warning: ", expectWarns); // requires -locale en_US
}
void check(String text, String expectText, int expectCount) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
@ -73,12 +73,14 @@ public class TestStdDoclet {
String line;
while ((line = in.readLine()) != null) {
System.err.println(line);
if (line.contains("DoesNotExist"))
if (line.contains("TestStdDoclet.java") && line.contains("DoesNotExist")) {
actualDocletWarnCount++;
if (line.matches("[0-9]+ warning(s)?"))
}
if (line.matches("[0-9]+ warning(s)?")) {
reportedDocletWarnCount =
Integer.valueOf(line.substring(0, line.indexOf(" ")));
}
}
} finally {
in.close();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -175,7 +175,7 @@ public class OptionProcessingFailureTest extends JavadocTester {
long sumErrors = optionDescriptions.stream().mapToLong(d -> d.nProcessErrors).sum() + nInitErrors;
boolean success = optionDescriptions.stream().allMatch(d -> d.success);
checkOutput(Output.OUT, sumErrors != 0 || !success, "error - ");
checkOutput(Output.OUT, sumErrors != 0 || !success, "error: ");
}
/* Creating a specialized consumer is even more lightweight than creating a POJO */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2018, 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
@ -79,7 +79,7 @@ public class BadOptionsTest extends TestRunner {
.run(Task.Expect.FAIL)
.writeAll();
checkFound(result.getOutput(Task.OutputKind.DIRECT),
"javadoc: error - error: no value for --add-modules option");
"error: no value for --add-modules option");
checkNotFound(result, "Exception", "at jdk.javadoc/");
}
@ -104,7 +104,7 @@ public class BadOptionsTest extends TestRunner {
.run(Task.Expect.FAIL)
.writeAll();
checkFound(result.getOutput(Task.OutputKind.DIRECT),
"javadoc: error - error: no value for --add-exports option");
"error: no value for --add-exports option");
checkNotFound(result, "Exception", "at jdk.javadoc/");
}
@ -116,7 +116,7 @@ public class BadOptionsTest extends TestRunner {
.run(Task.Expect.FAIL)
.writeAll();
checkFound(result.getOutput(Task.OutputKind.DIRECT),
"javadoc: error - error: bad value for --add-exports option: 'm/p'");
"error: bad value for --add-exports option: 'm/p'");
checkNotFound(result, "Exception", "at jdk.javadoc/");
}

View File

@ -233,6 +233,10 @@ public class CheckResourceKeys {
results.add("javadoc.note.pos.msg");
results.add("javadoc.warning.msg");
results.add("javadoc.err.message");
results.add("javadoc.warn.message");
results.add("javadoc.note.message");
return results;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 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
@ -75,7 +75,7 @@ public class MaxWarns {
String javadoc(File f) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
String[] args = { "-Xdoclint:none", "-d", "api", f.getPath() };
String[] args = { "-Xdoclint:none", "--no-platform-links", "-d", "api", f.getPath() };
int rc = jdk.javadoc.internal.tool.Main.execute(args, pw);
pw.flush();
return sw.toString();
@ -84,7 +84,7 @@ public class MaxWarns {
void check(String out, int count) {
System.err.println(out);
Pattern warn = Pattern.compile("""
warning - @param argument "i[0-9]+" is not a parameter name""");
warning: @param argument "i[0-9]+" is not a parameter name""");
Matcher m = warn.matcher(out);
int n = 0;
for (int start = 0; m.find(start); start = m.start() + 1) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@ -73,13 +73,13 @@ public class GetTask_DiagListenerTest extends APITest {
} else {
List<String> diagCodes = new ArrayList<String>();
for (Diagnostic d: dc.getDiagnostics()) {
System.err.println(d);
System.err.println("[" + d.getCode() + "]: " + d);
diagCodes.add(d.getCode());
}
List<String> expect = Arrays.asList(
"javadoc.note.msg", // Loading source file
"javadoc.note.message", // Loading source file
"compiler.err.expected4", // class, interface, enum, or record expected
"javadoc.note.msg"); // 1 error
"javadoc.note.message"); // 1 error
if (!diagCodes.equals(expect))
throw new Exception("unexpected diagnostics occurred");
System.err.println("diagnostics received as expected");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@ -116,13 +116,13 @@ public class DocLintTest {
DL_WRN12A(WARNING, "Test.java:12: warning: no description for @return"),
// javadoc messages about bad content: these should only appear when doclint is disabled
JD_WRN10(WARNING, "Test.java:10: warning - Tag @see: reference not found: DoesNotExist"),
JD_WRN13(WARNING, "Test.java:13: warning - @return tag has no arguments."),
JD_WRN10(WARNING, "Test.java:10: warning: Tag @see: reference not found: DoesNotExist"),
JD_WRN13(WARNING, "Test.java:13: warning: @return tag has no arguments."),
// javadoc messages for bad options
OPT_BADARG(ERROR, "javadoc: error - Invalid argument for -Xdoclint option"),
OPT_BADQUAL(ERROR, "javadoc: error - Access qualifiers not permitted for -Xdoclint arguments"),
OPT_BADPACKAGEARG(ERROR, "javadoc: error - Invalid argument for -Xdoclint/package option");
OPT_BADARG(ERROR, "error: Invalid argument for -Xdoclint option"),
OPT_BADQUAL(ERROR, "error: Access qualifiers not permitted for -Xdoclint arguments"),
OPT_BADPACKAGEARG(ERROR, "error: Invalid argument for -Xdoclint/package option");
final Diagnostic.Kind kind;
final String text;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, 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
@ -86,7 +86,7 @@ public class TestExceptionHandling extends TestRunner {
String errString = "Destination directory is not a directory: " + out.toString();
// check the regular message
assertPresent("javadoc: error - " + errString, tr.getOutputLines(Task.OutputKind.DIRECT));
assertPresent("error: " + errString, tr.getOutputLines(Task.OutputKind.DIRECT));
// check that first line of the stack trace is present
assertPresent("jdk.javadoc.internal.doclets.toolkit.util.SimpleDocletException: " +
errString, tr.getOutputLines(Task.OutputKind.STDERR));
@ -102,7 +102,7 @@ public class TestExceptionHandling extends TestRunner {
Task.Result tr = cmdTask.run(Task.Expect.FAIL);
// check the regular message
assertPresent("javadoc: error - Cannot find doclet class NonExistentDoclet",
assertPresent("error: Cannot find doclet class NonExistentDoclet",
tr.getOutputLines(Task.OutputKind.DIRECT));
// check that first line of the stack trace is present

View File

@ -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
@ -112,7 +112,7 @@ public class Modules extends ModuleTestBase {
javafile.toString());
assertMessagePresent("error: cannot access module-info");
assertMessageNotPresent("error - fatal error encountered");
assertMessageNotPresent("error: fatal error encountered");
}
@ -534,7 +534,7 @@ public class Modules extends ModuleTestBase {
"--module", "MIA",
"--expand-requires", "all");
assertMessagePresent("javadoc: error - module MIA not found");
assertMessagePresent("error: module MIA not found");
}
@Test
@ -556,7 +556,7 @@ public class Modules extends ModuleTestBase {
"--module", "M,N,L,MIA,O,P",
"--expand-requires", "all");
assertMessagePresent("javadoc: error - module MIA not found");
assertMessagePresent("error: module MIA not found");
}
@Test

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, 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
@ -180,7 +180,7 @@ public class PackageOptions extends ModuleTestBase {
"--module", "m1",
"-subpackages", "m1pub.pub1:pro");
assertMessagePresent("javadoc: error - No source files for package pro");
assertMessagePresent("error: No source files for package pro");
}
@Test

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 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
@ -70,10 +70,10 @@ public class RemoveOldDoclet extends JavadocTester {
"pkg");
checkExit(Exit.ERROR);
checkOutput(Output.OUT, true,
"javadoc: error - Class " + Doclet_CLASS_NAME + """
is not a valid doclet.
Note: As of JDK 13, the com.sun.javadoc API is no longer supported.""");
checkOutput(Output.OUT, true, String.format("""
error: Class %s is not a valid doclet.
Note: As of JDK 13, the com.sun.javadoc API is no longer supported.""",
Doclet_CLASS_NAME));
}
static class TestDoclet {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -58,7 +58,7 @@ public class TestWErrorOption extends JavadocTester {
"p");
checkExit(Exit.OK);
checkOutput(Output.OUT, false,
"javadoc: error - warnings found and -Werror specified");
"error: warnings found and -Werror specified");
checkOutput(Output.OUT, true,
"1 warning");
}
@ -74,9 +74,9 @@ public class TestWErrorOption extends JavadocTester {
"p");
checkExit(Exit.ERROR);
checkOutput(Output.OUT, true,
"C.java:6: warning - @return tag cannot be used in method with void return type.",
"C.java:6: warning: @return tag cannot be used in method with void return type.",
"""
javadoc: error - warnings found and -Werror specified
error: warnings found and -Werror specified
1 error
1 warning
""");