| /* |
| * 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 {@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 map of all taglets. |
| */ |
| private final LinkedHashMap<String,Taglet> allTaglets; |
| |
| /** |
| * Block (non-line) taglets, grouped by Site |
| */ |
| private Map<Site, List<Taglet>> blockTagletsBySite; |
| |
| /** |
| * The taglets that can appear inline in descriptive text. |
| */ |
| private List<Taglet> inlineTags; |
| |
| /** |
| * 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. |
| */ |
| 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 (@defaultValue, @treatAsPrivate). |
| */ |
| private final boolean javafx; |
| |
| /** |
| * Show the taglets table when it has been initialized. |
| */ |
| private final boolean showTaglets; |
| |
| /** |
| * 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 {@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 {@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 {@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. |
| */ |
| 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. |
| * @param name the name of the seen custom tag. |
| */ |
| void seenCustomTag(String name) { |
| unseenCustomTags.remove(name); |
| } |
| |
| /** |
| * 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. |
| * @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. |
| * @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. |
| * @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. |
| * |
| * @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. |
| */ |
| 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. |
| */ |
| 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()); |
| |
| // 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. |
| */ |
| 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 {@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. |
| * |
| * @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 "." |
| } |
| } |