8235306: Support doc-comment tags that can be inline or block tags

Reviewed-by: hannesw
This commit is contained in:
Jonathan Gibbons 2019-12-13 10:42:57 -08:00
parent 4d1176fd60
commit 3c0e2b4e16
23 changed files with 463 additions and 243 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2019, 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
@ -36,9 +36,10 @@ import com.sun.source.doctree.DocTree;
* The interface for a custom taglet supported by doclets such as
* the {@link jdk.javadoc.doclet.StandardDoclet standard doclet}.
* Custom taglets are used to handle custom tags in documentation
* comments; custom tags can be either <i>block tags</i>, which
* appear at the end of a comment, or <i>inline tags</i>, which
* can appear within the main body of a documentation comment.
* comments; custom tags can be instantiated individually as either
* <i>block tags</i>, which appear at the end of a comment,
* or <i>inline tags</i>, which can appear within the main body of a
* documentation comment.
*
* <p> Each implementation of a taglet must provide a public no-argument constructor
* to be used by doclets to instantiate the taglet. A doclet will interact
@ -78,20 +79,32 @@ import com.sun.source.doctree.DocTree;
public interface Taglet {
/**
* Returns the set of locations in which a tag may be used.
* @return the set of locations in which a tag may be used
* Returns the set of supported locations for block tags.
* @return the set of supported locations for block tags
*/
Set<Location> getAllowedLocations();
/**
* Indicates whether this taglet is for inline tags or not.
* @return true if this taglet is for an inline tag, and false otherwise
* Indicates whether this taglet supports inline tags.
*
* @return true if this taglet supports inline tags
*/
boolean isInlineTag();
/**
* Returns the name of the tag.
* @return the name of this custom tag.
* Indicates whether this taglet supports block tags.
*
* @return true if this taglet supports block tags
* @implSpec This implementation returns the inverse
* result to {@code isInlineTag}.
*/
default boolean isBlockTag() {
return !isInlineTag();
}
/**
* Returns the name of the tag supported by this taglet.
* @return the name of this tag
*/
String getName();
@ -115,10 +128,11 @@ public interface Taglet {
* Returns the string representation of a series of instances of
* this tag to be included in the generated output.
*
* <p>If this taglet is for an {@link #isInlineTag inline} tag it will
* be called once per instance of the tag, each time with a singleton list.
* Otherwise, if this tag is a block tag, it will be called once per
* comment, with a list of all the instances of the tag in a comment.
* <p>If this taglet supports {@link #isInlineTag inline} tags, it will
* be called once per instance of the inline tag, each time with a singleton list.
* If this taglet supports {@link #isBlockTag block} tags, it will be called once
* for each comment containing instances of block tags, with a list of all the instances
* of the block tag in that comment.
*
* @param tags the list of instances of this tag
* @param element the element to which the enclosing comment belongs
@ -133,14 +147,14 @@ public interface Taglet {
/**
* The kind of location in which a tag may be used.
*/
public static enum Location {
enum Location {
/** In an Overview document. */
OVERVIEW,
/** In the documentation for a module. */
MODULE,
/** In the documentation for a package. */
PACKAGE,
/** In the documentation for a class, interface or enum. */
/** In the documentation for a type, such as a class, interface or enum. */
TYPE,
/** In the documentation for a constructor. */
CONSTRUCTOR,

View File

@ -1323,16 +1323,16 @@ public class HtmlDocletWriter {
* an inline tag, such as in comments or in free-form text arguments
* to block tags.
*
* @param holderTag specific tag where comment resides
* @param element specific element where comment resides
* @param tags array of text tags and inline tags (often alternating)
present in the text of interest for this element
* @param isFirstSentence true if text is first sentence
* @param inSummary if the comment tags are added into the summary section
* @param holderTag specific tag where comment resides
* @param element specific element where comment resides
* @param trees array of text tags and inline tags (often alternating)
* present in the text of interest for this element
* @param isFirstSentence true if text is first sentence
* @param inSummary if the comment tags are added into the summary section
* @return a Content object
*/
public Content commentTagsToContent(DocTree holderTag, Element element,
List<? extends DocTree> tags, boolean isFirstSentence, boolean inSummary) {
List<? extends DocTree> trees, boolean isFirstSentence, boolean inSummary) {
final Content result = new ContentBuilder() {
@Override
@ -1342,10 +1342,10 @@ public class HtmlDocletWriter {
};
CommentHelper ch = utils.getCommentHelper(element);
// Array of all possible inline tags for this javadoc run
configuration.tagletManager.checkTags(element, tags, true);
configuration.tagletManager.checkTags(element, trees, true);
commentRemoved = false;
for (ListIterator<? extends DocTree> iterator = tags.listIterator(); iterator.hasNext();) {
for (ListIterator<? extends DocTree> iterator = trees.listIterator(); iterator.hasNext();) {
boolean isFirstNode = !iterator.hasPrevious();
DocTree tag = iterator.next();
boolean isLastNode = !iterator.hasNext();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2019, 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
@ -29,6 +29,7 @@ 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;
/**
@ -44,7 +45,7 @@ import jdk.javadoc.internal.doclets.toolkit.Content;
public abstract class BasePropertyTaglet extends BaseTaglet {
public BasePropertyTaglet(String name) {
super(name, false, EnumSet.of(Site.METHOD));
super(name, false, EnumSet.of(Location.METHOD));
}
/**

View File

@ -29,6 +29,7 @@ import java.util.Set;
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;
/**
@ -40,30 +41,29 @@ import jdk.javadoc.internal.doclets.toolkit.Content;
* deletion without notice.</b>
*/
public class BaseTaglet implements Taglet {
/**
* The different kinds of place where any given tag may be used.
*/
enum Site {
OVERVIEW, MODULE, PACKAGE, TYPE, CONSTRUCTOR, METHOD, FIELD
}
protected final String name;
private final boolean inline;
private final Set<Site> sites;
private final Set<Location> sites;
BaseTaglet(String name, boolean inline, Set<Site> sites) {
BaseTaglet(String name, boolean inline, Set<Location> sites) {
this.name = name;
this.inline = inline;
this.sites = sites;
}
@Override
public Set<Location> getAllowedLocations() {
return sites;
}
/**
* Returns true if this {@code Taglet} can be used in constructor documentation.
* @return true if this {@code Taglet} can be used in constructor documentation and false
* otherwise.
*/
public final boolean inConstructor() {
return sites.contains(Site.CONSTRUCTOR);
return sites.contains(Location.CONSTRUCTOR);
}
/**
@ -72,7 +72,7 @@ public class BaseTaglet implements Taglet {
* otherwise.
*/
public final boolean inField() {
return sites.contains(Site.FIELD);
return sites.contains(Location.FIELD);
}
/**
@ -81,7 +81,7 @@ public class BaseTaglet implements Taglet {
* otherwise.
*/
public final boolean inMethod() {
return sites.contains(Site.METHOD);
return sites.contains(Location.METHOD);
}
/**
@ -90,7 +90,7 @@ public class BaseTaglet implements Taglet {
* otherwise.
*/
public final boolean inOverview() {
return sites.contains(Site.OVERVIEW);
return sites.contains(Location.OVERVIEW);
}
/**
@ -99,7 +99,7 @@ public class BaseTaglet implements Taglet {
* otherwise.
*/
public final boolean inModule() {
return sites.contains(Site.MODULE);
return sites.contains(Location.MODULE);
}
/**
@ -108,7 +108,7 @@ public class BaseTaglet implements Taglet {
* otherwise.
*/
public final boolean inPackage() {
return sites.contains(Site.PACKAGE);
return sites.contains(Location.PACKAGE);
}
/**
@ -117,7 +117,7 @@ public class BaseTaglet implements Taglet {
* otherwise.
*/
public final boolean inType() {
return sites.contains(Site.TYPE);
return sites.contains(Location.TYPE);
}
/**

View File

@ -30,6 +30,7 @@ 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;
import static com.sun.source.doctree.DocTree.Kind.CODE;
@ -55,7 +56,7 @@ import static com.sun.source.doctree.DocTree.Kind.CODE;
public class CodeTaglet extends BaseTaglet {
CodeTaglet() {
super(CODE.tagName, true, EnumSet.allOf(Site.class));
super(CODE.tagName, true, EnumSet.allOf(Location.class));
}
@Override

View File

@ -28,7 +28,7 @@ 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;
import static com.sun.source.doctree.DocTree.Kind.DEPRECATED;
@ -46,7 +46,7 @@ public class DeprecatedTaglet extends BaseTaglet {
public DeprecatedTaglet() {
super(DEPRECATED.tagName, false,
EnumSet.of(Site.MODULE, Site.TYPE, Site.CONSTRUCTOR, Site.METHOD, Site.FIELD));
EnumSet.of(Location.MODULE, Location.TYPE, Location.CONSTRUCTOR, Location.METHOD, Location.FIELD));
}
@Override

View File

@ -29,6 +29,7 @@ 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;
import static com.sun.source.doctree.DocTree.Kind.DOC_ROOT;
@ -50,7 +51,7 @@ public class DocRootTaglet extends BaseTaglet {
* Construct a new DocRootTaglet.
*/
public DocRootTaglet() {
super(DOC_ROOT.tagName, true, EnumSet.allOf(Site.class));
super(DOC_ROOT.tagName, true, EnumSet.allOf(Location.class));
}
@Override

View File

@ -29,6 +29,7 @@ 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;
import static com.sun.source.doctree.DocTree.Kind.INDEX;
@ -42,7 +43,7 @@ import static com.sun.source.doctree.DocTree.Kind.INDEX;
public class IndexTaglet extends BaseTaglet {
IndexTaglet() {
super(INDEX.tagName, true, EnumSet.allOf(Site.class));
super(INDEX.tagName, true, EnumSet.allOf(Location.class));
}
@Override

View File

@ -30,6 +30,7 @@ import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import com.sun.source.doctree.DocTree;
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.Messages;
@ -57,7 +58,7 @@ public class InheritDocTaglet extends BaseTaglet {
* Construct a new InheritDocTaglet.
*/
public InheritDocTaglet () {
super(INHERIT_DOC.tagName, true, EnumSet.of(Site.TYPE, Site.METHOD));
super(INHERIT_DOC.tagName, true, EnumSet.of(Location.TYPE, Location.METHOD));
}
/**

View File

@ -29,6 +29,7 @@ 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;
import static com.sun.source.doctree.DocTree.Kind.LITERAL;
@ -48,7 +49,7 @@ import static com.sun.source.doctree.DocTree.Kind.LITERAL;
public class LiteralTaglet extends BaseTaglet {
LiteralTaglet() {
super(LITERAL.tagName, true, EnumSet.allOf(Site.class));
super(LITERAL.tagName, true, EnumSet.allOf(Location.class));
}
@Override

View File

@ -34,6 +34,7 @@ import javax.lang.model.element.TypeElement;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.ParamTree;
import jdk.javadoc.doclet.Taglet.Location;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.Messages;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
@ -65,7 +66,7 @@ public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
* Construct a ParamTaglet.
*/
public ParamTaglet() {
super(PARAM.tagName, false, EnumSet.of(Site.TYPE, Site.CONSTRUCTOR, Site.METHOD));
super(PARAM.tagName, false, EnumSet.of(Location.TYPE, Location.CONSTRUCTOR, Location.METHOD));
}
/**

View File

@ -34,6 +34,7 @@ import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeMirror;
import com.sun.source.doctree.DocTree;
import jdk.javadoc.doclet.Taglet.Location;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.Messages;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
@ -54,7 +55,7 @@ import static com.sun.source.doctree.DocTree.Kind.RETURN;
public class ReturnTaglet extends BaseTaglet implements InheritableTaglet {
public ReturnTaglet() {
super(RETURN.tagName, false, EnumSet.of(Site.METHOD));
super(RETURN.tagName, false, EnumSet.of(Location.METHOD));
}
@Override

View File

@ -31,6 +31,7 @@ import java.util.List;
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;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
@ -50,7 +51,7 @@ import static com.sun.source.doctree.DocTree.Kind.SEE;
public class SeeTaglet extends BaseTaglet implements InheritableTaglet {
public SeeTaglet() {
super(SEE.tagName, false, EnumSet.allOf(Site.class));
super(SEE.tagName, false, EnumSet.allOf(Location.class));
}
@Override

View File

@ -32,6 +32,7 @@ import java.util.Set;
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;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
@ -84,7 +85,7 @@ public class SimpleTaglet extends BaseTaglet implements InheritableTaglet {
* for package, 't' for type, 'm' for method, 'c' for constructor
* and 'f' for field.
*/
public SimpleTaglet(String tagName, String header, Set<Site> sites) {
public SimpleTaglet(String tagName, String header, Set<Location> sites) {
this(tagName, header, sites, true);
}
@ -97,38 +98,38 @@ public class SimpleTaglet extends BaseTaglet implements InheritableTaglet {
* for package, 't' for type, 'm' for method, 'c' for constructor
* and 'f' for field.
*/
public SimpleTaglet(String tagName, String header, Set<Site> sites, boolean enabled) {
public SimpleTaglet(String tagName, String header, Set<Location> sites, boolean enabled) {
super(tagName, false, sites);
this.header = header;
this.enabled = enabled;
}
private static Set<Site> getSites(String locations) {
Set<Site> set = EnumSet.noneOf(Site.class);
private static Set<Location> getSites(String locations) {
Set<Location> set = EnumSet.noneOf(Location.class);
for (int i = 0; i < locations.length(); i++) {
switch (locations.charAt(i)) {
case 'a': case 'A':
return EnumSet.allOf(Site.class);
return EnumSet.allOf(Location.class);
case 'c': case 'C':
set.add(Site.CONSTRUCTOR);
set.add(Location.CONSTRUCTOR);
break;
case 'f': case 'F':
set.add(Site.FIELD);
set.add(Location.FIELD);
break;
case 'm': case 'M':
set.add(Site.METHOD);
set.add(Location.METHOD);
break;
case 'o': case 'O':
set.add(Site.OVERVIEW);
set.add(Location.OVERVIEW);
break;
case 'p': case 'P':
set.add(Site.PACKAGE);
set.add(Location.PACKAGE);
break;
case 's': case 'S': // super-packages, anyone?
set.add(Site.MODULE);
set.add(Location.MODULE);
break;
case 't': case 'T':
set.add(Site.TYPE);
set.add(Location.TYPE);
break;
case 'x': case 'X':
break;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2019, 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
@ -29,6 +29,7 @@ import java.util.EnumSet;
import javax.lang.model.element.Element;
import com.sun.source.doctree.DocTree;
import jdk.javadoc.doclet.Taglet.Location;
import com.sun.source.doctree.SummaryTree;
import jdk.javadoc.internal.doclets.toolkit.Content;
@ -46,7 +47,7 @@ import static com.sun.source.doctree.DocTree.Kind.SUMMARY;
public class SummaryTaglet extends BaseTaglet {
public SummaryTaglet() {
super(SUMMARY.tagName, true, EnumSet.allOf(Site.class));
super(SUMMARY.tagName, true, EnumSet.allOf(Location.class));
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,6 +26,7 @@
package jdk.javadoc.internal.doclets.toolkit.taglets;
import com.sun.source.doctree.DocTree;
import jdk.javadoc.doclet.Taglet.Location;
import jdk.javadoc.internal.doclets.toolkit.Content;
import javax.lang.model.element.Element;
@ -45,8 +46,8 @@ import static com.sun.source.doctree.DocTree.Kind.SYSTEM_PROPERTY;
public class SystemPropertyTaglet extends BaseTaglet {
SystemPropertyTaglet(){
super(SYSTEM_PROPERTY.tagName, true, EnumSet.of(Site.CONSTRUCTOR, Site.METHOD, Site.FIELD,
Site.PACKAGE, Site.MODULE, Site.TYPE));
super(SYSTEM_PROPERTY.tagName, true, EnumSet.of(Location.CONSTRUCTOR, Location.METHOD, Location.FIELD,
Location.PACKAGE, Location.MODULE, Location.TYPE));
}
@Override

View File

@ -25,9 +25,11 @@
package jdk.javadoc.internal.doclets.toolkit.taglets;
import java.util.Set;
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;
/**
@ -35,6 +37,13 @@ import jdk.javadoc.internal.doclets.toolkit.Content;
*/
public interface Taglet {
/**
* Returns the set of allowed locations for block tags
* handled by this taglet.
*
* @return the set of allowable locations
*/
Set<Location> getAllowedLocations();
/**
* Return true if this <code>Taglet</code>
@ -43,7 +52,7 @@ public interface Taglet {
* is used in field documentation and false
* otherwise.
*/
public abstract boolean inField();
boolean inField();
/**
* Return true if this <code>Taglet</code>
@ -52,7 +61,7 @@ public interface Taglet {
* is used in constructor documentation and false
* otherwise.
*/
public abstract boolean inConstructor();
boolean inConstructor();
/**
* Return true if this <code>Taglet</code>
@ -61,7 +70,7 @@ public interface Taglet {
* is used in method documentation and false
* otherwise.
*/
public abstract boolean inMethod();
boolean inMethod();
/**
* Return true if this <code>Taglet</code>
@ -70,7 +79,7 @@ public interface Taglet {
* is used in method documentation and false
* otherwise.
*/
public abstract boolean inOverview();
boolean inOverview();
/**
* Return true if this <code>Taglet</code>
@ -79,7 +88,7 @@ public interface Taglet {
* is used in module documentation and false
* otherwise.
*/
public abstract boolean inModule();
boolean inModule();
/**
* Return true if this <code>Taglet</code>
@ -88,7 +97,7 @@ public interface Taglet {
* is used in package documentation and false
* otherwise.
*/
public abstract boolean inPackage();
boolean inPackage();
/**
* Return true if this <code>Taglet</code>
@ -98,7 +107,7 @@ public interface Taglet {
* is used in type documentation and false
* otherwise.
*/
public abstract boolean inType();
boolean inType();
/**
* Return true if this <code>Taglet</code>
@ -106,13 +115,24 @@ public interface Taglet {
* @return true if this <code>Taglet</code>
* is an inline tag and false otherwise.
*/
public abstract boolean isInlineTag();
boolean isInlineTag();
/**
* Indicates whether this taglet supports block tags.
*
* @return true if this taglet supports block tags
* @implSpec This implementation returns the inverse
* result to {@code isInlineTag}.
*/
default boolean isBlockTag() {
return !isInlineTag();
}
/**
* Return the name of this custom tag.
* @return the name of this custom tag.
*/
public abstract String getName();
String getName();
/**
* Given the <code>Tag</code> representation of this custom
@ -124,26 +144,23 @@ public interface Taglet {
* @throws UnsupportedOperationException thrown when the method is not supported by the taglet.
* @return the Content representation of this <code>Tag</code>.
*/
public abstract Content getTagletOutput(Element holder, DocTree tag, TagletWriter writer) throws
Content getTagletOutput(Element holder, DocTree tag, TagletWriter writer) throws
UnsupportedOperationException;
/**
* Given a <code>Doc</code> object, check if it holds any tags of
* this type. If it does, return the string representing the output.
* Given an element object, check if it holds any tags of
* this type. If it does, return the content representing the output.
* If it does not, return null.
* @param holder a {@link Doc} object holding the custom tag.
* @param holder an element holding the custom tag.
* @param writer a {@link TagletWriter} Taglet writer.
* @throws UnsupportedTagletOperationException thrown when the method is not
* supported by the taglet.
* @return the TagletOutput representation of this <code>Tag</code>.
* @return the content representation of this <code>Tag</code>.
*/
public abstract Content getTagletOutput(Element holder, TagletWriter writer) throws
Content getTagletOutput(Element holder, TagletWriter writer) throws
UnsupportedTagletOperationException;
@Override
public abstract String toString();
static class UnsupportedTagletOperationException extends UnsupportedOperationException {
class UnsupportedTagletOperationException extends UnsupportedOperationException {
private static final long serialVersionUID = -3530273193380250271L;
public UnsupportedTagletOperationException(String message) {
super(message);

View File

@ -25,8 +25,22 @@
package jdk.javadoc.internal.doclets.toolkit.taglets;
import java.io.*;
import java.util.*;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.TreeSet;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
@ -39,20 +53,32 @@ import javax.tools.JavaFileManager;
import javax.tools.StandardJavaFileManager;
import com.sun.source.doctree.DocTree;
import jdk.javadoc.doclet.Doclet;
import jdk.javadoc.doclet.DocletEnvironment;
import jdk.javadoc.doclet.Taglet.Location;
import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration;
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.taglets.BaseTaglet.Site;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.Utils;
import static javax.tools.DocumentationTool.Location.*;
import static com.sun.source.doctree.DocTree.Kind.*;
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.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.PROVIDES;
import static com.sun.source.doctree.DocTree.Kind.SEE;
import static com.sun.source.doctree.DocTree.Kind.SERIAL;
import static com.sun.source.doctree.DocTree.Kind.SERIAL_DATA;
import static com.sun.source.doctree.DocTree.Kind.SERIAL_FIELD;
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.USES;
import static com.sun.source.doctree.DocTree.Kind.VERSION;
import static javax.tools.DocumentationTool.Location.TAGLET_PATH;
/**
* Manages the {@code Taglet}s used by doclets.
@ -76,9 +102,9 @@ public class TagletManager {
private final LinkedHashMap<String,Taglet> allTaglets;
/**
* Block (non-line) taglets, grouped by Site
* Block (non-inline) taglets, grouped by Location
*/
private Map<Site, List<Taglet>> blockTagletsBySite;
private Map<Location, List<Taglet>> blockTagletsByLocation;
/**
* The taglets that can appear inline in descriptive text.
@ -329,10 +355,10 @@ public class TagletManager {
* Given a series of {@code DocTree}s, check for spelling mistakes.
* @param element the tags holder
* @param trees the trees containing the comments
* @param areInlineTags true if the array of tags are inline and false otherwise.
* @param inlineTrees true if the trees are inline and false otherwise.
*/
@SuppressWarnings("preview")
public void checkTags(Element element, Iterable<? extends DocTree> trees, boolean areInlineTags) {
public void checkTags(Element element, Iterable<? extends DocTree> trees, boolean inlineTrees) {
if (trees == null) {
return;
}
@ -357,69 +383,72 @@ public class TagletManager {
final Taglet taglet = allTaglets.get(name);
// Check and verify tag usage
if (taglet != null) {
if (areInlineTags && !taglet.isInlineTag()) {
if (inlineTrees && !taglet.isInlineTag()) {
printTagMisuseWarn(ch, taglet, tag, "inline");
}
// nothing more to do
if (element == null) {
return;
}
new SimpleElementVisitor14<Void, Void>() {
@Override
public Void visitModule(ModuleElement e, Void p) {
if (!taglet.inModule()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "module");
}
return null;
}
@Override
public Void visitPackage(PackageElement e, Void p) {
if (!taglet.inPackage()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "package");
if (!inlineTrees) {
new SimpleElementVisitor14<Void, Void>() {
@Override
public Void visitModule(ModuleElement e, Void p) {
if (!taglet.inModule()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "module");
}
return null;
}
return null;
}
@Override
public Void visitType(TypeElement e, Void p) {
if (!taglet.inType()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "class");
@Override
public Void visitPackage(PackageElement e, Void p) {
if (!taglet.inPackage()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "package");
}
return null;
}
return null;
}
@Override
public Void visitExecutable(ExecutableElement e, Void p) {
if (utils.isConstructor(e) && !taglet.inConstructor()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "constructor");
} else if (!taglet.inMethod()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "method");
@Override
public Void visitType(TypeElement e, Void p) {
if (!taglet.inType()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "class");
}
return null;
}
return null;
}
@Override
public Void visitVariable(VariableElement e, Void p) {
if (utils.isField(e) && !taglet.inField()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "field");
@Override
public Void visitExecutable(ExecutableElement e, Void p) {
if (utils.isConstructor(e) && !taglet.inConstructor()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "constructor");
} else if (!taglet.inMethod()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "method");
}
return null;
}
return null;
}
@Override
public Void visitUnknown(Element e, Void p) {
if (utils.isOverviewElement(e) && !taglet.inOverview()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "overview");
@Override
public Void visitVariable(VariableElement e, Void p) {
if (utils.isField(e) && !taglet.inField()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "field");
}
return null;
}
return null;
}
@Override
protected Void defaultAction(Element e, Void p) {
return null;
}
}.visit(element);
@Override
public Void visitUnknown(Element e, Void p) {
if (utils.isOverviewElement(e) && !taglet.inOverview()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "overview");
}
return null;
}
@Override
protected Void defaultAction(Element e, Void p) {
return null;
}
}.visit(element);
}
}
}
}
@ -504,36 +533,36 @@ public class TagletManager {
*/
@SuppressWarnings("fallthrough")
public List<Taglet> getBlockTaglets(Element e) {
if (blockTagletsBySite == null) {
if (blockTagletsByLocation == null) {
initBlockTaglets();
}
switch (e.getKind()) {
case CONSTRUCTOR:
return blockTagletsBySite.get(Site.CONSTRUCTOR);
return blockTagletsByLocation.get(Location.CONSTRUCTOR);
case METHOD:
return blockTagletsBySite.get(Site.METHOD);
return blockTagletsByLocation.get(Location.METHOD);
case ENUM_CONSTANT:
case FIELD:
return blockTagletsBySite.get(Site.FIELD);
return blockTagletsByLocation.get(Location.FIELD);
case ANNOTATION_TYPE:
case INTERFACE:
case CLASS:
case ENUM:
case RECORD:
return blockTagletsBySite.get(Site.TYPE);
return blockTagletsByLocation.get(Location.TYPE);
case MODULE:
return blockTagletsBySite.get(Site.MODULE);
return blockTagletsByLocation.get(Location.MODULE);
case PACKAGE:
return blockTagletsBySite.get(Site.PACKAGE);
return blockTagletsByLocation.get(Location.PACKAGE);
case OTHER:
if (e instanceof DocletElement) {
DocletElement de = (DocletElement)e;
switch (de.getSubKind()) {
case DOCFILE:
return blockTagletsBySite.get(Site.PACKAGE);
return blockTagletsByLocation.get(Location.PACKAGE);
case OVERVIEW:
return blockTagletsBySite.get(Site.OVERVIEW);
return blockTagletsByLocation.get(Location.OVERVIEW);
default:
// fall through
}
@ -549,9 +578,9 @@ public class TagletManager {
*/
private void initBlockTaglets() {
blockTagletsBySite = new EnumMap<>(Site.class);
for (Site site : Site.values()) {
blockTagletsBySite.put(site, new ArrayList<>());
blockTagletsByLocation = new EnumMap<>(Location.class);
for (Location site : Location.values()) {
blockTagletsByLocation.put(site, new ArrayList<>());
}
inlineTags = new ArrayList<>();
@ -559,27 +588,11 @@ public class TagletManager {
for (Taglet current : allTaglets.values()) {
if (current.isInlineTag()) {
inlineTags.add(current);
} else {
if (current.inOverview()) {
blockTagletsBySite.get(Site.OVERVIEW).add(current);
}
if (current.inModule()) {
blockTagletsBySite.get(Site.MODULE).add(current);
}
if (current.inPackage()) {
blockTagletsBySite.get(Site.PACKAGE).add(current);
}
if (current.inType()) {
blockTagletsBySite.get(Site.TYPE).add(current);
}
if (current.inConstructor()) {
blockTagletsBySite.get(Site.CONSTRUCTOR).add(current);
}
if (current.inMethod()) {
blockTagletsBySite.get(Site.METHOD).add(current);
}
if (current.inField()) {
blockTagletsBySite.get(Site.FIELD).add(current);
}
if (current.isBlockTag()) {
for (Location l : current.getAllowedLocations()) {
blockTagletsByLocation.get(l).add(current);
}
}
}
@ -610,26 +623,26 @@ public class TagletManager {
addStandardTaglet(new ThrowsTaglet());
addStandardTaglet(
new SimpleTaglet(EXCEPTION.tagName, null,
EnumSet.of(Site.METHOD, Site.CONSTRUCTOR)));
EnumSet.of(Location.METHOD, Location.CONSTRUCTOR)));
addStandardTaglet(
new SimpleTaglet(SINCE.tagName, resources.getText("doclet.Since"),
EnumSet.allOf(Site.class), !nosince));
EnumSet.allOf(Location.class), !nosince));
addStandardTaglet(
new SimpleTaglet(VERSION.tagName, resources.getText("doclet.Version"),
EnumSet.of(Site.OVERVIEW, Site.MODULE, Site.PACKAGE, Site.TYPE), showversion));
EnumSet.of(Location.OVERVIEW, Location.MODULE, Location.PACKAGE, Location.TYPE), showversion));
addStandardTaglet(
new SimpleTaglet(AUTHOR.tagName, resources.getText("doclet.Author"),
EnumSet.of(Site.OVERVIEW, Site.MODULE, Site.PACKAGE, Site.TYPE), showauthor));
EnumSet.of(Location.OVERVIEW, Location.MODULE, Location.PACKAGE, Location.TYPE), showauthor));
addStandardTaglet(
new SimpleTaglet(SERIAL_DATA.tagName, resources.getText("doclet.SerialData"),
EnumSet.noneOf(Site.class)));
EnumSet.noneOf(Location.class)));
addStandardTaglet(
new SimpleTaglet(HIDDEN.tagName, null,
EnumSet.of(Site.TYPE, Site.METHOD, Site.FIELD)));
EnumSet.of(Location.TYPE, Location.METHOD, Location.FIELD)));
// This appears to be a default custom (non-standard) taglet
Taglet factoryTaglet = new SimpleTaglet("factory", resources.getText("doclet.Factory"),
EnumSet.of(Site.METHOD));
EnumSet.of(Location.METHOD));
allTaglets.put(factoryTaglet.getName(), factoryTaglet);
addStandardTaglet(new SeeTaglet());
@ -647,15 +660,15 @@ public class TagletManager {
// Keep track of the names of standard tags for error checking purposes.
// The following are not handled above.
addStandardTaglet(new DeprecatedTaglet());
addStandardTaglet(new BaseTaglet(LINK.tagName, true, EnumSet.allOf(Site.class)));
addStandardTaglet(new BaseTaglet(LINK_PLAIN.tagName, true, EnumSet.allOf(Site.class)));
addStandardTaglet(new BaseTaglet(USES.tagName, false, EnumSet.of(Site.MODULE)));
addStandardTaglet(new BaseTaglet(PROVIDES.tagName, false, EnumSet.of(Site.MODULE)));
addStandardTaglet(new BaseTaglet(LINK.tagName, true, EnumSet.allOf(Location.class)));
addStandardTaglet(new BaseTaglet(LINK_PLAIN.tagName, true, EnumSet.allOf(Location.class)));
addStandardTaglet(new BaseTaglet(USES.tagName, false, EnumSet.of(Location.MODULE)));
addStandardTaglet(new BaseTaglet(PROVIDES.tagName, false, EnumSet.of(Location.MODULE)));
addStandardTaglet(
new SimpleTaglet(SERIAL.tagName, null,
EnumSet.of(Site.PACKAGE, Site.TYPE, Site.FIELD)));
EnumSet.of(Location.PACKAGE, Location.TYPE, Location.FIELD)));
addStandardTaglet(
new SimpleTaglet(SERIAL_FIELD.tagName, null, EnumSet.of(Site.FIELD)));
new SimpleTaglet(SERIAL_FIELD.tagName, null, EnumSet.of(Location.FIELD)));
}
/**
@ -666,11 +679,11 @@ public class TagletManager {
addStandardTaglet(new PropertySetterTaglet());
addStandardTaglet(new SimpleTaglet("propertyDescription",
resources.getText("doclet.PropertyDescription"),
EnumSet.of(Site.METHOD, Site.FIELD)));
EnumSet.of(Location.METHOD, Location.FIELD)));
addStandardTaglet(new SimpleTaglet("defaultValue", resources.getText("doclet.DefaultValue"),
EnumSet.of(Site.METHOD, Site.FIELD)));
EnumSet.of(Location.METHOD, Location.FIELD)));
addStandardTaglet(new SimpleTaglet("treatAsPrivate", null,
EnumSet.of(Site.TYPE, Site.METHOD, Site.FIELD)));
EnumSet.of(Location.TYPE, Location.METHOD, Location.FIELD)));
}
private void addStandardTaglet(Taglet taglet) {
@ -735,6 +748,7 @@ public class TagletManager {
for (Taglet t : taglets) {
String name = t.isInlineTag() ? "{@" + t.getName() + "}" : "@" + t.getName();
out.println(String.format("%20s", name) + ": "
+ format(t.isBlockTag(), "block")+ " "
+ format(t.inOverview(), "overview") + " "
+ format(t.inModule(), "module") + " "
+ format(t.inPackage(), "package") + " "

View File

@ -25,8 +25,13 @@
package jdk.javadoc.internal.doclets.toolkit.taglets;
import java.util.*;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
@ -34,6 +39,8 @@ import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import com.sun.source.doctree.DocTree;
import jdk.javadoc.doclet.Taglet.Location;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
import jdk.javadoc.internal.doclets.toolkit.util.DocFinder;
@ -54,7 +61,7 @@ public class ThrowsTaglet extends BaseTaglet
implements InheritableTaglet {
public ThrowsTaglet() {
super(THROWS.tagName, false, EnumSet.of(Site.CONSTRUCTOR, Site.METHOD));
super(THROWS.tagName, false, EnumSet.of(Location.CONSTRUCTOR, Location.METHOD));
}
@Override
@ -174,7 +181,7 @@ public class ThrowsTaglet extends BaseTaglet
* @return the Content representation of this <code>Tag</code>.
*/
protected Content throwsTagsOutput(Map<List<? extends DocTree>, ExecutableElement> throwTags,
TagletWriter writer, Set<String> alreadyDocumented, boolean allowDups) {
TagletWriter writer, Set<String> alreadyDocumented, boolean allowDups) {
Utils utils = writer.configuration().utils;
Content result = writer.getOutputInstance();
if (!throwTags.isEmpty()) {

View File

@ -22,10 +22,12 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.javadoc.internal.doclets.toolkit.taglets;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.Element;
@ -53,60 +55,57 @@ public class UserTaglet implements Taglet {
userTaglet = t;
}
public Set<jdk.javadoc.doclet.Taglet.Location> getAllowedLocations() {
return userTaglet.getAllowedLocations();
}
/**
* {@inheritDoc}
*/
public boolean inField() {
return userTaglet.isInlineTag()
|| userTaglet.getAllowedLocations().contains(FIELD);
return userTaglet.getAllowedLocations().contains(FIELD);
}
/**
* {@inheritDoc}
*/
public boolean inConstructor() {
return userTaglet.isInlineTag()
|| userTaglet.getAllowedLocations().contains(CONSTRUCTOR);
return userTaglet.getAllowedLocations().contains(CONSTRUCTOR);
}
/**
* {@inheritDoc}
*/
public boolean inMethod() {
return userTaglet.isInlineTag()
|| userTaglet.getAllowedLocations().contains(METHOD);
return userTaglet.getAllowedLocations().contains(METHOD);
}
/**
* {@inheritDoc}
*/
public boolean inOverview() {
return userTaglet.isInlineTag()
|| userTaglet.getAllowedLocations().contains(OVERVIEW);
return userTaglet.getAllowedLocations().contains(OVERVIEW);
}
/**
* {@inheritDoc}
*/
public boolean inModule() {
return userTaglet.isInlineTag()
|| userTaglet.getAllowedLocations().contains(MODULE);
return userTaglet.getAllowedLocations().contains(MODULE);
}
/**
* {@inheritDoc}
*/
public boolean inPackage() {
return userTaglet.isInlineTag()
|| userTaglet.getAllowedLocations().contains(PACKAGE);
return userTaglet.getAllowedLocations().contains(PACKAGE);
}
/**
* {@inheritDoc}
*/
public boolean inType() {
return userTaglet.isInlineTag()
|| userTaglet.getAllowedLocations().contains(TYPE);
return userTaglet.getAllowedLocations().contains(TYPE);
}
/**
@ -118,6 +117,10 @@ public class UserTaglet implements Taglet {
return userTaglet.isInlineTag();
}
public boolean isBlockTag() {
return userTaglet.isBlockTag();
}
/**
* {@inheritDoc}
*/

View File

@ -30,6 +30,7 @@ import javax.lang.model.element.Element;
import javax.lang.model.element.VariableElement;
import com.sun.source.doctree.DocTree;
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.Messages;
@ -59,7 +60,7 @@ public class ValueTaglet extends BaseTaglet {
* Construct a new ValueTaglet.
*/
public ValueTaglet() {
super(VALUE.tagName, true, EnumSet.allOf(Site.class));
super(VALUE.tagName, true, EnumSet.allOf(Location.class));
}
/**

View File

@ -0,0 +1,152 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8202947
* @summary Test bimodal (inline and block) taglets
* @library /tools/lib ../../lib
* @modules jdk.javadoc/jdk.javadoc.internal.tool
* @build toolbox.ToolBox javadoc.tester.*
* @run main TestBimodalTaglets
*/
import java.nio.file.Path;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.lang.model.element.Element;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.UnknownBlockTagTree;
import com.sun.source.doctree.UnknownInlineTagTree;
import javadoc.tester.JavadocTester;
import jdk.javadoc.doclet.Taglet;
import toolbox.ToolBox;
public class TestBimodalTaglets extends JavadocTester implements Taglet {
public static void main(String... args) throws Exception {
new TestBimodalTaglets().runTests(m -> new Object[] { Path.of(m.getName()) });
}
ToolBox tb = new ToolBox();
@Test
public void testBimodalTaglet(Path base) throws Exception {
Path src = base.resolve("src");
tb.writeJavaFiles(src,
"package p;\n"
+ comment("This is a comment.",
"Here is an inline {@test abc} test tag {@test def}.",
"@see Object",
"@test 123",
"@see String",
"@test 456")
+ "public class C { }\n");
javadoc("-d", base.resolve("out").toString(),
"--source-path", src.toString(),
"-tagletpath", System.getProperty("test.class.path"),
"-taglet", "TestBimodalTaglets",
"p");
checkOutput("p/C.html", true,
"Here is an inline INLINE[abc] test tag INLINE[def].",
"<dt>BLOCK:<dd>123<dd>456");
}
String comment(String... lines) {
return Arrays.stream(lines)
.collect(Collectors.joining("\n * ", "/**\n * ", "\n */"));
}
// the taglet ....
@Override
public Set<Location> getAllowedLocations() {
return EnumSet.allOf(Location.class);
}
@Override
public boolean isInlineTag() {
return true;
}
@Override
public boolean isBlockTag() {
return true;
}
@Override
public String getName() {
return "test";
}
@Override
public String toString(List<? extends DocTree> tags, Element element) {
if (tags.size() == 1 && tags.get(0) instanceof UnknownInlineTagTree) {
return inlineTagToString((UnknownInlineTagTree) tags.get(0));
} else {
return blockTagsToString(tags);
}
}
/**
* Converts an inline tag to a string composed of its contents wrapped in "INLINE[" ... "]"
*
* @param tag the tag
* @return the string
*/
private String inlineTagToString(UnknownInlineTagTree tag) {
return "INLINE[" +
toString(tag.getContent())
+ "]";
}
/**
* Converts a series of block tags to a string composed of a {@code> <dt>} header,
* followed by the contents of each tag preceded by {@code <dd>}.
* Note that the doclet provides the enclosing {@code <dl>...</dl>} around all the
* block tags.
*
* @param tags the tags
* @return the string
*/
private String blockTagsToString(List<? extends DocTree> tags) {
return "<dt>BLOCK:"
+ tags.stream()
.map (t -> (UnknownBlockTagTree) t)
.map(t -> "<dd>" + toString(t.getContent()))
.collect(Collectors.joining());
}
private String toString(List<? extends DocTree> trees) {
return trees.stream()
.map(Object::toString)
.collect(Collectors.joining());
}
}

View File

@ -1,31 +1,31 @@
@author: overview module package type ........... ...... ..... ...... disabled
{@code}: overview module package type constructor method field inline ........
@defaultValue: ........ ...... ....... .... ........... method field ...... ........
@deprecated: ........ module ....... type constructor method field ...... ........
{@docRoot}: overview module package type constructor method field inline ........
@exception: ........ ...... ....... .... constructor method ..... ...... ........
@factory: ........ ...... ....... .... ........... method ..... ...... ........
@hidden: ........ ...... ....... type ........... method field ...... ........
{@index}: overview module package type constructor method field inline ........
{@inheritDoc}: ........ ...... ....... type ........... method ..... inline ........
{@link}: overview module package type constructor method field inline ........
{@linkplain}: overview module package type constructor method field inline ........
{@literal}: overview module package type constructor method field inline ........
@param: ........ ...... ....... type constructor method ..... ...... ........
@propertyDescription: ........ ...... ....... .... ........... method field ...... ........
@propertyGetter: ........ ...... ....... .... ........... method ..... ...... ........
@propertySetter: ........ ...... ....... .... ........... method ..... ...... ........
@provides: ........ module ....... .... ........... ...... ..... ...... ........
@return: ........ ...... ....... .... ........... method ..... ...... ........
@see: overview module package type constructor method field ...... ........
@serial: ........ ...... package type ........... ...... field ...... ........
@serialData: ........ ...... ....... .... ........... ...... ..... ...... ........
@serialField: ........ ...... ....... .... ........... ...... field ...... ........
@since: overview module package type constructor method field ...... ........
{@summary}: overview module package type constructor method field inline ........
{@systemProperty}: ........ module package type constructor method field inline ........
@throws: ........ ...... ....... .... constructor method ..... ...... ........
@treatAsPrivate: ........ ...... ....... type ........... method field ...... ........
@uses: ........ module ....... .... ........... ...... ..... ...... ........
{@value}: overview module package type constructor method field inline ........
@version: overview module package type ........... ...... ..... ...... disabled
@author: block overview module package type ........... ...... ..... ...... disabled
{@code}: ..... overview module package type constructor method field inline ........
@defaultValue: block ........ ...... ....... .... ........... method field ...... ........
@deprecated: block ........ module ....... type constructor method field ...... ........
{@docRoot}: ..... overview module package type constructor method field inline ........
@exception: block ........ ...... ....... .... constructor method ..... ...... ........
@factory: block ........ ...... ....... .... ........... method ..... ...... ........
@hidden: block ........ ...... ....... type ........... method field ...... ........
{@index}: ..... overview module package type constructor method field inline ........
{@inheritDoc}: ..... ........ ...... ....... type ........... method ..... inline ........
{@link}: ..... overview module package type constructor method field inline ........
{@linkplain}: ..... overview module package type constructor method field inline ........
{@literal}: ..... overview module package type constructor method field inline ........
@param: block ........ ...... ....... type constructor method ..... ...... ........
@propertyDescription: block ........ ...... ....... .... ........... method field ...... ........
@propertyGetter: block ........ ...... ....... .... ........... method ..... ...... ........
@propertySetter: block ........ ...... ....... .... ........... method ..... ...... ........
@provides: block ........ module ....... .... ........... ...... ..... ...... ........
@return: block ........ ...... ....... .... ........... method ..... ...... ........
@see: block overview module package type constructor method field ...... ........
@serial: block ........ ...... package type ........... ...... field ...... ........
@serialData: block ........ ...... ....... .... ........... ...... ..... ...... ........
@serialField: block ........ ...... ....... .... ........... ...... field ...... ........
@since: block overview module package type constructor method field ...... ........
{@summary}: ..... overview module package type constructor method field inline ........
{@systemProperty}: ..... ........ module package type constructor method field inline ........
@throws: block ........ ...... ....... .... constructor method ..... ...... ........
@treatAsPrivate: block ........ ...... ....... type ........... method field ...... ........
@uses: block ........ module ....... .... ........... ...... ..... ...... ........
{@value}: ..... overview module package type constructor method field inline ........
@version: block overview module package type ........... ...... ..... ...... disabled