Missing standard Javadoc tags
The InvalidBlockTag check depends on JavadocTag, yet that is missing some of the tags described in the Documentation Comment Specification. In my case, specifically @hidden (which I'm using to exclude classes from being documented that only need to be visible because of how they're used in annotations and not because they're part of any API), but it would be a good idea to synch the list of supported block and inline tags with the official list.
Sample warning from a recent build of mine:
Warning: /{long-path-elided...}/validation/UDPPort.java:[81,12] [InvalidBlockTag] The tag @hidden is not allowed on this type of element.
(see https://errorprone.info/bugpattern/InvalidBlockTag)
Doc comment (on static inner class, but that appears unrelated) that triggered the warning:
/**
* Validator for {@link UDPPort}. Only used in Hibernate Validator.
* @hidden
*/
public static class PortValidator { /*...etc...*/ }
Official documentation says:
@hidden
@hiddenHides a program element from the generated API documentation. This tag may be used when it is not otherwise possible to design the API in a way that such items do not appear at all.
Introduced in JDK 9.
Official javadoc does not complain about this tag. I do not use custom tags.
Thanks for the report. I'd be happy to take a PR to add @hidden or any other standard block tags this check is missing
Seems to affect more inline tags, including for example {@summary ...}. In case it is helpful, at the end of the specification for the Standard Doclet (here for JDK 21) there is also a section about where the tags can be used.
But since Error Prone is accessing compiler internals anyway, would it maybe be possible as fallback to obtain the tag information from the JDK itself? It seems the relevant class is jdk.javadoc.internal.doclets.formats.html.taglets.TagletManager.
Here is a hacky proof-of-concept for JDK 17 / 21, but there might be a cleaner solution:
TagletManager usage proof-of-concept
import com.sun.source.util.DocTreePath;
import jdk.javadoc.doclet.Reporter;
import jdk.javadoc.doclet.StandardDoclet;
import jdk.javadoc.internal.doclets.formats.html.HtmlDoclet;
import jdk.javadoc.internal.doclets.toolkit.taglets.Taglet;
import jdk.javadoc.internal.doclets.toolkit.taglets.TagletManager;
import javax.lang.model.element.Element;
import javax.tools.Diagnostic;
import java.util.Locale;
import java.util.Map;
class Test {
public static void main(String[] args) throws Exception {
var doclet = new HtmlDoclet(new StandardDoclet());
doclet.init(Locale.ENGLISH, new Reporter() {
@Override
public void print(Diagnostic.Kind kind, String message) {
throw new AssertionError("should not be called");
}
@Override
public void print(Diagnostic.Kind kind, DocTreePath path, String message) {
throw new AssertionError("should not be called");
}
@Override
public void print(Diagnostic.Kind kind, Element element, String message) {
throw new AssertionError("should not be called");
}
});
var config = doclet.getConfiguration();
// TODO: `config` might not be fully initialized yet, but seems to work nonetheless
var tagletManager = new TagletManager(config);
var tagletsField = TagletManager.class.getDeclaredField("allTaglets");
tagletsField.setAccessible(true);
var taglets = (Map<String, Taglet>) tagletsField.get(tagletManager);
System.out.println(taglets.values());
}
}