--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java Sat Nov 28 18:52:17 2015 -0800
@@ -0,0 +1,774 @@
+/*
+ * Copyright (c) 2001, 2016, 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.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 com.sun.tools.javac.util.DefinedBy;
+import com.sun.tools.javac.util.DefinedBy.Api;
+
+import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
+import jdk.javadoc.internal.doclets.toolkit.util.MessageRetriever;
+import jdk.javadoc.internal.doclets.toolkit.util.Utils;
+
+import static javax.tools.DocumentationTool.Location.*;
+
+import static com.sun.source.doctree.DocTree.Kind.*;
+
+/**
+ * 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.
+ */
+ public static final char SIMPLE_TAGLET_OPT_SEPARATOR = ':';
+
+ /**
+ * The alternate separator for simple tag options. Use this
+ * when you want the default separator to be in the name of the
+ * custom tag.
+ */
+ public static final String ALT_SIMPLE_TAGLET_OPT_SEPARATOR = "-";
+
+ /**
+ * The map of custom tags.
+ */
+ private final LinkedHashMap<String,Taglet> customTags;
+
+ /**
+ * The array of custom tags that can appear in packages.
+ */
+ private List<Taglet> packageTags;
+
+ /**
+ * The array of custom tags that can appear in classes or interfaces.
+ */
+ private List<Taglet> typeTags;
+
+ /**
+ * The array of custom tags that can appear in fields.
+ */
+ private List<Taglet> fieldTags;
+
+ /**
+ * The array of custom tags that can appear in constructors.
+ */
+ private List<Taglet> constructorTags;
+
+ /**
+ * The array of custom tags that can appear in methods.
+ */
+ private List<Taglet> methodTags;
+
+ /**
+ * The array of custom tags that can appear in the overview.
+ */
+ private List<Taglet> overviewTags;
+
+ /**
+ * The array of custom tags that can appear in comments.
+ */
+ private List<Taglet> inlineTags;
+
+ /**
+ * The array of custom tags that can appear in the serialized form.
+ */
+ private List<Taglet> serializedFormTags;
+
+ /**
+ * The message retriever that will be used to print error messages.
+ */
+ private final MessageRetriever message;
+
+ /**
+ * 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.
+ */
+ private final Set<String> standardTagsLowercase;
+
+ /**
+ * 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).
+ */
+ private final Set<String> potentiallyConflictingTags;
+
+ /**
+ * The set of unseen custom tags.
+ */
+ private final Set<String> unseenCustomTags;
+
+ /**
+ * True if we do not want to use @since tags.
+ */
+ private final boolean nosince;
+
+ /**
+ * True if we want to use @version tags.
+ */
+ private final boolean showversion;
+
+ /**
+ * True if we want to use @author tags.
+ */
+ private final boolean showauthor;
+
+ /**
+ * True if we want to use JavaFX-related tags (@propertyGetter,
+ * @propertySetter, @propertyDescription, @defaultValue, @treatAsPrivate).
+ */
+ private final boolean javafx;
+
+ /**
+ * Construct a new <code>TagletManager</code>.
+ * @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 message the message retriever to print warnings.
+ */
+ public TagletManager(boolean nosince, boolean showversion,
+ boolean showauthor, boolean javafx,
+ MessageRetriever message) {
+ overridenStandardTags = new HashSet<>();
+ potentiallyConflictingTags = new HashSet<>();
+ standardTags = new HashSet<>();
+ standardTagsLowercase = new HashSet<>();
+ unseenCustomTags = new HashSet<>();
+ customTags = new LinkedHashMap<>();
+ this.nosince = nosince;
+ this.showversion = showversion;
+ this.showauthor = showauthor;
+ this.javafx = javafx;
+ this.message = message;
+ initStandardTaglets();
+ initStandardTagsLowercase();
+ }
+
+ /**
+ * Add a new <code>CustomTag</code>. 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>CustomTag</code> to add.
+ */
+ public void addCustomTag(Taglet customTag) {
+ if (customTag != null) {
+ String name = customTag.getName();
+ if (customTags.containsKey(name)) {
+ customTags.remove(name);
+ }
+ customTags.put(name, customTag);
+ checkTagName(name);
+ }
+ }
+
+ public Set<String> getCustomTagNames() {
+ return customTags.keySet();
+ }
+
+ /**
+ * Add a new <code>Taglet</code>. 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<?> customTagClass = tagClassLoader.loadClass(classname);
+ Object instance = customTagClass.newInstance();
+ Taglet newLegacy = new UserTaglet((jdk.javadoc.doclet.taglet.Taglet)instance);
+ String tname = newLegacy.getName();
+ Taglet t = customTags.get(tname);
+ if (t != null) {
+ customTags.remove(tname);
+ }
+ customTags.put(tname, newLegacy);
+ message.notice("doclet.Notice_taglet_registered", classname);
+ } catch (Exception exc) {
+ message.error("doclet.Error_taglet_not_registered", exc.getClass().getName(), classname);
+ }
+ }
+
+ /**
+ * Add a new <code>SimpleTaglet</code>. 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 = customTags.get(tagName);
+ locations = Utils.toLowerCase(locations);
+ if (tag == null || header != null) {
+ customTags.remove(tagName);
+ customTags.put(tagName, new SimpleTaglet(tagName, header, locations));
+ if (locations != null && locations.indexOf('x') == -1) {
+ checkTagName(tagName);
+ }
+ } else {
+ //Move to back
+ customTags.remove(tagName);
+ customTags.put(tagName, tag);
+ }
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * Check the taglet to see if it is a legacy taglet. Also
+ * check its name for errors.
+ */
+ private void checkTaglet(Object taglet) {
+ if (taglet instanceof Taglet) {
+ checkTagName(((Taglet) taglet).getName());
+ } else if (taglet instanceof jdk.javadoc.doclet.taglet.Taglet) {
+ jdk.javadoc.doclet.taglet.Taglet legacyTaglet = (jdk.javadoc.doclet.taglet.Taglet) taglet;
+ customTags.remove(legacyTaglet.getName());
+ customTags.put(legacyTaglet.getName(), new UserTaglet(legacyTaglet));
+ checkTagName(legacyTaglet.getName());
+ } else {
+ throw new IllegalArgumentException("Given object is not a taglet.");
+ }
+ }
+
+ /**
+ * 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.
+ */
+ public void seenCustomTag(String name) {
+ unseenCustomTags.remove(name);
+ }
+
+ /**
+ * Given an array of <code>Tag</code>s, check for spelling mistakes.
+ * @param utils the utility class to use
+ * @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(final Utils utils, 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) || customTags.containsKey(name))) {
+ if (standardTagsLowercase.contains(Utils.toLowerCase(name))) {
+ message.warning(ch.getDocTreePath(tag), "doclet.UnknownTagLowercase", ch.getTagName(tag));
+ continue;
+ } else {
+ message.warning(ch.getDocTreePath(tag), "doclet.UnknownTag", ch.getTagName(tag));
+ continue;
+ }
+ }
+ final Taglet taglet = customTags.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 @DefinedBy(Api.LANGUAGE_MODEL)
+ public Void visitPackage(PackageElement e, Void p) {
+ if (!taglet.inPackage()) {
+ printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "package");
+ }
+ return null;
+ }
+
+ @Override @DefinedBy(Api.LANGUAGE_MODEL)
+ public Void visitType(TypeElement e, Void p) {
+ if (!taglet.inType()) {
+ printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "class");
+ }
+ return null;
+ }
+
+ @Override @DefinedBy(Api.LANGUAGE_MODEL)
+ 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 @DefinedBy(Api.LANGUAGE_MODEL)
+ public Void visitVariable(VariableElement e, Void p) {
+ if (utils.isField(e) && !taglet.inField()) {
+ printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "field");
+ }
+ return null;
+ }
+
+ @Override @DefinedBy(Api.LANGUAGE_MODEL)
+ public Void visitUnknown(Element e, Void p) {
+ if (utils.isOverviewElement(e) && !taglet.inOverview()) {
+ printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "overview");
+ }
+ return null;
+ }
+
+ @Override @DefinedBy(Api.LANGUAGE_MODEL)
+ 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.
+ * @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<>();
+ if (taglet.inOverview()) {
+ locationsSet.add("overview");
+ }
+ 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");
+ }
+ String[] locations = locationsSet.toArray(new String[]{});
+ if (locations == null || locations.length == 0) {
+ //This known tag is excluded.
+ return;
+ }
+ StringBuilder combined_locations = new StringBuilder();
+ for (int i = 0; i < locations.length; i++) {
+ if (i > 0) {
+ combined_locations.append(", ");
+ }
+ combined_locations.append(locations[i]);
+ }
+ message.warning(ch.getDocTreePath(tag), "doclet.tag_misuse",
+ "@" + taglet.getName(), holderType, combined_locations.toString());
+ }
+
+ /**
+ * Return the array of <code>Taglet</code>s that can
+ * appear in packages.
+ * @return the array of <code>Taglet</code>s that can
+ * appear in packages.
+ */
+ public List<Taglet> getPackageCustomTaglets() {
+ if (packageTags == null) {
+ initCustomTaglets();
+ }
+ return packageTags;
+ }
+
+ /**
+ * Return the array of <code>Taglet</code>s that can
+ * appear in classes or interfaces.
+ * @return the array of <code>Taglet</code>s that can
+ * appear in classes or interfaces.
+ */
+ public List<Taglet> getTypeCustomTaglets() {
+ if (typeTags == null) {
+ initCustomTaglets();
+ }
+ return typeTags;
+ }
+
+ /**
+ * Return the array of inline <code>Taglet</code>s that can
+ * appear in comments.
+ * @return the array of <code>Taglet</code>s that can
+ * appear in comments.
+ */
+ public List<Taglet> getInlineCustomTaglets() {
+ if (inlineTags == null) {
+ initCustomTaglets();
+ }
+ return inlineTags;
+ }
+
+ /**
+ * Return the array of <code>Taglet</code>s that can
+ * appear in fields.
+ * @return the array of <code>Taglet</code>s that can
+ * appear in field.
+ */
+ public List<Taglet> getFieldCustomTaglets() {
+ if (fieldTags == null) {
+ initCustomTaglets();
+ }
+ return fieldTags;
+ }
+
+ /**
+ * Return the array of <code>Taglet</code>s that can
+ * appear in the serialized form.
+ * @return the array of <code>Taglet</code>s that can
+ * appear in the serialized form.
+ */
+ public List<Taglet> getSerializedFormTaglets() {
+ if (serializedFormTags == null) {
+ initCustomTaglets();
+ }
+ return serializedFormTags;
+ }
+
+ /**
+ * Returns the custom tags for a given element.
+ *
+ * @param e the element to get custom tags for
+ * @return the array of <code>Taglet</code>s that can
+ * appear in the given element.
+ */
+ public List<Taglet> getCustomTaglets(Element e) {
+ switch (e.getKind()) {
+ case CONSTRUCTOR:
+ return getConstructorCustomTaglets();
+ case METHOD:
+ return getMethodCustomTaglets();
+ case ENUM_CONSTANT:
+ case FIELD:
+ return getFieldCustomTaglets();
+ case ANNOTATION_TYPE:
+ case INTERFACE:
+ case CLASS:
+ case ENUM:
+ return getTypeCustomTaglets();
+ case PACKAGE:
+ return getPackageCustomTaglets();
+ case OTHER:
+ return getOverviewCustomTaglets();
+ default:
+ throw new AssertionError("unknown element: " + e + " ,kind: " + e.getKind());
+ }
+ }
+
+ /**
+ * Return a List of <code>Taglet</code>s that can
+ * appear in constructors.
+ * @return the array of <code>Taglet</code>s that can
+ * appear in constructors.
+ */
+ public List<Taglet> getConstructorCustomTaglets() {
+ if (constructorTags == null) {
+ initCustomTaglets();
+ }
+ return constructorTags;
+ }
+
+ /**
+ * Return a List of <code>Taglet</code>s that can
+ * appear in methods.
+ * @return the array of <code>Taglet</code>s that can
+ * appear in methods.
+ */
+ public List<Taglet> getMethodCustomTaglets() {
+ if (methodTags == null) {
+ initCustomTaglets();
+ }
+ return methodTags;
+ }
+
+ /**
+ * Return a List of <code>Taglet</code>s that can
+ * appear in an overview.
+ * @return the array of <code>Taglet</code>s that can
+ * appear in overview.
+ */
+ public List<Taglet> getOverviewCustomTaglets() {
+ if (overviewTags == null) {
+ initCustomTaglets();
+ }
+ return overviewTags;
+ }
+
+ /**
+ * Initialize the custom tag Lists.
+ */
+ private void initCustomTaglets() {
+
+ packageTags = new ArrayList<>();
+ typeTags = new ArrayList<>();
+ fieldTags = new ArrayList<>();
+ constructorTags = new ArrayList<>();
+ methodTags = new ArrayList<>();
+ inlineTags = new ArrayList<>();
+ overviewTags = new ArrayList<>();
+
+ for (Taglet current : customTags.values()) {
+ if (current.inPackage() && !current.isInlineTag()) {
+ packageTags.add(current);
+ }
+ if (current.inType() && !current.isInlineTag()) {
+ typeTags.add(current);
+ }
+ if (current.inField() && !current.isInlineTag()) {
+ fieldTags.add(current);
+ }
+ if (current.inConstructor() && !current.isInlineTag()) {
+ constructorTags.add(current);
+ }
+ if (current.inMethod() && !current.isInlineTag()) {
+ methodTags.add(current);
+ }
+ if (current.isInlineTag()) {
+ inlineTags.add(current);
+ }
+ if (current.inOverview() && !current.isInlineTag()) {
+ overviewTags.add(current);
+ }
+ }
+
+ //Init the serialized form tags
+ serializedFormTags = new ArrayList<>();
+ serializedFormTags.add(customTags.get(SERIAL_DATA.tagName));
+ serializedFormTags.add(customTags.get(THROWS.tagName));
+ if (!nosince)
+ serializedFormTags.add(customTags.get(SINCE.tagName));
+ serializedFormTags.add(customTags.get(SEE.tagName));
+ }
+
+ /**
+ * Initialize standard Javadoc tags for ordering purposes.
+ */
+ private void initStandardTaglets() {
+ if (javafx) {
+ initJavaFXTaglets();
+ }
+
+ Taglet temp;
+ addStandardTaglet(new ParamTaglet());
+ addStandardTaglet(new ReturnTaglet());
+ addStandardTaglet(new ThrowsTaglet());
+ addStandardTaglet(new SimpleTaglet(EXCEPTION.tagName, null,
+ SimpleTaglet.METHOD + SimpleTaglet.CONSTRUCTOR));
+ addStandardTaglet(!nosince, new SimpleTaglet(SINCE.tagName, message.getText("doclet.Since"),
+ SimpleTaglet.ALL));
+ addStandardTaglet(showversion, new SimpleTaglet(VERSION.tagName, message.getText("doclet.Version"),
+ SimpleTaglet.PACKAGE + SimpleTaglet.TYPE + SimpleTaglet.OVERVIEW));
+ addStandardTaglet(showauthor, new SimpleTaglet(AUTHOR.tagName, message.getText("doclet.Author"),
+ SimpleTaglet.PACKAGE + SimpleTaglet.TYPE + SimpleTaglet.OVERVIEW));
+ addStandardTaglet(new SimpleTaglet(SERIAL_DATA.tagName, message.getText("doclet.SerialData"),
+ SimpleTaglet.EXCLUDED));
+ customTags.put((temp = new SimpleTaglet("factory", message.getText("doclet.Factory"),
+ SimpleTaglet.METHOD)).getName(), temp);
+ addStandardTaglet(new SeeTaglet());
+ //Standard inline tags
+ addStandardTaglet(new DocRootTaglet());
+ addStandardTaglet(new InheritDocTaglet());
+ addStandardTaglet(new ValueTaglet());
+ addStandardTaglet(new LiteralTaglet());
+ addStandardTaglet(new CodeTaglet());
+ addStandardTaglet(new IndexTaglet());
+
+ // Keep track of the names of standard tags for error
+ // checking purposes. The following are not handled above.
+ standardTags.add(DEPRECATED.tagName);
+ standardTags.add(LINK.tagName);
+ standardTags.add(LINK_PLAIN.tagName);
+ standardTags.add(SERIAL.tagName);
+ standardTags.add(SERIAL_FIELD.tagName);
+ }
+
+ /**
+ * Initialize JavaFX-related tags.
+ */
+ private void initJavaFXTaglets() {
+ addStandardTaglet(new PropertyGetterTaglet());
+ addStandardTaglet(new PropertySetterTaglet());
+ addStandardTaglet(new SimpleTaglet("propertyDescription",
+ message.getText("doclet.PropertyDescription"),
+ SimpleTaglet.FIELD + SimpleTaglet.METHOD));
+ addStandardTaglet(new SimpleTaglet("defaultValue", message.getText("doclet.DefaultValue"),
+ SimpleTaglet.FIELD + SimpleTaglet.METHOD));
+ addStandardTaglet(new SimpleTaglet("treatAsPrivate", null,
+ SimpleTaglet.FIELD + SimpleTaglet.METHOD + SimpleTaglet.TYPE));
+ }
+
+ void addStandardTaglet(Taglet taglet) {
+ String name = taglet.getName();
+ customTags.put(name, taglet);
+ standardTags.add(name);
+ }
+
+ void addStandardTaglet(boolean enable, Taglet taglet) {
+ String name = taglet.getName();
+ if (enable)
+ customTags.put(name, taglet);
+ standardTags.add(name);
+ }
+
+ /**
+ * Initialize lowercase version of standard Javadoc tags.
+ */
+ private void initStandardTagsLowercase() {
+ for (String standardTag : standardTags) {
+ standardTagsLowercase.add(Utils.toLowerCase(standardTag));
+ }
+ }
+
+ public boolean isKnownCustomTag(String tagName) {
+ return customTags.containsKey(tagName);
+ }
+
+ /**
+ * 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) {
+ String[] namesArray = names.toArray(new String[] {});
+ String result = " ";
+ for (int i = 0; i < namesArray.length; i++) {
+ result += "@" + namesArray[i];
+ if (i + 1 < namesArray.length) {
+ result += ", ";
+ }
+ }
+ message.notice(noticeKey, result);
+ }
+ }
+
+ /**
+ * 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.
+ */
+ public Taglet getTaglet(String name) {
+ if (name.indexOf("@") == 0) {
+ return customTags.get(name.substring(1));
+ } else {
+ return customTags.get(name);
+ }
+
+ }
+}