blob: 2de85b93815e82f8cde89b3f4c7c77921ed8a4c7 [file] [log] [blame]
// Keep this file in sync with
// ../../../../../taglet/java/org/checkerframework/taglet/ManualTaglet.java .
package org.checkerframework.taglet;
import com.sun.source.doctree.DocTree;
import com.sun.source.doctree.TextTree;
import com.sun.source.doctree.UnknownBlockTagTree;
import com.sun.source.doctree.UnknownInlineTagTree;
import com.sun.source.util.SimpleDocTreeVisitor;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
import javax.lang.model.element.Element;
import jdk.javadoc.doclet.Taglet;
/**
* A taglet for processing the {@code @checker_framework.manual} javadoc block tag, which inserts
* references to the Checker Framework manual into javadoc.
*
* <p>The {@code @checker_framework.manual} tag is used as follows:
*
* <ul>
* <li>{@code @checker_framework.manual #} expands to a top-level link to the Checker Framework
* manual
* <li>{@code @checker_framework.manual #anchor text} expands to a link with some text to a
* particular part of the manual
* </ul>
*/
public class ManualTaglet implements Taglet {
private static final String NAME = "checker_framework.manual";
@Override
public String getName() {
return NAME;
}
private final EnumSet<Location> allowedSet = EnumSet.allOf(Location.class);
@Override
public Set<Taglet.Location> getAllowedLocations() {
return allowedSet;
}
@Override
public boolean isInlineTag() {
return false;
}
/**
* Formats a link, given an array of tokens.
*
* @param parts the array of tokens
* @return a link to the manual top-level if the array size is one, or a link to a part of the
* manual if it's larger than one
*/
private String formatLink(String[] parts) {
String anchor, text;
if (parts.length < 2) {
anchor = "";
text = "Checker Framework";
} else {
anchor = parts[0];
text = parts[1];
}
return String.format("<A HREF=\"https://checkerframework.org/manual/%s\">%s</A>", anchor, text);
}
/**
* Formats the {@code @checker_framework.manual} tag, prepending the tag header to the tag
* content.
*
* @param text the tag content
* @return the formatted tag
*/
private String formatHeader(String text) {
return String.format("<DT><B>See the Checker Framework Manual:</B><DD>%s<BR>", text);
}
@Override
public String toString(List<? extends DocTree> tags, Element element) {
if (tags.isEmpty()) {
return "";
}
StringJoiner sb = new StringJoiner(", ");
for (DocTree t : tags) {
String text = getText(t);
String[] split = text.split(" ", 2);
sb.add(formatLink(split));
}
return formatHeader(sb.toString());
}
static String getText(DocTree dt) {
return new SimpleDocTreeVisitor<String, Void>() {
@Override
public String visitUnknownBlockTag(UnknownBlockTagTree node, Void p) {
for (DocTree dt : node.getContent()) {
return dt.accept(this, null);
}
return "";
}
@Override
public String visitUnknownInlineTag(UnknownInlineTagTree node, Void p) {
for (DocTree dt : node.getContent()) {
return dt.accept(this, null);
}
return "";
}
@Override
public String visitText(TextTree node, Void p) {
return node.getBody();
}
@Override
protected String defaultAction(DocTree node, Void p) {
return "";
}
}.visit(dt, null);
}
}