/*
* Copyright (c) 2001, 2018, 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.io.*;
import java.util.*;
import javax.lang.model.element.Element;
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.SimpleElementVisitor9;
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.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.*;
Manages the Taglet
s used by doclets. This is NOT part of any supported API.
If you write code that depends on this, you do so at your own risk.
This code and its internal interfaces are subject to change or
deletion without notice.
Author: Jamie Ho
/**
* Manages the {@code Taglet}s used by doclets.
*
* <p><b>This is NOT part of any supported API.
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*
* @author Jamie Ho
*/
public class TagletManager {
The default separator for the simple tag option.
/**
* The default separator for the simple tag option.
*/
public static final char SIMPLE_TAGLET_OPT_SEPARATOR = ':';
The map of all taglets.
/**
* The map of all taglets.
*/
private final LinkedHashMap<String,Taglet> allTaglets;
Block (non-line) taglets, grouped by Site
/**
* Block (non-line) taglets, grouped by Site
*/
private Map<Site, List<Taglet>> blockTagletsBySite;
The taglets that can appear inline in descriptive text.
/**
* The taglets that can appear inline in descriptive text.
*/
private List<Taglet> inlineTags;
The taglets that can appear in the serialized form.
/**
* The taglets that can appear in the serialized form.
*/
private List<Taglet> serializedFormTags;
private final DocletEnvironment docEnv;
private final Doclet doclet;
private final Utils utils;
private final Messages messages;
private final Resources resources;
Keep track of standard tags.
/**
* Keep track of standard tags.
*/
private final Set<String> standardTags;
Keep track of standard tags in lowercase to compare for better
error messages when a tag like @docRoot is mistakenly spelled
lowercase @docroot.
/**
* Keep track of standard tags in lowercase to compare for better
* error messages when a tag like @docRoot is mistakenly spelled
* lowercase @docroot.
*/
private final Set<String> standardTagsLowercase;
Keep track of overriden standard tags.
/**
* Keep track of overriden standard tags.
*/
private final Set<String> overridenStandardTags;
Keep track of the tags that may conflict
with standard tags in the future (any custom tag without
a period in its name).
/**
* Keep track of the tags that may conflict
* with standard tags in the future (any custom tag without
* a period in its name).
*/
private final Set<String> potentiallyConflictingTags;
The set of unseen custom tags.
/**
* The set of unseen custom tags.
*/
private final Set<String> unseenCustomTags;
True if we do not want to use @since tags.
/**
* True if we do not want to use @since tags.
*/
private final boolean nosince;
True if we want to use @version tags.
/**
* True if we want to use @version tags.
*/
private final boolean showversion;
True if we want to use @author tags.
/**
* True if we want to use @author tags.
*/
private final boolean showauthor;
True if we want to use JavaFX-related tags (@defaultValue, @treatAsPrivate).
/**
* True if we want to use JavaFX-related tags (@defaultValue, @treatAsPrivate).
*/
private final boolean javafx;
Show the taglets table when it has been initialized.
/**
* Show the taglets table when it has been initialized.
*/
private final boolean showTaglets;
Construct a new TagletManager
. Params: - nosince – true if we do not want to use @since tags.
- showversion – true if we want to use @version tags.
- showauthor – true if we want to use @author tags.
- javafx – indicates whether javafx is active.
- configuration – the configuration for this taglet manager
/**
* Construct a new {@code TagletManager}.
* @param nosince true if we do not want to use @since tags.
* @param showversion true if we want to use @version tags.
* @param showauthor true if we want to use @author tags.
* @param javafx indicates whether javafx is active.
* @param configuration the configuration for this taglet manager
*/
public TagletManager(boolean nosince, boolean showversion,
boolean showauthor, boolean javafx,
BaseConfiguration configuration) {
overridenStandardTags = new HashSet<>();
potentiallyConflictingTags = new HashSet<>();
standardTags = new HashSet<>();
standardTagsLowercase = new HashSet<>();
unseenCustomTags = new HashSet<>();
allTaglets = new LinkedHashMap<>();
this.nosince = nosince;
this.showversion = showversion;
this.showauthor = showauthor;
this.javafx = javafx;
this.docEnv = configuration.docEnv;
this.doclet = configuration.doclet;
this.messages = configuration.getMessages();
this.resources = configuration.getResources();
this.showTaglets = configuration.showTaglets;
this.utils = configuration.utils;
initStandardTaglets();
}
Add a new Taglet
. This is used to add a Taglet from within a Doclet. No message is printed to indicate that the Taglet is properly registered because these Taglets are typically added for every execution of the Doclet. We don't want to see this type of error message every time. Params: - customTag – the new
Taglet
to add.
/**
* Add a new {@code Taglet}. This is used to add a Taglet from within
* a Doclet. No message is printed to indicate that the Taglet is properly
* registered because these Taglets are typically added for every execution of the
* Doclet. We don't want to see this type of error message every time.
* @param customTag the new {@code Taglet} to add.
*/
public void addCustomTag(Taglet customTag) {
if (customTag != null) {
String name = customTag.getName();
allTaglets.remove(name);
allTaglets.put(name, customTag);
checkTagName(name);
}
}
public Set<String> getAllTagletNames() {
return allTaglets.keySet();
}
Add a new Taglet
. Print a message to indicate whether or not the Taglet was registered properly. Params: - classname – the name of the class representing the custom tag.
- fileManager – the filemanager to load classes and resources.
- tagletPath – the path to the class representing the custom tag.
/**
* Add a new {@code Taglet}. Print a message to indicate whether or not
* the Taglet was registered properly.
* @param classname the name of the class representing the custom tag.
* @param fileManager the filemanager to load classes and resources.
* @param tagletPath the path to the class representing the custom tag.
*/
public void addCustomTag(String classname, JavaFileManager fileManager, String tagletPath) {
try {
ClassLoader tagClassLoader;
if (!fileManager.hasLocation(TAGLET_PATH)) {
List<File> paths = new ArrayList<>();
if (tagletPath != null) {
for (String pathname : tagletPath.split(File.pathSeparator)) {
paths.add(new File(pathname));
}
}
if (fileManager instanceof StandardJavaFileManager) {
((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, paths);
}
}
tagClassLoader = fileManager.getClassLoader(TAGLET_PATH);
Class<? extends jdk.javadoc.doclet.Taglet> customTagClass =
tagClassLoader.loadClass(classname).asSubclass(jdk.javadoc.doclet.Taglet.class);
jdk.javadoc.doclet.Taglet instance = customTagClass.getConstructor().newInstance();
instance.init(docEnv, doclet);
Taglet newLegacy = new UserTaglet(instance);
String tname = newLegacy.getName();
Taglet t = allTaglets.get(tname);
if (t != null) {
allTaglets.remove(tname);
}
allTaglets.put(tname, newLegacy);
messages.notice("doclet.Notice_taglet_registered", classname);
} catch (Exception exc) {
messages.error("doclet.Error_taglet_not_registered", exc.getClass().getName(), classname);
}
}
Add a new SimpleTaglet
. If this tag already exists and the header passed as an argument is null, move tag to the back of the list. If this tag already exists and the header passed as an argument is not null, overwrite previous tag with new one. Otherwise, add new SimpleTaglet to list. Params: - tagName – the name of this tag
- header – the header to output.
- locations – the possible locations that this tag
can appear in.
/**
* Add a new {@code SimpleTaglet}. If this tag already exists
* and the header passed as an argument is null, move tag to the back of the
* list. If this tag already exists and the header passed as an argument is
* not null, overwrite previous tag with new one. Otherwise, add new
* SimpleTaglet to list.
* @param tagName the name of this tag
* @param header the header to output.
* @param locations the possible locations that this tag
* can appear in.
*/
public void addNewSimpleCustomTag(String tagName, String header, String locations) {
if (tagName == null || locations == null) {
return;
}
Taglet tag = allTaglets.get(tagName);
if (tag == null || header != null) {
allTaglets.remove(tagName);
allTaglets.put(tagName, new SimpleTaglet(tagName, header, locations));
if (Utils.toLowerCase(locations).indexOf('x') == -1) {
checkTagName(tagName);
}
} else {
//Move to back
allTaglets.remove(tagName);
allTaglets.put(tagName, tag);
}
}
Given a tag name, add it to the set of tags it belongs to.
/**
* Given a tag name, add it to the set of tags it belongs to.
*/
private void checkTagName(String name) {
if (standardTags.contains(name)) {
overridenStandardTags.add(name);
} else {
if (name.indexOf('.') == -1) {
potentiallyConflictingTags.add(name);
}
unseenCustomTags.add(name);
}
}
Given a name of a seen custom tag, remove it from the set of unseen
custom tags.
Params: - name – the name of the seen custom tag.
/**
* Given a name of a seen custom tag, remove it from the set of unseen
* custom tags.
* @param name the name of the seen custom tag.
*/
void seenCustomTag(String name) {
unseenCustomTags.remove(name);
}
Given a series of DocTree
s, check for spelling mistakes. Params: - element – the tags holder
- trees – the trees containing the comments
- areInlineTags – true if the array of tags are inline and false otherwise.
/**
* 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.
*/
public void checkTags(Element element, Iterable<? extends DocTree> trees, boolean areInlineTags) {
if (trees == null) {
return;
}
CommentHelper ch = utils.getCommentHelper(element);
for (DocTree tag : trees) {
String name = tag.getKind().tagName;
if (name == null) {
continue;
}
if (name.length() > 0 && name.charAt(0) == '@') {
name = name.substring(1, name.length());
}
if (! (standardTags.contains(name) || allTaglets.containsKey(name))) {
if (standardTagsLowercase.contains(Utils.toLowerCase(name))) {
messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTagLowercase", ch.getTagName(tag));
continue;
} else {
messages.warning(ch.getDocTreePath(tag), "doclet.UnknownTag", ch.getTagName(tag));
continue;
}
}
final Taglet taglet = allTaglets.get(name);
// Check and verify tag usage
if (taglet != null) {
if (areInlineTags && !taglet.isInlineTag()) {
printTagMisuseWarn(ch, taglet, tag, "inline");
}
// nothing more to do
if (element == null) {
return;
}
new SimpleElementVisitor9<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");
}
return null;
}
@Override
public Void visitType(TypeElement e, Void p) {
if (!taglet.inType()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "class");
}
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");
}
return null;
}
@Override
public Void visitVariable(VariableElement e, Void p) {
if (utils.isField(e) && !taglet.inField()) {
printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "field");
}
return null;
}
@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);
}
}
}
Given the taglet, the tag and the type of documentation that the tag
was found in, print a tag misuse warning.
Params: - taglet – the taglet representing the misused tag.
- tag – the misused tag.
- holderType – the type of documentation that the misused tag was found in.
/**
* Given the taglet, the tag and the type of documentation that the tag
* was found in, print a tag misuse warning.
* @param taglet the taglet representing the misused tag.
* @param tag the misused tag.
* @param holderType the type of documentation that the misused tag was found in.
*/
private void printTagMisuseWarn(CommentHelper ch, Taglet taglet, DocTree tag, String holderType) {
Set<String> locationsSet = new LinkedHashSet<>();
// The following names should be localized
if (taglet.inOverview()) {
locationsSet.add("overview");
}
if (taglet.inModule()) {
locationsSet.add("module");
}
if (taglet.inPackage()) {
locationsSet.add("package");
}
if (taglet.inType()) {
locationsSet.add("class/interface");
}
if (taglet.inConstructor()) {
locationsSet.add("constructor");
}
if (taglet.inField()) {
locationsSet.add("field");
}
if (taglet.inMethod()) {
locationsSet.add("method");
}
if (taglet.isInlineTag()) {
locationsSet.add("inline text");
}
if (locationsSet.isEmpty()) {
//This known tag is excluded.
return;
}
StringBuilder combined_locations = new StringBuilder();
for (String location: locationsSet) {
if (combined_locations.length() > 0) {
combined_locations.append(", ");
}
combined_locations.append(location);
}
messages.warning(ch.getDocTreePath(tag), "doclet.tag_misuse",
"@" + taglet.getName(), holderType, combined_locations.toString());
}
Returns the taglets that can appear inline, in descriptive text.
Returns: the taglets that can appear inline
/**
* Returns the taglets that can appear inline, in descriptive text.
* @return the taglets that can appear inline
*/
List<Taglet> getInlineTaglets() {
if (inlineTags == null) {
initBlockTaglets();
}
return inlineTags;
}
Returns the taglets that can appear in the serialized form.
Returns: the taglet that can appear in the serialized form
/**
* Returns the taglets that can appear in the serialized form.
* @return the taglet that can appear in the serialized form
*/
public List<Taglet> getSerializedFormTaglets() {
if (serializedFormTags == null) {
initBlockTaglets();
}
return serializedFormTags;
}
Returns the custom tags for a given element.
Params: - e – the element to get custom tags for
Returns: the array of Taglet
s that can appear in the given element.
/**
* Returns the custom tags for a given element.
*
* @param e the element to get custom tags for
* @return the array of {@code Taglet}s that can
* appear in the given element.
*/
@SuppressWarnings("fallthrough")
public List<Taglet> getBlockTaglets(Element e) {
if (blockTagletsBySite == null) {
initBlockTaglets();
}
switch (e.getKind()) {
case CONSTRUCTOR:
return blockTagletsBySite.get(Site.CONSTRUCTOR);
case METHOD:
return blockTagletsBySite.get(Site.METHOD);
case ENUM_CONSTANT:
case FIELD:
return blockTagletsBySite.get(Site.FIELD);
case ANNOTATION_TYPE:
case INTERFACE:
case CLASS:
case ENUM:
return blockTagletsBySite.get(Site.TYPE);
case MODULE:
return blockTagletsBySite.get(Site.MODULE);
case PACKAGE:
return blockTagletsBySite.get(Site.PACKAGE);
case OTHER:
if (e instanceof DocletElement) {
DocletElement de = (DocletElement)e;
switch (de.getSubKind()) {
case DOCFILE:
return blockTagletsBySite.get(Site.PACKAGE);
case OVERVIEW:
return blockTagletsBySite.get(Site.OVERVIEW);
default:
// fall through
}
}
// fall through
default:
throw new AssertionError("unknown element: " + e + " ,kind: " + e.getKind());
}
}
Initialize the custom tag Lists.
/**
* Initialize the custom tag Lists.
*/
private void initBlockTaglets() {
blockTagletsBySite = new EnumMap<>(Site.class);
for (Site site : Site.values()) {
blockTagletsBySite.put(site, new ArrayList<>());
}
inlineTags = new ArrayList<>();
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);
}
}
}
//Init the serialized form tags
serializedFormTags = new ArrayList<>();
serializedFormTags.add(allTaglets.get(SERIAL_DATA.tagName));
serializedFormTags.add(allTaglets.get(THROWS.tagName));
if (!nosince)
serializedFormTags.add(allTaglets.get(SINCE.tagName));
serializedFormTags.add(allTaglets.get(SEE.tagName));
if (showTaglets) {
showTaglets(System.out);
}
}
Initialize standard Javadoc tags for ordering purposes.
/**
* Initialize standard Javadoc tags for ordering purposes.
*/
private void initStandardTaglets() {
if (javafx) {
initJavaFXTaglets();
}
addStandardTaglet(new ParamTaglet());
addStandardTaglet(new ReturnTaglet());
addStandardTaglet(new ThrowsTaglet());
addStandardTaglet(
new SimpleTaglet(EXCEPTION.tagName, null,
EnumSet.of(Site.METHOD, Site.CONSTRUCTOR)));
addStandardTaglet(
new SimpleTaglet(SINCE.tagName, resources.getText("doclet.Since"),
EnumSet.allOf(Site.class), !nosince));
addStandardTaglet(
new SimpleTaglet(VERSION.tagName, resources.getText("doclet.Version"),
EnumSet.of(Site.OVERVIEW, Site.MODULE, Site.PACKAGE, Site.TYPE), showversion));
addStandardTaglet(
new SimpleTaglet(AUTHOR.tagName, resources.getText("doclet.Author"),
EnumSet.of(Site.OVERVIEW, Site.MODULE, Site.PACKAGE, Site.TYPE), showauthor));
addStandardTaglet(
new SimpleTaglet(SERIAL_DATA.tagName, resources.getText("doclet.SerialData"),
EnumSet.noneOf(Site.class)));
addStandardTaglet(
new SimpleTaglet(HIDDEN.tagName, null,
EnumSet.of(Site.TYPE, Site.METHOD, Site.FIELD)));
// This appears to be a default custom (non-standard) taglet
Taglet factoryTaglet = new SimpleTaglet("factory", resources.getText("doclet.Factory"),
EnumSet.of(Site.METHOD));
allTaglets.put(factoryTaglet.getName(), factoryTaglet);
addStandardTaglet(new SeeTaglet());
// Standard inline tags
addStandardTaglet(new DocRootTaglet());
addStandardTaglet(new InheritDocTaglet());
addStandardTaglet(new ValueTaglet());
addStandardTaglet(new LiteralTaglet());
addStandardTaglet(new CodeTaglet());
addStandardTaglet(new IndexTaglet());
addStandardTaglet(new SummaryTaglet());
addStandardTaglet(new SystemPropertyTaglet());
// 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 SimpleTaglet(SERIAL.tagName, null,
EnumSet.of(Site.PACKAGE, Site.TYPE, Site.FIELD)));
addStandardTaglet(
new SimpleTaglet(SERIAL_FIELD.tagName, null, EnumSet.of(Site.FIELD)));
}
Initialize JavaFX-related tags.
/**
* Initialize JavaFX-related tags.
*/
private void initJavaFXTaglets() {
addStandardTaglet(new PropertyGetterTaglet());
addStandardTaglet(new PropertySetterTaglet());
addStandardTaglet(new SimpleTaglet("propertyDescription",
resources.getText("doclet.PropertyDescription"),
EnumSet.of(Site.METHOD, Site.FIELD)));
addStandardTaglet(new SimpleTaglet("defaultValue", resources.getText("doclet.DefaultValue"),
EnumSet.of(Site.METHOD, Site.FIELD)));
addStandardTaglet(new SimpleTaglet("treatAsPrivate", null,
EnumSet.of(Site.TYPE, Site.METHOD, Site.FIELD)));
}
private void addStandardTaglet(Taglet taglet) {
String name = taglet.getName();
allTaglets.put(name, taglet);
standardTags.add(name);
standardTagsLowercase.add(Utils.toLowerCase(name));
}
public boolean isKnownCustomTag(String tagName) {
return allTaglets.containsKey(tagName);
}
Print a list of Taglet
s that might conflict with standard tags in the future and a list of standard tags that have been overriden. /**
* Print a list of {@link Taglet}s that might conflict with
* standard tags in the future and a list of standard tags
* that have been overriden.
*/
public void printReport() {
printReportHelper("doclet.Notice_taglet_conflict_warn", potentiallyConflictingTags);
printReportHelper("doclet.Notice_taglet_overriden", overridenStandardTags);
printReportHelper("doclet.Notice_taglet_unseen", unseenCustomTags);
}
private void printReportHelper(String noticeKey, Set<String> names) {
if (names.size() > 0) {
StringBuilder result = new StringBuilder();
for (String name : names) {
result.append(result.length() == 0 ? " " : ", ");
result.append("@").append(name);
}
messages.notice(noticeKey, result);
}
}
Given the name of a tag, return the corresponding taglet.
Return null if the tag is unknown.
Params: - name – the name of the taglet to retrieve.
Returns: return the corresponding taglet. Return null if the tag is
unknown.
/**
* Given the name of a tag, return the corresponding taglet.
* Return null if the tag is unknown.
*
* @param name the name of the taglet to retrieve.
* @return return the corresponding taglet. Return null if the tag is
* unknown.
*/
Taglet getTaglet(String name) {
if (name.indexOf("@") == 0) {
return allTaglets.get(name.substring(1));
} else {
return allTaglets.get(name);
}
}
/*
* 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
* a need for a corresponding update to the spec.
*/
private void showTaglets(PrintStream out) {
Set<Taglet> taglets = new TreeSet<>((o1, o2) -> o1.getName().compareTo(o2.getName()));
taglets.addAll(allTaglets.values());
for (Taglet t : taglets) {
String name = t.isInlineTag() ? "{@" + t.getName() + "}" : "@" + t.getName();
out.println(String.format("%20s", name) + ": "
+ format(t.inOverview(), "overview") + " "
+ format(t.inModule(), "module") + " "
+ format(t.inPackage(), "package") + " "
+ format(t.inType(), "type") + " "
+ format(t.inConstructor(),"constructor") + " "
+ format(t.inMethod(), "method") + " "
+ format(t.inField(), "field") + " "
+ format(t.isInlineTag(), "inline")+ " "
+ format((t instanceof SimpleTaglet) && !((SimpleTaglet)t).enabled, "disabled"));
}
}
private String format(boolean b, String s) {
return b ? s : s.replaceAll(".", "."); // replace all with "."
}
}