8309566: Migrate away from TagletWriter and TagletWriterImpl
8311974: Clean up Utils.getBlockTags Reviewed-by: prappo
This commit is contained in:
parent
fb90af881b
commit
e51472e9a8
@ -46,7 +46,6 @@ import jdk.javadoc.internal.doclets.toolkit.Content;
|
|||||||
import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
|
import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.MemberWriter;
|
import jdk.javadoc.internal.doclets.toolkit.MemberWriter;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.DeprecatedTaglet;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,8 +256,8 @@ public abstract class AbstractMemberWriter implements MemberSummaryWriter, Membe
|
|||||||
* @param target the content to which the deprecated information will be added.
|
* @param target the content to which the deprecated information will be added.
|
||||||
*/
|
*/
|
||||||
protected void addDeprecatedInfo(Element member, Content target) {
|
protected void addDeprecatedInfo(Element member, Content target) {
|
||||||
Content output = (new DeprecatedTaglet()).getAllBlockTagOutput(member,
|
var t = configuration.tagletManager.getTaglet(DocTree.Kind.DEPRECATED);
|
||||||
writer.getTagletWriterInstance(false));
|
Content output = t.getAllBlockTagOutput(member, writer.getTagletWriterInstance(false));
|
||||||
if (!output.isEmpty()) {
|
if (!output.isEmpty()) {
|
||||||
target.add(HtmlTree.DIV(HtmlStyle.deprecationBlock, output));
|
target.add(HtmlTree.DIV(HtmlStyle.deprecationBlock, output));
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ModuleElement;
|
import javax.lang.model.element.ModuleElement;
|
||||||
@ -41,6 +42,7 @@ import javax.lang.model.util.SimpleElementVisitor8;
|
|||||||
|
|
||||||
import com.sun.source.doctree.DeprecatedTree;
|
import com.sun.source.doctree.DeprecatedTree;
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode;
|
import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode;
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
|
import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
|
||||||
@ -51,7 +53,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
|
|||||||
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
|
import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.ParamTaglet;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
|
import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
|
||||||
@ -92,6 +93,11 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
|
|||||||
this.classTree = classTree;
|
this.classTree = classTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Content getOutputInstance() {
|
||||||
|
return new ContentBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getHeader(String header) {
|
public Content getHeader(String header) {
|
||||||
HtmlTree body = getBody(getWindowTitle(utils.getSimpleName(typeElement)));
|
HtmlTree body = getBody(getWindowTitle(utils.getSimpleName(typeElement)));
|
||||||
@ -173,7 +179,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TypeElement getCurrentPageElement() {
|
public TypeElement getCurrentPageElement() {
|
||||||
return typeElement;
|
return typeElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,8 +274,8 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
|
|||||||
@Override
|
@Override
|
||||||
public void addParamInfo(Content target) {
|
public void addParamInfo(Content target) {
|
||||||
if (utils.hasBlockTag(typeElement, DocTree.Kind.PARAM)) {
|
if (utils.hasBlockTag(typeElement, DocTree.Kind.PARAM)) {
|
||||||
Content paramInfo = (new ParamTaglet()).getAllBlockTagOutput(typeElement,
|
var t = configuration.tagletManager.getTaglet(DocTree.Kind.PARAM);
|
||||||
getTagletWriterInstance(false));
|
Content paramInfo = t.getAllBlockTagOutput(typeElement, getTagletWriterInstance(false));
|
||||||
if (!paramInfo.isEmpty()) {
|
if (!paramInfo.isEmpty()) {
|
||||||
target.add(HtmlTree.DL(HtmlStyle.notes, paramInfo));
|
target.add(HtmlTree.DL(HtmlStyle.notes, paramInfo));
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,13 @@
|
|||||||
|
|
||||||
package jdk.javadoc.internal.doclets.formats.html;
|
package jdk.javadoc.internal.doclets.formats.html;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.InvalidPathException;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -39,6 +44,7 @@ import java.util.stream.Collectors;
|
|||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.PackageElement;
|
import javax.lang.model.element.PackageElement;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.tools.DocumentationTool;
|
||||||
import javax.tools.JavaFileManager;
|
import javax.tools.JavaFileManager;
|
||||||
import javax.tools.JavaFileObject;
|
import javax.tools.JavaFileObject;
|
||||||
import javax.tools.StandardJavaFileManager;
|
import javax.tools.StandardJavaFileManager;
|
||||||
@ -49,6 +55,7 @@ import jdk.javadoc.doclet.Reporter;
|
|||||||
import jdk.javadoc.doclet.StandardDoclet;
|
import jdk.javadoc.doclet.StandardDoclet;
|
||||||
import jdk.javadoc.doclet.Taglet;
|
import jdk.javadoc.doclet.Taglet;
|
||||||
import jdk.javadoc.internal.Versions;
|
import jdk.javadoc.internal.Versions;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.taglets.TagletManager;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseOptions;
|
import jdk.javadoc.internal.doclets.toolkit.BaseOptions;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.DocletException;
|
import jdk.javadoc.internal.doclets.toolkit.DocletException;
|
||||||
@ -61,6 +68,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
|||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.NewAPIBuilder;
|
import jdk.javadoc.internal.doclets.toolkit.util.NewAPIBuilder;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.PreviewAPIListBuilder;
|
import jdk.javadoc.internal.doclets.toolkit.util.PreviewAPIListBuilder;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.SimpleDocletException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the output based on the command-line options.
|
* Configure the output based on the command-line options.
|
||||||
@ -104,7 +112,7 @@ public class HtmlConfiguration extends BaseConfiguration {
|
|||||||
* 2. items for elements are added in bulk before generating the index files
|
* 2. items for elements are added in bulk before generating the index files
|
||||||
* 3. additional items are added as needed
|
* 3. additional items are added as needed
|
||||||
*/
|
*/
|
||||||
protected HtmlIndexBuilder mainIndex;
|
public HtmlIndexBuilder mainIndex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The collection of deprecated items, if any, to be displayed on the deprecated-list page,
|
* The collection of deprecated items, if any, to be displayed on the deprecated-list page,
|
||||||
@ -133,7 +141,7 @@ public class HtmlConfiguration extends BaseConfiguration {
|
|||||||
|
|
||||||
public Contents contents;
|
public Contents contents;
|
||||||
|
|
||||||
protected final Messages messages;
|
public final Messages messages;
|
||||||
|
|
||||||
public DocPaths docPaths;
|
public DocPaths docPaths;
|
||||||
|
|
||||||
@ -143,6 +151,11 @@ public class HtmlConfiguration extends BaseConfiguration {
|
|||||||
|
|
||||||
private final HtmlOptions options;
|
private final HtmlOptions options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The taglet manager.
|
||||||
|
*/
|
||||||
|
public TagletManager tagletManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kinds of conditional pages.
|
* Kinds of conditional pages.
|
||||||
*/
|
*/
|
||||||
@ -424,6 +437,125 @@ public class HtmlConfiguration extends BaseConfiguration {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String snippetPath = options.snippetPath();
|
||||||
|
if (snippetPath != null) {
|
||||||
|
Messages messages = getMessages();
|
||||||
|
JavaFileManager fm = getFileManager();
|
||||||
|
if (fm instanceof StandardJavaFileManager) {
|
||||||
|
try {
|
||||||
|
List<Path> sp = Arrays.stream(snippetPath.split(File.pathSeparator))
|
||||||
|
.map(Path::of)
|
||||||
|
.toList();
|
||||||
|
StandardJavaFileManager sfm = (StandardJavaFileManager) fm;
|
||||||
|
sfm.setLocationFromPaths(DocumentationTool.Location.SNIPPET_PATH, sp);
|
||||||
|
} catch (IOException | InvalidPathException e) {
|
||||||
|
throw new SimpleDocletException(messages.getResources().getText(
|
||||||
|
"doclet.error_setting_snippet_path", snippetPath, e), e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new SimpleDocletException(messages.getResources().getText(
|
||||||
|
"doclet.cannot_use_snippet_path", snippetPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initTagletManager(options.customTagStrs());
|
||||||
|
|
||||||
return super.finishOptionSettings0();
|
return super.finishOptionSettings0();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the taglet manager. The strings to initialize the simple custom tags should
|
||||||
|
* be in the following format: "[tag name]:[location str]:[heading]".
|
||||||
|
*
|
||||||
|
* @param customTagStrs the set two-dimensional arrays of strings. These arrays contain
|
||||||
|
* either -tag or -taglet arguments.
|
||||||
|
*/
|
||||||
|
private void initTagletManager(Set<List<String>> customTagStrs) {
|
||||||
|
tagletManager = tagletManager != null ? tagletManager : new TagletManager(this);
|
||||||
|
JavaFileManager fileManager = getFileManager();
|
||||||
|
Messages messages = getMessages();
|
||||||
|
try {
|
||||||
|
tagletManager.initTagletPath(fileManager);
|
||||||
|
tagletManager.loadTaglets(fileManager);
|
||||||
|
|
||||||
|
for (List<String> args : customTagStrs) {
|
||||||
|
if (args.get(0).equals("-taglet")) {
|
||||||
|
tagletManager.addCustomTag(args.get(1), fileManager);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Since there are few constraints on the characters in a tag name,
|
||||||
|
* and real world examples with ':' in the tag name, we cannot simply use
|
||||||
|
* String.split(regex); instead, we tokenize the string, allowing
|
||||||
|
* special characters to be escaped with '\'. */
|
||||||
|
List<String> tokens = tokenize(args.get(1), 3);
|
||||||
|
switch (tokens.size()) {
|
||||||
|
case 1 -> {
|
||||||
|
String tagName = args.get(1);
|
||||||
|
if (tagletManager.isKnownCustomTag(tagName)) {
|
||||||
|
//reorder a standard tag
|
||||||
|
tagletManager.addNewSimpleCustomTag(tagName, null, "");
|
||||||
|
} else {
|
||||||
|
//Create a simple tag with the heading that has the same name as the tag.
|
||||||
|
StringBuilder heading = new StringBuilder(tagName + ":");
|
||||||
|
heading.setCharAt(0, Character.toUpperCase(tagName.charAt(0)));
|
||||||
|
tagletManager.addNewSimpleCustomTag(tagName, heading.toString(), "a");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2 ->
|
||||||
|
//Add simple taglet without heading, probably to excluding it in the output.
|
||||||
|
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(1), "");
|
||||||
|
|
||||||
|
case 3 ->
|
||||||
|
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(2), tokens.get(1));
|
||||||
|
|
||||||
|
default ->
|
||||||
|
messages.error("doclet.Error_invalid_custom_tag_argument", args.get(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
messages.error("doclet.taglet_could_not_set_location", e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a string, return an array of tokens, separated by ':'.
|
||||||
|
* The separator character can be escaped with the '\' character.
|
||||||
|
* The '\' character may also be escaped with the '\' character.
|
||||||
|
*
|
||||||
|
* @param s the string to tokenize
|
||||||
|
* @param maxTokens the maximum number of tokens returned. If the
|
||||||
|
* max is reached, the remaining part of s is appended
|
||||||
|
* to the end of the last token.
|
||||||
|
* @return an array of tokens
|
||||||
|
*/
|
||||||
|
private List<String> tokenize(String s, int maxTokens) {
|
||||||
|
List<String> tokens = new ArrayList<>();
|
||||||
|
StringBuilder token = new StringBuilder();
|
||||||
|
boolean prevIsEscapeChar = false;
|
||||||
|
for (int i = 0; i < s.length(); i += Character.charCount(i)) {
|
||||||
|
int currentChar = s.codePointAt(i);
|
||||||
|
if (prevIsEscapeChar) {
|
||||||
|
// Case 1: escaped character
|
||||||
|
token.appendCodePoint(currentChar);
|
||||||
|
prevIsEscapeChar = false;
|
||||||
|
} else if (currentChar == ':' && tokens.size() < maxTokens - 1) {
|
||||||
|
// Case 2: separator
|
||||||
|
tokens.add(token.toString());
|
||||||
|
token = new StringBuilder();
|
||||||
|
} else if (currentChar == '\\') {
|
||||||
|
// Case 3: escape character
|
||||||
|
prevIsEscapeChar = true;
|
||||||
|
} else {
|
||||||
|
// Case 4: regular character
|
||||||
|
token.appendCodePoint(currentChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (token.length() > 0) {
|
||||||
|
tokens.add(token.toString());
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -319,6 +319,16 @@ public class HtmlDoclet extends AbstractDoclet {
|
|||||||
copyLegalFiles(options.createIndex());
|
copyLegalFiles(options.createIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateFiles() throws DocletException {
|
||||||
|
super.generateFiles();
|
||||||
|
|
||||||
|
if (configuration.tagletManager != null) { // may be null, if no files generated, perhaps because of errros
|
||||||
|
configuration.tagletManager.printReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void copyJqueryFiles() throws DocletException {
|
private void copyJqueryFiles() throws DocletException {
|
||||||
List<String> files = Arrays.asList(
|
List<String> files = Arrays.asList(
|
||||||
DocPaths.JQUERY_JS.getPath(),
|
DocPaths.JQUERY_JS.getPath(),
|
||||||
|
@ -41,6 +41,7 @@ import java.util.Optional;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.lang.model.element.AnnotationMirror;
|
import javax.lang.model.element.AnnotationMirror;
|
||||||
import javax.lang.model.element.AnnotationValue;
|
import javax.lang.model.element.AnnotationValue;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
@ -68,13 +69,11 @@ import com.sun.source.doctree.EndElementTree;
|
|||||||
import com.sun.source.doctree.EntityTree;
|
import com.sun.source.doctree.EntityTree;
|
||||||
import com.sun.source.doctree.ErroneousTree;
|
import com.sun.source.doctree.ErroneousTree;
|
||||||
import com.sun.source.doctree.EscapeTree;
|
import com.sun.source.doctree.EscapeTree;
|
||||||
import com.sun.source.doctree.IndexTree;
|
|
||||||
import com.sun.source.doctree.InheritDocTree;
|
import com.sun.source.doctree.InheritDocTree;
|
||||||
|
import com.sun.source.doctree.InlineTagTree;
|
||||||
import com.sun.source.doctree.LinkTree;
|
import com.sun.source.doctree.LinkTree;
|
||||||
import com.sun.source.doctree.LiteralTree;
|
import com.sun.source.doctree.LiteralTree;
|
||||||
import com.sun.source.doctree.StartElementTree;
|
import com.sun.source.doctree.StartElementTree;
|
||||||
import com.sun.source.doctree.SummaryTree;
|
|
||||||
import com.sun.source.doctree.SystemPropertyTree;
|
|
||||||
import com.sun.source.doctree.TextTree;
|
import com.sun.source.doctree.TextTree;
|
||||||
import com.sun.source.util.DocTreePath;
|
import com.sun.source.util.DocTreePath;
|
||||||
import com.sun.source.util.SimpleDocTreeVisitor;
|
import com.sun.source.util.SimpleDocTreeVisitor;
|
||||||
@ -91,12 +90,11 @@ import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
|
|||||||
import jdk.javadoc.internal.doclets.formats.html.markup.Script;
|
import jdk.javadoc.internal.doclets.formats.html.markup.Script;
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
|
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.taglets.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.taglets.TagletWriter;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.DocRootTaglet;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.Taglet;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.TagletWriter;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Comparators;
|
import jdk.javadoc.internal.doclets.toolkit.util.Comparators;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
|
||||||
@ -109,14 +107,9 @@ import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
|||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils.DeclarationPreviewLanguageFeatures;
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils.DeclarationPreviewLanguageFeatures;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils.ElementFlag;
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils.ElementFlag;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils.PreviewSummary;
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils.PreviewSummary;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
|
|
||||||
import jdk.javadoc.internal.doclint.HtmlTag;
|
import jdk.javadoc.internal.doclint.HtmlTag;
|
||||||
|
|
||||||
import static com.sun.source.doctree.DocTree.Kind.CODE;
|
|
||||||
import static com.sun.source.doctree.DocTree.Kind.COMMENT;
|
import static com.sun.source.doctree.DocTree.Kind.COMMENT;
|
||||||
import static com.sun.source.doctree.DocTree.Kind.LINK;
|
|
||||||
import static com.sun.source.doctree.DocTree.Kind.LINK_PLAIN;
|
|
||||||
import static com.sun.source.doctree.DocTree.Kind.SEE;
|
|
||||||
import static com.sun.source.doctree.DocTree.Kind.TEXT;
|
import static com.sun.source.doctree.DocTree.Kind.TEXT;
|
||||||
|
|
||||||
|
|
||||||
@ -160,11 +153,11 @@ public class HtmlDocletWriter {
|
|||||||
|
|
||||||
protected final Contents contents;
|
protected final Contents contents;
|
||||||
|
|
||||||
protected final Messages messages;
|
public final Messages messages;
|
||||||
|
|
||||||
protected final Resources resources;
|
protected final Resources resources;
|
||||||
|
|
||||||
protected final Links links;
|
public final Links links;
|
||||||
|
|
||||||
protected final DocPaths docPaths;
|
protected final DocPaths docPaths;
|
||||||
|
|
||||||
@ -197,7 +190,7 @@ public class HtmlDocletWriter {
|
|||||||
* (Ideally, javadoc should be tracking all id's generated in a file
|
* (Ideally, javadoc should be tracking all id's generated in a file
|
||||||
* to avoid generating duplicates.)
|
* to avoid generating duplicates.)
|
||||||
*/
|
*/
|
||||||
Map<String, Integer> indexAnchorTable = new HashMap<>();
|
public final Map<String, Integer> indexAnchorTable = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an {@code HtmlDocletWriter}.
|
* Creates an {@code HtmlDocletWriter}.
|
||||||
@ -278,7 +271,7 @@ public class HtmlDocletWriter {
|
|||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
//where:
|
//where:
|
||||||
// Note: {@docRoot} is not case sensitive when passed in with a command-line option:
|
// Note: {@docRoot} is not case-sensitive when passed in with a command-line option:
|
||||||
private static final Pattern docrootPattern =
|
private static final Pattern docrootPattern =
|
||||||
Pattern.compile(Pattern.quote("{@docroot}"), Pattern.CASE_INSENSITIVE);
|
Pattern.compile(Pattern.quote("{@docroot}"), Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
@ -374,9 +367,8 @@ public class HtmlDocletWriter {
|
|||||||
return !output.isEmpty();
|
return !output.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Content getInlineTagOutput(Element element, DocTree tree, TagletWriterImpl.Context context) {
|
private Content getInlineTagOutput(Element element, InlineTagTree tree, TagletWriter.Context context) {
|
||||||
return getTagletWriterInstance(context)
|
return getTagletWriterInstance(context).getInlineTagOutput(element, tree);
|
||||||
.getInlineTagOutput(element, configuration.tagletManager, tree);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -386,7 +378,7 @@ public class HtmlDocletWriter {
|
|||||||
* @return a TagletWriter that knows how to write HTML.
|
* @return a TagletWriter that knows how to write HTML.
|
||||||
*/
|
*/
|
||||||
public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
|
public TagletWriter getTagletWriterInstance(boolean isFirstSentence) {
|
||||||
return new TagletWriterImpl(this, isFirstSentence);
|
return new TagletWriter(this, isFirstSentence);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -395,8 +387,8 @@ public class HtmlDocletWriter {
|
|||||||
* @param context the enclosing context
|
* @param context the enclosing context
|
||||||
* @return a TagletWriter
|
* @return a TagletWriter
|
||||||
*/
|
*/
|
||||||
public TagletWriterImpl getTagletWriterInstance(TagletWriterImpl.Context context) {
|
public TagletWriter getTagletWriterInstance(TagletWriter.Context context) {
|
||||||
return new TagletWriterImpl(this, context);
|
return new TagletWriter(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -756,7 +748,7 @@ public class HtmlDocletWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Return a class cross link to external class documentation.
|
* Return a class cross-link to external class documentation.
|
||||||
* The -link option does not allow users to
|
* The -link option does not allow users to
|
||||||
* link to external classes in the "default" package.
|
* link to external classes in the "default" package.
|
||||||
*
|
*
|
||||||
@ -886,7 +878,7 @@ public class HtmlDocletWriter {
|
|||||||
*
|
*
|
||||||
* @return the type element of the current page.
|
* @return the type element of the current page.
|
||||||
*/
|
*/
|
||||||
protected TypeElement getCurrentPageElement() {
|
public TypeElement getCurrentPageElement() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1177,7 +1169,7 @@ public class HtmlDocletWriter {
|
|||||||
boolean isFirstSentence,
|
boolean isFirstSentence,
|
||||||
boolean inSummary) {
|
boolean inSummary) {
|
||||||
return commentTagsToContent(element, trees,
|
return commentTagsToContent(element, trees,
|
||||||
new TagletWriterImpl.Context(isFirstSentence, inSummary));
|
new TagletWriter.Context(isFirstSentence, inSummary));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1194,7 +1186,7 @@ public class HtmlDocletWriter {
|
|||||||
*/
|
*/
|
||||||
public Content commentTagsToContent(Element element,
|
public Content commentTagsToContent(Element element,
|
||||||
List<? extends DocTree> trees,
|
List<? extends DocTree> trees,
|
||||||
TagletWriterImpl.Context context)
|
TagletWriter.Context context)
|
||||||
{
|
{
|
||||||
final Content result = new ContentBuilder() {
|
final Content result = new ContentBuilder() {
|
||||||
@Override
|
@Override
|
||||||
@ -1307,12 +1299,6 @@ public class HtmlDocletWriter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean visitDocRoot(DocRootTree node, Content content) {
|
|
||||||
content.add(getInlineTagOutput(element, node, context));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean visitEndElement(EndElementTree node, Content content) {
|
public Boolean visitEndElement(EndElementTree node, Content content) {
|
||||||
content.add(RawHtml.endElement(node.getName()));
|
content.add(RawHtml.endElement(node.getName()));
|
||||||
@ -1361,43 +1347,6 @@ public class HtmlDocletWriter {
|
|||||||
return (context.isFirstSentence && !output.isEmpty());
|
return (context.isFirstSentence && !output.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean visitIndex(IndexTree node, Content content) {
|
|
||||||
Content output = getInlineTagOutput(element, node, context);
|
|
||||||
if (output != null) {
|
|
||||||
content.add(output);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean visitLink(LinkTree node, Content content) {
|
|
||||||
var inTags = context.inTags;
|
|
||||||
if (inTags.contains(LINK) || inTags.contains(LINK_PLAIN) || inTags.contains(SEE)) {
|
|
||||||
DocTreePath dtp = ch.getDocTreePath(node);
|
|
||||||
if (dtp != null) {
|
|
||||||
messages.warning(dtp, "doclet.see.nested_link", "{@" + node.getTagName() + "}");
|
|
||||||
}
|
|
||||||
Content label = commentTagsToContent(element, node.getLabel(), context);
|
|
||||||
if (label.isEmpty()) {
|
|
||||||
label = Text.of(node.getReference().getSignature());
|
|
||||||
}
|
|
||||||
content.add(label);
|
|
||||||
} else {
|
|
||||||
TagletWriterImpl t = getTagletWriterInstance(context.within(node));
|
|
||||||
content.add(t.linkTagOutput(element, node));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean visitLiteral(LiteralTree node, Content content) {
|
|
||||||
String s = node.getBody().getBody();
|
|
||||||
Content t = Text.of(Text.normalizeNewlines(s));
|
|
||||||
content.add(node.getKind() == CODE ? HtmlTree.CODE(t) : t);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean visitStartElement(StartElementTree node, Content content) {
|
public Boolean visitStartElement(StartElementTree node, Content content) {
|
||||||
Content attrs = new ContentBuilder();
|
Content attrs = new ContentBuilder();
|
||||||
@ -1411,22 +1360,6 @@ public class HtmlDocletWriter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean visitSummary(SummaryTree node, Content content) {
|
|
||||||
Content output = getInlineTagOutput(element, node, context);
|
|
||||||
content.add(output);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean visitSystemProperty(SystemPropertyTree node, Content content) {
|
|
||||||
Content output = getInlineTagOutput(element, node, context);
|
|
||||||
if (output != null) {
|
|
||||||
content.add(output);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CharSequence textCleanup(String text, boolean isLast) {
|
private CharSequence textCleanup(String text, boolean isLast) {
|
||||||
return textCleanup(text, isLast, false);
|
return textCleanup(text, isLast, false);
|
||||||
}
|
}
|
||||||
@ -1455,10 +1388,12 @@ public class HtmlDocletWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Boolean defaultAction(DocTree node, Content content) {
|
protected Boolean defaultAction(DocTree node, Content content) {
|
||||||
Content output = getInlineTagOutput(element, node, context);
|
if (node instanceof InlineTagTree itt) {
|
||||||
|
var output = getInlineTagOutput(element, itt, context);
|
||||||
if (output != null) {
|
if (output != null) {
|
||||||
content.add(output);
|
content.add(output);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1485,7 +1420,7 @@ public class HtmlDocletWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createSectionIdAndIndex(StartElementTree node, List<? extends DocTree> trees, Content attrs,
|
private void createSectionIdAndIndex(StartElementTree node, List<? extends DocTree> trees, Content attrs,
|
||||||
Element element, TagletWriterImpl.Context context) {
|
Element element, TagletWriter.Context context) {
|
||||||
// Use existing id attribute if available
|
// Use existing id attribute if available
|
||||||
String id = getIdAttributeValue(node).orElse(null);
|
String id = getIdAttributeValue(node).orElse(null);
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@ -1562,7 +1497,7 @@ public class HtmlDocletWriter {
|
|||||||
* @param detail the optional detail message which may contain preformatted text
|
* @param detail the optional detail message which may contain preformatted text
|
||||||
* @return the output
|
* @return the output
|
||||||
*/
|
*/
|
||||||
protected Content invalidTagOutput(String summary, Optional<Content> detail) {
|
public Content invalidTagOutput(String summary, Optional<Content> detail) {
|
||||||
if (detail.isEmpty() || detail.get().isEmpty()) {
|
if (detail.isEmpty() || detail.get().isEmpty()) {
|
||||||
return HtmlTree.SPAN(HtmlStyle.invalidTag, Text.of(summary));
|
return HtmlTree.SPAN(HtmlStyle.invalidTag, Text.of(summary));
|
||||||
}
|
}
|
||||||
@ -1665,7 +1600,7 @@ public class HtmlDocletWriter {
|
|||||||
}
|
}
|
||||||
}.visit(element);
|
}.visit(element);
|
||||||
if (redirectPathFromRoot != null) {
|
if (redirectPathFromRoot != null) {
|
||||||
text = "{@" + (new DocRootTaglet()).getName() + "}/"
|
text = "{@" + Kind.DOC_ROOT.tagName + "}/"
|
||||||
+ redirectPathFromRoot.resolve(text).getPath();
|
+ redirectPathFromRoot.resolve(text).getPath();
|
||||||
return replaceDocRootDir(text);
|
return replaceDocRootDir(text);
|
||||||
}
|
}
|
||||||
@ -2049,7 +1984,7 @@ public class HtmlDocletWriter {
|
|||||||
* Returns the path of module/package specific stylesheets for the element.
|
* Returns the path of module/package specific stylesheets for the element.
|
||||||
* @param element module/Package element
|
* @param element module/Package element
|
||||||
* @return list of path of module/package specific stylesheets
|
* @return list of path of module/package specific stylesheets
|
||||||
* @throws DocFileIOException
|
* @throws DocFileIOException if an issue arises while accessing any stylesheets
|
||||||
*/
|
*/
|
||||||
List<DocPath> getLocalStylesheets(Element element) throws DocFileIOException {
|
List<DocPath> getLocalStylesheets(Element element) throws DocFileIOException {
|
||||||
List<DocPath> stylesheets = new ArrayList<>();
|
List<DocPath> stylesheets = new ArrayList<>();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -394,7 +394,7 @@ public class HtmlIds {
|
|||||||
*
|
*
|
||||||
* @return the id
|
* @return the id
|
||||||
*/
|
*/
|
||||||
static HtmlId forParam(String paramName) {
|
public static HtmlId forParam(String paramName) {
|
||||||
return HtmlId.of("param-" + paramName);
|
return HtmlId.of("param-" + paramName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,7 +407,7 @@ public class HtmlIds {
|
|||||||
*
|
*
|
||||||
* @return the id
|
* @return the id
|
||||||
*/
|
*/
|
||||||
static HtmlId forText(String text, Map<String, Integer> counts) {
|
public static HtmlId forText(String text, Map<String, Integer> counts) {
|
||||||
String base = text.replaceAll("\\s+", "");
|
String base = text.replaceAll("\\s+", "");
|
||||||
int count = counts.compute(base, (k, v) -> v == null ? 0 : v + 1);
|
int count = counts.compute(base, (k, v) -> v == null ? 0 : v + 1);
|
||||||
return HtmlId.of(count == 0 ? base : base + "-" + count);
|
return HtmlId.of(count == 0 ? base : base + "-" + count);
|
||||||
|
@ -28,6 +28,7 @@ package jdk.javadoc.internal.doclets.formats.html;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
@ -100,6 +101,11 @@ public class HtmlOptions extends BaseOptions {
|
|||||||
*/
|
*/
|
||||||
private boolean createTree = true;
|
private boolean createTree = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arguments for command-line option {@code -tag} and {@code -taglet}.
|
||||||
|
*/
|
||||||
|
private final LinkedHashSet<List<String>> customTagStrs = new LinkedHashSet<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arguments for command-line option {@code -Xdoclint} and friends.
|
* Arguments for command-line option {@code -Xdoclint} and friends.
|
||||||
* Collected set of doclint options.
|
* Collected set of doclint options.
|
||||||
@ -175,6 +181,12 @@ public class HtmlOptions extends BaseOptions {
|
|||||||
*/
|
*/
|
||||||
private String packagesHeader = "";
|
private String packagesHeader = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Argument for command-line option {@code --snippet-path}.
|
||||||
|
* The path for external snippets.
|
||||||
|
*/
|
||||||
|
private String snippetPath = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Argument for command-line option {@code -splitindex}.
|
* Argument for command-line option {@code -splitindex}.
|
||||||
* True if command-line option "-splitindex" is used. Default value is
|
* True if command-line option "-splitindex" is used. Default value is
|
||||||
@ -182,11 +194,23 @@ public class HtmlOptions extends BaseOptions {
|
|||||||
*/
|
*/
|
||||||
private boolean splitIndex = false;
|
private boolean splitIndex = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Argument for command-line option {@code --show-taglets}.
|
||||||
|
* Show taglets (internal debug switch)
|
||||||
|
*/
|
||||||
|
private boolean showTaglets = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Argument for command-line option {@code -stylesheetfile}.
|
* Argument for command-line option {@code -stylesheetfile}.
|
||||||
*/
|
*/
|
||||||
private String stylesheetFile = "";
|
private String stylesheetFile = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Argument for command-line option {@code -tagletpath}.
|
||||||
|
* The path to Taglets
|
||||||
|
*/
|
||||||
|
private String tagletPath = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Argument for command-line option {@code -top}.
|
* Argument for command-line option {@code -top}.
|
||||||
*/
|
*/
|
||||||
@ -406,6 +430,44 @@ public class HtmlOptions extends BaseOptions {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
new Option(resources, "--snippet-path", 1) {
|
||||||
|
@Override
|
||||||
|
public boolean process(String opt, List<String> args) {
|
||||||
|
snippetPath = args.get(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
new Option(resources, "-tag", 1) {
|
||||||
|
@Override
|
||||||
|
public boolean process(String opt, List<String> args) {
|
||||||
|
ArrayList<String> list = new ArrayList<>();
|
||||||
|
list.add(opt);
|
||||||
|
list.add(args.get(0));
|
||||||
|
customTagStrs.add(list);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
new Option(resources, "-taglet", 1) {
|
||||||
|
@Override
|
||||||
|
public boolean process(String opt, List<String> args) {
|
||||||
|
ArrayList<String> list = new ArrayList<>();
|
||||||
|
list.add(opt);
|
||||||
|
list.add(args.get(0));
|
||||||
|
customTagStrs.add(list);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
new Option(resources, "-tagletpath", 1) {
|
||||||
|
@Override
|
||||||
|
public boolean process(String opt, List<String> args) {
|
||||||
|
tagletPath = args.get(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
new Option(resources, "-top", 1) {
|
new Option(resources, "-top", 1) {
|
||||||
@Override
|
@Override
|
||||||
public boolean process(String opt, List<String> args) {
|
public boolean process(String opt, List<String> args) {
|
||||||
@ -489,6 +551,14 @@ public class HtmlOptions extends BaseOptions {
|
|||||||
messages.warning("doclet.NoFrames_specified");
|
messages.warning("doclet.NoFrames_specified");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
new Hidden(resources, "--show-taglets") {
|
||||||
|
@Override
|
||||||
|
public boolean process(String opt, List<String> args) {
|
||||||
|
showTaglets = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
Set<BaseOptions.Option> allOptions = new TreeSet<>();
|
Set<BaseOptions.Option> allOptions = new TreeSet<>();
|
||||||
@ -620,6 +690,13 @@ public class HtmlOptions extends BaseOptions {
|
|||||||
return createTree;
|
return createTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arguments for command-line option {@code -tag} and {@code -taglet}.
|
||||||
|
*/
|
||||||
|
LinkedHashSet<List<String>> customTagStrs() {
|
||||||
|
return customTagStrs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arguments for command-line option {@code -Xdoclint} and friends.
|
* Arguments for command-line option {@code -Xdoclint} and friends.
|
||||||
* Collected set of doclint options.
|
* Collected set of doclint options.
|
||||||
@ -721,6 +798,22 @@ public class HtmlOptions extends BaseOptions {
|
|||||||
return packagesHeader;
|
return packagesHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Argument for command-line option {@code --show-taglets}.
|
||||||
|
* Show taglets (internal debug switch)
|
||||||
|
*/
|
||||||
|
public boolean showTaglets() {
|
||||||
|
return showTaglets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Argument for command-line option {@code --snippet-path}.
|
||||||
|
* The path for external snippets.
|
||||||
|
*/
|
||||||
|
public String snippetPath() {
|
||||||
|
return snippetPath;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Argument for command-line option {@code -splitindex}.
|
* Argument for command-line option {@code -splitindex}.
|
||||||
* True if command-line option "-splitindex" is used. Default value is
|
* True if command-line option "-splitindex" is used. Default value is
|
||||||
@ -737,6 +830,14 @@ public class HtmlOptions extends BaseOptions {
|
|||||||
return stylesheetFile;
|
return stylesheetFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Argument for command-line option {@code -tagletpath}.
|
||||||
|
* The path to Taglets
|
||||||
|
*/
|
||||||
|
public String tagletPath() {
|
||||||
|
return tagletPath;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Argument for command-line option {@code -top}.
|
* Argument for command-line option {@code -top}.
|
||||||
*/
|
*/
|
||||||
|
@ -25,20 +25,22 @@
|
|||||||
|
|
||||||
package jdk.javadoc.internal.doclets.formats.html;
|
package jdk.javadoc.internal.doclets.formats.html;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.List;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.element.VariableElement;
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
|
|
||||||
import com.sun.source.doctree.SerialFieldTree;
|
import com.sun.source.doctree.SerialFieldTree;
|
||||||
import com.sun.source.doctree.SerialTree;
|
import com.sun.source.doctree.SerialTree;
|
||||||
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.taglets.TagletWriter;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter;
|
import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter;
|
||||||
|
|
||||||
@ -134,7 +136,7 @@ public class HtmlSerialFieldWriter extends FieldWriterImpl
|
|||||||
if (!description.isEmpty()) {
|
if (!description.isEmpty()) {
|
||||||
Content serialFieldContent = writer.commentTagsToContent(field,
|
Content serialFieldContent = writer.commentTagsToContent(field,
|
||||||
description,
|
description,
|
||||||
new TagletWriterImpl.Context(false, false));
|
new TagletWriter.Context(false, false));
|
||||||
var div = HtmlTree.DIV(HtmlStyle.block, serialFieldContent);
|
var div = HtmlTree.DIV(HtmlStyle.block, serialFieldContent);
|
||||||
content.add(div);
|
content.add(div);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -34,7 +34,7 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
|||||||
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter;
|
import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.TagletManager;
|
import jdk.javadoc.internal.doclets.formats.html.taglets.TagletManager;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,985 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2003, 2023, 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. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.formats.html;
|
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
import javax.lang.model.element.ElementKind;
|
|
||||||
import javax.lang.model.element.ExecutableElement;
|
|
||||||
import javax.lang.model.element.ModuleElement;
|
|
||||||
import javax.lang.model.element.PackageElement;
|
|
||||||
import javax.lang.model.element.TypeElement;
|
|
||||||
import javax.lang.model.element.VariableElement;
|
|
||||||
import javax.lang.model.type.TypeMirror;
|
|
||||||
import javax.lang.model.util.SimpleElementVisitor14;
|
|
||||||
|
|
||||||
import com.sun.source.doctree.DeprecatedTree;
|
|
||||||
import com.sun.source.doctree.DocTree;
|
|
||||||
import com.sun.source.doctree.IndexTree;
|
|
||||||
import com.sun.source.doctree.LinkTree;
|
|
||||||
import com.sun.source.doctree.LiteralTree;
|
|
||||||
import com.sun.source.doctree.ParamTree;
|
|
||||||
import com.sun.source.doctree.ReturnTree;
|
|
||||||
import com.sun.source.doctree.SeeTree;
|
|
||||||
import com.sun.source.doctree.SnippetTree;
|
|
||||||
import com.sun.source.doctree.SpecTree;
|
|
||||||
import com.sun.source.doctree.SystemPropertyTree;
|
|
||||||
import com.sun.source.doctree.TextTree;
|
|
||||||
import com.sun.source.doctree.ThrowsTree;
|
|
||||||
import com.sun.source.util.DocTreePath;
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.DocletElement;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.ParamTaglet;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.TagletWriter;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.snippet.Style;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.snippet.StyledText;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils.PreviewFlagProvider;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
|
|
||||||
|
|
||||||
import static com.sun.source.doctree.DocTree.Kind.LINK_PLAIN;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The taglet writer that writes HTML.
|
|
||||||
*/
|
|
||||||
public class TagletWriterImpl extends TagletWriter {
|
|
||||||
/**
|
|
||||||
* A class that provides the information about the enclosing context for
|
|
||||||
* a series of {@code DocTree} nodes.
|
|
||||||
* This context may be used to determine the content that should be generated from the tree nodes.
|
|
||||||
*/
|
|
||||||
static class Context {
|
|
||||||
/**
|
|
||||||
* Whether or not the trees are appearing in a context of just the first sentence,
|
|
||||||
* such as in the summary table of the enclosing element.
|
|
||||||
*/
|
|
||||||
final boolean isFirstSentence;
|
|
||||||
/**
|
|
||||||
* Whether or not the trees are appearing in the "summary" section of the
|
|
||||||
* page for a declaration.
|
|
||||||
*/
|
|
||||||
final boolean inSummary;
|
|
||||||
/**
|
|
||||||
* The set of enclosing kinds of tags.
|
|
||||||
*/
|
|
||||||
final Set<DocTree.Kind> inTags;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an outermost context, with no enclosing tags.
|
|
||||||
*
|
|
||||||
* @param isFirstSentence {@code true} if the trees are appearing in a context of just the
|
|
||||||
* first sentence and {@code false} otherwise
|
|
||||||
* @param inSummary {@code true} if the trees are appearing in the "summary" section
|
|
||||||
* of the page for a declaration and {@code false} otherwise
|
|
||||||
*/
|
|
||||||
Context(boolean isFirstSentence, boolean inSummary) {
|
|
||||||
this(isFirstSentence, inSummary, EnumSet.noneOf(DocTree.Kind.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Context(boolean isFirstSentence, boolean inSummary, Set<DocTree.Kind> inTags) {
|
|
||||||
this.isFirstSentence = isFirstSentence;
|
|
||||||
this.inSummary = inSummary;
|
|
||||||
this.inTags = inTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@code Context} that includes an extra tag kind in the set of enclosing
|
|
||||||
* kinds of tags.
|
|
||||||
*
|
|
||||||
* @param tree the enclosing tree
|
|
||||||
*
|
|
||||||
* @return the new {@code Context}
|
|
||||||
*/
|
|
||||||
Context within(DocTree tree) {
|
|
||||||
var newInTags = EnumSet.copyOf(inTags);
|
|
||||||
newInTags.add(tree.getKind());
|
|
||||||
return new Context(isFirstSentence, inSummary, newInTags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final HtmlDocletWriter htmlWriter;
|
|
||||||
private final HtmlConfiguration configuration;
|
|
||||||
private final HtmlOptions options;
|
|
||||||
private final Utils utils;
|
|
||||||
private final Resources resources;
|
|
||||||
|
|
||||||
private final Messages messages;
|
|
||||||
|
|
||||||
private final Contents contents;
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
// Threshold for length of @see tag label for switching from inline to block layout.
|
|
||||||
private static final int TAG_LIST_ITEM_MAX_INLINE_LENGTH = 30;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a taglet writer.
|
|
||||||
*
|
|
||||||
* @param htmlWriter the {@code HtmlDocletWriter} for the page
|
|
||||||
* @param isFirstSentence {@code true} if this taglet writer is being used for a
|
|
||||||
* "first sentence" summary
|
|
||||||
*/
|
|
||||||
public TagletWriterImpl(HtmlDocletWriter htmlWriter, boolean isFirstSentence) {
|
|
||||||
this(htmlWriter, isFirstSentence, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a taglet writer.
|
|
||||||
*
|
|
||||||
* @param htmlWriter the {@code HtmlDocletWriter} for the page
|
|
||||||
* @param isFirstSentence {@code true} if this taglet writer is being used for a
|
|
||||||
* "first sentence" summary, and {@code false} otherwise
|
|
||||||
* @param inSummary {@code true} if this taglet writer is being used for the content
|
|
||||||
* of a {@code {@summary ...}} tag, and {@code false} otherwise
|
|
||||||
*/
|
|
||||||
public TagletWriterImpl(HtmlDocletWriter htmlWriter, boolean isFirstSentence, boolean inSummary) {
|
|
||||||
this(htmlWriter, new Context(isFirstSentence, inSummary));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a taglet writer.
|
|
||||||
*
|
|
||||||
* @param htmlWriter the {@code HtmlDocletWriter} for the page
|
|
||||||
* @param context the enclosing context for any tags
|
|
||||||
*/
|
|
||||||
public TagletWriterImpl(HtmlDocletWriter htmlWriter, Context context) {
|
|
||||||
super(context.isFirstSentence);
|
|
||||||
this.htmlWriter = htmlWriter;
|
|
||||||
this.context = context;
|
|
||||||
configuration = htmlWriter.configuration;
|
|
||||||
options = configuration.getOptions();
|
|
||||||
utils = configuration.utils;
|
|
||||||
messages = configuration.messages;
|
|
||||||
resources = configuration.getDocResources();
|
|
||||||
contents = configuration.getContents();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content getOutputInstance() {
|
|
||||||
return new ContentBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Content codeTagOutput(Element element, LiteralTree tag) {
|
|
||||||
return HtmlTree.CODE(Text.of(Text.normalizeNewlines(tag.getBody().getBody())));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Content indexTagOutput(Element element, IndexTree tag) {
|
|
||||||
CommentHelper ch = utils.getCommentHelper(element);
|
|
||||||
|
|
||||||
DocTree searchTerm = tag.getSearchTerm();
|
|
||||||
String tagText = (searchTerm instanceof TextTree tt) ? tt.getBody() : "";
|
|
||||||
if (tagText.charAt(0) == '"' && tagText.charAt(tagText.length() - 1) == '"') {
|
|
||||||
tagText = tagText.substring(1, tagText.length() - 1);
|
|
||||||
}
|
|
||||||
tagText = tagText.replaceAll("\\s+", " ");
|
|
||||||
|
|
||||||
Content desc = htmlWriter.commentTagsToContent(element, tag.getDescription(), context.within(tag));
|
|
||||||
String descText = extractText(desc);
|
|
||||||
|
|
||||||
return createAnchorAndSearchIndex(element, tagText, descText, tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ugly but simple;
|
|
||||||
// alternatives would be to walk the Content's tree structure, or to add new functionality to Content
|
|
||||||
private String extractText(Content c) {
|
|
||||||
return c.toString().replaceAll("<[^>]+>", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content getDocRootOutput() {
|
|
||||||
String path;
|
|
||||||
if (htmlWriter.pathToRoot.isEmpty())
|
|
||||||
path = ".";
|
|
||||||
else
|
|
||||||
path = htmlWriter.pathToRoot.getPath();
|
|
||||||
return Text.of(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content deprecatedTagOutput(Element element) {
|
|
||||||
ContentBuilder result = new ContentBuilder();
|
|
||||||
CommentHelper ch = utils.getCommentHelper(element);
|
|
||||||
List<? extends DeprecatedTree> deprs = utils.getDeprecatedTrees(element);
|
|
||||||
if (utils.isTypeElement(element)) {
|
|
||||||
if (utils.isDeprecated(element)) {
|
|
||||||
result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
|
||||||
htmlWriter.getDeprecatedPhrase(element)));
|
|
||||||
if (!deprs.isEmpty()) {
|
|
||||||
List<? extends DocTree> commentTrees = ch.getDescription(deprs.get(0));
|
|
||||||
if (!commentTrees.isEmpty()) {
|
|
||||||
result.add(commentTagsToOutput(element, null, commentTrees, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (utils.isDeprecated(element)) {
|
|
||||||
result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
|
||||||
htmlWriter.getDeprecatedPhrase(element)));
|
|
||||||
if (!deprs.isEmpty()) {
|
|
||||||
List<? extends DocTree> bodyTrees = ch.getBody(deprs.get(0));
|
|
||||||
Content body = commentTagsToOutput(element, null, bodyTrees, false);
|
|
||||||
if (!body.isEmpty())
|
|
||||||
result.add(HtmlTree.DIV(HtmlStyle.deprecationComment, body));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Element ee = utils.getEnclosingTypeElement(element);
|
|
||||||
if (utils.isDeprecated(ee)) {
|
|
||||||
result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
|
||||||
htmlWriter.getDeprecatedPhrase(ee)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content linkTagOutput(Element element, LinkTree tag) {
|
|
||||||
CommentHelper ch = utils.getCommentHelper(element);
|
|
||||||
|
|
||||||
var linkRef = tag.getReference();
|
|
||||||
if (linkRef == null) {
|
|
||||||
messages.warning(ch.getDocTreePath(tag), "doclet.link.no_reference");
|
|
||||||
return invalidTagOutput(resources.getText("doclet.tag.invalid_input", tag.toString()),
|
|
||||||
Optional.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
DocTree.Kind kind = tag.getKind();
|
|
||||||
String refSignature = ch.getReferencedSignature(linkRef);
|
|
||||||
|
|
||||||
return linkSeeReferenceOutput(element,
|
|
||||||
tag,
|
|
||||||
refSignature,
|
|
||||||
ch.getReferencedElement(tag),
|
|
||||||
(kind == LINK_PLAIN),
|
|
||||||
htmlWriter.commentTagsToContent(element, tag.getLabel(), context),
|
|
||||||
(key, args) -> messages.warning(ch.getDocTreePath(tag), key, args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Content literalTagOutput(Element element, LiteralTree tag) {
|
|
||||||
return Text.of(Text.normalizeNewlines(tag.getBody().getBody()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content getParamHeader(ParamTaglet.ParamKind kind) {
|
|
||||||
Content header = switch (kind) {
|
|
||||||
case PARAMETER -> contents.parameters;
|
|
||||||
case TYPE_PARAMETER -> contents.typeParameters;
|
|
||||||
case RECORD_COMPONENT -> contents.recordComponents;
|
|
||||||
default -> throw new IllegalArgumentException(kind.toString());
|
|
||||||
};
|
|
||||||
return HtmlTree.DT(header);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content paramTagOutput(Element element, ParamTree paramTag, String paramName) {
|
|
||||||
ContentBuilder body = new ContentBuilder();
|
|
||||||
CommentHelper ch = utils.getCommentHelper(element);
|
|
||||||
// define id attributes for state components so that generated descriptions may refer to them
|
|
||||||
boolean defineID = (element.getKind() == ElementKind.RECORD)
|
|
||||||
&& !paramTag.isTypeParameter();
|
|
||||||
Content nameContent = Text.of(paramName);
|
|
||||||
body.add(HtmlTree.CODE(defineID ? HtmlTree.SPAN_ID(HtmlIds.forParam(paramName), nameContent) : nameContent));
|
|
||||||
body.add(" - ");
|
|
||||||
List<? extends DocTree> description = ch.getDescription(paramTag);
|
|
||||||
body.add(htmlWriter.commentTagsToContent(element, description, context.within(paramTag)));
|
|
||||||
return HtmlTree.DD(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content returnTagOutput(Element element, ReturnTree returnTag, boolean inline) {
|
|
||||||
CommentHelper ch = utils.getCommentHelper(element);
|
|
||||||
List<? extends DocTree> desc = ch.getDescription(returnTag);
|
|
||||||
Content content = htmlWriter.commentTagsToContent(element, desc, context.within(returnTag));
|
|
||||||
return inline
|
|
||||||
? new ContentBuilder(contents.getContent("doclet.Returns_0", content))
|
|
||||||
: new ContentBuilder(HtmlTree.DT(contents.returns), HtmlTree.DD(content));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content seeTagOutput(Element holder, List<? extends SeeTree> seeTags) {
|
|
||||||
List<Content> links = new ArrayList<>();
|
|
||||||
for (SeeTree dt : seeTags) {
|
|
||||||
TagletWriterImpl t = new TagletWriterImpl(htmlWriter, context.within(dt));
|
|
||||||
links.add(t.seeTagOutput(holder, dt));
|
|
||||||
}
|
|
||||||
if (utils.isVariableElement(holder) && ((VariableElement)holder).getConstantValue() != null &&
|
|
||||||
htmlWriter instanceof ClassWriterImpl writer) {
|
|
||||||
//Automatically add link to constant values page for constant fields.
|
|
||||||
DocPath constantsPath =
|
|
||||||
htmlWriter.pathToRoot.resolve(DocPaths.CONSTANT_VALUES);
|
|
||||||
String whichConstant =
|
|
||||||
writer.getTypeElement().getQualifiedName() + "." +
|
|
||||||
utils.getSimpleName(holder);
|
|
||||||
DocLink link = constantsPath.fragment(whichConstant);
|
|
||||||
links.add(htmlWriter.links.createLink(link,
|
|
||||||
contents.getContent("doclet.Constants_Summary")));
|
|
||||||
}
|
|
||||||
if (utils.isClass(holder) && utils.isSerializable((TypeElement)holder)) {
|
|
||||||
//Automatically add link to serialized form page for serializable classes.
|
|
||||||
if (SerializedFormBuilder.serialInclude(utils, holder) &&
|
|
||||||
SerializedFormBuilder.serialInclude(utils, utils.containingPackage(holder))) {
|
|
||||||
DocPath serialPath = htmlWriter.pathToRoot.resolve(DocPaths.SERIALIZED_FORM);
|
|
||||||
DocLink link = serialPath.fragment(utils.getFullyQualifiedName(holder));
|
|
||||||
links.add(htmlWriter.links.createLink(link,
|
|
||||||
contents.getContent("doclet.Serialized_Form")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (links.isEmpty()) {
|
|
||||||
return Text.EMPTY;
|
|
||||||
}
|
|
||||||
// Use a different style if any link label is longer than 30 chars or contains commas.
|
|
||||||
boolean hasLongLabels = links.stream().anyMatch(this::isLongOrHasComma);
|
|
||||||
var seeList = HtmlTree.UL(hasLongLabels ? HtmlStyle.tagListLong : HtmlStyle.tagList);
|
|
||||||
links.stream()
|
|
||||||
.filter(Predicate.not(Content::isEmpty))
|
|
||||||
.forEach(item -> seeList.add(HtmlTree.LI(item)));
|
|
||||||
|
|
||||||
return new ContentBuilder(
|
|
||||||
HtmlTree.DT(contents.seeAlso),
|
|
||||||
HtmlTree.DD(seeList));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isLongOrHasComma(Content c) {
|
|
||||||
String s = c.toString()
|
|
||||||
.replaceAll("<.*?>", "") // ignore HTML
|
|
||||||
.replaceAll("&#?[A-Za-z0-9]+;", " ") // entities count as a single character
|
|
||||||
.replaceAll("\\R", "\n"); // normalize newlines
|
|
||||||
return s.length() > TAG_LIST_ITEM_MAX_INLINE_LENGTH || s.contains(",");
|
|
||||||
}
|
|
||||||
|
|
||||||
String textOf(List<? extends DocTree> trees) {
|
|
||||||
return trees.stream()
|
|
||||||
.filter(dt -> dt instanceof TextTree)
|
|
||||||
.map(dt -> ((TextTree) dt).getBody().trim())
|
|
||||||
.collect(Collectors.joining(" "));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@return the output for a single {@code @see} tag}
|
|
||||||
*
|
|
||||||
* @param element the element that has the documentation comment containing this tag
|
|
||||||
* @param seeTag the tag
|
|
||||||
*/
|
|
||||||
private Content seeTagOutput(Element element, SeeTree seeTag) {
|
|
||||||
List<? extends DocTree> ref = seeTag.getReference();
|
|
||||||
assert !ref.isEmpty();
|
|
||||||
DocTree ref0 = ref.get(0);
|
|
||||||
switch (ref0.getKind()) {
|
|
||||||
case TEXT, START_ELEMENT -> {
|
|
||||||
// @see "Reference"
|
|
||||||
// @see <a href="...">...</a>
|
|
||||||
return htmlWriter.commentTagsToContent(element, ref, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
case REFERENCE -> {
|
|
||||||
// @see reference label...
|
|
||||||
CommentHelper ch = utils.getCommentHelper(element);
|
|
||||||
String refSignature = ch.getReferencedSignature(ref0);
|
|
||||||
List<? extends DocTree> label = ref.subList(1, ref.size());
|
|
||||||
|
|
||||||
return linkSeeReferenceOutput(element,
|
|
||||||
seeTag,
|
|
||||||
refSignature,
|
|
||||||
ch.getReferencedElement(seeTag),
|
|
||||||
false,
|
|
||||||
htmlWriter.commentTagsToContent(element, label, context),
|
|
||||||
(key, args) -> messages.warning(ch.getDocTreePath(seeTag), key, args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
case ERRONEOUS -> {
|
|
||||||
return invalidTagOutput(resources.getText("doclet.tag.invalid_input",
|
|
||||||
ref0.toString()),
|
|
||||||
Optional.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
default -> throw new IllegalStateException(ref0.getKind().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Worker method to generate a link from the information in different kinds of tags,
|
|
||||||
* such as {@code {@link ...}} tags, {@code @see ...} tags and the {@code link} markup tag
|
|
||||||
* in a {@code {@snippet ...}} tag.
|
|
||||||
*
|
|
||||||
* @param holder the element that has the documentation comment containing the information
|
|
||||||
* @param refTree the tree node containing the information, or {@code null} if not available
|
|
||||||
* @param refSignature the normalized signature of the target of the reference
|
|
||||||
* @param ref the target of the reference
|
|
||||||
* @param isLinkPlain {@code true} if the link should be presented in "plain" font,
|
|
||||||
* or {@code false} for "code" font
|
|
||||||
* @param label the label for the link,
|
|
||||||
* or an empty item to use a default label derived from the signature
|
|
||||||
* @param reportWarning a function to report warnings about issues found in the reference
|
|
||||||
*
|
|
||||||
* @return the output containing the generated link, or content indicating an error
|
|
||||||
*/
|
|
||||||
private Content linkSeeReferenceOutput(Element holder,
|
|
||||||
DocTree refTree,
|
|
||||||
String refSignature,
|
|
||||||
Element ref,
|
|
||||||
boolean isLinkPlain,
|
|
||||||
Content label,
|
|
||||||
BiConsumer<String, Object[]> reportWarning) {
|
|
||||||
Content labelContent = plainOrCode(isLinkPlain, label);
|
|
||||||
|
|
||||||
// The signature from the @see tag. We will output this text when a label is not specified.
|
|
||||||
Content text = plainOrCode(isLinkPlain,
|
|
||||||
Text.of(Objects.requireNonNullElse(refSignature, "")));
|
|
||||||
|
|
||||||
CommentHelper ch = utils.getCommentHelper(holder);
|
|
||||||
TypeElement refClass = ch.getReferencedClass(ref);
|
|
||||||
Element refMem = ch.getReferencedMember(ref);
|
|
||||||
String refFragment = ch.getReferencedFragment(refSignature);
|
|
||||||
|
|
||||||
if (refFragment == null && refMem != null) {
|
|
||||||
refFragment = refMem.toString();
|
|
||||||
} else if (refFragment != null && refFragment.startsWith("#")) {
|
|
||||||
if (labelContent.isEmpty()) {
|
|
||||||
// A non-empty label is required for fragment links as the
|
|
||||||
// reference target does not provide a useful default label.
|
|
||||||
htmlWriter.messages.error(ch.getDocTreePath(refTree), "doclet.link.see.no_label");
|
|
||||||
return invalidTagOutput(resources.getText("doclet.link.see.no_label"),
|
|
||||||
Optional.of(refSignature));
|
|
||||||
}
|
|
||||||
refFragment = refFragment.substring(1);
|
|
||||||
}
|
|
||||||
if (refClass == null) {
|
|
||||||
ModuleElement refModule = ch.getReferencedModule(ref);
|
|
||||||
if (refModule != null && utils.isIncluded(refModule)) {
|
|
||||||
return htmlWriter.getModuleLink(refModule, labelContent.isEmpty() ? text : labelContent, refFragment);
|
|
||||||
}
|
|
||||||
//@see is not referencing an included class
|
|
||||||
PackageElement refPackage = ch.getReferencedPackage(ref);
|
|
||||||
if (refPackage != null && utils.isIncluded(refPackage)) {
|
|
||||||
//@see is referencing an included package
|
|
||||||
if (labelContent.isEmpty()) {
|
|
||||||
labelContent = plainOrCode(isLinkPlain,
|
|
||||||
Text.of(refPackage.getQualifiedName()));
|
|
||||||
}
|
|
||||||
return htmlWriter.getPackageLink(refPackage, labelContent, refFragment);
|
|
||||||
} else {
|
|
||||||
// @see is not referencing an included class, module or package. Check for cross links.
|
|
||||||
String refModuleName = ch.getReferencedModuleName(refSignature);
|
|
||||||
DocLink elementCrossLink = (refPackage != null) ? htmlWriter.getCrossPackageLink(refPackage) :
|
|
||||||
(configuration.extern.isModule(refModuleName))
|
|
||||||
? htmlWriter.getCrossModuleLink(utils.elementUtils.getModuleElement(refModuleName))
|
|
||||||
: null;
|
|
||||||
if (elementCrossLink != null) {
|
|
||||||
// Element cross link found
|
|
||||||
return htmlWriter.links.createExternalLink(elementCrossLink,
|
|
||||||
(labelContent.isEmpty() ? text : labelContent));
|
|
||||||
} else {
|
|
||||||
// No cross link found so print warning
|
|
||||||
if (!configuration.isDocLintReferenceGroupEnabled()) {
|
|
||||||
reportWarning.accept(
|
|
||||||
"doclet.link.see.reference_not_found",
|
|
||||||
new Object[] { refSignature});
|
|
||||||
}
|
|
||||||
return htmlWriter.invalidTagOutput(resources.getText("doclet.link.see.reference_invalid"),
|
|
||||||
Optional.of(labelContent.isEmpty() ? text: labelContent));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (refFragment == null) {
|
|
||||||
// Must be a class reference since refClass is not null and refFragment is null.
|
|
||||||
if (labelContent.isEmpty() && refTree != null) {
|
|
||||||
TypeMirror referencedType = ch.getReferencedType(refTree);
|
|
||||||
if (utils.isGenericType(referencedType)) {
|
|
||||||
// This is a generic type link, use the TypeMirror representation.
|
|
||||||
return plainOrCode(isLinkPlain, htmlWriter.getLink(
|
|
||||||
new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS, referencedType)));
|
|
||||||
}
|
|
||||||
labelContent = plainOrCode(isLinkPlain, Text.of(utils.getSimpleName(refClass)));
|
|
||||||
}
|
|
||||||
return htmlWriter.getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.PLAIN, refClass)
|
|
||||||
.label(labelContent));
|
|
||||||
} else if (refMem == null) {
|
|
||||||
// This is a fragment reference since refClass and refFragment are not null but refMem is null.
|
|
||||||
return htmlWriter.getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.PLAIN, refClass)
|
|
||||||
.label(labelContent)
|
|
||||||
.fragment(refFragment)
|
|
||||||
.style(null));
|
|
||||||
} else {
|
|
||||||
// Must be a member reference since refClass is not null and refMemName is not null.
|
|
||||||
// refMem is not null, so this @see tag must be referencing a valid member.
|
|
||||||
TypeElement containing = utils.getEnclosingTypeElement(refMem);
|
|
||||||
|
|
||||||
// Find the enclosing type where the method is actually visible
|
|
||||||
// in the inheritance hierarchy.
|
|
||||||
ExecutableElement overriddenMethod = null;
|
|
||||||
if (refMem.getKind() == ElementKind.METHOD) {
|
|
||||||
VisibleMemberTable vmt = configuration.getVisibleMemberTable(containing);
|
|
||||||
overriddenMethod = vmt.getOverriddenMethod((ExecutableElement)refMem);
|
|
||||||
|
|
||||||
if (overriddenMethod != null) {
|
|
||||||
containing = utils.getEnclosingTypeElement(overriddenMethod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (refSignature.trim().startsWith("#") &&
|
|
||||||
! (utils.isPublic(containing) || utils.isLinkable(containing))) {
|
|
||||||
// Since the link is relative and the holder is not even being
|
|
||||||
// documented, this must be an inherited link. Redirect it.
|
|
||||||
// The current class either overrides the referenced member or
|
|
||||||
// inherits it automatically.
|
|
||||||
if (htmlWriter instanceof ClassWriterImpl writer) {
|
|
||||||
containing = writer.getTypeElement();
|
|
||||||
} else if (!utils.isPublic(containing)) {
|
|
||||||
reportWarning.accept("doclet.link.see.reference_not_accessible",
|
|
||||||
new Object[] { utils.getFullyQualifiedName(containing)});
|
|
||||||
} else {
|
|
||||||
if (!configuration.isDocLintReferenceGroupEnabled()) {
|
|
||||||
reportWarning.accept("doclet.link.see.reference_not_found",
|
|
||||||
new Object[] { refSignature });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String refMemName = refFragment;
|
|
||||||
if (configuration.currentTypeElement != containing) {
|
|
||||||
refMemName = (utils.isConstructor(refMem))
|
|
||||||
? refMemName
|
|
||||||
: utils.getSimpleName(containing) + "." + refMemName;
|
|
||||||
}
|
|
||||||
if (utils.isExecutableElement(refMem)) {
|
|
||||||
if (refMemName.indexOf('(') < 0) {
|
|
||||||
refMemName += utils.makeSignature((ExecutableElement) refMem, null, true);
|
|
||||||
}
|
|
||||||
if (overriddenMethod != null) {
|
|
||||||
// The method to actually link.
|
|
||||||
refMem = overriddenMethod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return htmlWriter.getDocLink(HtmlLinkInfo.Kind.SHOW_PREVIEW, containing,
|
|
||||||
refMem, (labelContent.isEmpty()
|
|
||||||
? plainOrCode(isLinkPlain, Text.of(refMemName))
|
|
||||||
: labelContent), null, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Content plainOrCode(boolean plain, Content body) {
|
|
||||||
return (plain || body.isEmpty()) ? body : HtmlTree.CODE(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content simpleBlockTagOutput(Element element, List<? extends DocTree> simpleTags, String header) {
|
|
||||||
CommentHelper ch = utils.getCommentHelper(element);
|
|
||||||
ContentBuilder body = new ContentBuilder();
|
|
||||||
boolean many = false;
|
|
||||||
for (DocTree simpleTag : simpleTags) {
|
|
||||||
if (many) {
|
|
||||||
body.add(", ");
|
|
||||||
}
|
|
||||||
List<? extends DocTree> bodyTags = ch.getBody(simpleTag);
|
|
||||||
body.add(htmlWriter.commentTagsToContent(element, bodyTags, context.within(simpleTag)));
|
|
||||||
many = true;
|
|
||||||
}
|
|
||||||
return new ContentBuilder(
|
|
||||||
HtmlTree.DT(RawHtml.of(header)),
|
|
||||||
HtmlTree.DD(body));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Content snippetTagOutput(Element element, SnippetTree tag, StyledText content,
|
|
||||||
String id, String lang) {
|
|
||||||
var pre = new HtmlTree(TagName.PRE).setStyle(HtmlStyle.snippet);
|
|
||||||
if (id != null && !id.isBlank()) {
|
|
||||||
pre.put(HtmlAttr.ID, id);
|
|
||||||
}
|
|
||||||
var code = new HtmlTree(TagName.CODE)
|
|
||||||
.addUnchecked(Text.EMPTY); // Make sure the element is always rendered
|
|
||||||
if (lang != null && !lang.isBlank()) {
|
|
||||||
code.addStyle("language-" + lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
content.consumeBy((styles, sequence) -> {
|
|
||||||
CharSequence text = Text.normalizeNewlines(sequence);
|
|
||||||
if (styles.isEmpty()) {
|
|
||||||
code.add(text);
|
|
||||||
} else {
|
|
||||||
Element e = null;
|
|
||||||
String t = null;
|
|
||||||
boolean linkEncountered = false;
|
|
||||||
boolean markupEncountered = false;
|
|
||||||
Set<String> classes = new HashSet<>();
|
|
||||||
for (Style s : styles) {
|
|
||||||
if (s instanceof Style.Name n) {
|
|
||||||
classes.add(n.name());
|
|
||||||
} else if (s instanceof Style.Link l) {
|
|
||||||
assert !linkEncountered; // TODO: do not assert; pick the first link report on subsequent
|
|
||||||
linkEncountered = true;
|
|
||||||
t = l.target();
|
|
||||||
e = getLinkedElement(element, t);
|
|
||||||
if (e == null) {
|
|
||||||
// TODO: diagnostic output
|
|
||||||
}
|
|
||||||
} else if (s instanceof Style.Markup) {
|
|
||||||
markupEncountered = true;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// TODO: transform this if...else into an exhaustive
|
|
||||||
// switch over the sealed Style hierarchy when "Pattern
|
|
||||||
// Matching for switch" has been implemented (JEP 406
|
|
||||||
// and friends)
|
|
||||||
throw new AssertionError(styles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Content c;
|
|
||||||
if (markupEncountered) {
|
|
||||||
return;
|
|
||||||
} else if (linkEncountered) {
|
|
||||||
assert e != null;
|
|
||||||
//disable preview tagging inside the snippets:
|
|
||||||
PreviewFlagProvider prevPreviewProvider = utils.setPreviewFlagProvider(el -> false);
|
|
||||||
try {
|
|
||||||
c = linkSeeReferenceOutput(element,
|
|
||||||
null,
|
|
||||||
t,
|
|
||||||
e,
|
|
||||||
false, // TODO: for now
|
|
||||||
Text.of(sequence.toString()),
|
|
||||||
(key, args) -> { /* TODO: report diagnostic */ });
|
|
||||||
} finally {
|
|
||||||
utils.setPreviewFlagProvider(prevPreviewProvider);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c = HtmlTree.SPAN(Text.of(text));
|
|
||||||
classes.forEach(((HtmlTree) c)::addStyle);
|
|
||||||
}
|
|
||||||
code.add(c);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
String copyText = resources.getText("doclet.Copy_to_clipboard");
|
|
||||||
String copiedText = resources.getText("doclet.Copied_to_clipboard");
|
|
||||||
String copySnippetText = resources.getText("doclet.Copy_snippet_to_clipboard");
|
|
||||||
var snippetContainer = HtmlTree.DIV(HtmlStyle.snippetContainer,
|
|
||||||
new HtmlTree(TagName.BUTTON)
|
|
||||||
.add(HtmlTree.SPAN(Text.of(copyText))
|
|
||||||
.put(HtmlAttr.DATA_COPIED, copiedText))
|
|
||||||
.add(new HtmlTree(TagName.IMG)
|
|
||||||
.put(HtmlAttr.SRC, htmlWriter.pathToRoot.resolve(DocPaths.CLIPBOARD_SVG).getPath())
|
|
||||||
.put(HtmlAttr.ALT, copySnippetText))
|
|
||||||
.addStyle(HtmlStyle.copy)
|
|
||||||
.addStyle(HtmlStyle.snippetCopy)
|
|
||||||
.put(HtmlAttr.ARIA_LABEL, copySnippetText)
|
|
||||||
.put(HtmlAttr.ONCLICK, "copySnippet(this)"));
|
|
||||||
return snippetContainer.add(pre.add(code));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns the element that is linked from the context of the referrer using
|
|
||||||
* the provided signature; returns null if such element could not be found.
|
|
||||||
*
|
|
||||||
* This method is to be used when it is the target of the link that is
|
|
||||||
* important, not the container of the link (e.g. was it an @see,
|
|
||||||
* @link/@linkplain or @snippet tags, etc.)
|
|
||||||
*/
|
|
||||||
public Element getLinkedElement(Element referer, String signature) {
|
|
||||||
var factory = utils.docTrees.getDocTreeFactory();
|
|
||||||
var docCommentTree = utils.getDocCommentTree(referer);
|
|
||||||
var rootPath = new DocTreePath(utils.getTreePath(referer), docCommentTree);
|
|
||||||
var reference = factory.newReferenceTree(signature);
|
|
||||||
var fabricatedPath = new DocTreePath(rootPath, reference);
|
|
||||||
return utils.docTrees.getElement(fabricatedPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content specTagOutput(Element holder, List<? extends SpecTree> specTags) {
|
|
||||||
if (specTags.isEmpty()) {
|
|
||||||
return Text.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Content> links = specTags.stream()
|
|
||||||
.map(st -> specTagToContent(holder, st))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
// Use a different style if any link label is longer than 30 chars or contains commas.
|
|
||||||
boolean hasLongLabels = links.stream().anyMatch(this::isLongOrHasComma);
|
|
||||||
var specList = HtmlTree.UL(hasLongLabels ? HtmlStyle.tagListLong : HtmlStyle.tagList);
|
|
||||||
links.stream()
|
|
||||||
.filter(Predicate.not(Content::isEmpty))
|
|
||||||
.forEach(item -> specList.add(HtmlTree.LI(item)));
|
|
||||||
|
|
||||||
return new ContentBuilder(
|
|
||||||
HtmlTree.DT(contents.externalSpecifications),
|
|
||||||
HtmlTree.DD(specList));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Content specTagToContent(Element holder, SpecTree specTree) {
|
|
||||||
String specTreeURL = specTree.getURL().getBody();
|
|
||||||
List<? extends DocTree> specTreeLabel = specTree.getTitle();
|
|
||||||
Content label = htmlWriter.commentTagsToContent(holder, specTreeLabel, isFirstSentence);
|
|
||||||
return getExternalSpecContent(holder, specTree, specTreeURL,
|
|
||||||
textOf(specTreeLabel).replaceAll("\\s+", " "), label);
|
|
||||||
}
|
|
||||||
|
|
||||||
Content getExternalSpecContent(Element holder, DocTree docTree, String url, String searchText, Content title) {
|
|
||||||
URI specURI;
|
|
||||||
try {
|
|
||||||
// Use the canonical title of the spec if one is available
|
|
||||||
specURI = new URI(url);
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
CommentHelper ch = utils.getCommentHelper(holder);
|
|
||||||
DocTreePath dtp = ch.getDocTreePath(docTree);
|
|
||||||
htmlWriter.messages.error(dtp, "doclet.Invalid_URL", e.getMessage());
|
|
||||||
specURI = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Content titleWithAnchor = createAnchorAndSearchIndex(holder,
|
|
||||||
searchText,
|
|
||||||
title,
|
|
||||||
resources.getText("doclet.External_Specification"),
|
|
||||||
docTree);
|
|
||||||
|
|
||||||
if (specURI == null) {
|
|
||||||
return titleWithAnchor;
|
|
||||||
} else {
|
|
||||||
return HtmlTree.A(htmlWriter.resolveExternalSpecURI(specURI), titleWithAnchor);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Content systemPropertyTagOutput(Element element, SystemPropertyTree tag) {
|
|
||||||
String tagText = tag.getPropertyName().toString();
|
|
||||||
return HtmlTree.CODE(createAnchorAndSearchIndex(element, tagText,
|
|
||||||
resources.getText("doclet.System_Property"), tag));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content getThrowsHeader() {
|
|
||||||
return HtmlTree.DT(contents.throws_);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated(forRemoval = true)
|
|
||||||
private Content throwsTagOutput(Element element, ThrowsTree throwsTag, TypeMirror substituteType) {
|
|
||||||
ContentBuilder body = new ContentBuilder();
|
|
||||||
CommentHelper ch = utils.getCommentHelper(element);
|
|
||||||
Element exception = ch.getException(throwsTag);
|
|
||||||
Content excName;
|
|
||||||
if (substituteType != null) {
|
|
||||||
excName = htmlWriter.getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.PLAIN,
|
|
||||||
substituteType));
|
|
||||||
} else if (exception == null) {
|
|
||||||
excName = Text.of(throwsTag.getExceptionName().toString());
|
|
||||||
} else if (exception.asType() == null) {
|
|
||||||
excName = Text.of(utils.getFullyQualifiedName(exception));
|
|
||||||
} else {
|
|
||||||
HtmlLinkInfo link = new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.PLAIN,
|
|
||||||
exception.asType());
|
|
||||||
excName = htmlWriter.getLink(link);
|
|
||||||
}
|
|
||||||
body.add(HtmlTree.CODE(excName));
|
|
||||||
List<? extends DocTree> description = ch.getDescription(throwsTag);
|
|
||||||
Content desc = htmlWriter.commentTagsToContent(element, description, context.within(throwsTag));
|
|
||||||
if (desc != null && !desc.isEmpty()) {
|
|
||||||
body.add(" - ");
|
|
||||||
body.add(desc);
|
|
||||||
}
|
|
||||||
return HtmlTree.DD(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content throwsTagOutput(TypeMirror throwsType, Optional<Content> content) {
|
|
||||||
var linkInfo = new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.PLAIN, throwsType);
|
|
||||||
var link = htmlWriter.getLink(linkInfo);
|
|
||||||
var concat = new ContentBuilder(HtmlTree.CODE(link));
|
|
||||||
if (content.isPresent()) {
|
|
||||||
concat.add(" - ");
|
|
||||||
concat.add(content.get());
|
|
||||||
}
|
|
||||||
return HtmlTree.DD(concat);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content valueTagOutput(VariableElement field, String constantVal, boolean includeLink) {
|
|
||||||
return includeLink
|
|
||||||
? htmlWriter.getDocLink(HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS, field, constantVal)
|
|
||||||
: Text.of(constantVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Content invalidTagOutput(String summary, Optional<String> detail) {
|
|
||||||
return htmlWriter.invalidTagOutput(summary,
|
|
||||||
detail.isEmpty() || detail.get().isEmpty()
|
|
||||||
? Optional.empty()
|
|
||||||
: Optional.of(Text.of(Text.normalizeNewlines(detail.get()))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content commentTagsToOutput(DocTree holder, List<? extends DocTree> tags) {
|
|
||||||
return commentTagsToOutput(null, holder, tags, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content commentTagsToOutput(Element element, List<? extends DocTree> tags) {
|
|
||||||
return commentTagsToOutput(element, null, tags, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content commentTagsToOutput(Element holder,
|
|
||||||
DocTree holderTag,
|
|
||||||
List<? extends DocTree> tags,
|
|
||||||
boolean isFirstSentence)
|
|
||||||
{
|
|
||||||
return htmlWriter.commentTagsToContent(holder,
|
|
||||||
tags, holderTag == null ? context : context.within(holderTag));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BaseConfiguration configuration() {
|
|
||||||
return configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected TypeElement getCurrentPageElement() {
|
|
||||||
return htmlWriter.getCurrentPageElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
public HtmlDocletWriter getHtmlWriter() {
|
|
||||||
return htmlWriter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Content createAnchorAndSearchIndex(Element element, String tagText, String desc, DocTree tree) {
|
|
||||||
return createAnchorAndSearchIndex(element, tagText, Text.of(tagText), desc, tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("preview")
|
|
||||||
private Content createAnchorAndSearchIndex(Element element, String tagText, Content tagContent, String desc, DocTree tree) {
|
|
||||||
Content result = null;
|
|
||||||
if (context.isFirstSentence && context.inSummary || context.inTags.contains(DocTree.Kind.INDEX)) {
|
|
||||||
result = tagContent;
|
|
||||||
} else {
|
|
||||||
HtmlId id = HtmlIds.forText(tagText, htmlWriter.indexAnchorTable);
|
|
||||||
result = HtmlTree.SPAN(id, HtmlStyle.searchTagResult, tagContent);
|
|
||||||
if (options.createIndex() && !tagText.isEmpty()) {
|
|
||||||
String holder = getHolderName(element);
|
|
||||||
IndexItem item = IndexItem.of(element, tree, tagText, holder, desc,
|
|
||||||
new DocLink(htmlWriter.path, id.name()));
|
|
||||||
configuration.mainIndex.add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getHolderName(Element element) {
|
|
||||||
return new SimpleElementVisitor14<String, Void>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitModule(ModuleElement e, Void p) {
|
|
||||||
return resources.getText("doclet.module")
|
|
||||||
+ " " + utils.getFullyQualifiedName(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitPackage(PackageElement e, Void p) {
|
|
||||||
return resources.getText("doclet.package")
|
|
||||||
+ " " + utils.getFullyQualifiedName(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitType(TypeElement e, Void p) {
|
|
||||||
return utils.getTypeElementKindName(e, true)
|
|
||||||
+ " " + utils.getFullyQualifiedName(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitExecutable(ExecutableElement e, Void p) {
|
|
||||||
return utils.getFullyQualifiedName(utils.getEnclosingTypeElement(e))
|
|
||||||
+ "." + utils.getSimpleName(e)
|
|
||||||
+ utils.flatSignature(e, htmlWriter.getCurrentPageElement());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitVariable(VariableElement e, Void p) {
|
|
||||||
return utils.getFullyQualifiedName(utils.getEnclosingTypeElement(e))
|
|
||||||
+ "." + utils.getSimpleName(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String visitUnknown(Element e, Void p) {
|
|
||||||
if (e instanceof DocletElement de) {
|
|
||||||
return switch (de.getSubKind()) {
|
|
||||||
case OVERVIEW -> resources.getText("doclet.Overview");
|
|
||||||
case DOCFILE -> getHolderName(de);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return super.visitUnknown(e, p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String defaultAction(Element e, Void p) {
|
|
||||||
return utils.getFullyQualifiedName(e);
|
|
||||||
}
|
|
||||||
}.visit(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getHolderName(DocletElement de) {
|
|
||||||
PackageElement pe = de.getPackageElement();
|
|
||||||
if (pe.isUnnamed()) {
|
|
||||||
// if package is unnamed use enclosing module only if it is named
|
|
||||||
Element ee = pe.getEnclosingElement();
|
|
||||||
if (ee instanceof ModuleElement && !((ModuleElement)ee).isUnnamed()) {
|
|
||||||
return resources.getText("doclet.module") + " " + utils.getFullyQualifiedName(ee);
|
|
||||||
}
|
|
||||||
return pe.toString(); // "Unnamed package" or similar
|
|
||||||
}
|
|
||||||
return resources.getText("doclet.package") + " " + utils.getFullyQualifiedName(pe);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,35 +23,56 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import com.sun.source.doctree.UnknownBlockTagTree;
|
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
import jdk.javadoc.doclet.Taglet.Location;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base class that implements the {@link Taglet} interface.
|
* A base class that implements the {@link Taglet} interface.
|
||||||
*/
|
*/
|
||||||
public class BaseTaglet implements Taglet {
|
public class BaseTaglet implements Taglet {
|
||||||
|
// The following members are global to the lifetime of the doclet
|
||||||
|
protected final HtmlConfiguration config;
|
||||||
|
protected final Messages messages;
|
||||||
|
protected final Resources resources;
|
||||||
|
protected final Utils utils;
|
||||||
|
|
||||||
|
// The following members are specific to the instance of the taglet
|
||||||
protected final DocTree.Kind tagKind;
|
protected final DocTree.Kind tagKind;
|
||||||
protected final String name;
|
protected final String name;
|
||||||
private final boolean inline;
|
private final boolean inline;
|
||||||
private final Set<Location> sites;
|
private final Set<Location> sites;
|
||||||
|
|
||||||
BaseTaglet(DocTree.Kind tagKind, boolean inline, Set<Location> sites) {
|
// The following is dynamically set for the duration of the methods
|
||||||
this(tagKind.tagName, tagKind, inline, sites);
|
// getInlineTagOutput and getAllBlockTagOutput
|
||||||
|
// by those taglets that need to refer to it
|
||||||
|
protected TagletWriter tagletWriter;
|
||||||
|
|
||||||
|
public BaseTaglet(HtmlConfiguration config, DocTree.Kind tagKind, boolean inline, Set<Location> sites) {
|
||||||
|
this(config, tagKind.tagName, tagKind, inline, sites);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseTaglet(String name, boolean inline, Set<Location> sites) {
|
protected BaseTaglet(HtmlConfiguration config, String name, boolean inline, Set<Location> sites) {
|
||||||
this(name, inline ? DocTree.Kind.UNKNOWN_INLINE_TAG : DocTree.Kind.UNKNOWN_BLOCK_TAG, inline, sites);
|
this(config, name, inline ? DocTree.Kind.UNKNOWN_INLINE_TAG : DocTree.Kind.UNKNOWN_BLOCK_TAG, inline, sites);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BaseTaglet(String name, DocTree.Kind tagKind, boolean inline, Set<Location> sites) {
|
private BaseTaglet(HtmlConfiguration config, String name, DocTree.Kind tagKind, boolean inline, Set<Location> sites) {
|
||||||
|
this.config = config;
|
||||||
|
this.messages = config.getMessages();
|
||||||
|
this.resources = config.getDocResources();
|
||||||
|
this.utils = config.utils;
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.tagKind = tagKind;
|
this.tagKind = tagKind;
|
||||||
this.inline = inline;
|
this.inline = inline;
|
||||||
@ -63,41 +84,6 @@ public class BaseTaglet implements Taglet {
|
|||||||
return sites;
|
return sites;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean inField() {
|
|
||||||
return sites.contains(Location.FIELD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean inConstructor() {
|
|
||||||
return sites.contains(Location.CONSTRUCTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean inMethod() {
|
|
||||||
return sites.contains(Location.METHOD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean inOverview() {
|
|
||||||
return sites.contains(Location.OVERVIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean inModule() {
|
|
||||||
return sites.contains(Location.MODULE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean inPackage() {
|
|
||||||
return sites.contains(Location.PACKAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final boolean inType() {
|
|
||||||
return sites.contains(Location.TYPE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean isInlineTag() {
|
public final boolean isInlineTag() {
|
||||||
return inline;
|
return inline;
|
||||||
@ -117,28 +103,13 @@ public class BaseTaglet implements Taglet {
|
|||||||
return tagKind;
|
return tagKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether or not this taglet accepts a {@code DocTree} node.
|
|
||||||
* The taglet accepts a tree node if it has the same kind, and
|
|
||||||
* if the kind is {@code UNKNOWN_BLOCK_TAG} the same tag name.
|
|
||||||
*
|
|
||||||
* @param tree the tree node
|
|
||||||
* @return {@code true} if this taglet accepts this tree node
|
|
||||||
*/
|
|
||||||
public boolean accepts(DocTree tree) {
|
|
||||||
return (tree.getKind() == DocTree.Kind.UNKNOWN_BLOCK_TAG
|
|
||||||
&& tagKind == DocTree.Kind.UNKNOWN_BLOCK_TAG)
|
|
||||||
? ((UnknownBlockTagTree) tree).getTagName().equals(name)
|
|
||||||
: tree.getKind() == tagKind;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
* @implSpec This implementation throws {@link UnsupportedTagletOperationException}.
|
* @implSpec This implementation throws {@link UnsupportedTagletOperationException}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter writer) {
|
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter tagletWriter) {
|
||||||
throw new UnsupportedTagletOperationException("Method not supported in taglet " + getName() + ".");
|
throw new UnsupportedTagletOperationException("Method not supported in taglet " + getName() + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +119,7 @@ public class BaseTaglet implements Taglet {
|
|||||||
* @implSpec This implementation throws {@link UnsupportedTagletOperationException}
|
* @implSpec This implementation throws {@link UnsupportedTagletOperationException}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
|
public Content getAllBlockTagOutput(Element holder, TagletWriter tagletWriter) {
|
||||||
throw new UnsupportedTagletOperationException("Method not supported in taglet " + getName() + ".");
|
throw new UnsupportedTagletOperationException("Method not supported in taglet " + getName() + ".");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2003, 2023, 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
|
||||||
|
import com.sun.source.doctree.DeprecatedTree;
|
||||||
|
import com.sun.source.doctree.DocTree;
|
||||||
|
|
||||||
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taglet that represents the {@code @deprecated} tag.
|
||||||
|
*/
|
||||||
|
public class DeprecatedTaglet extends BaseTaglet {
|
||||||
|
|
||||||
|
DeprecatedTaglet(HtmlConfiguration config) {
|
||||||
|
super(config, DocTree.Kind.DEPRECATED, false,
|
||||||
|
EnumSet.of(Taglet.Location.MODULE, Taglet.Location.TYPE, Taglet.Location.CONSTRUCTOR, Taglet.Location.METHOD, Taglet.Location.FIELD));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Content getAllBlockTagOutput(Element element, TagletWriter tagletWriter) {
|
||||||
|
var htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
|
||||||
|
ContentBuilder result = new ContentBuilder();
|
||||||
|
CommentHelper ch = utils.getCommentHelper(element);
|
||||||
|
List<? extends DeprecatedTree> deprs = utils.getDeprecatedTrees(element);
|
||||||
|
if (utils.isTypeElement(element)) {
|
||||||
|
if (utils.isDeprecated(element)) {
|
||||||
|
result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
||||||
|
htmlWriter.getDeprecatedPhrase(element)));
|
||||||
|
if (!deprs.isEmpty()) {
|
||||||
|
List<? extends DocTree> commentTrees = ch.getDescription(deprs.get(0));
|
||||||
|
if (!commentTrees.isEmpty()) {
|
||||||
|
result.add(tagletWriter.commentTagsToOutput(element, null, commentTrees, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (utils.isDeprecated(element)) {
|
||||||
|
result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
||||||
|
htmlWriter.getDeprecatedPhrase(element)));
|
||||||
|
if (!deprs.isEmpty()) {
|
||||||
|
List<? extends DocTree> bodyTrees = ch.getBody(deprs.get(0));
|
||||||
|
Content body = tagletWriter.commentTagsToOutput(element, null, bodyTrees, false);
|
||||||
|
if (!body.isEmpty())
|
||||||
|
result.add(HtmlTree.DIV(HtmlStyle.deprecationComment, body));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Element ee = utils.getEnclosingTypeElement(element);
|
||||||
|
if (utils.isDeprecated(ee)) {
|
||||||
|
result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
|
||||||
|
htmlWriter.getDeprecatedPhrase(ee)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,13 +23,17 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,16 +42,14 @@ import jdk.javadoc.internal.doclets.toolkit.Content;
|
|||||||
* directory.
|
* directory.
|
||||||
*/
|
*/
|
||||||
public class DocRootTaglet extends BaseTaglet {
|
public class DocRootTaglet extends BaseTaglet {
|
||||||
|
DocRootTaglet(HtmlConfiguration config) {
|
||||||
/**
|
super(config, DocTree.Kind.DOC_ROOT, true, EnumSet.allOf(Taglet.Location.class));
|
||||||
* Construct a new DocRootTaglet.
|
|
||||||
*/
|
|
||||||
public DocRootTaglet() {
|
|
||||||
super(DocTree.Kind.DOC_ROOT, true, EnumSet.allOf(Location.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter writer) {
|
public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter tagletWriter) {
|
||||||
return writer.getDocRootOutput();
|
var htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
var pathToRoot = htmlWriter.pathToRoot;
|
||||||
|
return Text.of(pathToRoot.isEmpty() ? "." : pathToRoot.getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015, 2023, 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
|
||||||
|
import com.sun.source.doctree.DocTree;
|
||||||
|
import com.sun.source.doctree.IndexTree;
|
||||||
|
import com.sun.source.doctree.TextTree;
|
||||||
|
|
||||||
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An inline taglet used to index a word or a phrase.
|
||||||
|
* The enclosed text is interpreted as not containing HTML markup or
|
||||||
|
* nested javadoc tags.
|
||||||
|
*/
|
||||||
|
public class IndexTaglet extends BaseTaglet {
|
||||||
|
|
||||||
|
IndexTaglet(HtmlConfiguration config) {
|
||||||
|
super(config, DocTree.Kind.INDEX, true, EnumSet.allOf(Taglet.Location.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter tagletWriter) {
|
||||||
|
var context = tagletWriter.context;
|
||||||
|
var indexTree = (IndexTree) tag;
|
||||||
|
|
||||||
|
DocTree searchTerm = indexTree.getSearchTerm();
|
||||||
|
String tagText = (searchTerm instanceof TextTree tt) ? tt.getBody() : "";
|
||||||
|
if (tagText.charAt(0) == '"' && tagText.charAt(tagText.length() - 1) == '"') {
|
||||||
|
tagText = tagText.substring(1, tagText.length() - 1);
|
||||||
|
}
|
||||||
|
tagText = tagText.replaceAll("\\s+", " ");
|
||||||
|
|
||||||
|
Content desc = tagletWriter.htmlWriter.commentTagsToContent(element, indexTree.getDescription(), context.within(indexTree));
|
||||||
|
String descText = extractText(desc);
|
||||||
|
|
||||||
|
return tagletWriter.createAnchorAndSearchIndex(element, tagText, descText, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ugly but simple;
|
||||||
|
// alternatives would be to walk the Content's tree structure, or to add new functionality to Content
|
||||||
|
private String extractText(Content c) {
|
||||||
|
return c.toString().replaceAll("<[^>]+>", "");
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -36,10 +36,10 @@ import javax.lang.model.element.TypeElement;
|
|||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import com.sun.source.doctree.InheritDocTree;
|
import com.sun.source.doctree.InheritDocTree;
|
||||||
import com.sun.source.util.DocTreePath;
|
import com.sun.source.util.DocTreePath;
|
||||||
|
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
import jdk.javadoc.doclet.Taglet.Location;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result;
|
||||||
@ -54,8 +54,8 @@ public class InheritDocTaglet extends BaseTaglet {
|
|||||||
/**
|
/**
|
||||||
* Construct a new InheritDocTaglet.
|
* Construct a new InheritDocTaglet.
|
||||||
*/
|
*/
|
||||||
public InheritDocTaglet() {
|
InheritDocTaglet(HtmlConfiguration config) {
|
||||||
super(DocTree.Kind.INHERIT_DOC, true, EnumSet.of(Location.METHOD));
|
super(config, DocTree.Kind.INHERIT_DOC, true, EnumSet.of(Location.METHOD));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,9 +76,6 @@ public class InheritDocTaglet extends BaseTaglet {
|
|||||||
InheritDocTree inheritDoc,
|
InheritDocTree inheritDoc,
|
||||||
boolean isFirstSentence) {
|
boolean isFirstSentence) {
|
||||||
Content replacement = writer.getOutputInstance();
|
Content replacement = writer.getOutputInstance();
|
||||||
BaseConfiguration configuration = writer.configuration();
|
|
||||||
Messages messages = configuration.getMessages();
|
|
||||||
Utils utils = configuration.utils;
|
|
||||||
CommentHelper ch = utils.getCommentHelper(method);
|
CommentHelper ch = utils.getCommentHelper(method);
|
||||||
DocTreePath inheritDocPath = ch.getDocTreePath(inheritDoc);
|
DocTreePath inheritDocPath = ch.getDocTreePath(inheritDoc);
|
||||||
var path = inheritDocPath.getParentPath();
|
var path = inheritDocPath.getParentPath();
|
||||||
@ -103,7 +100,7 @@ public class InheritDocTaglet extends BaseTaglet {
|
|||||||
//
|
//
|
||||||
// This way we do more work in erroneous case, but less in the typical
|
// This way we do more work in erroneous case, but less in the typical
|
||||||
// case. We don't optimize for the former.
|
// case. We don't optimize for the former.
|
||||||
VisibleMemberTable visibleMemberTable = configuration.getVisibleMemberTable(supertype);
|
VisibleMemberTable visibleMemberTable = config.getVisibleMemberTable(supertype);
|
||||||
List<Element> methods = visibleMemberTable.getAllVisibleMembers(VisibleMemberTable.Kind.METHODS);
|
List<Element> methods = visibleMemberTable.getAllVisibleMembers(VisibleMemberTable.Kind.METHODS);
|
||||||
for (Element e : methods) {
|
for (Element e : methods) {
|
||||||
ExecutableElement m = (ExecutableElement) e;
|
ExecutableElement m = (ExecutableElement) e;
|
||||||
@ -142,7 +139,7 @@ public class InheritDocTaglet extends BaseTaglet {
|
|||||||
return replacement;
|
return replacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
Taglet taglet = configuration.tagletManager.getTaglet(ch.getTagName(holderTag));
|
Taglet taglet = config.tagletManager.getTaglet(ch.getTagName(holderTag));
|
||||||
// taglet is null if holderTag is unknown, which it shouldn't be since we reached here
|
// taglet is null if holderTag is unknown, which it shouldn't be since we reached here
|
||||||
assert taglet != null;
|
assert taglet != null;
|
||||||
if (!(taglet instanceof InheritableTaglet inheritableTaglet)) {
|
if (!(taglet instanceof InheritableTaglet inheritableTaglet)) {
|
||||||
@ -151,7 +148,7 @@ public class InheritDocTaglet extends BaseTaglet {
|
|||||||
return replacement;
|
return replacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
InheritableTaglet.Output inheritedDoc = inheritableTaglet.inherit(method, src, holderTag, isFirstSentence, configuration);
|
InheritableTaglet.Output inheritedDoc = inheritableTaglet.inherit(method, src, holderTag, isFirstSentence);
|
||||||
|
|
||||||
if (inheritedDoc.isValidInheritDocTag()) {
|
if (inheritedDoc.isValidInheritDocTag()) {
|
||||||
if (!inheritedDoc.inlineTags().isEmpty()) {
|
if (!inheritedDoc.inlineTags().isEmpty()) {
|
||||||
@ -182,6 +179,9 @@ public class InheritDocTaglet extends BaseTaglet {
|
|||||||
if (e.getKind() != ElementKind.METHOD) {
|
if (e.getKind() != ElementKind.METHOD) {
|
||||||
return tagletWriter.getOutputInstance();
|
return tagletWriter.getOutputInstance();
|
||||||
}
|
}
|
||||||
return retrieveInheritedDocumentation(tagletWriter, (ExecutableElement) e, (InheritDocTree) inheritDoc, tagletWriter.isFirstSentence);
|
return retrieveInheritedDocumentation(tagletWriter,
|
||||||
|
(ExecutableElement) e,
|
||||||
|
(InheritDocTree) inheritDoc,
|
||||||
|
tagletWriter.context.isFirstSentence);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -31,13 +31,12 @@ import java.util.List;
|
|||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A taglet should implement this interface if it supports an {@code {@inheritDoc}}
|
* A taglet should implement this interface if it supports an {@code {@inheritDoc}}
|
||||||
* tag or is automatically inherited if it is missing.
|
* tag or is automatically inherited if it is missing.
|
||||||
*/
|
*/
|
||||||
public interface InheritableTaglet extends Taglet {
|
public interface InheritableTaglet {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called by InheritDocTaglet on an inheritable taglet to expand {@inheritDoc S}
|
* Called by InheritDocTaglet on an inheritable taglet to expand {@inheritDoc S}
|
||||||
@ -52,7 +51,7 @@ public interface InheritableTaglet extends Taglet {
|
|||||||
* In the future, this could be reworked using some other mechanism,
|
* In the future, this could be reworked using some other mechanism,
|
||||||
* such as throwing an exception.
|
* such as throwing an exception.
|
||||||
*/
|
*/
|
||||||
Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence, BaseConfiguration configuration);
|
Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence);
|
||||||
|
|
||||||
record Output(DocTree holderTag,
|
record Output(DocTree holderTag,
|
||||||
Element holder,
|
Element holder,
|
@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2003, 2023, 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.lang.model.element.ModuleElement;
|
||||||
|
import javax.lang.model.element.PackageElement;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
|
import com.sun.source.doctree.DocTree;
|
||||||
|
import com.sun.source.doctree.LinkTree;
|
||||||
|
import com.sun.source.util.DocTreePath;
|
||||||
|
|
||||||
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.ClassWriterImpl;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
|
||||||
|
|
||||||
|
import static com.sun.source.doctree.DocTree.Kind.LINK;
|
||||||
|
import static com.sun.source.doctree.DocTree.Kind.LINK_PLAIN;
|
||||||
|
import static com.sun.source.doctree.DocTree.Kind.SEE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taglet that represents the {@code {@link ...}} and {@linkplain ...} tags,
|
||||||
|
* with support for links to program elements in {@code @see} and
|
||||||
|
* {@code {@snippet ...}} tags.
|
||||||
|
*/
|
||||||
|
public class LinkTaglet extends BaseTaglet {
|
||||||
|
LinkTaglet(HtmlConfiguration config, DocTree.Kind tagKind) {
|
||||||
|
super(config, tagKind, true, EnumSet.allOf(Taglet.Location.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter tagletWriter) {
|
||||||
|
this.tagletWriter = tagletWriter;
|
||||||
|
var linkTree = (LinkTree) tag;
|
||||||
|
var ch = utils.getCommentHelper(element);
|
||||||
|
var context = tagletWriter.context;
|
||||||
|
var htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
|
||||||
|
var inTags = context.inTags;
|
||||||
|
if (inTags.contains(LINK) || inTags.contains(LINK_PLAIN) || inTags.contains(SEE)) {
|
||||||
|
DocTreePath dtp = ch.getDocTreePath(linkTree);
|
||||||
|
if (dtp != null) {
|
||||||
|
messages.warning(dtp, "doclet.see.nested_link", "{@" + linkTree.getTagName() + "}");
|
||||||
|
}
|
||||||
|
Content label = htmlWriter.commentTagsToContent(element, linkTree.getLabel(), context.within(linkTree));
|
||||||
|
if (label.isEmpty()) {
|
||||||
|
label = Text.of(linkTree.getReference().getSignature());
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
var linkRef = linkTree.getReference();
|
||||||
|
if (linkRef == null) {
|
||||||
|
messages.warning(ch.getDocTreePath(tag), "doclet.link.no_reference");
|
||||||
|
return tagletWriter.invalidTagOutput(resources.getText("doclet.tag.invalid_input", tag.toString()),
|
||||||
|
Optional.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
DocTree.Kind kind = tag.getKind();
|
||||||
|
String refSignature = ch.getReferencedSignature(linkRef);
|
||||||
|
|
||||||
|
return linkSeeReferenceOutput(element,
|
||||||
|
tag,
|
||||||
|
refSignature,
|
||||||
|
ch.getReferencedElement(tag),
|
||||||
|
(kind == LINK_PLAIN),
|
||||||
|
htmlWriter.commentTagsToContent(element, linkTree.getLabel(), context.within(linkTree)),
|
||||||
|
(key, args) -> messages.warning(ch.getDocTreePath(tag), key, args),
|
||||||
|
tagletWriter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Worker method to generate a link from the information in different kinds of tags,
|
||||||
|
* such as {@code {@link ...}} tags, {@code @see ...} tags and the {@code link} markup tag
|
||||||
|
* in a {@code {@snippet ...}} tag.
|
||||||
|
*
|
||||||
|
* @param holder the element that has the documentation comment containing the information
|
||||||
|
* @param refTree the tree node containing the information, or {@code null} if not available
|
||||||
|
* @param refSignature the normalized signature of the target of the reference
|
||||||
|
* @param ref the target of the reference
|
||||||
|
* @param isLinkPlain {@code true} if the link should be presented in "plain" font,
|
||||||
|
* or {@code false} for "code" font
|
||||||
|
* @param label the label for the link,
|
||||||
|
* or an empty item to use a default label derived from the signature
|
||||||
|
* @param reportWarning a function to report warnings about issues found in the reference
|
||||||
|
* @param tagletWriter the writer providing the context for this call
|
||||||
|
*
|
||||||
|
* @return the output containing the generated link, or content indicating an error
|
||||||
|
*/
|
||||||
|
Content linkSeeReferenceOutput(Element holder,
|
||||||
|
DocTree refTree,
|
||||||
|
String refSignature,
|
||||||
|
Element ref,
|
||||||
|
boolean isLinkPlain,
|
||||||
|
Content label,
|
||||||
|
BiConsumer<String, Object[]> reportWarning,
|
||||||
|
TagletWriter tagletWriter) {
|
||||||
|
var config = tagletWriter.configuration;
|
||||||
|
var htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
|
||||||
|
Content labelContent = plainOrCode(isLinkPlain, label);
|
||||||
|
|
||||||
|
// The signature from the @see tag. We will output this text when a label is not specified.
|
||||||
|
Content text = plainOrCode(isLinkPlain,
|
||||||
|
Text.of(Objects.requireNonNullElse(refSignature, "")));
|
||||||
|
|
||||||
|
CommentHelper ch = utils.getCommentHelper(holder);
|
||||||
|
TypeElement refClass = ch.getReferencedClass(ref);
|
||||||
|
Element refMem = ch.getReferencedMember(ref);
|
||||||
|
String refFragment = ch.getReferencedFragment(refSignature);
|
||||||
|
|
||||||
|
if (refFragment == null && refMem != null) {
|
||||||
|
refFragment = refMem.toString();
|
||||||
|
} else if (refFragment != null && refFragment.startsWith("#")) {
|
||||||
|
if (labelContent.isEmpty()) {
|
||||||
|
// A non-empty label is required for fragment links as the
|
||||||
|
// reference target does not provide a useful default label.
|
||||||
|
htmlWriter.messages.error(ch.getDocTreePath(refTree), "doclet.link.see.no_label");
|
||||||
|
return tagletWriter.invalidTagOutput(resources.getText("doclet.link.see.no_label"),
|
||||||
|
Optional.of(refSignature));
|
||||||
|
}
|
||||||
|
refFragment = refFragment.substring(1);
|
||||||
|
}
|
||||||
|
if (refClass == null) {
|
||||||
|
ModuleElement refModule = ch.getReferencedModule(ref);
|
||||||
|
if (refModule != null && utils.isIncluded(refModule)) {
|
||||||
|
return htmlWriter.getModuleLink(refModule, labelContent.isEmpty() ? text : labelContent, refFragment);
|
||||||
|
}
|
||||||
|
//@see is not referencing an included class
|
||||||
|
PackageElement refPackage = ch.getReferencedPackage(ref);
|
||||||
|
if (refPackage != null && utils.isIncluded(refPackage)) {
|
||||||
|
//@see is referencing an included package
|
||||||
|
if (labelContent.isEmpty()) {
|
||||||
|
labelContent = plainOrCode(isLinkPlain,
|
||||||
|
Text.of(refPackage.getQualifiedName()));
|
||||||
|
}
|
||||||
|
return htmlWriter.getPackageLink(refPackage, labelContent, refFragment);
|
||||||
|
} else {
|
||||||
|
// @see is not referencing an included class, module or package. Check for cross-links.
|
||||||
|
String refModuleName = ch.getReferencedModuleName(refSignature);
|
||||||
|
DocLink elementCrossLink = (refPackage != null) ? htmlWriter.getCrossPackageLink(refPackage) :
|
||||||
|
(config.extern.isModule(refModuleName))
|
||||||
|
? htmlWriter.getCrossModuleLink(utils.elementUtils.getModuleElement(refModuleName))
|
||||||
|
: null;
|
||||||
|
if (elementCrossLink != null) {
|
||||||
|
// Element cross-link found
|
||||||
|
return htmlWriter.links.createExternalLink(elementCrossLink,
|
||||||
|
(labelContent.isEmpty() ? text : labelContent));
|
||||||
|
} else {
|
||||||
|
// No cross-link found so print warning
|
||||||
|
if (!config.isDocLintReferenceGroupEnabled()) {
|
||||||
|
reportWarning.accept(
|
||||||
|
"doclet.link.see.reference_not_found",
|
||||||
|
new Object[] { refSignature});
|
||||||
|
}
|
||||||
|
return htmlWriter.invalidTagOutput(resources.getText("doclet.link.see.reference_invalid"),
|
||||||
|
Optional.of(labelContent.isEmpty() ? text: labelContent));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (refFragment == null) {
|
||||||
|
// Must be a class reference since refClass is not null and refFragment is null.
|
||||||
|
if (labelContent.isEmpty() && refTree != null) {
|
||||||
|
TypeMirror referencedType = ch.getReferencedType(refTree);
|
||||||
|
if (utils.isGenericType(referencedType)) {
|
||||||
|
// This is a generic type link, use the TypeMirror representation.
|
||||||
|
return plainOrCode(isLinkPlain, htmlWriter.getLink(
|
||||||
|
new HtmlLinkInfo(config, HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS, referencedType)));
|
||||||
|
}
|
||||||
|
labelContent = plainOrCode(isLinkPlain, Text.of(utils.getSimpleName(refClass)));
|
||||||
|
}
|
||||||
|
return htmlWriter.getLink(new HtmlLinkInfo(config, HtmlLinkInfo.Kind.PLAIN, refClass)
|
||||||
|
.label(labelContent));
|
||||||
|
} else if (refMem == null) {
|
||||||
|
// This is a fragment reference since refClass and refFragment are not null but refMem is null.
|
||||||
|
return htmlWriter.getLink(new HtmlLinkInfo(config, HtmlLinkInfo.Kind.PLAIN, refClass)
|
||||||
|
.label(labelContent)
|
||||||
|
.fragment(refFragment)
|
||||||
|
.style(null));
|
||||||
|
} else {
|
||||||
|
// Must be a member reference since refClass is not null and refMemName is not null.
|
||||||
|
// refMem is not null, so this @see tag must be referencing a valid member.
|
||||||
|
TypeElement containing = utils.getEnclosingTypeElement(refMem);
|
||||||
|
|
||||||
|
// Find the enclosing type where the method is actually visible
|
||||||
|
// in the inheritance hierarchy.
|
||||||
|
ExecutableElement overriddenMethod = null;
|
||||||
|
if (refMem.getKind() == ElementKind.METHOD) {
|
||||||
|
VisibleMemberTable vmt = config.getVisibleMemberTable(containing);
|
||||||
|
overriddenMethod = vmt.getOverriddenMethod((ExecutableElement)refMem);
|
||||||
|
|
||||||
|
if (overriddenMethod != null) {
|
||||||
|
containing = utils.getEnclosingTypeElement(overriddenMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (refSignature.trim().startsWith("#") &&
|
||||||
|
! (utils.isPublic(containing) || utils.isLinkable(containing))) {
|
||||||
|
// Since the link is relative and the holder is not even being
|
||||||
|
// documented, this must be an inherited link. Redirect it.
|
||||||
|
// The current class either overrides the referenced member or
|
||||||
|
// inherits it automatically.
|
||||||
|
if (htmlWriter instanceof ClassWriterImpl cw) {
|
||||||
|
containing = cw.getTypeElement();
|
||||||
|
} else if (!utils.isPublic(containing)) {
|
||||||
|
reportWarning.accept("doclet.link.see.reference_not_accessible",
|
||||||
|
new Object[] { utils.getFullyQualifiedName(containing)});
|
||||||
|
} else {
|
||||||
|
if (!config.isDocLintReferenceGroupEnabled()) {
|
||||||
|
reportWarning.accept("doclet.link.see.reference_not_found",
|
||||||
|
new Object[] { refSignature });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String refMemName = refFragment;
|
||||||
|
if (config.currentTypeElement != containing) {
|
||||||
|
refMemName = (utils.isConstructor(refMem))
|
||||||
|
? refMemName
|
||||||
|
: utils.getSimpleName(containing) + "." + refMemName;
|
||||||
|
}
|
||||||
|
if (utils.isExecutableElement(refMem)) {
|
||||||
|
if (refMemName.indexOf('(') < 0) {
|
||||||
|
refMemName += utils.makeSignature((ExecutableElement) refMem, null, true);
|
||||||
|
}
|
||||||
|
if (overriddenMethod != null) {
|
||||||
|
// The method to actually link.
|
||||||
|
refMem = overriddenMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return htmlWriter.getDocLink(HtmlLinkInfo.Kind.SHOW_PREVIEW, containing,
|
||||||
|
refMem, (labelContent.isEmpty()
|
||||||
|
? plainOrCode(isLinkPlain, Text.of(refMemName))
|
||||||
|
: labelContent), null, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Content plainOrCode(boolean plain, Content body) {
|
||||||
|
return (plain || body.isEmpty()) ? body : HtmlTree.CODE(body);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
||||||
@ -31,29 +31,38 @@ import javax.lang.model.element.Element;
|
|||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import com.sun.source.doctree.LiteralTree;
|
import com.sun.source.doctree.LiteralTree;
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An inline taglet used to denote literal code fragments.
|
* An inline taglet used to denote literal text, possibly in monospace font.
|
||||||
* The enclosed text is interpreted as not containing HTML markup or
|
*
|
||||||
* nested javadoc tags, and is rendered in a font suitable for code.
|
* For example, the text:
|
||||||
|
* <blockquote> {@code {@literal a<B>c}} </blockquote>
|
||||||
|
* displays as:
|
||||||
|
* <blockquote> {@literal a<B>c} </blockquote>
|
||||||
*
|
*
|
||||||
* <p> The tag {@code {@code ...}} is equivalent to
|
* <p> The tag {@code {@code ...}} is equivalent to
|
||||||
* {@code <code>{@literal ...}</code>}.
|
* {@code <code>{@literal ...}</code>}.
|
||||||
|
*
|
||||||
* For example, the text:
|
* For example, the text:
|
||||||
* <blockquote> The type {@code {@code List<P>}} </blockquote>
|
* <blockquote> The type {@code {@code List<P>}} </blockquote>
|
||||||
* displays as:
|
* displays as:
|
||||||
* <blockquote> The type {@code List<P>} </blockquote>
|
* <blockquote> The type {@code List<P>} </blockquote>
|
||||||
*/
|
*/
|
||||||
public class CodeTaglet extends BaseTaglet {
|
public class LiteralTaglet extends BaseTaglet {
|
||||||
|
LiteralTaglet(HtmlConfiguration config, DocTree.Kind tagKind) {
|
||||||
CodeTaglet() {
|
super(config, tagKind, true, EnumSet.allOf(Taglet.Location.class));
|
||||||
super(DocTree.Kind.CODE, true, EnumSet.allOf(Location.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter writer) {
|
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter tagletWriter) {
|
||||||
return writer.codeTagOutput(element, (LiteralTree) tag);
|
var literalTree = (LiteralTree) tag;
|
||||||
|
var body = Text.of(Text.normalizeNewlines(literalTree.getBody().getBody()));
|
||||||
|
return tag.getKind() == DocTree.Kind.CODE ? HtmlTree.CODE(body) : body;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,9 +23,13 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.ElementKind;
|
import javax.lang.model.element.ElementKind;
|
||||||
@ -34,19 +38,24 @@ import javax.lang.model.element.TypeElement;
|
|||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import com.sun.source.doctree.ParamTree;
|
import com.sun.source.doctree.ParamTree;
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.Contents;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlIds;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A taglet that represents the {@code @param} tag.
|
* A taglet that represents the {@code @param} tag.
|
||||||
*/
|
*/
|
||||||
public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
||||||
|
|
||||||
public enum ParamKind {
|
public enum ParamKind {
|
||||||
/** Parameter of an executable element. */
|
/** Parameter of an executable element. */
|
||||||
PARAMETER,
|
PARAMETER,
|
||||||
@ -56,15 +65,15 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
TYPE_PARAMETER
|
TYPE_PARAMETER
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private final Contents contents;
|
||||||
* Construct a ParamTaglet.
|
|
||||||
*/
|
ParamTaglet(HtmlConfiguration config) {
|
||||||
public ParamTaglet() {
|
super(config, DocTree.Kind.PARAM, false, EnumSet.of(Taglet.Location.TYPE, Taglet.Location.CONSTRUCTOR, Taglet.Location.METHOD));
|
||||||
super(DocTree.Kind.PARAM, false, EnumSet.of(Location.TYPE, Location.CONSTRUCTOR, Location.METHOD));
|
contents = config.contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence, BaseConfiguration configuration) {
|
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence) {
|
||||||
assert dst.getKind() == ElementKind.METHOD;
|
assert dst.getKind() == ElementKind.METHOD;
|
||||||
assert tag.getKind() == DocTree.Kind.PARAM;
|
assert tag.getKind() == DocTree.Kind.PARAM;
|
||||||
var method = (ExecutableElement) dst;
|
var method = (ExecutableElement) dst;
|
||||||
@ -76,24 +85,24 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
} else {
|
} else {
|
||||||
parameterElements = method.getParameters();
|
parameterElements = method.getParameters();
|
||||||
}
|
}
|
||||||
Map<String, Integer> stringIntegerMap = mapNameToPosition(configuration.utils, parameterElements);
|
Map<String, Integer> stringIntegerMap = mapNameToPosition(utils, parameterElements);
|
||||||
CommentHelper ch = configuration.utils.getCommentHelper(dst);
|
CommentHelper ch = utils.getCommentHelper(dst);
|
||||||
Integer position = stringIntegerMap.get(ch.getParameterName(param));
|
Integer position = stringIntegerMap.get(ch.getParameterName(param));
|
||||||
if (position == null) {
|
if (position == null) {
|
||||||
return new Output(null, null, List.of(), true);
|
return new Output(null, null, List.of(), true);
|
||||||
}
|
}
|
||||||
// try to inherit description of the respective parameter in an overridden method
|
// try to inherit description of the respective parameter in an overridden method
|
||||||
try {
|
try {
|
||||||
var docFinder = configuration.utils.docFinder();
|
var docFinder = utils.docFinder();
|
||||||
|
|
||||||
Optional<Documentation> r;
|
Optional<Documentation> r;
|
||||||
if (src != null){
|
if (src != null){
|
||||||
r = docFinder.search((ExecutableElement) src,
|
r = docFinder.search((ExecutableElement) src,
|
||||||
m -> Result.fromOptional(extract(configuration.utils, m, position, param.isTypeParameter())))
|
m -> DocFinder.Result.fromOptional(extract(utils, m, position, param.isTypeParameter())))
|
||||||
.toOptional();
|
.toOptional();
|
||||||
} else {
|
} else {
|
||||||
r = docFinder.find((ExecutableElement) dst,
|
r = docFinder.find((ExecutableElement) dst,
|
||||||
m -> Result.fromOptional(extract(configuration.utils, m, position, param.isTypeParameter())))
|
m -> DocFinder.Result.fromOptional(extract(utils, m, position, param.isTypeParameter())))
|
||||||
.toOptional();
|
.toOptional();
|
||||||
}
|
}
|
||||||
return r.map(result -> new Output(result.paramTree, result.method, result.paramTree.getDescription(), true))
|
return r.map(result -> new Output(result.paramTree, result.method, result.paramTree.getDescription(), true))
|
||||||
@ -122,21 +131,21 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
|
public Content getAllBlockTagOutput(Element holder, TagletWriter tagletWriter) {
|
||||||
Utils utils = writer.configuration().utils;
|
this.tagletWriter = tagletWriter;
|
||||||
if (utils.isExecutableElement(holder)) {
|
if (utils.isExecutableElement(holder)) {
|
||||||
ExecutableElement member = (ExecutableElement) holder;
|
ExecutableElement member = (ExecutableElement) holder;
|
||||||
Content output = convertParams(member, ParamKind.TYPE_PARAMETER,
|
Content output = convertParams(member, ParamKind.TYPE_PARAMETER,
|
||||||
utils.getTypeParamTrees(member), member.getTypeParameters(), writer);
|
utils.getTypeParamTrees(member), member.getTypeParameters(), tagletWriter);
|
||||||
output.add(convertParams(member, ParamKind.PARAMETER,
|
output.add(convertParams(member, ParamKind.PARAMETER,
|
||||||
utils.getParamTrees(member), member.getParameters(), writer));
|
utils.getParamTrees(member), member.getParameters(), tagletWriter));
|
||||||
return output;
|
return output;
|
||||||
} else {
|
} else {
|
||||||
TypeElement typeElement = (TypeElement) holder;
|
TypeElement typeElement = (TypeElement) holder;
|
||||||
Content output = convertParams(typeElement, ParamKind.TYPE_PARAMETER,
|
Content output = convertParams(typeElement, ParamKind.TYPE_PARAMETER,
|
||||||
utils.getTypeParamTrees(typeElement), typeElement.getTypeParameters(), writer);
|
utils.getTypeParamTrees(typeElement), typeElement.getTypeParameters(), tagletWriter);
|
||||||
output.add(convertParams(typeElement, ParamKind.RECORD_COMPONENT,
|
output.add(convertParams(typeElement, ParamKind.RECORD_COMPONENT,
|
||||||
utils.getParamTrees(typeElement), typeElement.getRecordComponents(), writer));
|
utils.getParamTrees(typeElement), typeElement.getRecordComponents(), tagletWriter));
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,10 +172,9 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
List<? extends Element> parameters,
|
List<? extends Element> parameters,
|
||||||
TagletWriter writer) {
|
TagletWriter writer) {
|
||||||
Map<Integer, ParamTree> tagOfPosition = new HashMap<>();
|
Map<Integer, ParamTree> tagOfPosition = new HashMap<>();
|
||||||
Messages messages = writer.configuration().getMessages();
|
CommentHelper ch = utils.getCommentHelper(e);
|
||||||
CommentHelper ch = writer.configuration().utils.getCommentHelper(e);
|
|
||||||
if (!tags.isEmpty()) {
|
if (!tags.isEmpty()) {
|
||||||
Map<String, Integer> positionOfName = mapNameToPosition(writer.configuration().utils, parameters);
|
Map<String, Integer> positionOfName = mapNameToPosition(utils, parameters);
|
||||||
for (ParamTree tag : tags) {
|
for (ParamTree tag : tags) {
|
||||||
String name = ch.getParameterName(tag);
|
String name = ch.getParameterName(tag);
|
||||||
String paramName = kind == ParamKind.TYPE_PARAMETER ? "<" + name + ">" : name;
|
String paramName = kind == ParamKind.TYPE_PARAMETER ? "<" + name + ">" : name;
|
||||||
@ -176,7 +184,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
case TYPE_PARAMETER -> "doclet.TypeParameters_warn";
|
case TYPE_PARAMETER -> "doclet.TypeParameters_warn";
|
||||||
case RECORD_COMPONENT -> "doclet.RecordComponents_warn";
|
case RECORD_COMPONENT -> "doclet.RecordComponents_warn";
|
||||||
};
|
};
|
||||||
if (!writer.configuration().isDocLintReferenceGroupEnabled()) {
|
if (!config.isDocLintReferenceGroupEnabled()) {
|
||||||
messages.warning(ch.getDocTreePath(tag), key, paramName);
|
messages.warning(ch.getDocTreePath(tag), key, paramName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,7 +196,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
case TYPE_PARAMETER -> "doclet.TypeParameters_dup_warn";
|
case TYPE_PARAMETER -> "doclet.TypeParameters_dup_warn";
|
||||||
case RECORD_COMPONENT -> "doclet.RecordComponents_dup_warn";
|
case RECORD_COMPONENT -> "doclet.RecordComponents_dup_warn";
|
||||||
};
|
};
|
||||||
if (!writer.configuration().isDocLintReferenceGroupEnabled()) {
|
if (!config.isDocLintReferenceGroupEnabled()) {
|
||||||
messages.warning(ch.getDocTreePath(tag), key, paramName);
|
messages.warning(ch.getDocTreePath(tag), key, paramName);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -205,7 +213,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
if (tag != null) {
|
if (tag != null) {
|
||||||
result.add(convertParam(e, kind, writer, tag,
|
result.add(convertParam(e, kind, writer, tag,
|
||||||
ch.getParameterName(tag), result.isEmpty()));
|
ch.getParameterName(tag), result.isEmpty()));
|
||||||
} else if (writer.configuration().utils.isMethod(e)) {
|
} else if (utils.isMethod(e)) {
|
||||||
result.add(getInheritedTagletOutput(kind, e, writer,
|
result.add(getInheritedTagletOutput(kind, e, writer,
|
||||||
parameters.get(i), i, result.isEmpty()));
|
parameters.get(i), i, result.isEmpty()));
|
||||||
}
|
}
|
||||||
@ -233,10 +241,9 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
Element param,
|
Element param,
|
||||||
int position,
|
int position,
|
||||||
boolean isFirst) {
|
boolean isFirst) {
|
||||||
Utils utils = writer.configuration().utils;
|
|
||||||
Content result = writer.getOutputInstance();
|
Content result = writer.getOutputInstance();
|
||||||
var r = utils.docFinder().search((ExecutableElement) holder,
|
var r = utils.docFinder().search((ExecutableElement) holder,
|
||||||
m -> Result.fromOptional(extract(utils, m, position, kind == ParamKind.TYPE_PARAMETER)))
|
m -> DocFinder.Result.fromOptional(extract(utils, m, position, kind == ParamTaglet.ParamKind.TYPE_PARAMETER)))
|
||||||
.toOptional();
|
.toOptional();
|
||||||
if (r.isPresent()) {
|
if (r.isPresent()) {
|
||||||
String name = kind != ParamKind.TYPE_PARAMETER
|
String name = kind != ParamKind.TYPE_PARAMETER
|
||||||
@ -249,6 +256,31 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Content getParamHeader(ParamKind kind) {
|
||||||
|
var header = switch (kind) {
|
||||||
|
case PARAMETER -> contents.parameters;
|
||||||
|
case TYPE_PARAMETER -> contents.typeParameters;
|
||||||
|
case RECORD_COMPONENT -> contents.recordComponents;
|
||||||
|
};
|
||||||
|
return HtmlTree.DT(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Content paramTagOutput(Element element, ParamTree paramTag, String paramName) {
|
||||||
|
var context = tagletWriter.context;
|
||||||
|
var htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
var body = new ContentBuilder();
|
||||||
|
CommentHelper ch = utils.getCommentHelper(element);
|
||||||
|
// define id attributes for state components so that generated descriptions may refer to them
|
||||||
|
boolean defineID = (element.getKind() == ElementKind.RECORD)
|
||||||
|
&& !paramTag.isTypeParameter();
|
||||||
|
Content nameContent = Text.of(paramName);
|
||||||
|
body.add(HtmlTree.CODE(defineID ? HtmlTree.SPAN_ID(HtmlIds.forParam(paramName), nameContent) : nameContent));
|
||||||
|
body.add(" - ");
|
||||||
|
List<? extends DocTree> description = ch.getDescription(paramTag);
|
||||||
|
body.add(htmlWriter.commentTagsToContent(element, description, context.within(paramTag)));
|
||||||
|
return HtmlTree.DD(body);
|
||||||
|
}
|
||||||
|
|
||||||
private record Documentation(ParamTree paramTree, ExecutableElement method) { }
|
private record Documentation(ParamTree paramTree, ExecutableElement method) { }
|
||||||
|
|
||||||
private static Optional<Documentation> extract(Utils utils, ExecutableElement method, Integer position, boolean typeParam) {
|
private static Optional<Documentation> extract(Utils utils, ExecutableElement method, Integer position, boolean typeParam) {
|
||||||
@ -276,9 +308,9 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
boolean isFirstParam) {
|
boolean isFirstParam) {
|
||||||
Content result = writer.getOutputInstance();
|
Content result = writer.getOutputInstance();
|
||||||
if (isFirstParam) {
|
if (isFirstParam) {
|
||||||
result.add(writer.getParamHeader(kind));
|
result.add(getParamHeader(kind));
|
||||||
}
|
}
|
||||||
result.add(writer.paramTagOutput(e, paramTag, name));
|
result.add(paramTagOutput(e, paramTag, name));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -37,21 +37,25 @@ import javax.lang.model.type.TypeMirror;
|
|||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import com.sun.source.doctree.ReturnTree;
|
import com.sun.source.doctree.ReturnTree;
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.Contents;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A taglet that represents the {@code @return} and {@code {@return }} tags.
|
* A taglet that represents the {@code @return} and {@code {@return }} tags.
|
||||||
*/
|
*/
|
||||||
public class ReturnTaglet extends BaseTaglet implements InheritableTaglet {
|
public class ReturnTaglet extends BaseTaglet implements InheritableTaglet {
|
||||||
|
private final Contents contents;
|
||||||
|
|
||||||
public ReturnTaglet() {
|
ReturnTaglet(HtmlConfiguration config) {
|
||||||
super(DocTree.Kind.RETURN, true, EnumSet.of(Location.METHOD));
|
super(config, DocTree.Kind.RETURN, true, EnumSet.of(Taglet.Location.METHOD));
|
||||||
|
contents = config.contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -60,14 +64,14 @@ public class ReturnTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence, BaseConfiguration configuration) {
|
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence) {
|
||||||
try {
|
try {
|
||||||
var docFinder = configuration.utils.docFinder();
|
var docFinder = utils.docFinder();
|
||||||
Optional<Documentation> r;
|
Optional<Documentation> r;
|
||||||
if (src == null) {
|
if (src == null) {
|
||||||
r = docFinder.find((ExecutableElement) dst, m -> Result.fromOptional(extract(configuration.utils, m))).toOptional();
|
r = docFinder.find((ExecutableElement) dst, m -> DocFinder.Result.fromOptional(extract(utils, m))).toOptional();
|
||||||
} else {
|
} else {
|
||||||
r = docFinder.search((ExecutableElement) src, m -> Result.fromOptional(extract(configuration.utils, m))).toOptional();
|
r = docFinder.search((ExecutableElement) src, m -> DocFinder.Result.fromOptional(extract(utils, m))).toOptional();
|
||||||
}
|
}
|
||||||
return r.map(result -> new Output(result.returnTree, result.method, result.returnTree.getDescription(), true))
|
return r.map(result -> new Output(result.returnTree, result.method, result.returnTree.getDescription(), true))
|
||||||
.orElseGet(() -> new Output(null, null, List.of(), true));
|
.orElseGet(() -> new Output(null, null, List.of(), true));
|
||||||
@ -77,22 +81,22 @@ public class ReturnTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter writer) {
|
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter tagletWriter) {
|
||||||
return writer.returnTagOutput(element, (ReturnTree) tag, true);
|
this.tagletWriter = tagletWriter;
|
||||||
|
return returnTagOutput(element, (ReturnTree) tag, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
|
public Content getAllBlockTagOutput(Element holder, TagletWriter tagletWriter) {
|
||||||
assert holder.getKind() == ElementKind.METHOD : holder.getKind();
|
assert holder.getKind() == ElementKind.METHOD : holder.getKind();
|
||||||
var method = (ExecutableElement) holder;
|
var method = (ExecutableElement) holder;
|
||||||
Messages messages = writer.configuration().getMessages();
|
this.tagletWriter = tagletWriter;
|
||||||
Utils utils = writer.configuration().utils;
|
|
||||||
List<? extends ReturnTree> tags = utils.getReturnTrees(holder);
|
List<? extends ReturnTree> tags = utils.getReturnTrees(holder);
|
||||||
|
|
||||||
// make sure we are not using @return on a method with the void return type
|
// make sure we are not using @return on a method with the void return type
|
||||||
TypeMirror returnType = utils.getReturnType(writer.getCurrentPageElement(), method);
|
TypeMirror returnType = utils.getReturnType(tagletWriter.getCurrentPageElement(), method);
|
||||||
if (returnType != null && utils.isVoid(returnType)) {
|
if (returnType != null && utils.isVoid(returnType)) {
|
||||||
if (!tags.isEmpty() && !writer.configuration().isDocLintReferenceGroupEnabled()) {
|
if (!tags.isEmpty() && !config.isDocLintReferenceGroupEnabled()) {
|
||||||
messages.warning(holder, "doclet.Return_tag_on_void_method");
|
messages.warning(holder, "doclet.Return_tag_on_void_method");
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -103,11 +107,31 @@ public class ReturnTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
// above for a case where @return is used for void
|
// above for a case where @return is used for void
|
||||||
|
|
||||||
var docFinder = utils.docFinder();
|
var docFinder = utils.docFinder();
|
||||||
return docFinder.search(method, m -> Result.fromOptional(extract(utils, m))).toOptional()
|
return docFinder.search(method, m -> DocFinder.Result.fromOptional(extract(utils, m))).toOptional()
|
||||||
.map(r -> writer.returnTagOutput(r.method, r.returnTree, false))
|
.map(r -> returnTagOutput(r.method, r.returnTree, false))
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output for a {@code @return} tag.
|
||||||
|
*
|
||||||
|
* @param element the element that owns the doc comment
|
||||||
|
* @param returnTag the return tag to document
|
||||||
|
* @param inline whether this should be written as an inline instance or block instance
|
||||||
|
*
|
||||||
|
* @return the output
|
||||||
|
*/
|
||||||
|
public Content returnTagOutput(Element element, ReturnTree returnTag, boolean inline) {
|
||||||
|
var context = tagletWriter.context;
|
||||||
|
var htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
var ch = utils.getCommentHelper(element);
|
||||||
|
List<? extends DocTree> desc = ch.getDescription(returnTag);
|
||||||
|
Content content = htmlWriter.commentTagsToContent(element, desc, context.within(returnTag));
|
||||||
|
return inline
|
||||||
|
? new ContentBuilder(contents.getContent("doclet.Returns_0", content))
|
||||||
|
: new ContentBuilder(HtmlTree.DT(contents.returns), HtmlTree.DD(content));
|
||||||
|
}
|
||||||
|
|
||||||
private record Documentation(ReturnTree returnTree, ExecutableElement method) { }
|
private record Documentation(ReturnTree returnTree, ExecutableElement method) { }
|
||||||
|
|
||||||
private static Optional<Documentation> extract(Utils utils, ExecutableElement method) {
|
private static Optional<Documentation> extract(Utils utils, ExecutableElement method) {
|
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2001, 2023, 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.element.VariableElement;
|
||||||
|
|
||||||
|
import com.sun.source.doctree.DocTree;
|
||||||
|
import com.sun.source.doctree.SeeTree;
|
||||||
|
|
||||||
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.ClassWriterImpl;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.Contents;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlDocletWriter;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||||
|
|
||||||
|
public class SeeTaglet extends BaseTaglet implements InheritableTaglet {
|
||||||
|
SeeTaglet(HtmlConfiguration config) {
|
||||||
|
super(config, DocTree.Kind.SEE, false, EnumSet.allOf(Taglet.Location.class));
|
||||||
|
contents = config.contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Contents contents;
|
||||||
|
private HtmlDocletWriter htmlWriter;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence) {
|
||||||
|
CommentHelper ch = utils.getCommentHelper(dst);
|
||||||
|
var path = ch.getDocTreePath(tag);
|
||||||
|
messages.warning(path, "doclet.inheritDocWithinInappropriateTag");
|
||||||
|
return new Output(null, null, List.of(), true /* true, otherwise there will be an exception up the stack */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Content getAllBlockTagOutput(Element holder, TagletWriter tagletWriter) {
|
||||||
|
this.tagletWriter = tagletWriter;
|
||||||
|
List<? extends SeeTree> tags = utils.getSeeTrees(holder);
|
||||||
|
Element e = holder;
|
||||||
|
if (utils.isMethod(holder)) {
|
||||||
|
var docFinder = utils.docFinder();
|
||||||
|
Optional<Documentation> result = docFinder.search((ExecutableElement) holder,
|
||||||
|
m -> DocFinder.Result.fromOptional(extract(utils, m))).toOptional();
|
||||||
|
if (result.isPresent()) {
|
||||||
|
ExecutableElement m = result.get().method();
|
||||||
|
tags = utils.getSeeTrees(m);
|
||||||
|
e = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return seeTagOutput(e, tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output for {@code @see} tags.
|
||||||
|
*
|
||||||
|
* @param holder The element that owns the doc comment
|
||||||
|
* @param seeTags the list of tags
|
||||||
|
*
|
||||||
|
* @return the output
|
||||||
|
*/
|
||||||
|
public Content seeTagOutput(Element holder, List<? extends SeeTree> seeTags) {
|
||||||
|
htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
|
||||||
|
List<Content> links = new ArrayList<>();
|
||||||
|
for (SeeTree dt : seeTags) {
|
||||||
|
links.add(seeTagOutput(holder, dt));
|
||||||
|
}
|
||||||
|
if (utils.isVariableElement(holder) && ((VariableElement)holder).getConstantValue() != null &&
|
||||||
|
htmlWriter instanceof ClassWriterImpl classWriter) {
|
||||||
|
//Automatically add link to constant values page for constant fields.
|
||||||
|
DocPath constantsPath =
|
||||||
|
htmlWriter.pathToRoot.resolve(DocPaths.CONSTANT_VALUES);
|
||||||
|
String whichConstant =
|
||||||
|
classWriter.getTypeElement().getQualifiedName() + "." +
|
||||||
|
utils.getSimpleName(holder);
|
||||||
|
DocLink link = constantsPath.fragment(whichConstant);
|
||||||
|
links.add(htmlWriter.links.createLink(link,
|
||||||
|
contents.getContent("doclet.Constants_Summary")));
|
||||||
|
}
|
||||||
|
if (utils.isClass(holder) && utils.isSerializable((TypeElement)holder)) {
|
||||||
|
//Automatically add link to serialized form page for serializable classes.
|
||||||
|
if (SerializedFormBuilder.serialInclude(utils, holder) &&
|
||||||
|
SerializedFormBuilder.serialInclude(utils, utils.containingPackage(holder))) {
|
||||||
|
DocPath serialPath = htmlWriter.pathToRoot.resolve(DocPaths.SERIALIZED_FORM);
|
||||||
|
DocLink link = serialPath.fragment(utils.getFullyQualifiedName(holder));
|
||||||
|
links.add(htmlWriter.links.createLink(link,
|
||||||
|
contents.getContent("doclet.Serialized_Form")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (links.isEmpty()) {
|
||||||
|
return Text.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
var seeList = tagletWriter.tagList(links);
|
||||||
|
return new ContentBuilder(
|
||||||
|
HtmlTree.DT(contents.seeAlso),
|
||||||
|
HtmlTree.DD(seeList));
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Documentation(List<? extends SeeTree> seeTrees, ExecutableElement method) { }
|
||||||
|
|
||||||
|
private static Optional<Documentation> extract(Utils utils, ExecutableElement method) {
|
||||||
|
List<? extends SeeTree> tags = utils.getSeeTrees(method);
|
||||||
|
return tags.isEmpty() ? Optional.empty() : Optional.of(new Documentation(tags, method));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@return the output for a single {@code @see} tag}
|
||||||
|
*
|
||||||
|
* @param element the element that has the documentation comment containing this tag
|
||||||
|
* @param seeTag the tag
|
||||||
|
*/
|
||||||
|
private Content seeTagOutput(Element element, SeeTree seeTag) {
|
||||||
|
|
||||||
|
List<? extends DocTree> ref = seeTag.getReference();
|
||||||
|
assert !ref.isEmpty();
|
||||||
|
DocTree ref0 = ref.get(0);
|
||||||
|
switch (ref0.getKind()) {
|
||||||
|
case TEXT, START_ELEMENT -> {
|
||||||
|
// @see "Reference"
|
||||||
|
// @see <a href="...">...</a>
|
||||||
|
return htmlWriter.commentTagsToContent(element, ref, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
case REFERENCE -> {
|
||||||
|
// @see reference label...
|
||||||
|
CommentHelper ch = utils.getCommentHelper(element);
|
||||||
|
String refSignature = ch.getReferencedSignature(ref0);
|
||||||
|
List<? extends DocTree> label = ref.subList(1, ref.size());
|
||||||
|
|
||||||
|
var lt = (LinkTaglet) config.tagletManager.getTaglet(DocTree.Kind.LINK);
|
||||||
|
return lt.linkSeeReferenceOutput(element,
|
||||||
|
seeTag,
|
||||||
|
refSignature,
|
||||||
|
ch.getReferencedElement(seeTag),
|
||||||
|
false,
|
||||||
|
htmlWriter.commentTagsToContent(element, label, tagletWriter.getContext().within(seeTag)),
|
||||||
|
(key, args) -> messages.warning(ch.getDocTreePath(seeTag), key, args),
|
||||||
|
tagletWriter
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
case ERRONEOUS -> {
|
||||||
|
return tagletWriter.invalidTagOutput(resources.getText("doclet.tag.invalid_input",
|
||||||
|
ref0.toString()),
|
||||||
|
Optional.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
default -> throw new IllegalStateException(ref0.getKind().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -34,14 +34,17 @@ import javax.lang.model.element.Element;
|
|||||||
import javax.lang.model.element.ElementKind;
|
import javax.lang.model.element.ElementKind;
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
|
||||||
|
import com.sun.source.doctree.BlockTagTree;
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
import com.sun.source.doctree.UnknownBlockTagTree;
|
||||||
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom single-argument block tag.
|
* A custom single-argument block tag.
|
||||||
@ -51,15 +54,9 @@ public class SimpleTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
/**
|
/**
|
||||||
* The header to output.
|
* The header to output.
|
||||||
*/
|
*/
|
||||||
protected String header;
|
private final String header;
|
||||||
|
|
||||||
/**
|
private final boolean enabled;
|
||||||
* Whether or not the taglet should generate output.
|
|
||||||
* Standard tags like {@code @author}, {@code @since}, {@code @version} can
|
|
||||||
* be disabled by command-line options; custom tags created with -tag can be
|
|
||||||
* disabled with an X in the defining string.
|
|
||||||
*/
|
|
||||||
protected final boolean enabled;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a {@code SimpleTaglet}.
|
* Constructs a {@code SimpleTaglet}.
|
||||||
@ -72,8 +69,8 @@ public class SimpleTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
* See {@link #getLocations(String) getLocations} for the
|
* See {@link #getLocations(String) getLocations} for the
|
||||||
* complete list.
|
* complete list.
|
||||||
*/
|
*/
|
||||||
public SimpleTaglet(String tagName, String header, String locations) {
|
SimpleTaglet(HtmlConfiguration config, String tagName, String header, String locations) {
|
||||||
this(tagName, header, getLocations(locations), isEnabled(locations));
|
this(config, tagName, header, getLocations(locations), isEnabled(locations));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,8 +80,8 @@ public class SimpleTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
* @param header the header to output
|
* @param header the header to output
|
||||||
* @param locations the possible locations that this tag can appear in
|
* @param locations the possible locations that this tag can appear in
|
||||||
*/
|
*/
|
||||||
public SimpleTaglet(DocTree.Kind tagKind, String header, Set<Location> locations) {
|
SimpleTaglet(HtmlConfiguration config, DocTree.Kind tagKind, String header, Set<Taglet.Location> locations) {
|
||||||
this(tagKind, header, locations, true);
|
this(config, tagKind, header, locations, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,8 +91,8 @@ public class SimpleTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
* @param header the header to output
|
* @param header the header to output
|
||||||
* @param locations the possible locations that this tag can appear in
|
* @param locations the possible locations that this tag can appear in
|
||||||
*/
|
*/
|
||||||
public SimpleTaglet(String tagName, String header, Set<Location> locations) {
|
SimpleTaglet(HtmlConfiguration config, String tagName, String header, Set<Taglet.Location> locations) {
|
||||||
this(tagName, header, locations, true);
|
this(config, tagName, header, locations, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -105,8 +102,8 @@ public class SimpleTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
* @param header the header to output
|
* @param header the header to output
|
||||||
* @param locations the possible locations that this tag can appear in
|
* @param locations the possible locations that this tag can appear in
|
||||||
*/
|
*/
|
||||||
public SimpleTaglet(String tagName, String header, Set<Location> locations, boolean enabled) {
|
private SimpleTaglet(HtmlConfiguration config, String tagName, String header, Set<Taglet.Location> locations, boolean enabled) {
|
||||||
super(tagName, false, locations);
|
super(config, tagName, false, locations);
|
||||||
this.header = header;
|
this.header = header;
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
}
|
}
|
||||||
@ -118,38 +115,136 @@ public class SimpleTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
* @param header the header to output
|
* @param header the header to output
|
||||||
* @param locations the possible locations that this tag can appear in
|
* @param locations the possible locations that this tag can appear in
|
||||||
*/
|
*/
|
||||||
public SimpleTaglet(DocTree.Kind tagKind, String header, Set<Location> locations, boolean enabled) {
|
protected SimpleTaglet(HtmlConfiguration config, DocTree.Kind tagKind, String header, Set<Taglet.Location> locations, boolean enabled) {
|
||||||
super(tagKind, false, locations);
|
super(config, tagKind, false, locations);
|
||||||
this.header = header;
|
this.header = header;
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<Location> getLocations(String locations) {
|
@Override
|
||||||
Set<Location> set = EnumSet.noneOf(Location.class);
|
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence) {
|
||||||
|
assert dst.getKind() == ElementKind.METHOD;
|
||||||
|
assert !isFirstSentence;
|
||||||
|
try {
|
||||||
|
var docFinder = utils.docFinder();
|
||||||
|
Optional<Documentation> r;
|
||||||
|
if (src == null) {
|
||||||
|
r = docFinder.find((ExecutableElement) dst,
|
||||||
|
m -> DocFinder.Result.fromOptional(extractFirst(m))).toOptional();
|
||||||
|
} else {
|
||||||
|
r = docFinder.search((ExecutableElement) src,
|
||||||
|
m -> DocFinder.Result.fromOptional(extractFirst(m))).toOptional();
|
||||||
|
}
|
||||||
|
return r.map(result -> new Output(result.tag, result.method, result.description, true))
|
||||||
|
.orElseGet(()->new Output(null, null, List.of(), true));
|
||||||
|
} catch (DocFinder.NoOverriddenMethodFound e) {
|
||||||
|
return new Output(null, null, List.of(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the taglet should generate output.
|
||||||
|
* Standard tags like {@code @author}, {@code @since}, {@code @version} can
|
||||||
|
* be disabled by command-line options; custom tags created with -tag can be
|
||||||
|
* disabled with an X in the defining string.
|
||||||
|
*/
|
||||||
|
boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this taglet accepts a {@code BlockTagTree} node.
|
||||||
|
* The taglet accepts a tree node if it has the same kind, and
|
||||||
|
* if the kind is {@code UNKNOWN_BLOCK_TAG} the same tag name.
|
||||||
|
*
|
||||||
|
* @param tree the tree node
|
||||||
|
* @return {@code true} if this taglet accepts this tree node
|
||||||
|
*/
|
||||||
|
private boolean accepts(BlockTagTree tree) {
|
||||||
|
return (tree.getKind() == DocTree.Kind.UNKNOWN_BLOCK_TAG && tagKind == DocTree.Kind.UNKNOWN_BLOCK_TAG)
|
||||||
|
? tree.getTagName().equals(name)
|
||||||
|
: tree.getKind() == tagKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
record Documentation(DocTree tag, List<? extends DocTree> description, ExecutableElement method) { }
|
||||||
|
|
||||||
|
private Optional<Documentation> extractFirst(ExecutableElement m) {
|
||||||
|
List<? extends DocTree> tags = utils.getBlockTags(m, this::accepts);
|
||||||
|
if (tags.isEmpty()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
DocTree t = tags.get(0);
|
||||||
|
return Optional.of(new Documentation(t, utils.getCommentHelper(m).getDescription(t), m));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Content getAllBlockTagOutput(Element holder, TagletWriter tagletWriter) {
|
||||||
|
this.tagletWriter = tagletWriter;
|
||||||
|
List<? extends DocTree> tags = utils.getBlockTags(holder, this::accepts);
|
||||||
|
if (header == null || tags.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return simpleBlockTagOutput(holder, tags, header, tagletWriter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output for a series of simple tags.
|
||||||
|
*
|
||||||
|
* @param element The element that owns the doc comment
|
||||||
|
* @param simpleTags the list of simple tags
|
||||||
|
* @param header the header for the series of tags
|
||||||
|
*
|
||||||
|
* @return the output
|
||||||
|
*/
|
||||||
|
private Content simpleBlockTagOutput(Element element,
|
||||||
|
List<? extends DocTree> simpleTags,
|
||||||
|
String header,
|
||||||
|
TagletWriter writer) {
|
||||||
|
var ch = utils.getCommentHelper(element);
|
||||||
|
var context = tagletWriter.context;
|
||||||
|
var htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
|
||||||
|
ContentBuilder body = new ContentBuilder();
|
||||||
|
boolean many = false;
|
||||||
|
for (DocTree simpleTag : simpleTags) {
|
||||||
|
if (many) {
|
||||||
|
body.add(", ");
|
||||||
|
}
|
||||||
|
List<? extends DocTree> bodyTags = ch.getBody(simpleTag);
|
||||||
|
body.add(htmlWriter.commentTagsToContent(element, bodyTags, context.within(simpleTag)));
|
||||||
|
many = true;
|
||||||
|
}
|
||||||
|
return new ContentBuilder(
|
||||||
|
HtmlTree.DT(RawHtml.of(header)),
|
||||||
|
HtmlTree.DD(body));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<Taglet.Location> getLocations(String locations) {
|
||||||
|
Set<Taglet.Location> set = EnumSet.noneOf(Taglet.Location.class);
|
||||||
for (int i = 0; i < locations.length(); i++) {
|
for (int i = 0; i < locations.length(); i++) {
|
||||||
switch (locations.charAt(i)) {
|
switch (locations.charAt(i)) {
|
||||||
case 'a': case 'A':
|
case 'a': case 'A':
|
||||||
return EnumSet.allOf(Location.class);
|
return EnumSet.allOf(Taglet.Location.class);
|
||||||
case 'c': case 'C':
|
case 'c': case 'C':
|
||||||
set.add(Location.CONSTRUCTOR);
|
set.add(Taglet.Location.CONSTRUCTOR);
|
||||||
break;
|
break;
|
||||||
case 'f': case 'F':
|
case 'f': case 'F':
|
||||||
set.add(Location.FIELD);
|
set.add(Taglet.Location.FIELD);
|
||||||
break;
|
break;
|
||||||
case 'm': case 'M':
|
case 'm': case 'M':
|
||||||
set.add(Location.METHOD);
|
set.add(Taglet.Location.METHOD);
|
||||||
break;
|
break;
|
||||||
case 'o': case 'O':
|
case 'o': case 'O':
|
||||||
set.add(Location.OVERVIEW);
|
set.add(Taglet.Location.OVERVIEW);
|
||||||
break;
|
break;
|
||||||
case 'p': case 'P':
|
case 'p': case 'P':
|
||||||
set.add(Location.PACKAGE);
|
set.add(Taglet.Location.PACKAGE);
|
||||||
break;
|
break;
|
||||||
case 's': case 'S': // super-packages, anyone?
|
case 's': case 'S': // super-packages, anyone?
|
||||||
set.add(Location.MODULE);
|
set.add(Taglet.Location.MODULE);
|
||||||
break;
|
break;
|
||||||
case 't': case 'T':
|
case 't': case 'T':
|
||||||
set.add(Location.TYPE);
|
set.add(Taglet.Location.TYPE);
|
||||||
break;
|
break;
|
||||||
case 'x': case 'X':
|
case 'x': case 'X':
|
||||||
break;
|
break;
|
||||||
@ -161,46 +256,4 @@ public class SimpleTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
private static boolean isEnabled(String locations) {
|
private static boolean isEnabled(String locations) {
|
||||||
return locations.matches("[^Xx]*");
|
return locations.matches("[^Xx]*");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence, BaseConfiguration configuration) {
|
|
||||||
assert dst.getKind() == ElementKind.METHOD;
|
|
||||||
assert !isFirstSentence;
|
|
||||||
try {
|
|
||||||
var docFinder = configuration.utils.docFinder();
|
|
||||||
Optional<Documentation> r;
|
|
||||||
if (src == null) {
|
|
||||||
r = docFinder.find((ExecutableElement) dst,
|
|
||||||
m -> Result.fromOptional(extractFirst(m, configuration.utils))).toOptional();
|
|
||||||
} else {
|
|
||||||
r = docFinder.search((ExecutableElement) src,
|
|
||||||
m -> Result.fromOptional(extractFirst(m, configuration.utils))).toOptional();
|
|
||||||
}
|
|
||||||
return r.map(result -> new Output(result.tag, result.method, result.description, true))
|
|
||||||
.orElseGet(()->new Output(null, null, List.of(), true));
|
|
||||||
} catch (DocFinder.NoOverriddenMethodFound e) {
|
|
||||||
return new Output(null, null, List.of(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
record Documentation(DocTree tag, List<? extends DocTree> description, ExecutableElement method) { }
|
|
||||||
|
|
||||||
private Optional<Documentation> extractFirst(ExecutableElement m, Utils utils) {
|
|
||||||
List<? extends DocTree> tags = utils.getBlockTags(m, this);
|
|
||||||
if (tags.isEmpty()) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
DocTree t = tags.get(0);
|
|
||||||
return Optional.of(new Documentation(t, utils.getCommentHelper(m).getDescription(t), m));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
|
|
||||||
Utils utils = writer.configuration().utils;
|
|
||||||
List<? extends DocTree> tags = utils.getBlockTags(holder, this);
|
|
||||||
if (header == null || tags.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return writer.simpleBlockTagOutput(holder, tags, header);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,34 +23,46 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.PackageElement;
|
import javax.lang.model.element.PackageElement;
|
||||||
import javax.tools.Diagnostic;
|
import javax.tools.Diagnostic;
|
||||||
import javax.tools.DocumentationTool.Location;
|
import javax.tools.DocumentationTool;
|
||||||
import javax.tools.FileObject;
|
import javax.tools.FileObject;
|
||||||
|
|
||||||
import com.sun.source.doctree.AttributeTree;
|
import com.sun.source.doctree.AttributeTree;
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import com.sun.source.doctree.SnippetTree;
|
import com.sun.source.doctree.SnippetTree;
|
||||||
import com.sun.source.doctree.TextTree;
|
import com.sun.source.doctree.TextTree;
|
||||||
|
import com.sun.source.util.DocTreePath;
|
||||||
|
|
||||||
import jdk.javadoc.doclet.Taglet;
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.Action;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.ParseException;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.Parser;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.Style;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.StyledText;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.DocletElement;
|
import jdk.javadoc.internal.doclets.toolkit.DocletElement;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.snippet.Action;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.snippet.ParseException;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.snippet.Parser;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.snippet.StyledText;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,8 +102,8 @@ public class SnippetTaglet extends BaseTaglet {
|
|||||||
public String getIdentifier() {return identifier;}
|
public String getIdentifier() {return identifier;}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SnippetTaglet() {
|
SnippetTaglet(HtmlConfiguration config) {
|
||||||
super(DocTree.Kind.SNIPPET, true, EnumSet.allOf(Taglet.Location.class));
|
super(config, DocTree.Kind.SNIPPET, true, EnumSet.allOf(Taglet.Location.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -109,16 +121,116 @@ public class SnippetTaglet extends BaseTaglet {
|
|||||||
* one of the named regions in the snippets content.
|
* one of the named regions in the snippets content.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter writer) {
|
public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter tagletWriter) {
|
||||||
|
this.tagletWriter = tagletWriter;
|
||||||
try {
|
try {
|
||||||
return generateContent(holder, tag, writer);
|
return generateContent(holder, tag);
|
||||||
} catch (BadSnippetException e) {
|
} catch (BadSnippetException e) {
|
||||||
error(writer, holder, e.tag(), e.key(), e.args());
|
error(tagletWriter, holder, e.tag(), e.key(), e.args());
|
||||||
String details = writer.configuration().getDocResources().getText(e.key(), e.args());
|
String details = config.getDocResources().getText(e.key(), e.args());
|
||||||
return badSnippet(writer, Optional.of(details));
|
return badSnippet(tagletWriter, Optional.of(details));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output for a {@code {@snippet ...}} tag.
|
||||||
|
*
|
||||||
|
* @param element The element that owns the doc comment
|
||||||
|
* @param tag the snippet tag
|
||||||
|
* @param id the value of the id attribute, or null if not defined
|
||||||
|
* @param lang the value of the lang attribute, or null if not defined
|
||||||
|
*
|
||||||
|
* @return the output
|
||||||
|
*/
|
||||||
|
private Content snippetTagOutput(Element element, SnippetTree tag, StyledText content,
|
||||||
|
String id, String lang) {
|
||||||
|
var pathToRoot = tagletWriter.htmlWriter.pathToRoot;
|
||||||
|
var pre = new HtmlTree(TagName.PRE).setStyle(HtmlStyle.snippet);
|
||||||
|
if (id != null && !id.isBlank()) {
|
||||||
|
pre.put(HtmlAttr.ID, id);
|
||||||
|
}
|
||||||
|
var code = new HtmlTree(TagName.CODE)
|
||||||
|
.addUnchecked(Text.EMPTY); // Make sure the element is always rendered
|
||||||
|
if (lang != null && !lang.isBlank()) {
|
||||||
|
code.addStyle("language-" + lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
content.consumeBy((styles, sequence) -> {
|
||||||
|
CharSequence text = Text.normalizeNewlines(sequence);
|
||||||
|
if (styles.isEmpty()) {
|
||||||
|
code.add(text);
|
||||||
|
} else {
|
||||||
|
Element e = null;
|
||||||
|
String t = null;
|
||||||
|
boolean linkEncountered = false;
|
||||||
|
boolean markupEncountered = false;
|
||||||
|
Set<String> classes = new HashSet<>();
|
||||||
|
for (Style s : styles) {
|
||||||
|
if (s instanceof Style.Name n) {
|
||||||
|
classes.add(n.name());
|
||||||
|
} else if (s instanceof Style.Link l) {
|
||||||
|
assert !linkEncountered; // TODO: do not assert; pick the first link report on subsequent
|
||||||
|
linkEncountered = true;
|
||||||
|
t = l.target();
|
||||||
|
e = getLinkedElement(element, t);
|
||||||
|
if (e == null) {
|
||||||
|
// TODO: diagnostic output
|
||||||
|
}
|
||||||
|
} else if (s instanceof Style.Markup) {
|
||||||
|
markupEncountered = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// TODO: transform this if...else into an exhaustive
|
||||||
|
// switch over the sealed Style hierarchy when "Pattern
|
||||||
|
// Matching for switch" has been implemented (JEP 406
|
||||||
|
// and friends)
|
||||||
|
throw new AssertionError(styles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Content c;
|
||||||
|
if (markupEncountered) {
|
||||||
|
return;
|
||||||
|
} else if (linkEncountered) {
|
||||||
|
assert e != null;
|
||||||
|
//disable preview tagging inside the snippets:
|
||||||
|
Utils.PreviewFlagProvider prevPreviewProvider = utils.setPreviewFlagProvider(el -> false);
|
||||||
|
try {
|
||||||
|
var lt = (LinkTaglet) config.tagletManager.getTaglet(DocTree.Kind.LINK);
|
||||||
|
c = lt.linkSeeReferenceOutput(element,
|
||||||
|
null,
|
||||||
|
t,
|
||||||
|
e,
|
||||||
|
false, // TODO: for now
|
||||||
|
Text.of(sequence.toString()),
|
||||||
|
(key, args) -> { /* TODO: report diagnostic */ },
|
||||||
|
tagletWriter);
|
||||||
|
} finally {
|
||||||
|
utils.setPreviewFlagProvider(prevPreviewProvider);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c = HtmlTree.SPAN(Text.of(text));
|
||||||
|
classes.forEach(((HtmlTree) c)::addStyle);
|
||||||
|
}
|
||||||
|
code.add(c);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
String copyText = resources.getText("doclet.Copy_to_clipboard");
|
||||||
|
String copiedText = resources.getText("doclet.Copied_to_clipboard");
|
||||||
|
String copySnippetText = resources.getText("doclet.Copy_snippet_to_clipboard");
|
||||||
|
var snippetContainer = HtmlTree.DIV(HtmlStyle.snippetContainer,
|
||||||
|
new HtmlTree(TagName.BUTTON)
|
||||||
|
.add(HtmlTree.SPAN(Text.of(copyText))
|
||||||
|
.put(HtmlAttr.DATA_COPIED, copiedText))
|
||||||
|
.add(new HtmlTree(TagName.IMG)
|
||||||
|
.put(HtmlAttr.SRC, pathToRoot.resolve(DocPaths.CLIPBOARD_SVG).getPath())
|
||||||
|
.put(HtmlAttr.ALT, copySnippetText))
|
||||||
|
.addStyle(HtmlStyle.copy)
|
||||||
|
.addStyle(HtmlStyle.snippetCopy)
|
||||||
|
.put(HtmlAttr.ARIA_LABEL, copySnippetText)
|
||||||
|
.put(HtmlAttr.ONCLICK, "copySnippet(this)"));
|
||||||
|
return snippetContainer.add(pre.add(code));
|
||||||
|
}
|
||||||
|
|
||||||
private static final class BadSnippetException extends Exception {
|
private static final class BadSnippetException extends Exception {
|
||||||
|
|
||||||
@java.io.Serial
|
@java.io.Serial
|
||||||
@ -147,7 +259,7 @@ public class SnippetTaglet extends BaseTaglet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Content generateContent(Element holder, DocTree tag, TagletWriter writer)
|
private Content generateContent(Element holder, DocTree tag)
|
||||||
throws BadSnippetException
|
throws BadSnippetException
|
||||||
{
|
{
|
||||||
SnippetTree snippetTag = (SnippetTree) tag;
|
SnippetTree snippetTag = (SnippetTree) tag;
|
||||||
@ -212,11 +324,10 @@ public class SnippetTaglet extends BaseTaglet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we didn't create JavaFileManager, so we won't close it; even if an error occurs
|
// we didn't create JavaFileManager, so we won't close it; even if an error occurs
|
||||||
var fileManager = writer.configuration().getFileManager();
|
var fileManager = config.getFileManager();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// first, look in local snippet-files subdirectory
|
// first, look in local snippet-files subdirectory
|
||||||
var utils = writer.configuration().utils;
|
|
||||||
var pkg = getPackageElement(holder, utils);
|
var pkg = getPackageElement(holder, utils);
|
||||||
var pkgLocation = utils.getLocationForPackage(pkg);
|
var pkgLocation = utils.getLocationForPackage(pkg);
|
||||||
var pkgName = pkg.getQualifiedName().toString(); // note: empty string for unnamed package
|
var pkgName = pkg.getQualifiedName().toString(); // note: empty string for unnamed package
|
||||||
@ -224,8 +335,8 @@ public class SnippetTaglet extends BaseTaglet {
|
|||||||
fileObject = fileManager.getFileForInput(pkgLocation, pkgName, relativeName);
|
fileObject = fileManager.getFileForInput(pkgLocation, pkgName, relativeName);
|
||||||
|
|
||||||
// if not found in local snippet-files directory, look on snippet path
|
// if not found in local snippet-files directory, look on snippet path
|
||||||
if (fileObject == null && fileManager.hasLocation(Location.SNIPPET_PATH)) {
|
if (fileObject == null && fileManager.hasLocation(DocumentationTool.Location.SNIPPET_PATH)) {
|
||||||
fileObject = fileManager.getFileForInput(Location.SNIPPET_PATH, "", v);
|
fileObject = fileManager.getFileForInput(DocumentationTool.Location.SNIPPET_PATH, "", v);
|
||||||
}
|
}
|
||||||
} catch (IOException | IllegalArgumentException e) { // TODO: test this when JDK-8276892 is integrated
|
} catch (IOException | IllegalArgumentException e) { // TODO: test this when JDK-8276892 is integrated
|
||||||
// JavaFileManager.getFileForInput can throw IllegalArgumentException in certain cases
|
// JavaFileManager.getFileForInput can throw IllegalArgumentException in certain cases
|
||||||
@ -265,36 +376,35 @@ public class SnippetTaglet extends BaseTaglet {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Diags d = (text, pos) -> {
|
Diags d = (text, pos) -> {
|
||||||
var path = writer.configuration().utils.getCommentHelper(holder)
|
var path = utils.getCommentHelper(holder)
|
||||||
.getDocTreePath(snippetTag.getBody());
|
.getDocTreePath(snippetTag.getBody());
|
||||||
writer.configuration().getReporter().print(Diagnostic.Kind.WARNING,
|
config.getReporter().print(Diagnostic.Kind.WARNING,
|
||||||
path, pos, pos, pos, text);
|
path, pos, pos, pos, text);
|
||||||
};
|
};
|
||||||
if (inlineContent != null) {
|
if (inlineContent != null) {
|
||||||
inlineSnippet = parse(writer.configuration().getDocResources(), d, language, inlineContent);
|
inlineSnippet = parse(resources, d, language, inlineContent);
|
||||||
}
|
}
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
var path = writer.configuration().utils.getCommentHelper(holder)
|
var path = utils.getCommentHelper(holder)
|
||||||
.getDocTreePath(snippetTag.getBody());
|
.getDocTreePath(snippetTag.getBody());
|
||||||
// TODO: there should be a method in Messages; that method should mirror Reporter's; use that method instead accessing Reporter.
|
// TODO: there should be a method in Messages; that method should mirror Reporter's; use that method instead accessing Reporter.
|
||||||
String msg = writer.configuration().getDocResources()
|
String msg = resources.getText("doclet.snippet.markup", e.getMessage());
|
||||||
.getText("doclet.snippet.markup", e.getMessage());
|
config.getReporter().print(Diagnostic.Kind.ERROR,
|
||||||
writer.configuration().getReporter().print(Diagnostic.Kind.ERROR,
|
|
||||||
path, e.getPosition(), e.getPosition(), e.getPosition(), msg);
|
path, e.getPosition(), e.getPosition(), e.getPosition(), msg);
|
||||||
return badSnippet(writer, Optional.of(e.getMessage()));
|
return badSnippet(tagletWriter, Optional.of(e.getMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var finalFileObject = fileObject;
|
var finalFileObject = fileObject;
|
||||||
Diags d = (text, pos) -> writer.configuration().getMessages().warning(finalFileObject, pos, pos, pos, text);
|
Diags d = (text, pos) -> messages.warning(finalFileObject, pos, pos, pos, text);
|
||||||
if (externalContent != null) {
|
if (externalContent != null) {
|
||||||
externalSnippet = parse(writer.configuration().getDocResources(), d, language, externalContent);
|
externalSnippet = parse(resources, d, language, externalContent);
|
||||||
}
|
}
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
assert fileObject != null;
|
assert fileObject != null;
|
||||||
writer.configuration().getMessages().error(fileObject, e.getPosition(),
|
messages.error(fileObject, e.getPosition(),
|
||||||
e.getPosition(), e.getPosition(), "doclet.snippet.markup", e.getMessage());
|
e.getPosition(), e.getPosition(), "doclet.snippet.markup", e.getMessage());
|
||||||
return badSnippet(writer, Optional.of(e.getMessage()));
|
return badSnippet(tagletWriter, Optional.of(e.getMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// the region must be matched at least in one content: it can be matched
|
// the region must be matched at least in one content: it can be matched
|
||||||
@ -343,7 +453,7 @@ public class SnippetTaglet extends BaseTaglet {
|
|||||||
? null
|
? null
|
||||||
: stringValueOf(idAttr);
|
: stringValueOf(idAttr);
|
||||||
|
|
||||||
return writer.snippetTagOutput(holder, snippetTag, text, id, lang);
|
return snippetTagOutput(holder, snippetTag, text, id, lang);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -399,12 +509,11 @@ public class SnippetTaglet extends BaseTaglet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void error(TagletWriter writer, Element holder, DocTree tag, String key, Object... args) {
|
private void error(TagletWriter writer, Element holder, DocTree tag, String key, Object... args) {
|
||||||
writer.configuration().getMessages().error(
|
messages.error(utils.getCommentHelper(holder).getDocTreePath(tag), key, args);
|
||||||
writer.configuration().utils.getCommentHelper(holder).getDocTreePath(tag), key, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Content badSnippet(TagletWriter writer, Optional<String> details) {
|
private Content badSnippet(TagletWriter writer, Optional<String> details) {
|
||||||
Resources resources = writer.configuration().getDocResources();
|
var resources = config.getDocResources();
|
||||||
return writer.invalidTagOutput(resources.getText("doclet.tag.invalid", "snippet"), details);
|
return writer.invalidTagOutput(resources.getText("doclet.tag.invalid", "snippet"), details);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,4 +570,21 @@ public class SnippetTaglet extends BaseTaglet {
|
|||||||
// The most trivial example of such a string is " ". In fact, any string
|
// The most trivial example of such a string is " ". In fact, any string
|
||||||
// with a trailing non-empty blank line would do.
|
// with a trailing non-empty blank line would do.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the element that is linked from the context of the referrer using
|
||||||
|
* the provided signature; returns null if such element could not be found.
|
||||||
|
*
|
||||||
|
* This method is to be used when it is the target of the link that is
|
||||||
|
* important, not the container of the link (e.g. was it an @see,
|
||||||
|
* @link/@linkplain or @snippet tags, etc.)
|
||||||
|
*/
|
||||||
|
private Element getLinkedElement(Element referer, String signature) {
|
||||||
|
var factory = utils.docTrees.getDocTreeFactory();
|
||||||
|
var docCommentTree = utils.getDocCommentTree(referer);
|
||||||
|
var rootPath = new DocTreePath(utils.getTreePath(referer), docCommentTree);
|
||||||
|
var reference = factory.newReferenceTree(signature);
|
||||||
|
var fabricatedPath = new DocTreePath(rootPath, reference);
|
||||||
|
return utils.docTrees.getElement(fabricatedPath);
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, 2023, 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
|
||||||
|
import com.sun.source.doctree.DocTree;
|
||||||
|
import com.sun.source.doctree.SpecTree;
|
||||||
|
import com.sun.source.doctree.TextTree;
|
||||||
|
import com.sun.source.util.DocTreePath;
|
||||||
|
|
||||||
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.Contents;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A taglet that represents the {@code @spec} tag.
|
||||||
|
*/
|
||||||
|
public class SpecTaglet extends BaseTaglet implements InheritableTaglet {
|
||||||
|
private final Contents contents;
|
||||||
|
|
||||||
|
SpecTaglet(HtmlConfiguration config) {
|
||||||
|
super(config, DocTree.Kind.SPEC, false, EnumSet.allOf(Taglet.Location.class));
|
||||||
|
this.contents = config.contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence) {
|
||||||
|
CommentHelper ch = utils.getCommentHelper(dst);
|
||||||
|
var path = ch.getDocTreePath(tag);
|
||||||
|
messages.warning(path, "doclet.inheritDocWithinInappropriateTag");
|
||||||
|
return new Output(null, null, List.of(), true /* true, otherwise there will be an exception up the stack */);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Content getAllBlockTagOutput(Element holder, TagletWriter tagletWriter) {
|
||||||
|
this.tagletWriter = tagletWriter;
|
||||||
|
List<? extends SpecTree> tags = utils.getSpecTrees(holder);
|
||||||
|
Element e = holder;
|
||||||
|
if (utils.isMethod(holder)) {
|
||||||
|
var docFinder = utils.docFinder();
|
||||||
|
Optional<Documentation> result = docFinder.search((ExecutableElement) holder,
|
||||||
|
m -> DocFinder.Result.fromOptional(extract(utils, m))).toOptional();
|
||||||
|
if (result.isPresent()) {
|
||||||
|
e = result.get().method();
|
||||||
|
tags = result.get().specTrees();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return specTagOutput(e, tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output for one or more {@code @spec} tags.
|
||||||
|
*
|
||||||
|
* @param holder the element that owns the doc comment
|
||||||
|
* @param specTags the array of @spec tags.
|
||||||
|
*
|
||||||
|
* @return the output
|
||||||
|
*/
|
||||||
|
public Content specTagOutput(Element holder, List<? extends SpecTree> specTags) {
|
||||||
|
if (specTags.isEmpty()) {
|
||||||
|
return Text.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
var links = specTags.stream()
|
||||||
|
.map(st -> specTagToContent(holder, st)).toList();
|
||||||
|
|
||||||
|
var specList = tagletWriter.tagList(links);
|
||||||
|
return new ContentBuilder(
|
||||||
|
HtmlTree.DT(contents.externalSpecifications),
|
||||||
|
HtmlTree.DD(specList));
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Documentation(List<? extends SpecTree> specTrees, ExecutableElement method) { }
|
||||||
|
|
||||||
|
private static Optional<Documentation> extract(Utils utils, ExecutableElement method) {
|
||||||
|
List<? extends SpecTree> tags = utils.getSpecTrees(method);
|
||||||
|
return tags.isEmpty() ? Optional.empty() : Optional.of(new Documentation(tags, method));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Content specTagToContent(Element holder, SpecTree specTree) {
|
||||||
|
var htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
String specTreeURL = specTree.getURL().getBody();
|
||||||
|
List<? extends DocTree> specTreeLabel = specTree.getTitle();
|
||||||
|
Content label = htmlWriter.commentTagsToContent(holder, specTreeLabel, tagletWriter.context.isFirstSentence);
|
||||||
|
return getExternalSpecContent(holder, specTree, specTreeURL,
|
||||||
|
textOf(specTreeLabel).replaceAll("\\s+", " "), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String textOf(List<? extends DocTree> trees) {
|
||||||
|
return trees.stream()
|
||||||
|
.filter(dt -> dt instanceof TextTree)
|
||||||
|
.map(dt -> ((TextTree) dt).getBody().trim())
|
||||||
|
.collect(Collectors.joining(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
Content getExternalSpecContent(Element holder,
|
||||||
|
DocTree docTree,
|
||||||
|
String url,
|
||||||
|
String searchText,
|
||||||
|
Content title) {
|
||||||
|
URI specURI;
|
||||||
|
try {
|
||||||
|
// Use the canonical title of the spec if one is available
|
||||||
|
specURI = new URI(url);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
CommentHelper ch = utils.getCommentHelper(holder);
|
||||||
|
DocTreePath dtp = ch.getDocTreePath(docTree);
|
||||||
|
tagletWriter.htmlWriter.messages.error(dtp, "doclet.Invalid_URL", e.getMessage());
|
||||||
|
specURI = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Content titleWithAnchor = tagletWriter.createAnchorAndSearchIndex(holder,
|
||||||
|
searchText,
|
||||||
|
title,
|
||||||
|
resources.getText("doclet.External_Specification"),
|
||||||
|
docTree);
|
||||||
|
|
||||||
|
if (specURI == null) {
|
||||||
|
return titleWithAnchor;
|
||||||
|
} else {
|
||||||
|
var htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
return HtmlTree.A(htmlWriter.resolveExternalSpecURI(specURI), titleWithAnchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,14 +23,17 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
import com.sun.source.doctree.SummaryTree;
|
import com.sun.source.doctree.SummaryTree;
|
||||||
|
|
||||||
|
import jdk.javadoc.doclet.Taglet.Location;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,13 +41,13 @@ import jdk.javadoc.internal.doclets.toolkit.Content;
|
|||||||
*/
|
*/
|
||||||
public class SummaryTaglet extends BaseTaglet {
|
public class SummaryTaglet extends BaseTaglet {
|
||||||
|
|
||||||
public SummaryTaglet() {
|
SummaryTaglet(HtmlConfiguration config) {
|
||||||
super(DocTree.Kind.SUMMARY, true, EnumSet.allOf(Location.class));
|
super(config, DocTree.Kind.SUMMARY, true, EnumSet.allOf(Location.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter writer) {
|
public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter tagletWriter) {
|
||||||
return writer.commentTagsToOutput(holder, tag, ((SummaryTree)tag).getSummary(),
|
return tagletWriter.commentTagsToOutput(holder, tag, ((SummaryTree)tag).getSummary(),
|
||||||
writer.isFirstSentence);
|
tagletWriter.context.isFirstSentence);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,27 +23,46 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import com.sun.source.doctree.SystemPropertyTree;
|
import com.sun.source.doctree.SystemPropertyTree;
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
import jdk.javadoc.doclet.Taglet;
|
||||||
import java.util.EnumSet;
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A taglet that represents the {@code @systemProperty} tag.
|
* A taglet that represents the {@code @systemProperty} tag.
|
||||||
*/
|
*/
|
||||||
public class SystemPropertyTaglet extends BaseTaglet {
|
public class SystemPropertyTaglet extends BaseTaglet {
|
||||||
|
|
||||||
SystemPropertyTaglet() {
|
SystemPropertyTaglet(HtmlConfiguration config) {
|
||||||
super(DocTree.Kind.SYSTEM_PROPERTY, true, EnumSet.allOf(Location.class));
|
super(config, DocTree.Kind.SYSTEM_PROPERTY, true, EnumSet.allOf(Taglet.Location.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter writer) {
|
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter tagletWriter) {
|
||||||
return writer.systemPropertyTagOutput(element, (SystemPropertyTree) tag);
|
this.tagletWriter = tagletWriter;
|
||||||
|
return systemPropertyTagOutput(element, (SystemPropertyTree) tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output for a {@code {@systemProperty...}} tag.
|
||||||
|
*
|
||||||
|
* @param element the element that owns the doc comment
|
||||||
|
* @param tag the system property tag
|
||||||
|
*
|
||||||
|
* @return the output
|
||||||
|
*/
|
||||||
|
private Content systemPropertyTagOutput(Element element, SystemPropertyTree tag) {
|
||||||
|
String tagText = tag.getPropertyName().toString();
|
||||||
|
return HtmlTree.CODE(tagletWriter.createAnchorAndSearchIndex(element, tagText,
|
||||||
|
resources.getText("doclet.System_Property"), tag));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,17 +23,25 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
import jdk.javadoc.doclet.Taglet.Location;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the taglet interface used internally within the doclet.
|
* This is the taglet interface used internally within the doclet.
|
||||||
|
*
|
||||||
|
* The public {@link jdk.javadoc.doclet.Taglet} interface only supports
|
||||||
|
* output to strings. This interface supports structured output,
|
||||||
|
* to {@link Content} objects, such as {@link HtmlTree}.
|
||||||
|
*
|
||||||
|
* User-provided taglets are supported using the {@link UserTaglet}
|
||||||
|
* wrapper class.
|
||||||
*/
|
*/
|
||||||
public interface Taglet {
|
public interface Taglet {
|
||||||
/**
|
/**
|
||||||
@ -49,7 +57,9 @@ public interface Taglet {
|
|||||||
* @return {@code true} if this {@code Taglet} can be used in field documentation
|
* @return {@code true} if this {@code Taglet} can be used in field documentation
|
||||||
* and {@code false} otherwise
|
* and {@code false} otherwise
|
||||||
*/
|
*/
|
||||||
boolean inField();
|
default boolean inField() {
|
||||||
|
return getAllowedLocations().contains(Location.FIELD);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this {@code Taglet} can be used in constructor documentation.
|
* Indicates whether this {@code Taglet} can be used in constructor documentation.
|
||||||
@ -57,7 +67,9 @@ public interface Taglet {
|
|||||||
* @return {@code true} if this {@code Taglet} can be used in constructor documentation
|
* @return {@code true} if this {@code Taglet} can be used in constructor documentation
|
||||||
* and {@code false} otherwise
|
* and {@code false} otherwise
|
||||||
*/
|
*/
|
||||||
boolean inConstructor();
|
default boolean inConstructor() {
|
||||||
|
return getAllowedLocations().contains(Location.CONSTRUCTOR);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this {@code Taglet} can be used in method documentation.
|
* Indicates whether this {@code Taglet} can be used in method documentation.
|
||||||
@ -65,7 +77,9 @@ public interface Taglet {
|
|||||||
* @return {@code true} if this {@code Taglet} can be used in method documentation
|
* @return {@code true} if this {@code Taglet} can be used in method documentation
|
||||||
* and {@code false} otherwise
|
* and {@code false} otherwise
|
||||||
*/
|
*/
|
||||||
boolean inMethod();
|
default boolean inMethod() {
|
||||||
|
return getAllowedLocations().contains(Location.METHOD);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this {@code Taglet} can be used in overview documentation.
|
* Indicates whether this {@code Taglet} can be used in overview documentation.
|
||||||
@ -73,7 +87,9 @@ public interface Taglet {
|
|||||||
* @return {@code true} if this {@code Taglet} can be used in overview documentation
|
* @return {@code true} if this {@code Taglet} can be used in overview documentation
|
||||||
* and {@code false} otherwise
|
* and {@code false} otherwise
|
||||||
*/
|
*/
|
||||||
boolean inOverview();
|
default boolean inOverview() {
|
||||||
|
return getAllowedLocations().contains(Location.OVERVIEW);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this {@code Taglet} can be used in module documentation.
|
* Indicates whether this {@code Taglet} can be used in module documentation.
|
||||||
@ -81,7 +97,9 @@ public interface Taglet {
|
|||||||
* @return {@code true} if this {@code Taglet} can be used in module documentation
|
* @return {@code true} if this {@code Taglet} can be used in module documentation
|
||||||
* and {@code false} otherwise
|
* and {@code false} otherwise
|
||||||
*/
|
*/
|
||||||
boolean inModule();
|
default boolean inModule() {
|
||||||
|
return getAllowedLocations().contains(Location.MODULE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this {@code Taglet} can be used in package documentation.
|
* Indicates whether this {@code Taglet} can be used in package documentation.
|
||||||
@ -89,7 +107,9 @@ public interface Taglet {
|
|||||||
* @return {@code true} if this {@code Taglet} can be used in package documentation
|
* @return {@code true} if this {@code Taglet} can be used in package documentation
|
||||||
* and {@code false} otherwise
|
* and {@code false} otherwise
|
||||||
*/
|
*/
|
||||||
boolean inPackage();
|
default boolean inPackage() {
|
||||||
|
return getAllowedLocations().contains(Location.PACKAGE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this {@code Taglet} can be used in type documentation (classes or interfaces).
|
* Indicates whether this {@code Taglet} can be used in type documentation (classes or interfaces).
|
||||||
@ -97,7 +117,9 @@ public interface Taglet {
|
|||||||
* @return {@code true} if this {@code Taglet} can be used in type documentation
|
* @return {@code true} if this {@code Taglet} can be used in type documentation
|
||||||
* and {@code false} otherwise
|
* and {@code false} otherwise
|
||||||
*/
|
*/
|
||||||
boolean inType();
|
default boolean inType() {
|
||||||
|
return getAllowedLocations().contains(Location.TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this {@code Taglet} represents an inline tag.
|
* Indicates whether this {@code Taglet} represents an inline tag.
|
||||||
@ -130,12 +152,12 @@ public interface Taglet {
|
|||||||
*
|
*
|
||||||
* @param owner the element for the enclosing doc comment
|
* @param owner the element for the enclosing doc comment
|
||||||
* @param tag the tag
|
* @param tag the tag
|
||||||
* @param writer the taglet-writer used in this doclet
|
* @param tagletWriter the taglet-writer used in this doclet
|
||||||
*
|
*
|
||||||
* @return the output for this tag
|
* @return the output for this tag
|
||||||
* @throws UnsupportedTagletOperationException if the method is not supported by the taglet
|
* @throws UnsupportedTagletOperationException if the method is not supported by the taglet
|
||||||
*/
|
*/
|
||||||
Content getInlineTagOutput(Element owner, DocTree tag, TagletWriter writer) throws
|
Content getInlineTagOutput(Element owner, DocTree tag, TagletWriter tagletWriter) throws
|
||||||
UnsupportedTagletOperationException;
|
UnsupportedTagletOperationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,12 +165,12 @@ public interface Taglet {
|
|||||||
* all instances of block tags handled by this taglet.
|
* all instances of block tags handled by this taglet.
|
||||||
*
|
*
|
||||||
* @param owner the element for the enclosing doc comment
|
* @param owner the element for the enclosing doc comment
|
||||||
* @param writer the taglet-writer used in this doclet
|
* @param tagletWriter the taglet-writer used in this doclet
|
||||||
*
|
*
|
||||||
* @return the output for this tag
|
* @return the output for this tag
|
||||||
* @throws UnsupportedTagletOperationException if the method is not supported by the taglet
|
* @throws UnsupportedTagletOperationException if the method is not supported by the taglet
|
||||||
*/
|
*/
|
||||||
Content getAllBlockTagOutput(Element owner, TagletWriter writer) throws
|
Content getAllBlockTagOutput(Element owner, TagletWriter tagletWriter) throws
|
||||||
UnsupportedTagletOperationException;
|
UnsupportedTagletOperationException;
|
||||||
|
|
||||||
class UnsupportedTagletOperationException extends UnsupportedOperationException {
|
class UnsupportedTagletOperationException extends UnsupportedOperationException {
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -55,8 +55,8 @@ import com.sun.source.doctree.DocTree;
|
|||||||
import jdk.javadoc.doclet.Doclet;
|
import jdk.javadoc.doclet.Doclet;
|
||||||
import jdk.javadoc.doclet.DocletEnvironment;
|
import jdk.javadoc.doclet.DocletEnvironment;
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
import jdk.javadoc.doclet.Taglet.Location;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseOptions;
|
import jdk.javadoc.internal.doclets.formats.html.HtmlOptions;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.DocletElement;
|
import jdk.javadoc.internal.doclets.toolkit.DocletElement;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
||||||
@ -66,8 +66,6 @@ import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
|||||||
import static com.sun.source.doctree.DocTree.Kind.AUTHOR;
|
import static com.sun.source.doctree.DocTree.Kind.AUTHOR;
|
||||||
import static com.sun.source.doctree.DocTree.Kind.EXCEPTION;
|
import static com.sun.source.doctree.DocTree.Kind.EXCEPTION;
|
||||||
import static com.sun.source.doctree.DocTree.Kind.HIDDEN;
|
import static com.sun.source.doctree.DocTree.Kind.HIDDEN;
|
||||||
import static com.sun.source.doctree.DocTree.Kind.LINK;
|
|
||||||
import static com.sun.source.doctree.DocTree.Kind.LINK_PLAIN;
|
|
||||||
import static com.sun.source.doctree.DocTree.Kind.PARAM;
|
import static com.sun.source.doctree.DocTree.Kind.PARAM;
|
||||||
import static com.sun.source.doctree.DocTree.Kind.PROVIDES;
|
import static com.sun.source.doctree.DocTree.Kind.PROVIDES;
|
||||||
import static com.sun.source.doctree.DocTree.Kind.SEE;
|
import static com.sun.source.doctree.DocTree.Kind.SEE;
|
||||||
@ -78,10 +76,11 @@ import static com.sun.source.doctree.DocTree.Kind.SINCE;
|
|||||||
import static com.sun.source.doctree.DocTree.Kind.THROWS;
|
import static com.sun.source.doctree.DocTree.Kind.THROWS;
|
||||||
import static com.sun.source.doctree.DocTree.Kind.USES;
|
import static com.sun.source.doctree.DocTree.Kind.USES;
|
||||||
import static com.sun.source.doctree.DocTree.Kind.VERSION;
|
import static com.sun.source.doctree.DocTree.Kind.VERSION;
|
||||||
|
|
||||||
import static javax.tools.DocumentationTool.Location.TAGLET_PATH;
|
import static javax.tools.DocumentationTool.Location.TAGLET_PATH;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the {@code Taglet}s used by doclets.
|
* Manages the {@code Taglet}s used by the standard doclet.
|
||||||
*/
|
*/
|
||||||
public class TagletManager {
|
public class TagletManager {
|
||||||
|
|
||||||
@ -173,32 +172,32 @@ public class TagletManager {
|
|||||||
|
|
||||||
private final String tagletPath;
|
private final String tagletPath;
|
||||||
|
|
||||||
private final BaseConfiguration configuration;
|
private final HtmlConfiguration config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code TagletManager}.
|
* Constructs a new {@code TagletManager}.
|
||||||
*
|
*
|
||||||
* @param configuration the configuration for this taglet manager
|
* @param config the configuration for this taglet manager
|
||||||
*/
|
*/
|
||||||
public TagletManager(BaseConfiguration configuration) {
|
public TagletManager(HtmlConfiguration config) {
|
||||||
overriddenStandardTags = new HashSet<>();
|
overriddenStandardTags = new HashSet<>();
|
||||||
potentiallyConflictingTags = new HashSet<>();
|
potentiallyConflictingTags = new HashSet<>();
|
||||||
standardTags = new HashSet<>();
|
standardTags = new HashSet<>();
|
||||||
standardTagsLowercase = new HashSet<>();
|
standardTagsLowercase = new HashSet<>();
|
||||||
unseenCustomTags = new HashSet<>();
|
unseenCustomTags = new HashSet<>();
|
||||||
allTaglets = new LinkedHashMap<>();
|
allTaglets = new LinkedHashMap<>();
|
||||||
this.configuration = configuration;
|
this.config = config;
|
||||||
BaseOptions options = configuration.getOptions();
|
HtmlOptions options = config.getOptions();
|
||||||
this.nosince = options.noSince();
|
this.nosince = options.noSince();
|
||||||
this.showversion = options.showVersion();
|
this.showversion = options.showVersion();
|
||||||
this.showauthor = options.showAuthor();
|
this.showauthor = options.showAuthor();
|
||||||
this.javafx = options.javafx();
|
this.javafx = options.javafx();
|
||||||
this.docEnv = configuration.docEnv;
|
this.docEnv = config.docEnv;
|
||||||
this.doclet = configuration.doclet;
|
this.doclet = config.doclet;
|
||||||
this.messages = configuration.getMessages();
|
this.messages = config.getMessages();
|
||||||
this.resources = configuration.getDocResources();
|
this.resources = config.getDocResources();
|
||||||
this.showTaglets = options.showTaglets();
|
this.showTaglets = options.showTaglets();
|
||||||
this.utils = configuration.utils;
|
this.utils = config.utils;
|
||||||
this.tagletPath = options.tagletPath();
|
this.tagletPath = options.tagletPath();
|
||||||
initStandardTaglets();
|
initStandardTaglets();
|
||||||
}
|
}
|
||||||
@ -239,7 +238,7 @@ public class TagletManager {
|
|||||||
*/
|
*/
|
||||||
public void addCustomTag(String classname, JavaFileManager fileManager) {
|
public void addCustomTag(String classname, JavaFileManager fileManager) {
|
||||||
ClassLoader tagClassLoader = fileManager.getClassLoader(TAGLET_PATH);
|
ClassLoader tagClassLoader = fileManager.getClassLoader(TAGLET_PATH);
|
||||||
if (configuration.workArounds.accessInternalAPI()) {
|
if (config.workArounds.accessInternalAPI()) {
|
||||||
Module thisModule = getClass().getModule();
|
Module thisModule = getClass().getModule();
|
||||||
Module tagletLoaderUnnamedModule = tagClassLoader.getUnnamedModule();
|
Module tagletLoaderUnnamedModule = tagClassLoader.getUnnamedModule();
|
||||||
List<String> pkgs = List.of(
|
List<String> pkgs = List.of(
|
||||||
@ -309,7 +308,7 @@ public class TagletManager {
|
|||||||
// remove + put in both branches below move the tag to the back of the map's ordering
|
// remove + put in both branches below move the tag to the back of the map's ordering
|
||||||
Taglet tag = allTaglets.remove(tagName);
|
Taglet tag = allTaglets.remove(tagName);
|
||||||
if (tag == null || header != null) {
|
if (tag == null || header != null) {
|
||||||
allTaglets.put(tagName, new SimpleTaglet(tagName, header, locations));
|
allTaglets.put(tagName, new SimpleTaglet(config, tagName, header, locations));
|
||||||
if (Utils.toLowerCase(locations).indexOf('x') == -1) {
|
if (Utils.toLowerCase(locations).indexOf('x') == -1) {
|
||||||
checkTagName(tagName);
|
checkTagName(tagName);
|
||||||
}
|
}
|
||||||
@ -371,7 +370,7 @@ public class TagletManager {
|
|||||||
final Taglet taglet = allTaglets.get(name);
|
final Taglet taglet = allTaglets.get(name);
|
||||||
// Check and verify tag usage
|
// Check and verify tag usage
|
||||||
if (taglet != null) {
|
if (taglet != null) {
|
||||||
if (taglet instanceof SimpleTaglet st && !st.enabled) {
|
if (taglet instanceof SimpleTaglet st && !st.isEnabled()) {
|
||||||
// taglet has been disabled
|
// taglet has been disabled
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -591,69 +590,69 @@ public class TagletManager {
|
|||||||
initJavaFXTaglets();
|
initJavaFXTaglets();
|
||||||
}
|
}
|
||||||
|
|
||||||
addStandardTaglet(new ParamTaglet());
|
addStandardTaglet(new ParamTaglet(config));
|
||||||
addStandardTaglet(new ReturnTaglet());
|
addStandardTaglet(new ReturnTaglet(config));
|
||||||
addStandardTaglet(new ThrowsTaglet(configuration), EXCEPTION);
|
addStandardTaglet(new ThrowsTaglet(config), EXCEPTION);
|
||||||
addStandardTaglet(
|
addStandardTaglet(
|
||||||
new SimpleTaglet(SINCE, resources.getText("doclet.Since"),
|
new SimpleTaglet(config, SINCE, resources.getText("doclet.Since"),
|
||||||
EnumSet.allOf(Location.class), !nosince));
|
EnumSet.allOf(Location.class), !nosince));
|
||||||
addStandardTaglet(
|
addStandardTaglet(
|
||||||
new SimpleTaglet(VERSION, resources.getText("doclet.Version"),
|
new SimpleTaglet(config, VERSION, resources.getText("doclet.Version"),
|
||||||
EnumSet.of(Location.OVERVIEW, Location.MODULE, Location.PACKAGE, Location.TYPE), showversion));
|
EnumSet.of(Location.OVERVIEW, Location.MODULE, Location.PACKAGE, Location.TYPE), showversion));
|
||||||
addStandardTaglet(
|
addStandardTaglet(
|
||||||
new SimpleTaglet(AUTHOR, resources.getText("doclet.Author"),
|
new SimpleTaglet(config, AUTHOR, resources.getText("doclet.Author"),
|
||||||
EnumSet.of(Location.OVERVIEW, Location.MODULE, Location.PACKAGE, Location.TYPE), showauthor));
|
EnumSet.of(Location.OVERVIEW, Location.MODULE, Location.PACKAGE, Location.TYPE), showauthor));
|
||||||
addStandardTaglet(
|
addStandardTaglet(
|
||||||
new SimpleTaglet(SERIAL_DATA, resources.getText("doclet.SerialData"),
|
new SimpleTaglet(config, SERIAL_DATA, resources.getText("doclet.SerialData"),
|
||||||
EnumSet.noneOf(Location.class)));
|
EnumSet.noneOf(Location.class)));
|
||||||
addStandardTaglet(
|
addStandardTaglet(
|
||||||
new SimpleTaglet(HIDDEN, null,
|
new SimpleTaglet(config, HIDDEN, null,
|
||||||
EnumSet.of(Location.TYPE, Location.METHOD, Location.FIELD)));
|
EnumSet.of(Location.TYPE, Location.METHOD, Location.FIELD)));
|
||||||
|
|
||||||
// This appears to be a default custom (non-standard) taglet
|
// This appears to be a default custom (non-standard) taglet
|
||||||
Taglet factoryTaglet = new SimpleTaglet("factory", resources.getText("doclet.Factory"),
|
Taglet factoryTaglet = new SimpleTaglet(config, "factory", resources.getText("doclet.Factory"),
|
||||||
EnumSet.of(Location.METHOD));
|
EnumSet.of(Location.METHOD));
|
||||||
allTaglets.put(factoryTaglet.getName(), factoryTaglet);
|
allTaglets.put(factoryTaglet.getName(), factoryTaglet);
|
||||||
|
|
||||||
addStandardTaglet(new SeeTaglet());
|
addStandardTaglet(new SeeTaglet(config));
|
||||||
addStandardTaglet(new SpecTaglet());
|
addStandardTaglet(new SpecTaglet(config));
|
||||||
|
|
||||||
// Standard inline tags
|
// Standard inline tags
|
||||||
addStandardTaglet(new DocRootTaglet());
|
addStandardTaglet(new DocRootTaglet(config));
|
||||||
addStandardTaglet(new InheritDocTaglet());
|
addStandardTaglet(new InheritDocTaglet(config));
|
||||||
addStandardTaglet(new ValueTaglet());
|
addStandardTaglet(new ValueTaglet(config));
|
||||||
addStandardTaglet(new LiteralTaglet());
|
addStandardTaglet(new LinkTaglet(config, DocTree.Kind.LINK));
|
||||||
addStandardTaglet(new CodeTaglet());
|
addStandardTaglet(new LinkTaglet(config, DocTree.Kind.LINK_PLAIN));
|
||||||
addStandardTaglet(new SnippetTaglet());
|
addStandardTaglet(new LiteralTaglet(config, DocTree.Kind.CODE));
|
||||||
addStandardTaglet(new IndexTaglet());
|
addStandardTaglet(new LiteralTaglet(config, DocTree.Kind.LITERAL));
|
||||||
addStandardTaglet(new SummaryTaglet());
|
addStandardTaglet(new SnippetTaglet(config));
|
||||||
addStandardTaglet(new SystemPropertyTaglet());
|
addStandardTaglet(new IndexTaglet(config));
|
||||||
|
addStandardTaglet(new SummaryTaglet(config));
|
||||||
|
addStandardTaglet(new SystemPropertyTaglet(config));
|
||||||
|
|
||||||
// Keep track of the names of standard tags for error checking purposes.
|
// Keep track of the names of standard tags for error checking purposes.
|
||||||
// The following are not handled above.
|
// The following are not handled above.
|
||||||
addStandardTaglet(new DeprecatedTaglet());
|
addStandardTaglet(new DeprecatedTaglet(config));
|
||||||
addStandardTaglet(new BaseTaglet(LINK, true, EnumSet.allOf(Location.class)));
|
addStandardTaglet(new BaseTaglet(config, USES, false, EnumSet.of(jdk.javadoc.doclet.Taglet.Location.MODULE)));
|
||||||
addStandardTaglet(new BaseTaglet(LINK_PLAIN, true, EnumSet.allOf(Location.class)));
|
addStandardTaglet(new BaseTaglet(config, PROVIDES, false, EnumSet.of(jdk.javadoc.doclet.Taglet.Location.MODULE)));
|
||||||
addStandardTaglet(new BaseTaglet(USES, false, EnumSet.of(Location.MODULE)));
|
|
||||||
addStandardTaglet(new BaseTaglet(PROVIDES, false, EnumSet.of(Location.MODULE)));
|
|
||||||
addStandardTaglet(
|
addStandardTaglet(
|
||||||
new SimpleTaglet(SERIAL, null,
|
new SimpleTaglet(config, SERIAL, null,
|
||||||
EnumSet.of(Location.PACKAGE, Location.TYPE, Location.FIELD)));
|
EnumSet.of(jdk.javadoc.doclet.Taglet.Location.PACKAGE, jdk.javadoc.doclet.Taglet.Location.TYPE, jdk.javadoc.doclet.Taglet.Location.FIELD)));
|
||||||
addStandardTaglet(
|
addStandardTaglet(
|
||||||
new SimpleTaglet(SERIAL_FIELD, null, EnumSet.of(Location.FIELD)));
|
new SimpleTaglet(config, SERIAL_FIELD, null, EnumSet.of(jdk.javadoc.doclet.Taglet.Location.FIELD)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize JavaFX-related tags.
|
* Initialize JavaFX-related tags.
|
||||||
*/
|
*/
|
||||||
private void initJavaFXTaglets() {
|
private void initJavaFXTaglets() {
|
||||||
addStandardTaglet(new SimpleTaglet("propertyDescription",
|
addStandardTaglet(new SimpleTaglet(config, "propertyDescription",
|
||||||
resources.getText("doclet.PropertyDescription"),
|
resources.getText("doclet.PropertyDescription"),
|
||||||
EnumSet.of(Location.METHOD, Location.FIELD)));
|
EnumSet.of(jdk.javadoc.doclet.Taglet.Location.METHOD, jdk.javadoc.doclet.Taglet.Location.FIELD)));
|
||||||
addStandardTaglet(new SimpleTaglet("defaultValue", resources.getText("doclet.DefaultValue"),
|
addStandardTaglet(new SimpleTaglet(config, "defaultValue", resources.getText("doclet.DefaultValue"),
|
||||||
EnumSet.of(Location.METHOD, Location.FIELD)));
|
EnumSet.of(jdk.javadoc.doclet.Taglet.Location.METHOD, jdk.javadoc.doclet.Taglet.Location.FIELD)));
|
||||||
addStandardTaglet(new SimpleTaglet("treatAsPrivate", null,
|
addStandardTaglet(new SimpleTaglet(config, "treatAsPrivate", null,
|
||||||
EnumSet.of(Location.TYPE, Location.METHOD, Location.FIELD)));
|
EnumSet.of(jdk.javadoc.doclet.Taglet.Location.TYPE, jdk.javadoc.doclet.Taglet.Location.METHOD, jdk.javadoc.doclet.Taglet.Location.FIELD)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addStandardTaglet(Taglet taglet) {
|
private void addStandardTaglet(Taglet taglet) {
|
||||||
@ -711,6 +710,14 @@ public class TagletManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Taglet getTaglet(DocTree.Kind kind) {
|
||||||
|
return switch (kind) {
|
||||||
|
case DEPRECATED, LINK, LINK_PLAIN, PARAM, RETURN, THROWS -> getTaglet(kind.tagName);
|
||||||
|
default ->
|
||||||
|
throw new IllegalArgumentException(kind.toString());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The output of this method is the basis for a table at the end of the
|
* The output of this method is the basis for a table at the end of the
|
||||||
* doc comment specification, so any changes in the output may indicate
|
* doc comment specification, so any changes in the output may indicate
|
||||||
@ -732,7 +739,7 @@ public class TagletManager {
|
|||||||
+ format(t.inMethod(), "method") + " "
|
+ format(t.inMethod(), "method") + " "
|
||||||
+ format(t.inField(), "field") + " "
|
+ format(t.inField(), "field") + " "
|
||||||
+ format(t.isInlineTag(), "inline")+ " "
|
+ format(t.isInlineTag(), "inline")+ " "
|
||||||
+ format((t instanceof SimpleTaglet st) && !st.enabled, "disabled"));
|
+ format((t instanceof SimpleTaglet st) && !st.isEnabled(), "disabled"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,474 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2003, 2023, 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.ElementKind;
|
||||||
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
import javax.lang.model.element.ModuleElement;
|
||||||
|
import javax.lang.model.element.PackageElement;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.lang.model.element.VariableElement;
|
||||||
|
import javax.lang.model.util.SimpleElementVisitor14;
|
||||||
|
|
||||||
|
import com.sun.source.doctree.DocTree;
|
||||||
|
|
||||||
|
import com.sun.source.doctree.InlineTagTree;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlDocletWriter;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlIds;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlOptions;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.taglets.Taglet.UnsupportedTagletOperationException;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.DocletElement;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.IndexItem;
|
||||||
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context and utility methods for taglet classes.
|
||||||
|
*/
|
||||||
|
public class TagletWriter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that provides the information about the enclosing context for
|
||||||
|
* a series of {@code DocTree} nodes.
|
||||||
|
* This context may be used to determine the content that should be generated from the tree nodes.
|
||||||
|
*/
|
||||||
|
public static class Context {
|
||||||
|
/**
|
||||||
|
* Whether the trees are appearing in a context of just the first sentence,
|
||||||
|
* such as in the summary table of the enclosing element.
|
||||||
|
*/
|
||||||
|
public final boolean isFirstSentence;
|
||||||
|
/**
|
||||||
|
* Whether the trees are appearing in the "summary" section of the
|
||||||
|
* page for a declaration.
|
||||||
|
*/
|
||||||
|
public final boolean inSummary;
|
||||||
|
/**
|
||||||
|
* The set of enclosing kinds of tags.
|
||||||
|
*/
|
||||||
|
public final Set<DocTree.Kind> inTags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an outermost context, with no enclosing tags.
|
||||||
|
*
|
||||||
|
* @param isFirstSentence {@code true} if the trees are appearing in a context of just the
|
||||||
|
* first sentence and {@code false} otherwise
|
||||||
|
* @param inSummary {@code true} if the trees are appearing in the "summary" section
|
||||||
|
* of the page for a declaration and {@code false} otherwise
|
||||||
|
*/
|
||||||
|
public Context(boolean isFirstSentence, boolean inSummary) {
|
||||||
|
this(isFirstSentence, inSummary, EnumSet.noneOf(DocTree.Kind.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context(boolean isFirstSentence, boolean inSummary, Set<DocTree.Kind> inTags) {
|
||||||
|
this.isFirstSentence = isFirstSentence;
|
||||||
|
this.inSummary = inSummary;
|
||||||
|
this.inTags = inTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@code Context} that includes an extra tag kind in the set of enclosing
|
||||||
|
* kinds of tags.
|
||||||
|
*
|
||||||
|
* @param tree the enclosing tree
|
||||||
|
*
|
||||||
|
* @return the new {@code Context}
|
||||||
|
*/
|
||||||
|
public Context within(DocTree tree) {
|
||||||
|
var newInTags = EnumSet.copyOf(inTags);
|
||||||
|
newInTags.add(tree.getKind());
|
||||||
|
return new Context(isFirstSentence, inSummary, newInTags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final HtmlDocletWriter htmlWriter;
|
||||||
|
public final HtmlConfiguration configuration;
|
||||||
|
public final HtmlOptions options;
|
||||||
|
public final Utils utils;
|
||||||
|
public final Resources resources;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The context in which to generate the output for a series of {@code DocTree} nodes.
|
||||||
|
*/
|
||||||
|
public final Context context;
|
||||||
|
/**
|
||||||
|
* Creates a taglet writer.
|
||||||
|
*
|
||||||
|
* @param htmlWriter the {@code HtmlDocletWriter} for the page
|
||||||
|
* @param isFirstSentence {@code true} if this taglet writer is being used for a
|
||||||
|
* "first sentence" summary
|
||||||
|
*/
|
||||||
|
public TagletWriter(HtmlDocletWriter htmlWriter, boolean isFirstSentence) {
|
||||||
|
this(htmlWriter, isFirstSentence, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a taglet writer.
|
||||||
|
*
|
||||||
|
* @param htmlWriter the {@code HtmlDocletWriter} for the page
|
||||||
|
* @param isFirstSentence {@code true} if this taglet writer is being used for a
|
||||||
|
* "first sentence" summary, and {@code false} otherwise
|
||||||
|
* @param inSummary {@code true} if this taglet writer is being used for the content
|
||||||
|
* of a {@code {@summary ...}} tag, and {@code false} otherwise
|
||||||
|
*/
|
||||||
|
public TagletWriter(HtmlDocletWriter htmlWriter, boolean isFirstSentence, boolean inSummary) {
|
||||||
|
this(htmlWriter, new Context(isFirstSentence, inSummary));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a taglet writer.
|
||||||
|
*
|
||||||
|
* @param htmlWriter the {@code HtmlDocletWriter} for the page
|
||||||
|
* @param context the enclosing context for any tags
|
||||||
|
*/
|
||||||
|
public TagletWriter(HtmlDocletWriter htmlWriter, Context context) {
|
||||||
|
this.htmlWriter = Objects.requireNonNull(htmlWriter);
|
||||||
|
this.context = Objects.requireNonNull(context);
|
||||||
|
configuration = htmlWriter.configuration;
|
||||||
|
options = configuration.getOptions();
|
||||||
|
utils = configuration.utils;
|
||||||
|
resources = configuration.getDocResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Context getContext() {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an instance of an output object.
|
||||||
|
*
|
||||||
|
* @return an instance of an output object
|
||||||
|
*/
|
||||||
|
public Content getOutputInstance() {
|
||||||
|
return new ContentBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output for an invalid tag. The returned content uses special styling to
|
||||||
|
* highlight the problem. Depending on the presence of the {@code detail} string the method
|
||||||
|
* returns a plain text span or an expandable component.
|
||||||
|
*
|
||||||
|
* @param summary the single-line summary message
|
||||||
|
* @param detail the optional detail message which may contain preformatted text
|
||||||
|
* @return the output
|
||||||
|
*/
|
||||||
|
public Content invalidTagOutput(String summary, Optional<String> detail) {
|
||||||
|
return htmlWriter.invalidTagOutput(summary,
|
||||||
|
detail.isEmpty() || detail.get().isEmpty()
|
||||||
|
? Optional.empty()
|
||||||
|
: Optional.of(Text.of(Text.normalizeNewlines(detail.get()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the main type element of the current page or null for pages that don't have one.
|
||||||
|
*
|
||||||
|
* @return the type element of the current page or null.
|
||||||
|
*/
|
||||||
|
public TypeElement getCurrentPageElement() {
|
||||||
|
return htmlWriter.getCurrentPageElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content generated from the block tags for a given element.
|
||||||
|
* The content is generated according to the order of the list of taglets.
|
||||||
|
* The result is a possibly-empty list of the output generated by each
|
||||||
|
* of the given taglets for all of the tags they individually support.
|
||||||
|
*
|
||||||
|
* @param tagletManager the manager that manages the taglets
|
||||||
|
* @param element the element that we are to write tags for
|
||||||
|
* @param taglets the taglets for the tags to write
|
||||||
|
*
|
||||||
|
* @return the content
|
||||||
|
*/
|
||||||
|
public Content getBlockTagOutput(TagletManager tagletManager,
|
||||||
|
Element element,
|
||||||
|
List<Taglet> taglets) {
|
||||||
|
for (Taglet t : taglets) {
|
||||||
|
if (!t.isBlockTag()) {
|
||||||
|
throw new IllegalArgumentException(t.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Content output = getOutputInstance();
|
||||||
|
tagletManager.checkTags(element, utils.getBlockTags(element));
|
||||||
|
tagletManager.checkTags(element, utils.getFullBody(element));
|
||||||
|
for (Taglet taglet : taglets) {
|
||||||
|
if (utils.isTypeElement(element) && taglet instanceof ParamTaglet) {
|
||||||
|
// The type parameters and state components are documented in a special
|
||||||
|
// section away from the tag info, so skip here.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.getKind() == ElementKind.MODULE && taglet instanceof BaseTaglet t) {
|
||||||
|
switch (t.getTagKind()) {
|
||||||
|
// @uses and @provides are handled separately, so skip here.
|
||||||
|
// See ModuleWriterImpl.computeModulesData
|
||||||
|
case USES:
|
||||||
|
case PROVIDES:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (taglet instanceof DeprecatedTaglet) {
|
||||||
|
//Deprecated information is documented "inline", not in tag info
|
||||||
|
//section.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (taglet instanceof SimpleTaglet st && !st.isEnabled()) {
|
||||||
|
// taglet has been disabled
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Content tagletOutput = taglet.getAllBlockTagOutput(element, this);
|
||||||
|
if (tagletOutput != null) {
|
||||||
|
tagletManager.seenTag(taglet.getName());
|
||||||
|
output.add(tagletOutput);
|
||||||
|
}
|
||||||
|
} catch (UnsupportedTagletOperationException e) {
|
||||||
|
// malformed taglet:
|
||||||
|
// claims to support block tags (see Taglet.isBlockTag) but does not provide the
|
||||||
|
// appropriate method, Taglet.getAllBlockTagOutput.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content generated from an inline tag in the doc comment for a given element,
|
||||||
|
* or {@code null} if the tag is not supported or does not return any output.
|
||||||
|
*
|
||||||
|
* @param holder the element associated with the doc comment
|
||||||
|
* @param inlineTag the inline tag to be documented
|
||||||
|
*
|
||||||
|
* @return the content, or {@code null}
|
||||||
|
*/
|
||||||
|
public Content getInlineTagOutput(Element holder,
|
||||||
|
InlineTagTree inlineTag) {
|
||||||
|
var tagletManager = configuration.tagletManager;
|
||||||
|
Map<String, Taglet> inlineTags = tagletManager.getInlineTaglets();
|
||||||
|
CommentHelper ch = configuration.utils.getCommentHelper(holder);
|
||||||
|
final String inlineTagName = ch.getTagName(inlineTag);
|
||||||
|
Taglet t = inlineTags.get(inlineTagName);
|
||||||
|
if (t == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Content tagletOutput = t.getInlineTagOutput(holder, inlineTag, this);
|
||||||
|
tagletManager.seenTag(t.getName());
|
||||||
|
return tagletOutput;
|
||||||
|
} catch (UnsupportedTagletOperationException e) {
|
||||||
|
// malformed taglet:
|
||||||
|
// claims to support inline tags (see Taglet.isInlineTag) but does not provide the
|
||||||
|
// appropriate method, Taglet.getInlineTagOutput.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts inline tags and text to content, expanding the
|
||||||
|
* inline tags along the way. Called wherever text can contain
|
||||||
|
* an inline tag, such as in comments or in free-form text arguments
|
||||||
|
* to block tags.
|
||||||
|
*
|
||||||
|
* @param holderTree the tree that holds the documentation
|
||||||
|
* @param trees list of {@code DocTree} nodes containing text and inline tags (often alternating)
|
||||||
|
* present in the text of interest for this doc
|
||||||
|
*
|
||||||
|
* @return the generated content
|
||||||
|
*/
|
||||||
|
public Content commentTagsToOutput(DocTree holderTree, List<? extends DocTree> trees) {
|
||||||
|
return commentTagsToOutput(null, holderTree, trees, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts inline tags and text to content, expanding the
|
||||||
|
* inline tags along the way. Called wherever text can contain
|
||||||
|
* an inline tag, such as in comments or in free-form text arguments
|
||||||
|
* to block tags.
|
||||||
|
*
|
||||||
|
* @param element The element that owns the documentation
|
||||||
|
* @param trees list of {@code DocTree} nodes containing text and inline tags (often alternating)
|
||||||
|
* present in the text of interest for this doc
|
||||||
|
*
|
||||||
|
* @return the generated content
|
||||||
|
*/
|
||||||
|
public Content commentTagsToOutput(Element element, List<? extends DocTree> trees) {
|
||||||
|
return commentTagsToOutput(element, null, trees, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts inline tags and text to content, expanding the
|
||||||
|
* inline tags along the way. Called wherever text can contain
|
||||||
|
* an inline tag, such as in comments or in free-form text arguments
|
||||||
|
* to non-inline tags.
|
||||||
|
*
|
||||||
|
* @param element the element where comment resides
|
||||||
|
* @param holder the tag that holds the documentation
|
||||||
|
* @param trees array of text tags and inline tags (often alternating)
|
||||||
|
* present in the text of interest for this doc
|
||||||
|
* @param isFirstSentence true if this is the first sentence
|
||||||
|
*
|
||||||
|
* @return the generated content
|
||||||
|
*/
|
||||||
|
public Content commentTagsToOutput(Element element,
|
||||||
|
DocTree holder,
|
||||||
|
List<? extends DocTree> trees,
|
||||||
|
boolean isFirstSentence)
|
||||||
|
{
|
||||||
|
return htmlWriter.commentTagsToContent(element,
|
||||||
|
trees, holder == null ? context : context.within(holder));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Content createAnchorAndSearchIndex(Element element, String tagText, String desc, DocTree tree) {
|
||||||
|
return createAnchorAndSearchIndex(element, tagText, Text.of(tagText), desc, tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("preview")
|
||||||
|
Content createAnchorAndSearchIndex(Element element, String tagText, Content tagContent, String desc, DocTree tree) {
|
||||||
|
Content result;
|
||||||
|
if (context.isFirstSentence && context.inSummary || context.inTags.contains(DocTree.Kind.INDEX)) {
|
||||||
|
result = tagContent;
|
||||||
|
} else {
|
||||||
|
HtmlId id = HtmlIds.forText(tagText, htmlWriter.indexAnchorTable);
|
||||||
|
result = HtmlTree.SPAN(id, HtmlStyle.searchTagResult, tagContent);
|
||||||
|
if (options.createIndex() && !tagText.isEmpty()) {
|
||||||
|
String holder = getHolderName(element);
|
||||||
|
IndexItem item = IndexItem.of(element, tree, tagText, holder, desc,
|
||||||
|
new DocLink(htmlWriter.path, id.name()));
|
||||||
|
configuration.mainIndex.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHolderName(Element element) {
|
||||||
|
return new SimpleElementVisitor14<String, Void>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String visitModule(ModuleElement e, Void p) {
|
||||||
|
return resources.getText("doclet.module")
|
||||||
|
+ " " + utils.getFullyQualifiedName(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String visitPackage(PackageElement e, Void p) {
|
||||||
|
return resources.getText("doclet.package")
|
||||||
|
+ " " + utils.getFullyQualifiedName(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String visitType(TypeElement e, Void p) {
|
||||||
|
return utils.getTypeElementKindName(e, true)
|
||||||
|
+ " " + utils.getFullyQualifiedName(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String visitExecutable(ExecutableElement e, Void p) {
|
||||||
|
return utils.getFullyQualifiedName(utils.getEnclosingTypeElement(e))
|
||||||
|
+ "." + utils.getSimpleName(e)
|
||||||
|
+ utils.flatSignature(e, htmlWriter.getCurrentPageElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String visitVariable(VariableElement e, Void p) {
|
||||||
|
return utils.getFullyQualifiedName(utils.getEnclosingTypeElement(e))
|
||||||
|
+ "." + utils.getSimpleName(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String visitUnknown(Element e, Void p) {
|
||||||
|
if (e instanceof DocletElement de) {
|
||||||
|
return switch (de.getSubKind()) {
|
||||||
|
case OVERVIEW -> resources.getText("doclet.Overview");
|
||||||
|
case DOCFILE -> getHolderName(de);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return super.visitUnknown(e, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String defaultAction(Element e, Void p) {
|
||||||
|
return utils.getFullyQualifiedName(e);
|
||||||
|
}
|
||||||
|
}.visit(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getHolderName(DocletElement de) {
|
||||||
|
PackageElement pe = de.getPackageElement();
|
||||||
|
if (pe.isUnnamed()) {
|
||||||
|
// if package is unnamed use enclosing module only if it is named
|
||||||
|
Element ee = pe.getEnclosingElement();
|
||||||
|
if (ee instanceof ModuleElement && !((ModuleElement)ee).isUnnamed()) {
|
||||||
|
return resources.getText("doclet.module") + " " + utils.getFullyQualifiedName(ee);
|
||||||
|
}
|
||||||
|
return pe.toString(); // "Unnamed package" or similar
|
||||||
|
}
|
||||||
|
return resources.getText("doclet.package") + " " + utils.getFullyQualifiedName(pe);
|
||||||
|
}
|
||||||
|
|
||||||
|
Content tagList(List<Content> items) {
|
||||||
|
// Use a different style if any list item is longer than 30 chars or contains commas.
|
||||||
|
boolean hasLongLabels = items.stream().anyMatch(this::isLongOrHasComma);
|
||||||
|
var list = HtmlTree.UL(hasLongLabels ? HtmlStyle.tagListLong : HtmlStyle.tagList);
|
||||||
|
items.stream()
|
||||||
|
.filter(Predicate.not(Content::isEmpty))
|
||||||
|
.forEach(item -> list.add(HtmlTree.LI(item)));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Threshold for length of list item for switching from inline to block layout.
|
||||||
|
private static final int TAG_LIST_ITEM_MAX_INLINE_LENGTH = 30;
|
||||||
|
|
||||||
|
private boolean isLongOrHasComma(Content c) {
|
||||||
|
String s = c.toString()
|
||||||
|
.replaceAll("<.*?>", "") // ignore HTML
|
||||||
|
.replaceAll("&#?[A-Za-z0-9]+;", " ") // entities count as a single character
|
||||||
|
.replaceAll("\\R", "\n"); // normalize newlines
|
||||||
|
return s.length() > TAG_LIST_ITEM_MAX_INLINE_LENGTH || s.contains(",");
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
@ -53,13 +53,14 @@ import com.sun.source.doctree.DocTree;
|
|||||||
import com.sun.source.doctree.InheritDocTree;
|
import com.sun.source.doctree.InheritDocTree;
|
||||||
import com.sun.source.doctree.ThrowsTree;
|
import com.sun.source.doctree.ThrowsTree;
|
||||||
|
|
||||||
import com.sun.source.util.DocTreePath;
|
import jdk.javadoc.doclet.Taglet;
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
import jdk.javadoc.internal.doclets.formats.html.Contents;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo;
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
|
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
|
||||||
|
|
||||||
@ -156,19 +157,19 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
* mA as a member of the supertype of C that names A.
|
* mA as a member of the supertype of C that names A.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public ThrowsTaglet(BaseConfiguration configuration) {
|
private final HtmlConfiguration config;
|
||||||
|
private final Contents contents;
|
||||||
|
|
||||||
|
ThrowsTaglet(HtmlConfiguration config) {
|
||||||
// of all language elements only constructors and methods can declare
|
// of all language elements only constructors and methods can declare
|
||||||
// thrown exceptions and, hence, document them
|
// thrown exceptions and, hence, document them
|
||||||
super(DocTree.Kind.THROWS, false, EnumSet.of(Location.CONSTRUCTOR, Location.METHOD));
|
super(config, DocTree.Kind.THROWS, false, EnumSet.of(Taglet.Location.CONSTRUCTOR, Taglet.Location.METHOD));
|
||||||
this.configuration = configuration;
|
this.config = config;
|
||||||
this.utils = this.configuration.utils;
|
contents = config.contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final BaseConfiguration configuration;
|
|
||||||
private final Utils utils;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence, BaseConfiguration configuration) {
|
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence) {
|
||||||
// This method shouldn't be called because {@inheritDoc} tags inside
|
// This method shouldn't be called because {@inheritDoc} tags inside
|
||||||
// exception tags aren't dealt with individually. {@inheritDoc} tags
|
// exception tags aren't dealt with individually. {@inheritDoc} tags
|
||||||
// inside exception tags are collectively dealt with in
|
// inside exception tags are collectively dealt with in
|
||||||
@ -177,13 +178,13 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
|
public Content getAllBlockTagOutput(Element holder, TagletWriter tagletWriter) {
|
||||||
|
this.tagletWriter = tagletWriter;
|
||||||
try {
|
try {
|
||||||
return getAllBlockTagOutput0(holder, writer);
|
return getAllBlockTagOutput0(holder);
|
||||||
} catch (Failure f) {
|
} catch (Failure f) {
|
||||||
// note that `f.holder()` is not necessarily the same as `holder`
|
// note that `f.holder()` is not necessarily the same as `holder`
|
||||||
var ch = utils.getCommentHelper(f.holder());
|
var ch = utils.getCommentHelper(f.holder());
|
||||||
var messages = configuration.getMessages();
|
|
||||||
if (f instanceof Failure.ExceptionTypeNotFound e) {
|
if (f instanceof Failure.ExceptionTypeNotFound e) {
|
||||||
var path = ch.getDocTreePath(e.tag().getExceptionName());
|
var path = ch.getDocTreePath(e.tag().getExceptionName());
|
||||||
messages.warning(path, "doclet.throws.reference_not_found");
|
messages.warning(path, "doclet.throws.reference_not_found");
|
||||||
@ -210,14 +211,13 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
// since {@inheritDoc} in @throws is processed by ThrowsTaglet (this taglet) rather than
|
// since {@inheritDoc} in @throws is processed by ThrowsTaglet (this taglet) rather than
|
||||||
// InheritDocTaglet, we have to duplicate some of the behavior of the latter taglet
|
// InheritDocTaglet, we have to duplicate some of the behavior of the latter taglet
|
||||||
String signature = utils.getSimpleName(holder)
|
String signature = utils.getSimpleName(holder)
|
||||||
+ utils.flatSignature((ExecutableElement) holder, writer.getCurrentPageElement());
|
+ utils.flatSignature((ExecutableElement) holder, tagletWriter.getCurrentPageElement());
|
||||||
configuration.getMessages().warning(holder, "doclet.noInheritedDoc", signature);
|
messages.warning(holder, "doclet.noInheritedDoc", signature);
|
||||||
}
|
}
|
||||||
return writer.getOutputInstance(); // TODO: consider invalid rather than empty output
|
return tagletWriter.getOutputInstance(); // TODO: consider invalid rather than empty output
|
||||||
}
|
}
|
||||||
|
|
||||||
private Content getAllBlockTagOutput0(Element holder,
|
private Content getAllBlockTagOutput0(Element holder)
|
||||||
TagletWriter writer)
|
|
||||||
throws Failure.ExceptionTypeNotFound,
|
throws Failure.ExceptionTypeNotFound,
|
||||||
Failure.NotExceptionType,
|
Failure.NotExceptionType,
|
||||||
Failure.Invalid,
|
Failure.Invalid,
|
||||||
@ -235,20 +235,20 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
}
|
}
|
||||||
var executable = (ExecutableElement) holder;
|
var executable = (ExecutableElement) holder;
|
||||||
ExecutableType instantiatedType = utils.asInstantiatedMethodType(
|
ExecutableType instantiatedType = utils.asInstantiatedMethodType(
|
||||||
writer.getCurrentPageElement(), executable);
|
tagletWriter.getCurrentPageElement(), executable);
|
||||||
List<? extends TypeMirror> substitutedExceptionTypes = instantiatedType.getThrownTypes();
|
List<? extends TypeMirror> substitutedExceptionTypes = instantiatedType.getThrownTypes();
|
||||||
List<? extends TypeMirror> originalExceptionTypes = executable.getThrownTypes();
|
List<? extends TypeMirror> originalExceptionTypes = executable.getThrownTypes();
|
||||||
Map<TypeMirror, TypeMirror> typeSubstitutions = getSubstitutedThrownTypes(
|
Map<TypeMirror, TypeMirror> typeSubstitutions = getSubstitutedThrownTypes(
|
||||||
utils.typeUtils,
|
utils.typeUtils,
|
||||||
originalExceptionTypes,
|
originalExceptionTypes,
|
||||||
substitutedExceptionTypes);
|
substitutedExceptionTypes);
|
||||||
var exceptionSection = new ExceptionSectionBuilder(writer);
|
var exceptionSection = new ExceptionSectionBuilder(tagletWriter, this);
|
||||||
// Step 1: Document exception tags
|
// Step 1: Document exception tags
|
||||||
Set<TypeMirror> alreadyDocumentedExceptions = new HashSet<>();
|
Set<TypeMirror> alreadyDocumentedExceptions = new HashSet<>();
|
||||||
List<ThrowsTree> exceptionTags = utils.getThrowsTrees(executable);
|
List<ThrowsTree> exceptionTags = utils.getThrowsTrees(executable);
|
||||||
for (ThrowsTree t : exceptionTags) {
|
for (ThrowsTree t : exceptionTags) {
|
||||||
Element exceptionElement = getExceptionType(t, executable);
|
Element exceptionElement = getExceptionType(t, executable);
|
||||||
outputAnExceptionTagDeeply(exceptionSection, exceptionElement, t, executable, alreadyDocumentedExceptions, typeSubstitutions, writer);
|
outputAnExceptionTagDeeply(exceptionSection, exceptionElement, t, executable, alreadyDocumentedExceptions, typeSubstitutions);
|
||||||
}
|
}
|
||||||
// Step 2: Document exception types from the `throws` clause (of a method)
|
// Step 2: Document exception types from the `throws` clause (of a method)
|
||||||
//
|
//
|
||||||
@ -277,7 +277,7 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (Map.Entry<ThrowsTree, ExecutableElement> e : r.entrySet()) {
|
for (Map.Entry<ThrowsTree, ExecutableElement> e : r.entrySet()) {
|
||||||
outputAnExceptionTagDeeply(exceptionSection, exceptionElement, e.getKey(), e.getValue(), alreadyDocumentedExceptions, typeSubstitutions, writer);
|
outputAnExceptionTagDeeply(exceptionSection, exceptionElement, e.getKey(), e.getValue(), alreadyDocumentedExceptions, typeSubstitutions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,13 +299,41 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
return exceptionSection.build();
|
return exceptionSection.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the header for the {@code @throws} tag.
|
||||||
|
*
|
||||||
|
* @return the header for the throws tag
|
||||||
|
*/
|
||||||
|
private Content getThrowsHeader() {
|
||||||
|
return HtmlTree.DT(contents.throws_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output for a default {@code @throws} tag.
|
||||||
|
*
|
||||||
|
* @param throwsType the type that is thrown
|
||||||
|
* @param content the optional content to add as a description
|
||||||
|
*
|
||||||
|
* @return the output
|
||||||
|
*/
|
||||||
|
private Content throwsTagOutput(TypeMirror throwsType, Optional<Content> content) {
|
||||||
|
var htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
var linkInfo = new HtmlLinkInfo(config, HtmlLinkInfo.Kind.PLAIN, throwsType);
|
||||||
|
var link = htmlWriter.getLink(linkInfo);
|
||||||
|
var concat = new ContentBuilder(HtmlTree.CODE(link));
|
||||||
|
if (content.isPresent()) {
|
||||||
|
concat.add(" - ");
|
||||||
|
concat.add(content.get());
|
||||||
|
}
|
||||||
|
return HtmlTree.DD(concat);
|
||||||
|
}
|
||||||
|
|
||||||
private void outputAnExceptionTagDeeply(ExceptionSectionBuilder exceptionSection,
|
private void outputAnExceptionTagDeeply(ExceptionSectionBuilder exceptionSection,
|
||||||
Element originalExceptionElement,
|
Element originalExceptionElement,
|
||||||
ThrowsTree tag,
|
ThrowsTree tag,
|
||||||
ExecutableElement holder,
|
ExecutableElement holder,
|
||||||
Set<TypeMirror> alreadyDocumentedExceptions,
|
Set<TypeMirror> alreadyDocumentedExceptions,
|
||||||
Map<TypeMirror, TypeMirror> typeSubstitutions,
|
Map<TypeMirror, TypeMirror> typeSubstitutions)
|
||||||
TagletWriter writer)
|
|
||||||
throws Failure.ExceptionTypeNotFound,
|
throws Failure.ExceptionTypeNotFound,
|
||||||
Failure.NotExceptionType,
|
Failure.NotExceptionType,
|
||||||
Failure.Invalid,
|
Failure.Invalid,
|
||||||
@ -314,7 +342,7 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
Failure.NoOverrideFound,
|
Failure.NoOverrideFound,
|
||||||
DocFinder.NoOverriddenMethodFound
|
DocFinder.NoOverriddenMethodFound
|
||||||
{
|
{
|
||||||
outputAnExceptionTagDeeply(exceptionSection, originalExceptionElement, tag, holder, true, alreadyDocumentedExceptions, typeSubstitutions, writer);
|
outputAnExceptionTagDeeply(exceptionSection, originalExceptionElement, tag, holder, true, alreadyDocumentedExceptions, typeSubstitutions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void outputAnExceptionTagDeeply(ExceptionSectionBuilder exceptionSection,
|
private void outputAnExceptionTagDeeply(ExceptionSectionBuilder exceptionSection,
|
||||||
@ -323,8 +351,7 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
ExecutableElement holder,
|
ExecutableElement holder,
|
||||||
boolean beginNewEntry,
|
boolean beginNewEntry,
|
||||||
Set<TypeMirror> alreadyDocumentedExceptions,
|
Set<TypeMirror> alreadyDocumentedExceptions,
|
||||||
Map<TypeMirror, TypeMirror> typeSubstitutions,
|
Map<TypeMirror, TypeMirror> typeSubstitutions)
|
||||||
TagletWriter writer)
|
|
||||||
throws Failure.ExceptionTypeNotFound,
|
throws Failure.ExceptionTypeNotFound,
|
||||||
Failure.NotExceptionType,
|
Failure.NotExceptionType,
|
||||||
Failure.Invalid,
|
Failure.Invalid,
|
||||||
@ -355,7 +382,7 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
exceptionSection.beginEntry(exceptionType);
|
exceptionSection.beginEntry(exceptionType);
|
||||||
}
|
}
|
||||||
// append to the current entry
|
// append to the current entry
|
||||||
exceptionSection.continueEntry(writer.commentTagsToOutput(holder, description));
|
exceptionSection.continueEntry(tagletWriter.commentTagsToOutput(holder, description));
|
||||||
if (beginNewEntry) { // if added a new entry, end it
|
if (beginNewEntry) { // if added a new entry, end it
|
||||||
exceptionSection.endEntry();
|
exceptionSection.endEntry();
|
||||||
}
|
}
|
||||||
@ -373,7 +400,7 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
// if there's anything preceding {@inheritDoc}, assume an entry has been added before
|
// if there's anything preceding {@inheritDoc}, assume an entry has been added before
|
||||||
assert exceptionSection.debugEntryBegun();
|
assert exceptionSection.debugEntryBegun();
|
||||||
Content beforeInheritDoc = writer.commentTagsToOutput(holder, description.subList(0, i));
|
Content beforeInheritDoc = tagletWriter.commentTagsToOutput(holder, description.subList(0, i));
|
||||||
exceptionSection.continueEntry(beforeInheritDoc);
|
exceptionSection.continueEntry(beforeInheritDoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,7 +413,7 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
if (supertype == null) {
|
if (supertype == null) {
|
||||||
throw new Failure.NoOverrideFound(tag, holder, inheritDoc);
|
throw new Failure.NoOverrideFound(tag, holder, inheritDoc);
|
||||||
}
|
}
|
||||||
VisibleMemberTable visibleMemberTable = configuration.getVisibleMemberTable(supertype);
|
VisibleMemberTable visibleMemberTable = config.getVisibleMemberTable(supertype);
|
||||||
List<Element> methods = visibleMemberTable.getAllVisibleMembers(VisibleMemberTable.Kind.METHODS);
|
List<Element> methods = visibleMemberTable.getAllVisibleMembers(VisibleMemberTable.Kind.METHODS);
|
||||||
for (Element e : methods) {
|
for (Element e : methods) {
|
||||||
ExecutableElement m = (ExecutableElement) e;
|
ExecutableElement m = (ExecutableElement) e;
|
||||||
@ -422,11 +449,11 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
throw new Failure.Invalid(tag, holder);
|
throw new Failure.Invalid(tag, holder);
|
||||||
}
|
}
|
||||||
for (Map.Entry<ThrowsTree, ExecutableElement> e : tags.entrySet()) {
|
for (Map.Entry<ThrowsTree, ExecutableElement> e : tags.entrySet()) {
|
||||||
outputAnExceptionTagDeeply(exceptionSection, originalExceptionElement, e.getKey(), e.getValue(), addNewEntryRecursively, alreadyDocumentedExceptions, typeSubstitutions, writer);
|
outputAnExceptionTagDeeply(exceptionSection, originalExceptionElement, e.getKey(), e.getValue(), addNewEntryRecursively, alreadyDocumentedExceptions, typeSubstitutions);
|
||||||
}
|
}
|
||||||
// this might be an empty list, which is fine
|
// this might be an empty list, which is fine
|
||||||
if (!loneInheritDoc) {
|
if (!loneInheritDoc) {
|
||||||
Content afterInheritDoc = writer.commentTagsToOutput(holder, description.subList(i + 1, description.size()));
|
Content afterInheritDoc = tagletWriter.commentTagsToOutput(holder, description.subList(i + 1, description.size()));
|
||||||
exceptionSection.continueEntry(afterInheritDoc);
|
exceptionSection.continueEntry(afterInheritDoc);
|
||||||
}
|
}
|
||||||
if (add) {
|
if (add) {
|
||||||
@ -604,7 +631,7 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
return toResult(exceptionType, method, tags);
|
return toResult(exceptionType, method, tags);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Result<Map<ThrowsTree, ExecutableElement>> result;
|
DocFinder.Result<Map<ThrowsTree, ExecutableElement>> result;
|
||||||
try {
|
try {
|
||||||
if (src.isPresent()) {
|
if (src.isPresent()) {
|
||||||
result = utils.docFinder().search(src.get(), criterion);
|
result = utils.docFinder().search(src.get(), criterion);
|
||||||
@ -623,20 +650,20 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
} catch (Failure f) {
|
} catch (Failure f) {
|
||||||
throw newAssertionError(f);
|
throw newAssertionError(f);
|
||||||
}
|
}
|
||||||
if (result instanceof Result.Conclude<Map<ThrowsTree, ExecutableElement>> c) {
|
if (result instanceof DocFinder.Result.Conclude<Map<ThrowsTree, ExecutableElement>> c) {
|
||||||
return c.value();
|
return c.value();
|
||||||
}
|
}
|
||||||
return Map.of(); // an empty map is effectively ordered
|
return Map.of(); // an empty map is effectively ordered
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Result<Map<ThrowsTree, ExecutableElement>> toResult(Element target,
|
private static DocFinder.Result<Map<ThrowsTree, ExecutableElement>> toResult(Element target,
|
||||||
ExecutableElement holder,
|
ExecutableElement holder,
|
||||||
List<ThrowsTree> tags) {
|
List<ThrowsTree> tags) {
|
||||||
if (!tags.isEmpty()) {
|
if (!tags.isEmpty()) {
|
||||||
// if there are tags for the target exception type, conclude search successfully
|
// if there are tags for the target exception type, conclude search successfully
|
||||||
return Result.CONCLUDE(toExceptionTags(holder, tags));
|
return DocFinder.Result.CONCLUDE(toExceptionTags(holder, tags));
|
||||||
}
|
}
|
||||||
return Result.CONTINUE();
|
return DocFinder.Result.CONTINUE();
|
||||||
// TODO: reintroduce this back for JDK-8295800:
|
// TODO: reintroduce this back for JDK-8295800:
|
||||||
// if (holder.getThrownTypes().contains(target.asType())) {
|
// if (holder.getThrownTypes().contains(target.asType())) {
|
||||||
// // if there are no tags for the target exception type, BUT that type is
|
// // if there are no tags for the target exception type, BUT that type is
|
||||||
@ -694,14 +721,16 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
private static class ExceptionSectionBuilder {
|
private static class ExceptionSectionBuilder {
|
||||||
|
|
||||||
private final TagletWriter writer;
|
private final TagletWriter writer;
|
||||||
|
private final ThrowsTaglet taglet;
|
||||||
private final Content result;
|
private final Content result;
|
||||||
private ContentBuilder current;
|
private Content current;
|
||||||
private boolean began;
|
private boolean began;
|
||||||
private boolean headerAdded;
|
private boolean headerAdded;
|
||||||
private TypeMirror exceptionType;
|
private TypeMirror exceptionType;
|
||||||
|
|
||||||
ExceptionSectionBuilder(TagletWriter writer) {
|
ExceptionSectionBuilder(TagletWriter writer, ThrowsTaglet taglet) {
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
|
this.taglet = taglet;
|
||||||
this.result = writer.getOutputInstance();
|
this.result = writer.getOutputInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -710,7 +739,7 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
began = true;
|
began = true;
|
||||||
current = new ContentBuilder();
|
current = writer.getOutputInstance();
|
||||||
this.exceptionType = exceptionType;
|
this.exceptionType = exceptionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,9 +757,10 @@ public class ThrowsTaglet extends BaseTaglet implements InheritableTaglet {
|
|||||||
began = false;
|
began = false;
|
||||||
if (!headerAdded) {
|
if (!headerAdded) {
|
||||||
headerAdded = true;
|
headerAdded = true;
|
||||||
result.add(writer.getThrowsHeader());
|
result.add(taglet.getThrowsHeader());
|
||||||
}
|
}
|
||||||
result.add(writer.throwsTagOutput(exceptionType, current.isEmpty() ? Optional.empty() : Optional.of(current)));
|
result.add(taglet.throwsTagOutput(exceptionType,
|
||||||
|
current.isEmpty() ? Optional.empty() : Optional.of(current)));
|
||||||
current = null;
|
current = null;
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -31,11 +31,9 @@ import java.util.Set;
|
|||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
|
import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
|
||||||
|
|
||||||
import static jdk.javadoc.doclet.Taglet.Location.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A taglet wrapper, allows the public taglet {@link jdk.javadoc.doclet.Taglet}
|
* A taglet wrapper, allows the public taglet {@link jdk.javadoc.doclet.Taglet}
|
||||||
@ -45,7 +43,7 @@ public final class UserTaglet implements Taglet {
|
|||||||
|
|
||||||
private final jdk.javadoc.doclet.Taglet userTaglet;
|
private final jdk.javadoc.doclet.Taglet userTaglet;
|
||||||
|
|
||||||
public UserTaglet(jdk.javadoc.doclet.Taglet t) {
|
UserTaglet(jdk.javadoc.doclet.Taglet t) {
|
||||||
userTaglet = t;
|
userTaglet = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,41 +52,6 @@ public final class UserTaglet implements Taglet {
|
|||||||
return userTaglet.getAllowedLocations();
|
return userTaglet.getAllowedLocations();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean inField() {
|
|
||||||
return userTaglet.getAllowedLocations().contains(FIELD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean inConstructor() {
|
|
||||||
return userTaglet.getAllowedLocations().contains(CONSTRUCTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean inMethod() {
|
|
||||||
return userTaglet.getAllowedLocations().contains(METHOD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean inOverview() {
|
|
||||||
return userTaglet.getAllowedLocations().contains(OVERVIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean inModule() {
|
|
||||||
return userTaglet.getAllowedLocations().contains(MODULE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean inPackage() {
|
|
||||||
return userTaglet.getAllowedLocations().contains(PACKAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean inType() {
|
|
||||||
return userTaglet.getAllowedLocations().contains(TYPE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInlineTag() {
|
public boolean isInlineTag() {
|
||||||
return userTaglet.isInlineTag();
|
return userTaglet.isInlineTag();
|
||||||
@ -105,17 +68,17 @@ public final class UserTaglet implements Taglet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter writer) {
|
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter tagletWriter) {
|
||||||
Content output = writer.getOutputInstance();
|
Content output = tagletWriter.getOutputInstance();
|
||||||
output.add(RawHtml.of(userTaglet.toString(List.of(tag), element)));
|
output.add(RawHtml.of(userTaglet.toString(List.of(tag), element)));
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
|
public Content getAllBlockTagOutput(Element holder, TagletWriter tagletWriter) {
|
||||||
Content output = writer.getOutputInstance();
|
Content output = tagletWriter.getOutputInstance();
|
||||||
Utils utils = writer.configuration().utils;
|
var utils = tagletWriter.utils;
|
||||||
List<? extends DocTree> tags = utils.getBlockTags(holder, this);
|
List<? extends DocTree> tags = utils.getBlockTags(holder, getName());
|
||||||
if (!tags.isEmpty()) {
|
if (!tags.isEmpty()) {
|
||||||
String tagString = userTaglet.toString(tags, holder);
|
String tagString = userTaglet.toString(tags, holder);
|
||||||
if (tagString != null) {
|
if (tagString != null) {
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,23 +23,26 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.IllegalFormatException;
|
import java.util.IllegalFormatException;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.VariableElement;
|
import javax.lang.model.element.VariableElement;
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
import com.sun.source.doctree.DocTree;
|
||||||
import com.sun.source.doctree.TextTree;
|
import com.sun.source.doctree.TextTree;
|
||||||
import com.sun.source.doctree.ValueTree;
|
import com.sun.source.doctree.ValueTree;
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
|
import jdk.javadoc.doclet.Taglet;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo;
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Messages;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An inline taglet representing the value tag. This tag should only be used with
|
* An inline taglet representing the value tag. This tag should only be used with
|
||||||
@ -52,11 +55,8 @@ import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
|||||||
*/
|
*/
|
||||||
public class ValueTaglet extends BaseTaglet {
|
public class ValueTaglet extends BaseTaglet {
|
||||||
|
|
||||||
/**
|
ValueTaglet(HtmlConfiguration config) {
|
||||||
* Construct a new ValueTaglet.
|
super(config, DocTree.Kind.VALUE, true, EnumSet.allOf(Taglet.Location.class));
|
||||||
*/
|
|
||||||
public ValueTaglet() {
|
|
||||||
super(DocTree.Kind.VALUE, true, EnumSet.allOf(Location.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,11 +83,9 @@ public class ValueTaglet extends BaseTaglet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter writer) {
|
public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter tagletWriter) {
|
||||||
BaseConfiguration configuration = writer.configuration();
|
this.tagletWriter = tagletWriter;
|
||||||
Utils utils = configuration.utils;
|
VariableElement field = getVariableElement(holder, config, tag);
|
||||||
Messages messages = configuration.getMessages();
|
|
||||||
VariableElement field = getVariableElement(holder, configuration, tag);
|
|
||||||
if (field == null) {
|
if (field == null) {
|
||||||
if (tag.toString().isEmpty()) {
|
if (tag.toString().isEmpty()) {
|
||||||
//Invalid use of @value
|
//Invalid use of @value
|
||||||
@ -107,25 +105,40 @@ public class ValueTaglet extends BaseTaglet {
|
|||||||
f = f.substring(1, f.length() - 1);
|
f = f.substring(1, f.length() - 1);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
text = String.format(configuration.getLocale(), f, field.getConstantValue());
|
text = String.format(config.getLocale(), f, field.getConstantValue());
|
||||||
} catch (IllegalFormatException e) {
|
} catch (IllegalFormatException e) {
|
||||||
messages.error(holder,
|
messages.error(holder,
|
||||||
"doclet.value_tag_invalid_format", format);
|
"doclet.value_tag_invalid_format", format);
|
||||||
return writer.invalidTagOutput(
|
return tagletWriter.invalidTagOutput(
|
||||||
messages.getResources().getText("doclet.value_tag_invalid_format", format),
|
messages.getResources().getText("doclet.value_tag_invalid_format", format),
|
||||||
Optional.empty());
|
Optional.empty());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
text = utils.constantValueExpression(field);
|
text = utils.constantValueExpression(field);
|
||||||
}
|
}
|
||||||
return writer.valueTagOutput(field,
|
return valueTagOutput(field, text, !field.equals(holder));
|
||||||
text,
|
|
||||||
!field.equals(holder));
|
|
||||||
} else {
|
} else {
|
||||||
//Referenced field is not a constant.
|
//Referenced field is not a constant.
|
||||||
messages.warning(holder,
|
messages.warning(holder,
|
||||||
"doclet.value_tag_invalid_constant", utils.getSimpleName(field));
|
"doclet.value_tag_invalid_constant", utils.getSimpleName(field));
|
||||||
}
|
}
|
||||||
return writer.getOutputInstance();
|
return tagletWriter.getOutputInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the output for a {@code {@value}} tag.
|
||||||
|
*
|
||||||
|
* @param field the constant field that holds the value tag
|
||||||
|
* @param constantVal the constant value to document
|
||||||
|
* @param includeLink true if we should link the constant text to the
|
||||||
|
* constant field itself
|
||||||
|
*
|
||||||
|
* @return the output
|
||||||
|
*/
|
||||||
|
private Content valueTagOutput(VariableElement field, String constantVal, boolean includeLink) {
|
||||||
|
var htmlWriter = tagletWriter.htmlWriter;
|
||||||
|
return includeLink
|
||||||
|
? htmlWriter.getDocLink(HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS, field, constantVal)
|
||||||
|
: Text.of(constantVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,29 +23,21 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
|
||||||
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
|
||||||
import com.sun.source.doctree.IndexTree;
|
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An inline taglet used to index a word or a phrase.
|
* Classes used to build the output for documentation comment tags.
|
||||||
* The enclosed text is interpreted as not containing HTML markup or
|
*
|
||||||
* nested javadoc tags.
|
* Tags are either inline tags, meaning they can be used within a
|
||||||
|
* sentence or phrase, or are block tags, meaning that they provide
|
||||||
|
* additional details that follow the main description in a comment.
|
||||||
|
* Taglets model that distinction.
|
||||||
|
*
|
||||||
|
* Inline tags are always processed individually, within the surrounding
|
||||||
|
* context. In general, inline tags always generate some (non-empty) output,
|
||||||
|
* even if the output is some form indicating an error. It is almost never
|
||||||
|
* correct to not generate any output to place between the parts of the
|
||||||
|
* comment that come before and after the tag in the underlying comment.
|
||||||
|
*
|
||||||
|
* Conversely, block tags of any given kind are always processed as a
|
||||||
|
* group, even if they do not appear contiguously in the underlying comment.
|
||||||
*/
|
*/
|
||||||
public class IndexTaglet extends BaseTaglet {
|
package jdk.javadoc.internal.doclets.formats.html.taglets;
|
||||||
|
|
||||||
IndexTaglet() {
|
|
||||||
super(DocTree.Kind.INDEX, true, EnumSet.allOf(Location.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter writer) {
|
|
||||||
return writer.indexTagOutput(element, (IndexTree) tag);
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets.snippet;
|
package jdk.javadoc.internal.doclets.formats.html.taglets.snippet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An action described by markup. Such an action is typically an opaque compound
|
* An action described by markup. Such an action is typically an opaque compound
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets.snippet;
|
package jdk.javadoc.internal.doclets.formats.html.taglets.snippet;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets.snippet;
|
package jdk.javadoc.internal.doclets.formats.html.taglets.snippet;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets.snippet;
|
package jdk.javadoc.internal.doclets.formats.html.taglets.snippet;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets.snippet;
|
package jdk.javadoc.internal.doclets.formats.html.taglets.snippet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An action that associates text with a name.
|
* An action that associates text with a name.
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets.snippet;
|
package jdk.javadoc.internal.doclets.formats.html.taglets.snippet;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets.snippet;
|
package jdk.javadoc.internal.doclets.formats.html.taglets.snippet;
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets.snippet;
|
package jdk.javadoc.internal.doclets.formats.html.taglets.snippet;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -38,8 +38,8 @@ import java.util.regex.Matcher;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.regex.PatternSyntaxException;
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
|
import jdk.javadoc.internal.doclets.formats.html.taglets.SnippetTaglet;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.SnippetTaglet;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Semantics of a EOL comment; plus
|
* Semantics of a EOL comment; plus
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets.snippet;
|
package jdk.javadoc.internal.doclets.formats.html.taglets.snippet;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets.snippet;
|
package jdk.javadoc.internal.doclets.formats.html.taglets.snippet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A style of a snippet text character.
|
* A style of a snippet text character.
|
@ -23,7 +23,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets.snippet;
|
package jdk.javadoc.internal.doclets.formats.html.taglets.snippet;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit;
|
package jdk.javadoc.internal.doclets.toolkit;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@ -36,8 +35,6 @@ import javax.lang.model.element.TypeElement;
|
|||||||
|
|
||||||
import jdk.javadoc.doclet.Doclet;
|
import jdk.javadoc.doclet.Doclet;
|
||||||
import jdk.javadoc.doclet.DocletEnvironment;
|
import jdk.javadoc.doclet.DocletEnvironment;
|
||||||
import jdk.javadoc.doclet.StandardDoclet;
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.HtmlDoclet;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.builders.AbstractBuilder;
|
import jdk.javadoc.internal.doclets.toolkit.builders.AbstractBuilder;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.builders.BuilderFactory;
|
import jdk.javadoc.internal.doclets.toolkit.builders.BuilderFactory;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
|
import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
|
||||||
@ -68,25 +65,6 @@ public abstract class AbstractDoclet implements Doclet {
|
|||||||
*/
|
*/
|
||||||
protected Utils utils;
|
protected Utils utils;
|
||||||
|
|
||||||
/**
|
|
||||||
* The only doclet that may use this toolkit is {@value}
|
|
||||||
*/
|
|
||||||
private static final String TOOLKIT_DOCLET_NAME =
|
|
||||||
jdk.javadoc.internal.doclets.formats.html.HtmlDoclet.class.getName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify that the only doclet that is using this toolkit is
|
|
||||||
* #TOOLKIT_DOCLET_NAME.
|
|
||||||
*/
|
|
||||||
private boolean isValidDoclet() {
|
|
||||||
if (!getClass().getName().equals(TOOLKIT_DOCLET_NAME)) {
|
|
||||||
messages.error("doclet.Toolkit_Usage_Violation",
|
|
||||||
TOOLKIT_DOCLET_NAME);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method that starts the execution of the doclet.
|
* The method that starts the execution of the doclet.
|
||||||
*
|
*
|
||||||
@ -101,13 +79,9 @@ public abstract class AbstractDoclet implements Doclet {
|
|||||||
messages = configuration.getMessages();
|
messages = configuration.getMessages();
|
||||||
BaseOptions options = configuration.getOptions();
|
BaseOptions options = configuration.getOptions();
|
||||||
|
|
||||||
if (!isValidDoclet()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
startGeneration();
|
generateFiles();
|
||||||
return true;
|
return true;
|
||||||
} catch (UncheckedDocletException e) {
|
} catch (UncheckedDocletException e) {
|
||||||
throw (DocletException) e.getCause();
|
throw (DocletException) e.getCause();
|
||||||
@ -151,7 +125,7 @@ public abstract class AbstractDoclet implements Doclet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void reportInternalError(Throwable t) {
|
private void reportInternalError(Throwable t) {
|
||||||
if (getClass().equals(StandardDoclet.class) || getClass().equals(HtmlDoclet.class)) {
|
if (getClass().getModule() == AbstractDoclet.class.getModule()) {
|
||||||
System.err.println(configuration.getDocResources().getText("doclet.internal.report.bug"));
|
System.err.println(configuration.getDocResources().getText("doclet.internal.report.bug"));
|
||||||
}
|
}
|
||||||
dumpStack(true, t);
|
dumpStack(true, t);
|
||||||
@ -188,7 +162,7 @@ public abstract class AbstractDoclet implements Doclet {
|
|||||||
*
|
*
|
||||||
* @throws DocletException if there is a problem while generating the documentation
|
* @throws DocletException if there is a problem while generating the documentation
|
||||||
*/
|
*/
|
||||||
private void startGeneration() throws DocletException {
|
protected void generateFiles() throws DocletException {
|
||||||
|
|
||||||
// Modules with no documented classes may be specified on the
|
// Modules with no documented classes may be specified on the
|
||||||
// command line to specify a service provider, allow these.
|
// command line to specify a service provider, allow these.
|
||||||
@ -211,7 +185,6 @@ public abstract class AbstractDoclet implements Doclet {
|
|||||||
generateModuleFiles();
|
generateModuleFiles();
|
||||||
|
|
||||||
generateOtherFiles(classTree);
|
generateOtherFiles(classTree);
|
||||||
configuration.tagletManager.printReport();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -26,12 +26,7 @@
|
|||||||
package jdk.javadoc.internal.doclets.toolkit;
|
package jdk.javadoc.internal.doclets.toolkit;
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.InvalidPathException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -53,10 +48,8 @@ import javax.lang.model.element.PackageElement;
|
|||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
import javax.lang.model.util.SimpleElementVisitor14;
|
import javax.lang.model.util.SimpleElementVisitor14;
|
||||||
import javax.tools.DocumentationTool;
|
|
||||||
import javax.tools.JavaFileManager;
|
import javax.tools.JavaFileManager;
|
||||||
import javax.tools.JavaFileObject;
|
import javax.tools.JavaFileObject;
|
||||||
import javax.tools.StandardJavaFileManager;
|
|
||||||
|
|
||||||
import com.sun.source.tree.CompilationUnitTree;
|
import com.sun.source.tree.CompilationUnitTree;
|
||||||
import com.sun.source.util.TreePath;
|
import com.sun.source.util.TreePath;
|
||||||
@ -68,7 +61,6 @@ import jdk.javadoc.doclet.Reporter;
|
|||||||
import jdk.javadoc.doclet.StandardDoclet;
|
import jdk.javadoc.doclet.StandardDoclet;
|
||||||
import jdk.javadoc.doclet.Taglet;
|
import jdk.javadoc.doclet.Taglet;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.builders.BuilderFactory;
|
import jdk.javadoc.internal.doclets.toolkit.builders.BuilderFactory;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.TagletManager;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Comparators;
|
import jdk.javadoc.internal.doclets.toolkit.util.Comparators;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFileFactory;
|
import jdk.javadoc.internal.doclets.toolkit.util.DocFileFactory;
|
||||||
@ -100,11 +92,6 @@ public abstract class BaseConfiguration {
|
|||||||
*/
|
*/
|
||||||
protected BuilderFactory builderFactory;
|
protected BuilderFactory builderFactory;
|
||||||
|
|
||||||
/**
|
|
||||||
* The taglet manager.
|
|
||||||
*/
|
|
||||||
public TagletManager tagletManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The meta tag keywords instance.
|
* The meta tag keywords instance.
|
||||||
*/
|
*/
|
||||||
@ -374,28 +361,6 @@ public abstract class BaseConfiguration {
|
|||||||
}
|
}
|
||||||
typeElementCatalog = new TypeElementCatalog(includedTypeElements, this);
|
typeElementCatalog = new TypeElementCatalog(includedTypeElements, this);
|
||||||
|
|
||||||
String snippetPath = options.snippetPath();
|
|
||||||
if (snippetPath != null) {
|
|
||||||
Messages messages = getMessages();
|
|
||||||
JavaFileManager fm = getFileManager();
|
|
||||||
if (fm instanceof StandardJavaFileManager) {
|
|
||||||
try {
|
|
||||||
List<Path> sp = Arrays.stream(snippetPath.split(File.pathSeparator))
|
|
||||||
.map(Path::of)
|
|
||||||
.toList();
|
|
||||||
StandardJavaFileManager sfm = (StandardJavaFileManager) fm;
|
|
||||||
sfm.setLocationFromPaths(DocumentationTool.Location.SNIPPET_PATH, sp);
|
|
||||||
} catch (IOException | InvalidPathException e) {
|
|
||||||
throw new SimpleDocletException(messages.getResources().getText(
|
|
||||||
"doclet.error_setting_snippet_path", snippetPath, e), e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new SimpleDocletException(messages.getResources().getText(
|
|
||||||
"doclet.cannot_use_snippet_path", snippetPath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initTagletManager(options.customTagStrs());
|
|
||||||
options.groupPairs().forEach(grp -> {
|
options.groupPairs().forEach(grp -> {
|
||||||
if (showModules) {
|
if (showModules) {
|
||||||
group.checkModuleGroups(grp.first, grp.second);
|
group.checkModuleGroups(grp.first, grp.second);
|
||||||
@ -451,100 +416,6 @@ public abstract class BaseConfiguration {
|
|||||||
DocFileFactory.getFactory(this).setDestDir(destDirName);
|
DocFileFactory.getFactory(this).setDestDir(destDirName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the taglet manager. The strings to initialize the simple custom tags should
|
|
||||||
* be in the following format: "[tag name]:[location str]:[heading]".
|
|
||||||
*
|
|
||||||
* @param customTagStrs the set two dimensional arrays of strings. These arrays contain
|
|
||||||
* either -tag or -taglet arguments.
|
|
||||||
*/
|
|
||||||
private void initTagletManager(Set<List<String>> customTagStrs) {
|
|
||||||
tagletManager = tagletManager != null ? tagletManager : new TagletManager(this);
|
|
||||||
JavaFileManager fileManager = getFileManager();
|
|
||||||
Messages messages = getMessages();
|
|
||||||
try {
|
|
||||||
tagletManager.initTagletPath(fileManager);
|
|
||||||
tagletManager.loadTaglets(fileManager);
|
|
||||||
|
|
||||||
for (List<String> args : customTagStrs) {
|
|
||||||
if (args.get(0).equals("-taglet")) {
|
|
||||||
tagletManager.addCustomTag(args.get(1), fileManager);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Since there are few constraints on the characters in a tag name,
|
|
||||||
* and real world examples with ':' in the tag name, we cannot simply use
|
|
||||||
* String.split(regex); instead, we tokenize the string, allowing
|
|
||||||
* special characters to be escaped with '\'. */
|
|
||||||
List<String> tokens = tokenize(args.get(1), 3);
|
|
||||||
switch (tokens.size()) {
|
|
||||||
case 1 -> {
|
|
||||||
String tagName = args.get(1);
|
|
||||||
if (tagletManager.isKnownCustomTag(tagName)) {
|
|
||||||
//reorder a standard tag
|
|
||||||
tagletManager.addNewSimpleCustomTag(tagName, null, "");
|
|
||||||
} else {
|
|
||||||
//Create a simple tag with the heading that has the same name as the tag.
|
|
||||||
StringBuilder heading = new StringBuilder(tagName + ":");
|
|
||||||
heading.setCharAt(0, Character.toUpperCase(tagName.charAt(0)));
|
|
||||||
tagletManager.addNewSimpleCustomTag(tagName, heading.toString(), "a");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2 ->
|
|
||||||
//Add simple taglet without heading, probably to excluding it in the output.
|
|
||||||
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(1), "");
|
|
||||||
|
|
||||||
case 3 ->
|
|
||||||
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(2), tokens.get(1));
|
|
||||||
|
|
||||||
default ->
|
|
||||||
messages.error("doclet.Error_invalid_custom_tag_argument", args.get(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
messages.error("doclet.taglet_could_not_set_location", e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a string, return an array of tokens, separated by ':'.
|
|
||||||
* The separator character can be escaped with the '\' character.
|
|
||||||
* The '\' character may also be escaped with the '\' character.
|
|
||||||
*
|
|
||||||
* @param s the string to tokenize
|
|
||||||
* @param maxTokens the maximum number of tokens returned. If the
|
|
||||||
* max is reached, the remaining part of s is appended
|
|
||||||
* to the end of the last token.
|
|
||||||
* @return an array of tokens
|
|
||||||
*/
|
|
||||||
private List<String> tokenize(String s, int maxTokens) {
|
|
||||||
List<String> tokens = new ArrayList<>();
|
|
||||||
StringBuilder token = new StringBuilder();
|
|
||||||
boolean prevIsEscapeChar = false;
|
|
||||||
for (int i = 0; i < s.length(); i += Character.charCount(i)) {
|
|
||||||
int currentChar = s.codePointAt(i);
|
|
||||||
if (prevIsEscapeChar) {
|
|
||||||
// Case 1: escaped character
|
|
||||||
token.appendCodePoint(currentChar);
|
|
||||||
prevIsEscapeChar = false;
|
|
||||||
} else if (currentChar == ':' && tokens.size() < maxTokens - 1) {
|
|
||||||
// Case 2: separator
|
|
||||||
tokens.add(token.toString());
|
|
||||||
token = new StringBuilder();
|
|
||||||
} else if (currentChar == '\\') {
|
|
||||||
// Case 3: escape character
|
|
||||||
prevIsEscapeChar = true;
|
|
||||||
} else {
|
|
||||||
// Case 4: regular character
|
|
||||||
token.appendCodePoint(currentChar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (token.length() > 0) {
|
|
||||||
tokens.add(token.toString());
|
|
||||||
}
|
|
||||||
return tokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the given doc-file subdirectory should be excluded and
|
* Return true if the given doc-file subdirectory should be excluded and
|
||||||
* false otherwise.
|
* false otherwise.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -32,29 +32,20 @@ import java.io.OutputStreamWriter;
|
|||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.ZoneOffset;
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.time.temporal.TemporalUnit;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.MissingResourceException;
|
import java.util.MissingResourceException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
import jdk.javadoc.doclet.Doclet;
|
import jdk.javadoc.doclet.Doclet;
|
||||||
import jdk.javadoc.doclet.Reporter;
|
import jdk.javadoc.doclet.Reporter;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
||||||
|
|
||||||
import static javax.tools.Diagnostic.Kind.ERROR;
|
import static javax.tools.Diagnostic.Kind.ERROR;
|
||||||
@ -87,11 +78,6 @@ public abstract class BaseOptions {
|
|||||||
*/
|
*/
|
||||||
private boolean copyDocfileSubdirs = false;
|
private boolean copyDocfileSubdirs = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Arguments for command-line option {@code -tag} and {@code -taglet}.
|
|
||||||
*/
|
|
||||||
private final LinkedHashSet<List<String>> customTagStrs = new LinkedHashSet<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Argument for command-line option {@code --date}.
|
* Argument for command-line option {@code --date}.
|
||||||
* {@code null} if option not given.
|
* {@code null} if option not given.
|
||||||
@ -265,12 +251,6 @@ public abstract class BaseOptions {
|
|||||||
*/
|
*/
|
||||||
private boolean showAuthor = false;
|
private boolean showAuthor = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Argument for command-line option {@code --show-taglets}.
|
|
||||||
* Show taglets (internal debug switch)
|
|
||||||
*/
|
|
||||||
private boolean showTaglets = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Argument for command-line option {@code -version}.
|
* Argument for command-line option {@code -version}.
|
||||||
* Generate version specific information for the all the classes
|
* Generate version specific information for the all the classes
|
||||||
@ -313,18 +293,6 @@ public abstract class BaseOptions {
|
|||||||
*/
|
*/
|
||||||
private boolean summarizeOverriddenMethods = false;
|
private boolean summarizeOverriddenMethods = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Argument for command-line option {@code -tagletpath}.
|
|
||||||
* The path to Taglets
|
|
||||||
*/
|
|
||||||
private String tagletPath = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Argument for command-line option {@code --snippet-path}.
|
|
||||||
* The path for external snippets.
|
|
||||||
*/
|
|
||||||
private String snippetPath = null;
|
|
||||||
|
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
|
|
||||||
private final BaseConfiguration config;
|
private final BaseConfiguration config;
|
||||||
@ -617,44 +585,6 @@ public abstract class BaseOptions {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
new Option(resources, "-tag", 1) {
|
|
||||||
@Override
|
|
||||||
public boolean process(String opt, List<String> args) {
|
|
||||||
ArrayList<String> list = new ArrayList<>();
|
|
||||||
list.add(opt);
|
|
||||||
list.add(args.get(0));
|
|
||||||
customTagStrs.add(list);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
new Option(resources, "-taglet", 1) {
|
|
||||||
@Override
|
|
||||||
public boolean process(String opt, List<String> args) {
|
|
||||||
ArrayList<String> list = new ArrayList<>();
|
|
||||||
list.add(opt);
|
|
||||||
list.add(args.get(0));
|
|
||||||
customTagStrs.add(list);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
new Option(resources, "-tagletpath", 1) {
|
|
||||||
@Override
|
|
||||||
public boolean process(String opt, List<String> args) {
|
|
||||||
tagletPath = args.get(0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
new Option(resources, "--snippet-path", 1) {
|
|
||||||
@Override
|
|
||||||
public boolean process(String opt, List<String> args) {
|
|
||||||
snippetPath = args.get(0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
new Option(resources, "-version") {
|
new Option(resources, "-version") {
|
||||||
@Override
|
@Override
|
||||||
public boolean process(String opt, List<String> args) {
|
public boolean process(String opt, List<String> args) {
|
||||||
@ -705,14 +635,6 @@ public abstract class BaseOptions {
|
|||||||
disableJavaFxStrictChecks = true;
|
disableJavaFxStrictChecks = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
new Hidden(resources, "--show-taglets") {
|
|
||||||
@Override
|
|
||||||
public boolean process(String opt, List<String> args) {
|
|
||||||
showTaglets = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return new TreeSet<>(options);
|
return new TreeSet<>(options);
|
||||||
@ -801,13 +723,6 @@ public abstract class BaseOptions {
|
|||||||
return copyDocfileSubdirs;
|
return copyDocfileSubdirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Arguments for command-line option {@code -tag} and {@code -taglet}.
|
|
||||||
*/
|
|
||||||
LinkedHashSet<List<String>> customTagStrs() {
|
|
||||||
return customTagStrs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Argument for command-line option {@code --date}.
|
* Argument for command-line option {@code --date}.
|
||||||
*/
|
*/
|
||||||
@ -1023,20 +938,12 @@ public abstract class BaseOptions {
|
|||||||
* Generate author specific information for all the classes if @author
|
* Generate author specific information for all the classes if @author
|
||||||
* tag is used in the doc comment and if -author option is used.
|
* tag is used in the doc comment and if -author option is used.
|
||||||
* <code>showauthor</code> is set to true if -author option is used.
|
* <code>showauthor</code> is set to true if -author option is used.
|
||||||
* Default is don't show author information.
|
* Default is to not show author information.
|
||||||
*/
|
*/
|
||||||
public boolean showAuthor() {
|
public boolean showAuthor() {
|
||||||
return showAuthor;
|
return showAuthor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Argument for command-line option {@code --show-taglets}.
|
|
||||||
* Show taglets (internal debug switch)
|
|
||||||
*/
|
|
||||||
public boolean showTaglets() {
|
|
||||||
return showTaglets;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Argument for command-line option {@code -version}.
|
* Argument for command-line option {@code -version}.
|
||||||
* Generate version specific information for the all the classes
|
* Generate version specific information for the all the classes
|
||||||
@ -1089,22 +996,6 @@ public abstract class BaseOptions {
|
|||||||
return summarizeOverriddenMethods;
|
return summarizeOverriddenMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Argument for command-line option {@code -tagletpath}.
|
|
||||||
* The path to Taglets
|
|
||||||
*/
|
|
||||||
public String tagletPath() {
|
|
||||||
return tagletPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Argument for command-line option {@code --snippet-path}.
|
|
||||||
* The path for external snippets.
|
|
||||||
*/
|
|
||||||
public String snippetPath() {
|
|
||||||
return snippetPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract static class Option implements Doclet.Option, Comparable<Option> {
|
protected abstract static class Option implements Doclet.Option, Comparable<Option> {
|
||||||
private final String[] names;
|
private final String[] names;
|
||||||
private final String parameters;
|
private final String parameters;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -33,6 +33,12 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
|
|||||||
* The interface for writing class output.
|
* The interface for writing class output.
|
||||||
*/
|
*/
|
||||||
public interface ClassWriter {
|
public interface ClassWriter {
|
||||||
|
/**
|
||||||
|
* Returns an instance of an output object.
|
||||||
|
*
|
||||||
|
* @return an instance of an output object
|
||||||
|
*/
|
||||||
|
Content getOutputInstance();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the header of the page.
|
* Get the header of the page.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -37,7 +37,6 @@ import javax.lang.model.element.TypeElement;
|
|||||||
import javax.lang.model.element.VariableElement;
|
import javax.lang.model.element.VariableElement;
|
||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
|
|
||||||
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
|
import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.CommentUtils;
|
import jdk.javadoc.internal.doclets.toolkit.CommentUtils;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
import jdk.javadoc.internal.doclets.toolkit.Content;
|
||||||
@ -143,7 +142,7 @@ public class ClassBuilder extends AbstractBuilder {
|
|||||||
* @throws DocletException if there is a problem while building the documentation
|
* @throws DocletException if there is a problem while building the documentation
|
||||||
*/
|
*/
|
||||||
protected void buildClassInfo(Content target) throws DocletException {
|
protected void buildClassInfo(Content target) throws DocletException {
|
||||||
Content c = new ContentBuilder();
|
Content c = writer.getOutputInstance();
|
||||||
buildParamInfo(c);
|
buildParamInfo(c);
|
||||||
buildSuperInterfacesInfo(c);
|
buildSuperInterfacesInfo(c);
|
||||||
buildImplementedInterfacesInfo(c);
|
buildImplementedInterfacesInfo(c);
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
doclet.Generating_0=Generating {0}...
|
doclet.Generating_0=Generating {0}...
|
||||||
doclet.Toolkit_Usage_Violation=The Doclet Toolkit can only be used by {0}
|
|
||||||
doclet.MissingSerialTag=in class {0}, missing @serial tag for default serializable field: {1}.
|
doclet.MissingSerialTag=in class {0}, missing @serial tag for default serializable field: {1}.
|
||||||
doclet.MissingSerialDataTag=in class {0}, missing @serialData tag in method {1}.
|
doclet.MissingSerialDataTag=in class {0}, missing @serialData tag in method {1}.
|
||||||
doclet.Serializable_no_customization=No readObject or writeObject method declared.
|
doclet.Serializable_no_customization=No readObject or writeObject method declared.
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2003, 2022, 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. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
|
||||||
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A taglet that represents the {@code @deprecated} tag.
|
|
||||||
*/
|
|
||||||
public class DeprecatedTaglet extends BaseTaglet {
|
|
||||||
|
|
||||||
public DeprecatedTaglet() {
|
|
||||||
super(DocTree.Kind.DEPRECATED, false,
|
|
||||||
EnumSet.of(Location.MODULE, Location.TYPE, Location.CONSTRUCTOR, Location.METHOD, Location.FIELD));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
|
|
||||||
return writer.deprecatedTagOutput(holder);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2003, 2022, 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. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
|
||||||
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
|
||||||
import com.sun.source.doctree.LiteralTree;
|
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An inline taglet used to denote literal text.
|
|
||||||
* For example, the text:
|
|
||||||
* <blockquote> {@code {@literal a<B>c}} </blockquote>
|
|
||||||
* displays as:
|
|
||||||
* <blockquote> {@literal a<B>c} </blockquote>
|
|
||||||
*/
|
|
||||||
public class LiteralTaglet extends BaseTaglet {
|
|
||||||
|
|
||||||
LiteralTaglet() {
|
|
||||||
super(DocTree.Kind.LITERAL, true, EnumSet.allOf(Location.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content getInlineTagOutput(Element e, DocTree tag, TagletWriter writer) {
|
|
||||||
return writer.literalTagOutput(e, (LiteralTree) tag);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2001, 2023, 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. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
|
||||||
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
import javax.lang.model.element.ExecutableElement;
|
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
|
||||||
import com.sun.source.doctree.SeeTree;
|
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A taglet that represents the {@code @see} tag.
|
|
||||||
*/
|
|
||||||
public class SeeTaglet extends BaseTaglet implements InheritableTaglet {
|
|
||||||
|
|
||||||
public SeeTaglet() {
|
|
||||||
super(DocTree.Kind.SEE, false, EnumSet.allOf(Location.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence, BaseConfiguration configuration) {
|
|
||||||
CommentHelper ch = configuration.utils.getCommentHelper(dst);
|
|
||||||
var path = ch.getDocTreePath(tag);
|
|
||||||
configuration.getMessages().warning(path, "doclet.inheritDocWithinInappropriateTag");
|
|
||||||
return new Output(null, null, List.of(), true /* true, otherwise there will be an exception up the stack */);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
|
|
||||||
Utils utils = writer.configuration().utils;
|
|
||||||
List<? extends SeeTree> tags = utils.getSeeTrees(holder);
|
|
||||||
Element e = holder;
|
|
||||||
if (utils.isMethod(holder)) {
|
|
||||||
var docFinder = utils.docFinder();
|
|
||||||
Optional<Documentation> result = docFinder.search((ExecutableElement) holder,
|
|
||||||
m -> Result.fromOptional(extract(utils, m))).toOptional();
|
|
||||||
if (result.isPresent()) {
|
|
||||||
ExecutableElement m = result.get().method();
|
|
||||||
tags = utils.getSeeTrees(m);
|
|
||||||
e = m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return writer.seeTagOutput(e, tags);
|
|
||||||
}
|
|
||||||
|
|
||||||
private record Documentation(List<? extends SeeTree> seeTrees, ExecutableElement method) { }
|
|
||||||
|
|
||||||
private static Optional<Documentation> extract(Utils utils, ExecutableElement method) {
|
|
||||||
List<? extends SeeTree> tags = utils.getSeeTrees(method);
|
|
||||||
return tags.isEmpty() ? Optional.empty() : Optional.of(new Documentation(tags, method));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2019, 2023, 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. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
|
||||||
|
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
import javax.lang.model.element.ExecutableElement;
|
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
|
||||||
import com.sun.source.doctree.SpecTree;
|
|
||||||
import jdk.javadoc.doclet.Taglet.Location;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A taglet that represents the {@code @spec} tag.
|
|
||||||
*/
|
|
||||||
public class SpecTaglet extends BaseTaglet implements InheritableTaglet {
|
|
||||||
|
|
||||||
public SpecTaglet() {
|
|
||||||
super(DocTree.Kind.SPEC, false, EnumSet.allOf(Location.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Output inherit(Element dst, Element src, DocTree tag, boolean isFirstSentence, BaseConfiguration configuration) {
|
|
||||||
CommentHelper ch = configuration.utils.getCommentHelper(dst);
|
|
||||||
var path = ch.getDocTreePath(tag);
|
|
||||||
configuration.getMessages().warning(path, "doclet.inheritDocWithinInappropriateTag");
|
|
||||||
return new Output(null, null, List.of(), true /* true, otherwise there will be an exception up the stack */);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Content getAllBlockTagOutput(Element holder, TagletWriter writer) {
|
|
||||||
Utils utils = writer.configuration().utils;
|
|
||||||
List<? extends SpecTree> tags = utils.getSpecTrees(holder);
|
|
||||||
Element e = holder;
|
|
||||||
if (utils.isMethod(holder)) {
|
|
||||||
var docFinder = utils.docFinder();
|
|
||||||
Optional<Documentation> result = docFinder.search((ExecutableElement) holder,
|
|
||||||
m -> Result.fromOptional(extract(utils, m))).toOptional();
|
|
||||||
if (result.isPresent()) {
|
|
||||||
e = result.get().method();
|
|
||||||
tags = result.get().specTrees();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return writer.specTagOutput(e, tags);
|
|
||||||
}
|
|
||||||
|
|
||||||
private record Documentation(List<? extends SpecTree> specTrees, ExecutableElement method) { }
|
|
||||||
|
|
||||||
private static Optional<Documentation> extract(Utils utils, ExecutableElement method) {
|
|
||||||
List<? extends SpecTree> tags = utils.getSpecTrees(method);
|
|
||||||
return tags.isEmpty() ? Optional.empty() : Optional.of(new Documentation(tags, method));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,420 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2003, 2022, 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. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import javax.lang.model.element.Element;
|
|
||||||
import javax.lang.model.element.ElementKind;
|
|
||||||
import javax.lang.model.element.TypeElement;
|
|
||||||
import javax.lang.model.element.VariableElement;
|
|
||||||
import javax.lang.model.type.TypeMirror;
|
|
||||||
|
|
||||||
import com.sun.source.doctree.DocTree;
|
|
||||||
import com.sun.source.doctree.SpecTree;
|
|
||||||
import com.sun.source.doctree.IndexTree;
|
|
||||||
import com.sun.source.doctree.LinkTree;
|
|
||||||
import com.sun.source.doctree.LiteralTree;
|
|
||||||
import com.sun.source.doctree.ParamTree;
|
|
||||||
import com.sun.source.doctree.ReturnTree;
|
|
||||||
import com.sun.source.doctree.SeeTree;
|
|
||||||
import com.sun.source.doctree.SnippetTree;
|
|
||||||
import com.sun.source.doctree.SystemPropertyTree;
|
|
||||||
import com.sun.source.doctree.ThrowsTree;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Content;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.Taglet.UnsupportedTagletOperationException;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.snippet.StyledText;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The interface for the taglet writer.
|
|
||||||
*/
|
|
||||||
public abstract class TagletWriter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True if we only want to write the first sentence.
|
|
||||||
*/
|
|
||||||
protected final boolean isFirstSentence;
|
|
||||||
|
|
||||||
protected TagletWriter(boolean isFirstSentence) {
|
|
||||||
this.isFirstSentence = isFirstSentence;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an instance of an output object.
|
|
||||||
*
|
|
||||||
* @return an instance of an output object
|
|
||||||
*/
|
|
||||||
public abstract Content getOutputInstance();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a {@code {@code ...}} tag.
|
|
||||||
*
|
|
||||||
* @param element The element that owns the doc comment
|
|
||||||
* @param tag the tag
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content codeTagOutput(Element element, LiteralTree tag);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a {@code {@index...}} tag.
|
|
||||||
*
|
|
||||||
* @param element The element that owns the doc comment
|
|
||||||
* @param tag the tag
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content indexTagOutput(Element element, IndexTree tag);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a {@code {@docRoot}} tag.
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content getDocRootOutput();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a {@code @deprecated} tag.
|
|
||||||
*
|
|
||||||
* @param element The element that owns the doc comment
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content deprecatedTagOutput(Element element);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a {@code {@link ...}} or {@code {@linkplain ...}} tag.
|
|
||||||
*
|
|
||||||
* @param element The element that owns the doc comment
|
|
||||||
* @param tag the tag
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content linkTagOutput(Element element, LinkTree tag);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a {@code {@literal ...}} tag.
|
|
||||||
*
|
|
||||||
* @param element The element that owns the doc comment
|
|
||||||
* @param tag the tag
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content literalTagOutput(Element element, LiteralTree tag);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the header for the {@code @param} tags.
|
|
||||||
*
|
|
||||||
* @param kind the kind of header that is required
|
|
||||||
*
|
|
||||||
* @return the header
|
|
||||||
*/
|
|
||||||
protected abstract Content getParamHeader(ParamTaglet.ParamKind kind);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a {@code @param} tag.
|
|
||||||
* Note we cannot rely on the name in the tag, because we might be
|
|
||||||
* inheriting the tag.
|
|
||||||
*
|
|
||||||
* @param element The element that owns the doc comment
|
|
||||||
* @param paramTag the parameter to document
|
|
||||||
* @param paramName the name of the parameter
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content paramTagOutput(Element element, ParamTree paramTag, String paramName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a {@code @return} tag.
|
|
||||||
*
|
|
||||||
* @param element the element that owns the doc comment
|
|
||||||
* @param returnTag the return tag to document
|
|
||||||
* @param inline whether this should be written as an inline instance or block instance
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content returnTagOutput(Element element, ReturnTree returnTag, boolean inline);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for {@code @see} tags.
|
|
||||||
*
|
|
||||||
* @param element The element that owns the doc comment
|
|
||||||
* @param seeTags the list of tags
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content seeTagOutput(Element element, List<? extends SeeTree> seeTags);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a series of simple tags.
|
|
||||||
*
|
|
||||||
* @param element The element that owns the doc comment
|
|
||||||
* @param simpleTags the list of simple tags
|
|
||||||
* @param header the header for the series of tags
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content simpleBlockTagOutput(Element element, List<? extends DocTree> simpleTags, String header);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a {@code {@snippet ...}} tag.
|
|
||||||
*
|
|
||||||
* @param element The element that owns the doc comment
|
|
||||||
* @param snippetTag the snippet tag
|
|
||||||
* @param id the value of the id attribute, or null if not defined
|
|
||||||
* @param lang the value of the lang attribute, or null if not defined
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content snippetTagOutput(Element element, SnippetTree snippetTag, StyledText text,
|
|
||||||
String id, String lang);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for one or more {@code @spec} tags.
|
|
||||||
*
|
|
||||||
* @param element the element that owns the doc comment
|
|
||||||
* @param specTags the array of @spec tags.
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content specTagOutput(Element element, List<? extends SpecTree> specTags);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a {@code {@systemProperty...}} tag.
|
|
||||||
*
|
|
||||||
* @param element the element that owns the doc comment
|
|
||||||
* @param systemPropertyTag the system property tag
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content systemPropertyTagOutput(Element element, SystemPropertyTree systemPropertyTag);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the header for the {@code @throws} tag.
|
|
||||||
*
|
|
||||||
* @return the header for the throws tag
|
|
||||||
*/
|
|
||||||
protected abstract Content getThrowsHeader();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a default {@code @throws} tag.
|
|
||||||
*
|
|
||||||
* @param throwsType the type that is thrown
|
|
||||||
* @param content the optional content to add as a description
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content throwsTagOutput(TypeMirror throwsType, Optional<Content> content);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for a {@code {@value}} tag.
|
|
||||||
*
|
|
||||||
* @param field the constant field that holds the value tag
|
|
||||||
* @param constantVal the constant value to document
|
|
||||||
* @param includeLink true if we should link the constant text to the
|
|
||||||
* constant field itself
|
|
||||||
*
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content valueTagOutput(VariableElement field,
|
|
||||||
String constantVal, boolean includeLink);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the output for an invalid tag. The returned content uses special styling to
|
|
||||||
* highlight the problem. Depending on the presence of the {@code detail} string the method
|
|
||||||
* returns a plain text span or an expandable component.
|
|
||||||
*
|
|
||||||
* @param summary the single-line summary message
|
|
||||||
* @param detail the optional detail message which may contain preformatted text
|
|
||||||
* @return the output
|
|
||||||
*/
|
|
||||||
protected abstract Content invalidTagOutput(String summary, Optional<String> detail);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the main type element of the current page or null for pages that don't have one.
|
|
||||||
*
|
|
||||||
* @return the type element of the current page or null.
|
|
||||||
*/
|
|
||||||
protected abstract TypeElement getCurrentPageElement();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the content generated from the block tags for a given element.
|
|
||||||
* The content is generated according to the order of the list of taglets.
|
|
||||||
* The result is a possibly-empty list of the output generated by each
|
|
||||||
* of the given taglets for all of the tags they individually support.
|
|
||||||
*
|
|
||||||
* @param tagletManager the manager that manages the taglets
|
|
||||||
* @param element the element that we are to write tags for
|
|
||||||
* @param taglets the taglets for the tags to write
|
|
||||||
*
|
|
||||||
* @return the content
|
|
||||||
*/
|
|
||||||
public Content getBlockTagOutput(TagletManager tagletManager,
|
|
||||||
Element element,
|
|
||||||
List<Taglet> taglets) {
|
|
||||||
for (Taglet t : taglets) {
|
|
||||||
if (!t.isBlockTag()) {
|
|
||||||
throw new IllegalArgumentException(t.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Content output = getOutputInstance();
|
|
||||||
Utils utils = configuration().utils;
|
|
||||||
tagletManager.checkTags(element, utils.getBlockTags(element));
|
|
||||||
tagletManager.checkTags(element, utils.getFullBody(element));
|
|
||||||
for (Taglet taglet : taglets) {
|
|
||||||
if (utils.isTypeElement(element) && taglet instanceof ParamTaglet) {
|
|
||||||
// The type parameters and state components are documented in a special
|
|
||||||
// section away from the tag info, so skip here.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.getKind() == ElementKind.MODULE && taglet instanceof BaseTaglet t) {
|
|
||||||
switch (t.getTagKind()) {
|
|
||||||
// @uses and @provides are handled separately, so skip here.
|
|
||||||
// See ModuleWriterImpl.computeModulesData
|
|
||||||
case USES:
|
|
||||||
case PROVIDES:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (taglet instanceof DeprecatedTaglet) {
|
|
||||||
//Deprecated information is documented "inline", not in tag info
|
|
||||||
//section.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (taglet instanceof SimpleTaglet st && !st.enabled) {
|
|
||||||
// taglet has been disabled
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Content tagletOutput = taglet.getAllBlockTagOutput(element, this);
|
|
||||||
if (tagletOutput != null) {
|
|
||||||
tagletManager.seenTag(taglet.getName());
|
|
||||||
output.add(tagletOutput);
|
|
||||||
}
|
|
||||||
} catch (UnsupportedTagletOperationException e) {
|
|
||||||
// malformed taglet:
|
|
||||||
// claims to support block tags (see Taglet.isBlockTag) but does not provide the
|
|
||||||
// appropriate method, Taglet.getAllBlockTagOutput.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the content generated from an inline tag in the doc comment for a given element,
|
|
||||||
* or {@code null} if the tag is not supported or does not return any output.
|
|
||||||
*
|
|
||||||
* @param holder the element associated with the doc comment
|
|
||||||
* @param tagletManager the taglet manager for the current doclet
|
|
||||||
* @param inlineTag the inline tag to be documented
|
|
||||||
*
|
|
||||||
* @return the content, or {@code null}
|
|
||||||
*/
|
|
||||||
public Content getInlineTagOutput(Element holder,
|
|
||||||
TagletManager tagletManager,
|
|
||||||
DocTree inlineTag) {
|
|
||||||
|
|
||||||
Map<String, Taglet> inlineTags = tagletManager.getInlineTaglets();
|
|
||||||
CommentHelper ch = configuration().utils.getCommentHelper(holder);
|
|
||||||
final String inlineTagName = ch.getTagName(inlineTag);
|
|
||||||
Taglet t = inlineTags.get(inlineTagName);
|
|
||||||
if (t == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Content tagletOutput = t.getInlineTagOutput(holder, inlineTag, this);
|
|
||||||
tagletManager.seenTag(t.getName());
|
|
||||||
return tagletOutput;
|
|
||||||
} catch (UnsupportedTagletOperationException e) {
|
|
||||||
// malformed taglet:
|
|
||||||
// claims to support inline tags (see Taglet.isInlineTag) but does not provide the
|
|
||||||
// appropriate method, Taglet.getInlineTagOutput.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts inline tags and text to content, expanding the
|
|
||||||
* inline tags along the way. Called wherever text can contain
|
|
||||||
* an inline tag, such as in comments or in free-form text arguments
|
|
||||||
* to block tags.
|
|
||||||
*
|
|
||||||
* @param holderTree the tree that holds the documentation
|
|
||||||
* @param trees list of {@code DocTree} nodes containing text and inline tags (often alternating)
|
|
||||||
* present in the text of interest for this doc
|
|
||||||
*
|
|
||||||
* @return the generated content
|
|
||||||
*/
|
|
||||||
public abstract Content commentTagsToOutput(DocTree holderTree, List<? extends DocTree> trees);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts inline tags and text to content, expanding the
|
|
||||||
* inline tags along the way. Called wherever text can contain
|
|
||||||
* an inline tag, such as in comments or in free-form text arguments
|
|
||||||
* to block tags.
|
|
||||||
*
|
|
||||||
* @param element The element that owns the documentation
|
|
||||||
* @param trees list of {@code DocTree} nodes containing text and inline tags (often alternating)
|
|
||||||
* present in the text of interest for this doc
|
|
||||||
*
|
|
||||||
* @return the generated content
|
|
||||||
*/
|
|
||||||
public abstract Content commentTagsToOutput(Element element, List<? extends DocTree> trees);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts inline tags and text to content, expanding the
|
|
||||||
* inline tags along the way. Called wherever text can contain
|
|
||||||
* an inline tag, such as in comments or in free-form text arguments
|
|
||||||
* to non-inline tags.
|
|
||||||
*
|
|
||||||
* @param element the element where comment resides
|
|
||||||
* @param holder the tag that holds the documentation
|
|
||||||
* @param trees array of text tags and inline tags (often alternating)
|
|
||||||
* present in the text of interest for this doc
|
|
||||||
* @param isFirstSentence true if this is the first sentence
|
|
||||||
*
|
|
||||||
* @return the generated content
|
|
||||||
*/
|
|
||||||
public abstract Content commentTagsToOutput(Element element, DocTree holder,
|
|
||||||
List<? extends DocTree> trees, boolean isFirstSentence);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an instance of the configuration used for this doclet.
|
|
||||||
*
|
|
||||||
* @return an instance of the configuration used for this doclet
|
|
||||||
*/
|
|
||||||
public abstract BaseConfiguration configuration();
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2003, 2022, 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. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This package has classes used to generate output for Javadoc tags.
|
|
||||||
*
|
|
||||||
* <p>Doclets no longer have to implement their own version of standard tags
|
|
||||||
* such as @param and @throws. Individual taglets provide
|
|
||||||
* common processing, independent of the output format.
|
|
||||||
* Each doclet must have a taglet writer that takes a taglet
|
|
||||||
* as input and writes doclet-dependent output. The taglet itself will
|
|
||||||
* do the tag processing. For example, suppose we are outputting
|
|
||||||
* @throws tags. The taglet would:
|
|
||||||
* <ul>
|
|
||||||
* <li> Retrieve the list of throws tags to be documented.
|
|
||||||
* <li> Replace {@inheritDoc} with the appropriate documentation.
|
|
||||||
* <li> Add throws documentation for exceptions that are declared in
|
|
||||||
* the signature of the method but not documented with the throws tags.
|
|
||||||
* </ul>
|
|
||||||
* After doing the steps above, the taglet would pass the information to
|
|
||||||
* the taglet writer for writing. The taglets are essentially builders for
|
|
||||||
* tags.
|
|
||||||
*/
|
|
||||||
package jdk.javadoc.internal.doclets.toolkit.taglets;
|
|
@ -34,7 +34,6 @@ import java.text.ParseException;
|
|||||||
import java.text.RuleBasedCollator;
|
import java.text.RuleBasedCollator;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
@ -116,13 +115,12 @@ import com.sun.source.tree.LineMap;
|
|||||||
import com.sun.source.util.DocSourcePositions;
|
import com.sun.source.util.DocSourcePositions;
|
||||||
import com.sun.source.util.DocTrees;
|
import com.sun.source.util.DocTrees;
|
||||||
import com.sun.source.util.TreePath;
|
import com.sun.source.util.TreePath;
|
||||||
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.BaseOptions;
|
import jdk.javadoc.internal.doclets.toolkit.BaseOptions;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.CommentUtils;
|
import jdk.javadoc.internal.doclets.toolkit.CommentUtils;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.CommentUtils.DocCommentInfo;
|
import jdk.javadoc.internal.doclets.toolkit.CommentUtils.DocCommentInfo;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
import jdk.javadoc.internal.doclets.toolkit.Resources;
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.BaseTaglet;
|
|
||||||
import jdk.javadoc.internal.doclets.toolkit.taglets.Taglet;
|
|
||||||
|
|
||||||
import static javax.lang.model.element.ElementKind.*;
|
import static javax.lang.model.element.ElementKind.*;
|
||||||
import static javax.lang.model.type.TypeKind.*;
|
import static javax.lang.model.type.TypeKind.*;
|
||||||
@ -991,7 +989,7 @@ public class Utils {
|
|||||||
/**
|
/**
|
||||||
* Return the type's dimension information, as a string.
|
* Return the type's dimension information, as a string.
|
||||||
* <p>
|
* <p>
|
||||||
* For example, a two dimensional array of String returns "{@code [][]}".
|
* For example, a two-dimensional array of String returns "{@code [][]}".
|
||||||
*
|
*
|
||||||
* @return the type's dimension information as a string.
|
* @return the type's dimension information as a string.
|
||||||
*/
|
*/
|
||||||
@ -2087,47 +2085,102 @@ public class Utils {
|
|||||||
commentHelperCache.remove(element);
|
commentHelperCache.remove(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the "raw" list of block tags from the doc-comment tree for an element,
|
||||||
|
* or an empty list if there is no such comment.
|
||||||
|
*
|
||||||
|
* Note: The list may include {@code ErroneousTree} nodes.
|
||||||
|
*
|
||||||
|
* @param element the element
|
||||||
|
* @return the list
|
||||||
|
*/
|
||||||
public List<? extends DocTree> getBlockTags(Element element) {
|
public List<? extends DocTree> getBlockTags(Element element) {
|
||||||
return getBlockTags(getDocCommentTree(element));
|
return getBlockTags(getDocCommentTree(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the "raw" list of block tags from a {@code DocCommentTree}, or an empty list
|
||||||
|
* if the doc-comment tree is {@code null}.
|
||||||
|
*
|
||||||
|
* Note: The list may include {@code ErroneousTree} nodes.
|
||||||
|
*
|
||||||
|
* @param dcTree the doc-comment tree
|
||||||
|
* @return the list
|
||||||
|
*/
|
||||||
public List<? extends DocTree> getBlockTags(DocCommentTree dcTree) {
|
public List<? extends DocTree> getBlockTags(DocCommentTree dcTree) {
|
||||||
return dcTree == null ? List.of() : dcTree.getBlockTags();
|
return dcTree == null ? List.of() : dcTree.getBlockTags();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<? extends DocTree> getBlockTags(Element element, Predicate<DocTree> filter) {
|
/**
|
||||||
|
* Returns the list of block tags for the doc-comment tree for an element that match
|
||||||
|
* a given filter, or an empty list if there is no such doc-comment.
|
||||||
|
*
|
||||||
|
* @param element the element
|
||||||
|
* @param filter the filter
|
||||||
|
* @return the list
|
||||||
|
*/
|
||||||
|
public List<? extends BlockTagTree> getBlockTags(Element element, Predicate<? super BlockTagTree> filter) {
|
||||||
return getBlockTags(element).stream()
|
return getBlockTags(element).stream()
|
||||||
.filter(t -> t.getKind() != ERRONEOUS)
|
.filter(t -> t.getKind() != ERRONEOUS)
|
||||||
|
.map(t -> (BlockTagTree) t)
|
||||||
.filter(filter)
|
.filter(filter)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends DocTree> List<T> getBlockTags(Element element, Predicate<DocTree> filter, Class<T> tClass) {
|
/**
|
||||||
|
* Returns the list of block tags for the doc-comment tree for an element that match
|
||||||
|
* a given filter, or an empty list if there is no such doc-comment.
|
||||||
|
*
|
||||||
|
* @param <T> the type of the required block tags
|
||||||
|
* @param element the element
|
||||||
|
* @param filter the filter
|
||||||
|
* @return the list
|
||||||
|
*/
|
||||||
|
public <T extends BlockTagTree> List<T> getBlockTags(Element element,
|
||||||
|
Predicate<? super BlockTagTree> filter,
|
||||||
|
Class<T> tClass) {
|
||||||
return getBlockTags(element).stream()
|
return getBlockTags(element).stream()
|
||||||
.filter(t -> t.getKind() != ERRONEOUS)
|
.filter(t -> t.getKind() != ERRONEOUS)
|
||||||
|
.map(t -> (BlockTagTree) t)
|
||||||
.filter(filter)
|
.filter(filter)
|
||||||
.map(tClass::cast)
|
.map(tClass::cast)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<? extends DocTree> getBlockTags(Element element, DocTree.Kind kind) {
|
/**
|
||||||
|
* Returns the list of block tags for the doc-comment tree for an element,
|
||||||
|
* or an empty list if there is no such doc-comment.
|
||||||
|
*
|
||||||
|
* @param element the element
|
||||||
|
* @return the list
|
||||||
|
*/
|
||||||
|
public List<? extends BlockTagTree> getBlockTags(Element element, DocTree.Kind kind) {
|
||||||
return getBlockTags(element, t -> t.getKind() == kind);
|
return getBlockTags(element, t -> t.getKind() == kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends DocTree> List<? extends T> getBlockTags(Element element, DocTree.Kind kind, Class<T> tClass) {
|
/**
|
||||||
|
* Returns the list of block tags for the doc-comment tree for an element that match a given kind,
|
||||||
|
* or an empty list if there is no such doc-comment.
|
||||||
|
*
|
||||||
|
* @param <T> the type of the required block tags
|
||||||
|
* @param element the element
|
||||||
|
* @param kind the kind for the required block tags
|
||||||
|
* @return the list
|
||||||
|
*/
|
||||||
|
public <T extends BlockTagTree> List<? extends T> getBlockTags(Element element, DocTree.Kind kind, Class<T> tClass) {
|
||||||
return getBlockTags(element, t -> t.getKind() == kind, tClass);
|
return getBlockTags(element, t -> t.getKind() == kind, tClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<? extends DocTree> getBlockTags(Element element, Taglet taglet) {
|
/**
|
||||||
return getBlockTags(element, t -> {
|
* Returns the list of block tags for the doc-comment tree for an element that match a given name,
|
||||||
if (taglet instanceof BaseTaglet baseTaglet) {
|
* or an empty list if there is no such doc-comment.
|
||||||
return baseTaglet.accepts(t);
|
*
|
||||||
} else if (t instanceof BlockTagTree blockTagTree) {
|
* @param element the element
|
||||||
return blockTagTree.getTagName().equals(taglet.getName());
|
* @param tagName the name of the required block tags
|
||||||
} else {
|
* @return the list
|
||||||
return false;
|
*/
|
||||||
}
|
public List<? extends BlockTagTree> getBlockTags(Element element, String tagName) {
|
||||||
});
|
return getBlockTags(element, t -> t.getTagName().equals(tagName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasBlockTag(Element element, DocTree.Kind kind) {
|
public boolean hasBlockTag(Element element, DocTree.Kind kind) {
|
||||||
|
Loading…
Reference in New Issue
Block a user