Skip to content
Permalink
Browse files
8261079: Fix support for @hidden in classes and interfaces
Reviewed-by: jjg
  • Loading branch information
hns committed Feb 12, 2021
1 parent 9c0ec8d commit 3210095a175e66e227a23c73c154c4c9a26c3584
Showing with 403 additions and 132 deletions.
  1. +4 −6 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java
  2. +1 −8 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
  3. +1 −1 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java
  4. +45 −42 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java
  5. +15 −13 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java
  6. +3 −2 ...jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java
  7. +4 −1 ...jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java
  8. +2 −4 ...dk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java
  9. +41 −21 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java
  10. +28 −25 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java
  11. +58 −8 test/langtools/jdk/javadoc/doclet/testHiddenTag/TestHiddenTag.java
  12. +1 −1 test/langtools/jdk/javadoc/doclet/testHiddenTag/pkg1/A.java
  13. +33 −0 test/langtools/jdk/javadoc/doclet/testHiddenTag/pkg1/Child.java
  14. +53 −0 test/langtools/jdk/javadoc/doclet/testHiddenTag/pkg1/Intf.java
  15. +58 −0 test/langtools/jdk/javadoc/doclet/testHiddenTag/pkg1/InvisibleParent.java
  16. +56 −0 test/langtools/jdk/javadoc/doclet/testHiddenTag/pkg2/UndocumentedParent.java
@@ -265,7 +265,7 @@ public boolean finishOptionSettings() {
}
docPaths = new DocPaths(utils);
setCreateOverview();
setTopFile(docEnv);
setTopFile();
initDocLint(options.doclintOpts(), tagletManager.getAllTagletNames());
return true;
}
@@ -277,11 +277,9 @@ public boolean finishOptionSettings() {
* "package-summary.html" of the respective package if there is only one
* package to document. It will be a class page(first in the sorted order),
* if only classes are provided on the command line.
*
* @param docEnv the doclet environment
*/
protected void setTopFile(DocletEnvironment docEnv) {
if (!checkForDeprecation(docEnv)) {
protected void setTopFile() {
if (!checkForDeprecation()) {
return;
}
if (options.createOverview()) {
@@ -313,7 +311,7 @@ protected TypeElement getValidClass(List<TypeElement> classes) {
return null;
}

protected boolean checkForDeprecation(DocletEnvironment docEnv) {
protected boolean checkForDeprecation() {
for (TypeElement te : getIncludedTypeElements()) {
if (isGeneratedDoc(te)) {
return true;
@@ -313,7 +313,7 @@ private void addMethodInfo(ExecutableElement method, Content dl) {
// printed. If no overridden or implementation info needs to be
// printed, do not print this section.
if ((!intfacs.isEmpty()
&& vmt.getImplementedMethods(method).isEmpty() == false)
&& !vmt.getImplementedMethods(method).isEmpty())
|| overriddenMethod != null) {
MethodWriterImpl.addImplementsInfo(this, method, dl);
if (overriddenMethod != null) {
@@ -806,13 +806,6 @@ public Content getCrossClassLink(TypeElement classElement, String refMemName,
return null;
}

public boolean isClassLinkable(TypeElement typeElement) {
if (utils.isIncluded(typeElement)) {
return configuration.isGeneratedDoc(typeElement);
}
return configuration.extern.isExternal(typeElement);
}

public DocLink getCrossPackageLink(PackageElement element) {
return configuration.extern.getExternalLink(element, pathToRoot,
DocPaths.PACKAGE_SUMMARY.getPath());
@@ -105,7 +105,7 @@ protected Content getClassLink(LinkInfo linkInfo) {

Content link = new ContentBuilder();
if (utils.isIncluded(typeElement)) {
if (configuration.isGeneratedDoc(typeElement)) {
if (configuration.isGeneratedDoc(typeElement) && !utils.hasHiddenTag(typeElement)) {
DocPath filename = getPath(classLinkInfo);
if (linkInfo.linkToSelf ||
!(docPaths.forName(typeElement)).equals(m_writer.filename)) {
@@ -149,20 +149,22 @@ public void addComments(TypeMirror holderType, ExecutableElement method, Content
utils.isLinkable(holder))) {
writer.addInlineComment(method, methodDocTree);
} else {
Content link =
writer.getDocLink(HtmlLinkInfo.Kind.EXECUTABLE_ELEMENT_COPY,
holder, method,
utils.isIncluded(holder)
? utils.getSimpleName(holder)
: utils.getFullyQualifiedName(holder));
Content codeLink = HtmlTree.CODE(link);
Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel,
utils.isClass(holder)
? contents.descfrmClassLabel
: contents.descfrmInterfaceLabel);
descfrmLabel.add(Entity.NO_BREAK_SPACE);
descfrmLabel.add(codeLink);
methodDocTree.add(HtmlTree.DIV(HtmlStyle.block, descfrmLabel));
if (!utils.hasHiddenTag(holder) && !utils.hasHiddenTag(method)) {
Content link =
writer.getDocLink(HtmlLinkInfo.Kind.EXECUTABLE_ELEMENT_COPY,
holder, method,
utils.isIncluded(holder)
? utils.getSimpleName(holder)
: utils.getFullyQualifiedName(holder));
Content codeLink = HtmlTree.CODE(link);
Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel,
utils.isClass(holder)
? contents.descfrmClassLabel
: contents.descfrmInterfaceLabel);
descfrmLabel.add(Entity.NO_BREAK_SPACE);
descfrmLabel.add(codeLink);
methodDocTree.add(HtmlTree.DIV(HtmlStyle.block, descfrmLabel));
}
writer.addInlineComment(method, methodDocTree);
}
}
@@ -265,36 +267,37 @@ protected static void addOverridden(HtmlDocletWriter writer,
//is not visible so don't document this.
return;
}
if (utils.hasHiddenTag(holder) || utils.hasHiddenTag(method)) {
return;
}

if (method != null) {
Contents contents = writer.contents;
Content label;
HtmlLinkInfo.Kind context;
if (utils.isAbstract(holder) && utils.isAbstract(method)){
//Abstract method is implemented from abstract class,
//not overridden
label = contents.specifiedByLabel;
context = HtmlLinkInfo.Kind.METHOD_SPECIFIED_BY;
} else {
label = contents.overridesLabel;
context = HtmlLinkInfo.Kind.METHOD_OVERRIDES;
}
dl.add(HtmlTree.DT(label));
Content overriddenTypeLink =
writer.getLink(new HtmlLinkInfo(writer.configuration, context, overriddenType));
Content codeOverriddenTypeLink = HtmlTree.CODE(overriddenTypeLink);
Content methlink = writer.getLink(
new HtmlLinkInfo(writer.configuration, HtmlLinkInfo.Kind.MEMBER, holder)
.where(writer.htmlIds.forMember(method).name())
.label(method.getSimpleName()));
Content codeMethLink = HtmlTree.CODE(methlink);
Content dd = HtmlTree.DD(codeMethLink);
dd.add(Entity.NO_BREAK_SPACE);
dd.add(contents.inClass);
dd.add(Entity.NO_BREAK_SPACE);
dd.add(codeOverriddenTypeLink);
dl.add(dd);
Contents contents = writer.contents;
Content label;
HtmlLinkInfo.Kind context;
if (utils.isAbstract(holder) && utils.isAbstract(method)) {
//Abstract method is implemented from abstract class,
//not overridden
label = contents.specifiedByLabel;
context = HtmlLinkInfo.Kind.METHOD_SPECIFIED_BY;
} else {
label = contents.overridesLabel;
context = HtmlLinkInfo.Kind.METHOD_OVERRIDES;
}
dl.add(HtmlTree.DT(label));
Content overriddenTypeLink =
writer.getLink(new HtmlLinkInfo(writer.configuration, context, overriddenType));
Content codeOverriddenTypeLink = HtmlTree.CODE(overriddenTypeLink);
Content methlink = writer.getLink(
new HtmlLinkInfo(writer.configuration, HtmlLinkInfo.Kind.MEMBER, holder)
.where(writer.htmlIds.forMember(method).name())
.label(method.getSimpleName()));
Content codeMethLink = HtmlTree.CODE(methlink);
Content dd = HtmlTree.DD(codeMethLink);
dd.add(Entity.NO_BREAK_SPACE);
dd.add(contents.inClass);
dd.add(Entity.NO_BREAK_SPACE);
dd.add(codeOverriddenTypeLink);
dl.add(dd);
}

/**
@@ -111,19 +111,21 @@ public void addComments(ExecutableElement property, Content propertyDocTree) {
(!utils.isPublic(holder) || utils.isLinkable(holder))) {
writer.addInlineComment(property, propertyDocTree);
} else {
Content link =
writer.getDocLink(HtmlLinkInfo.Kind.PROPERTY_COPY,
holder, property,
utils.isIncluded(holder)
? holder.getSimpleName() : holder.getQualifiedName());
Content codeLink = HtmlTree.CODE(link);
Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel,
utils.isClass(holder)
? contents.descfrmClassLabel
: contents.descfrmInterfaceLabel);
descfrmLabel.add(Entity.NO_BREAK_SPACE);
descfrmLabel.add(codeLink);
propertyDocTree.add(HtmlTree.DIV(HtmlStyle.block, descfrmLabel));
if (!utils.hasHiddenTag(holder) && !utils.hasHiddenTag(property)) {
Content link =
writer.getDocLink(HtmlLinkInfo.Kind.PROPERTY_COPY,
holder, property,
utils.isIncluded(holder)
? holder.getSimpleName() : holder.getQualifiedName());
Content codeLink = HtmlTree.CODE(link);
Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel,
utils.isClass(holder)
? contents.descfrmClassLabel
: contents.descfrmInterfaceLabel);
descfrmLabel.add(Entity.NO_BREAK_SPACE);
descfrmLabel.add(codeLink);
propertyDocTree.add(HtmlTree.DIV(HtmlStyle.block, descfrmLabel));
}
writer.addInlineComment(property, propertyDocTree);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2021, 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
@@ -137,7 +137,8 @@ public Content getClassSerializedHeader() {
* @return true if the class, that is being processed, is generated and is visible.
*/
public boolean isVisibleClass(TypeElement typeElement) {
return visibleClasses.contains(typeElement) && configuration.isGeneratedDoc(typeElement);
return visibleClasses.contains(typeElement) && configuration.isGeneratedDoc(typeElement)
&& !utils.hasHiddenTag(typeElement);
}

/**
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, 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
@@ -409,6 +409,9 @@ private void buildInheritedSummary(MemberSummaryWriter writer,
if (inheritedClass == typeElement) {
continue;
}
if (utils.hasHiddenTag(inheritedClass)) {
continue;
}

List<Element> members = inheritedMembersFromMap.stream()
.filter(e -> utils.getEnclosingTypeElement(e) == inheritedClass)
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, 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
@@ -552,10 +552,8 @@ private static boolean serialClassInclude(Utils utils, TypeElement te) {
if (utils.isSerializable(te)) {
if (utils.hasDocCommentTree(te) && !utils.getSerialTrees(te).isEmpty()) {
return serialDocInclude(utils, te);
} else if (utils.isPublic(te) || utils.isProtected(te)) {
return true;
} else {
return false;
return utils.isPublic(te) || utils.isProtected(te);
}
}
return false;
@@ -609,7 +609,8 @@ public boolean isOrdinaryClass(TypeElement te) {
}

public boolean isUndocumentedEnclosure(TypeElement enclosingTypeElement) {
return (isPackagePrivate(enclosingTypeElement) || isPrivate(enclosingTypeElement))
return (isPackagePrivate(enclosingTypeElement) || isPrivate(enclosingTypeElement)
|| hasHiddenTag(enclosingTypeElement))
&& !isLinkable(enclosingTypeElement);
}

@@ -1157,10 +1158,11 @@ public boolean isDocumentedAnnotation(TypeElement annotation) {
*/
public boolean isLinkable(TypeElement typeElem) {
return
(typeElem != null &&
(isIncluded(typeElem) && configuration.isGeneratedDoc(typeElem))) ||
typeElem != null &&
((isIncluded(typeElem) && configuration.isGeneratedDoc(typeElem) &&
!hasHiddenTag(typeElem)) ||
(configuration.extern.isExternal(typeElem) &&
(isPublic(typeElem) || isProtected(typeElem)));
(isPublic(typeElem) || isProtected(typeElem))));
}

/**
@@ -1183,7 +1185,7 @@ public boolean isLinkable(TypeElement typeElem, Element elem) {
return isLinkable((TypeElement) elem); // defer to existing behavior
}

if (isIncluded(elem)) {
if (isIncluded(elem) && !hasHiddenTag(elem)) {
return true;
}

@@ -1553,16 +1555,17 @@ public String propertyName(ExecutableElement e) {
}

/**
* Returns true if the element is included, contains &#64;hidden tag,
* Returns true if the element is included or selected, contains &#64;hidden tag,
* or if javafx flag is present and element contains &#64;treatAsPrivate
* tag.
* @param e the queried element
* @return true if it exists, false otherwise
*/
public boolean hasHiddenTag(Element e) {
// prevent needless tests on elements which are not included
// Non-included elements may still be visible via "transclusion" from undocumented enclosures,
// but we don't want to run doclint on them, possibly causing warnings or errors.
if (!isIncluded(e)) {
return false;
return hasBlockTagUnchecked(e, HIDDEN);
}
if (options.javafx() &&
hasBlockTag(e, DocTree.Kind.UNKNOWN_BLOCK_TAG, "treatAsPrivate")) {
@@ -2265,12 +2268,14 @@ protected String defaultAction(Element e, Void p) {
}

public TypeElement getEnclosingTypeElement(Element e) {
if (e.getKind() == ElementKind.PACKAGE)
if (isPackage(e) || isModule(e)) {
return null;
}
Element encl = e.getEnclosingElement();
ElementKind kind = encl.getKind();
if (kind == ElementKind.PACKAGE)
if (isPackage(encl)) {
return null;
}
ElementKind kind = encl.getKind();
while (!(kind.isClass() || kind.isInterface())) {
encl = encl.getEnclosingElement();
kind = encl.getKind();
@@ -2591,7 +2596,10 @@ public void removeCommentHelper(Element element) {
}

public List<? extends DocTree> getBlockTags(Element element) {
DocCommentTree dcTree = getDocCommentTree(element);
return getBlockTags(getDocCommentTree(element));
}

public List<? extends DocTree> getBlockTags(DocCommentTree dcTree) {
return dcTree == null ? Collections.emptyList() : dcTree.getBlockTags();
}

@@ -2641,14 +2649,26 @@ public boolean hasBlockTag(Element element, DocTree.Kind kind) {
public boolean hasBlockTag(Element element, DocTree.Kind kind, final String tagName) {
if (hasDocCommentTree(element)) {
CommentHelper ch = getCommentHelper(element);
String tname = tagName != null && tagName.startsWith("@")
? tagName.substring(1)
: tagName;
for (DocTree dt : getBlockTags(element, kind)) {
for (DocTree dt : getBlockTags(ch.dcTree)) {
if (dt.getKind() == kind && (tagName == null || ch.getTagName(dt).equals(tagName))) {
return true;
}
}
}
return false;
}

/*
* Tests whether an element's doc comment contains a block tag without caching it or
* running doclint on it. This is done by using getDocCommentInfo(Element) to retrieve
* the doc comment info.
*/
boolean hasBlockTagUnchecked(Element element, DocTree.Kind kind) {
DocCommentInfo dcInfo = getDocCommentInfo(element);
if (dcInfo != null && dcInfo.dcTree != null) {
for (DocTree dt : getBlockTags(dcInfo.dcTree)) {
if (dt.getKind() == kind) {
if (tname == null || ch.getTagName(dt).equals(tname)) {
return true;
}
return true;
}
}
}
@@ -2701,7 +2721,7 @@ public boolean hasDocCommentTree(Element element) {

/**
* Retrieves the doc comments for a given element.
* @param element
* @param element the element
* @return DocCommentTree for the Element
*/
public DocCommentTree getDocCommentTree0(Element element) {
@@ -2759,7 +2779,7 @@ private DocCommentInfo getDocCommentInfo(Element element) {

private DocCommentInfo getDocCommentInfo0(Element element) {
// prevent nasty things downstream with overview element
if (element.getKind() != ElementKind.OTHER) {
if (!isOverviewElement(element)) {
TreePath path = getTreePath(element);
if (path != null) {
DocCommentTree docCommentTree = docTrees.getDocCommentTree(path);
Loading

0 comments on commit 3210095

Please sign in to comment.