Skip to content
Permalink
Browse files

8224052: Javadoc doesn't handle non-public intermediate types well

Reviewed-by: jjg
  • Loading branch information
hns committed Jan 16, 2020
1 parent 995fae6 commit 5903e20af2b94bb59516ab277b74ef66bd777ed8
Showing with 244 additions and 46 deletions.
  1. +9 −5 ...vadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java
  2. +1 −1 ...avadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java
  3. +1 −1 ...are/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java
  4. +8 −0 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java
  5. +2 −2 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriterImpl.java
  6. +9 −0 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
  7. +2 −2 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java
  8. +2 −2 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java
  9. +12 −2 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java
  10. +1 −1 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ReturnTaglet.java
  11. +10 −1 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java
  12. +52 −14 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ThrowsTaglet.java
  13. +46 −7 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java
  14. +43 −5 test/langtools/jdk/javadoc/doclet/testMemberInheritance/TestMemberInheritance.java
  15. +1 −1 test/langtools/jdk/javadoc/doclet/testMemberInheritance/pkg2/DocumentedNonGenericChild.java
  16. +10 −2 test/langtools/jdk/javadoc/doclet/testMemberInheritance/pkg2/UndocumentedGenericParent.java
  17. +35 −0 test/langtools/jdk/javadoc/doclet/testMemberInheritance/pkg3/PrivateGenericParent.java
@@ -35,6 +35,7 @@
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.SimpleTypeVisitor9;
@@ -141,10 +142,10 @@ protected void addInheritedSummaryLink(TypeElement te, Element member, Content l
* @param isVarArg true if this is a link to var arg.
* @param tree the content tree to which the parameter information will be added.
*/
protected void addParam(ExecutableElement member, VariableElement param,
protected void addParam(ExecutableElement member, VariableElement param, TypeMirror paramType,
boolean isVarArg, Content tree) {
Content link = writer.getLink(new LinkInfoImpl(configuration, EXECUTABLE_MEMBER_PARAM,
param.asType()).varargs(isVarArg));
paramType).varargs(isVarArg));
tree.add(link);
if(name(param).length() > 0) {
tree.add(Entity.NO_BREAK_SPACE);
@@ -208,9 +209,11 @@ protected Content getParameters(ExecutableElement member, boolean includeAnnotat
sep = "," + DocletConstants.NL;
}
int paramstart;
ExecutableType instMeth = utils.asInstantiatedMethodType(typeElement, member);
for (paramstart = 0; paramstart < parameters.size(); paramstart++) {
paramTree.add(sep);
VariableElement param = parameters.get(paramstart);
TypeMirror paramType = instMeth.getParameterTypes().get(paramstart);

if (param.getKind() != ElementKind.INSTANCE_INIT) {
if (includeAnnotations) {
@@ -220,7 +223,7 @@ protected Content getParameters(ExecutableElement member, boolean includeAnnotat
paramTree.add(DocletConstants.NL);
}
}
addParam(member, param,
addParam(member, param, paramType,
(paramstart == parameters.size() - 1) && member.isVarArgs(), paramTree);
break;
}
@@ -237,7 +240,8 @@ protected Content getParameters(ExecutableElement member, boolean includeAnnotat
paramTree.add(DocletConstants.NL);
}
}
addParam(member, parameters.get(i), (i == parameters.size() - 1) && member.isVarArgs(),
addParam(member, parameters.get(i), instMeth.getParameterTypes().get(i),
(i == parameters.size() - 1) && member.isVarArgs(),
paramTree);
}

@@ -251,7 +255,7 @@ protected Content getParameters(ExecutableElement member, boolean includeAnnotat
* @return the content tree containing the exceptions information.
*/
protected Content getExceptions(ExecutableElement member) {
List<? extends TypeMirror> exceptions = member.getThrownTypes();
List<? extends TypeMirror> exceptions = utils.asInstantiatedMethodType(typeElement, member).getThrownTypes();
Content htmltree = new ContentBuilder();
if (!exceptions.isEmpty()) {
Content link = writer.getLink(new LinkInfoImpl(configuration, MEMBER, exceptions.get(0)));
@@ -264,7 +264,7 @@ private TypeMirror getType(Element member) {
if (utils.isConstructor(member))
return null;
if (utils.isExecutableElement(member))
return utils.getReturnType((ExecutableElement)member);
return utils.getReturnType(typeElement, (ExecutableElement)member);
return member.asType();
}
}
@@ -266,7 +266,7 @@ protected Content getDeprecatedLink(Element member) {

private TypeMirror getType(Element member) {
return utils.isExecutableElement(member)
? utils.getReturnType((ExecutableElement) member)
? utils.getReturnType(typeElement, (ExecutableElement) member)
: member.asType();
}
}
@@ -204,6 +204,14 @@ public Content getClassInfo(Content classInfoTree) {
return getMemberTree(HtmlStyle.description, classInfoTree);
}

/**
* {@inheritDoc}
*/
@Override
protected TypeElement getCurrentPageElement() {
return typeElement;
}

/**
* {@inheritDoc}
*/
@@ -115,7 +115,7 @@ public Content getFieldDocTreeHeader(VariableElement field, Content fieldDetails
@Override
public Content getSignature(VariableElement field) {
return new MemberSignature(field)
.addType(field.asType())
.addType(utils.asInstantiatedFieldType(typeElement, field))
.toContent();
}

@@ -262,7 +262,7 @@ protected void addInheritedSummaryLink(TypeElement typeElement, Element member,
*/
@Override
protected void addSummaryType(Element member, Content tdSummaryType) {
addModifierAndType(member, member.asType(), tdSummaryType);
addModifierAndType(member, utils.asInstantiatedFieldType(typeElement, (VariableElement)member), tdSummaryType);
}

/**
@@ -860,6 +860,15 @@ public String getEnclosingPackageName(TypeElement te) {
return (encl.isUnnamed()) ? "" : (encl.getQualifiedName() + ".");
}

/**
* Return the main type element of the current page or null for pages that don't have one.
*
* @return the type element of the current page.
*/
protected TypeElement getCurrentPageElement() {
return null;
}

/**
* Add the class link, with only class name as the strong link and prefixing
* plain package name.
@@ -290,7 +290,7 @@ public void addInheritedSummaryLabel(TypeElement typeElement, Content inheritedT
@Override
protected void addSummaryType(Element member, Content tdSummaryType) {
ExecutableElement meth = (ExecutableElement)member;
addModifierAndType(meth, utils.getReturnType(meth), tdSummaryType);
addModifierAndType(meth, utils.getReturnType(typeElement, meth), tdSummaryType);
}

/**
@@ -386,7 +386,7 @@ protected static void addImplementsInfo(HtmlDocletWriter writer,
* @return content containing the return type
*/
protected Content getReturnType(ExecutableElement method) {
TypeMirror type = utils.getReturnType(method);
TypeMirror type = utils.getReturnType(typeElement, method);
if (type != null) {
return writer.getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.RETURN_TYPE, type));
}
@@ -109,7 +109,7 @@ public Content getPropertyDocTreeHeader(ExecutableElement property,
@Override
public Content getSignature(ExecutableElement property) {
return new MemberSignature(property)
.addType(utils.getReturnType(property))
.addType(utils.getReturnType(typeElement, property))
.toContent();
}

@@ -282,7 +282,7 @@ protected void addInheritedSummaryLink(TypeElement typeElement, Element member,
*/
@Override
protected void addSummaryType(Element member, Content tdSummaryType) {
addModifierAndType(member, utils.getReturnType((ExecutableElement)member), tdSummaryType);
addModifierAndType(member, utils.getReturnType(typeElement, (ExecutableElement)member), tdSummaryType);
}

/**
@@ -341,12 +341,15 @@ public Content getThrowsHeader() {
/**
* {@inheritDoc}
*/
public Content throwsTagOutput(Element element, DocTree throwsTag) {
public Content throwsTagOutput(Element element, DocTree throwsTag, TypeMirror substituteType) {
ContentBuilder body = new ContentBuilder();
CommentHelper ch = utils.getCommentHelper(element);
Element exception = ch.getException(configuration, throwsTag);
Content excName;
if (exception == null) {
if (substituteType != null) {
excName = htmlWriter.getLink(new LinkInfoImpl(configuration, LinkInfoImpl.Kind.MEMBER,
substituteType));
} else if (exception == null) {
excName = new RawHtml(ch.getExceptionName(throwsTag).toString());
} else if (exception.asType() == null) {
excName = new RawHtml(utils.getFullyQualifiedName(exception));
@@ -415,6 +418,13 @@ public BaseConfiguration configuration() {
return configuration;
}

/**
* {@inheritDoc}
*/
protected TypeElement getCurrentPageElement() {
return htmlWriter.getCurrentPageElement();
}

@SuppressWarnings("preview")
private Content createAnchorAndSearchIndex(Element element, String tagText, String desc, boolean isSystemProperty) {
Content result = null;
@@ -74,7 +74,7 @@ public void inherit(DocFinder.Input input, DocFinder.Output output) {
public Content getTagletOutput(Element holder, TagletWriter writer) {
Messages messages = writer.configuration().getMessages();
Utils utils = writer.configuration().utils;
TypeMirror returnType = utils.getReturnType((ExecutableElement)holder);
TypeMirror returnType = utils.getReturnType(writer.getCurrentPageElement(), (ExecutableElement)holder);
List<? extends DocTree> tags = utils.getBlockTags(holder, name);

//Make sure we are not using @return tag on method with void return type.
@@ -27,6 +27,7 @@

import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;

@@ -189,9 +190,10 @@ protected TagletWriter(boolean isFirstSentence) {
*
* @param element
* @param throwsTag the throws tag.
* @param substituteType instantiated type of a generic type-variable, or null.
* @return the output of the throws tag.
*/
protected abstract Content throwsTagOutput(Element element, DocTree throwsTag);
protected abstract Content throwsTagOutput(Element element, DocTree throwsTag, TypeMirror substituteType);

/**
* Return the output for the throws tag.
@@ -213,6 +215,13 @@ protected TagletWriter(boolean isFirstSentence) {
protected abstract Content valueTagOutput(VariableElement field,
String constantVal, boolean includeLink);

/**
* Return the main type element of the current page or null for pages that don't have one.
*
* @return the type element of the current page or null.
*/
protected abstract TypeElement getCurrentPageElement();

/**
* Given an output object, append to it the tag documentation for
* the given member.
@@ -31,6 +31,7 @@
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;

import com.sun.source.doctree.DocTree;
@@ -99,8 +100,8 @@ private Content linkToUndocumentedDeclaredExceptions(List<? extends TypeMirror>
for (TypeMirror declaredExceptionType : declaredExceptionTypes) {
TypeElement klass = utils.asTypeElement(declaredExceptionType);
if (klass != null &&
!alreadyDocumented.contains(utils.getSimpleName(klass)) &&
!alreadyDocumented.contains(utils.getFullyQualifiedName(klass))) {
!alreadyDocumented.contains(declaredExceptionType.toString()) &&
!alreadyDocumented.contains(utils.getFullyQualifiedName(klass, false))) {
if (alreadyDocumented.isEmpty()) {
result.add(writer.getThrowsHeader());
}
@@ -117,7 +118,7 @@ private Content linkToUndocumentedDeclaredExceptions(List<? extends TypeMirror>
*/
private Content inheritThrowsDocumentation(Element holder,
List<? extends TypeMirror> declaredExceptionTypes, Set<String> alreadyDocumented,
TagletWriter writer) {
Map<String, TypeMirror> typeSubstitutions, TagletWriter writer) {
Utils utils = writer.configuration().utils;
Content result = writer.getOutputInstance();
if (utils.isExecutableElement(holder)) {
@@ -138,7 +139,8 @@ private Content inheritThrowsDocumentation(Element holder,
declaredExceptionTags.put(inheritedDoc.tagList, (ExecutableElement)inheritedDoc.holder);
}
}
result.add(throwsTagsOutput(declaredExceptionTags, writer, alreadyDocumented, false));
result.add(throwsTagsOutput(declaredExceptionTags, writer, alreadyDocumented,
typeSubstitutions, false));
}
return result;
}
@@ -149,17 +151,21 @@ private Content inheritThrowsDocumentation(Element holder,
public Content getTagletOutput(Element holder, TagletWriter writer) {
Utils utils = writer.configuration().utils;
ExecutableElement execHolder = (ExecutableElement) holder;
ExecutableType instantiatedType = utils.asInstantiatedMethodType(
writer.getCurrentPageElement(), (ExecutableElement)holder);
List<? extends TypeMirror> thrownTypes = instantiatedType.getThrownTypes();
Map<String, TypeMirror> typeSubstitutions = getSubstitutedThrownTypes(
((ExecutableElement) holder).getThrownTypes(), thrownTypes);
Map<List<? extends DocTree>, ExecutableElement> tagsMap = new LinkedHashMap<>();
tagsMap.put(utils.getThrowsTrees(execHolder), execHolder);
Content result = writer.getOutputInstance();
HashSet<String> alreadyDocumented = new HashSet<>();
if (!tagsMap.isEmpty()) {
result.add(throwsTagsOutput(tagsMap, writer, alreadyDocumented, true));
result.add(throwsTagsOutput(tagsMap, writer, alreadyDocumented, typeSubstitutions, true));
}
result.add(inheritThrowsDocumentation(holder,
execHolder.getThrownTypes(), alreadyDocumented, writer));
result.add(linkToUndocumentedDeclaredExceptions(
execHolder.getThrownTypes(), alreadyDocumented, writer));
thrownTypes, alreadyDocumented, typeSubstitutions, writer));
result.add(linkToUndocumentedDeclaredExceptions(thrownTypes, alreadyDocumented, writer));
return result;
}

@@ -174,7 +180,8 @@ public Content getTagletOutput(Element holder, TagletWriter writer) {
* @return the Content representation of this <code>Tag</code>.
*/
protected Content throwsTagsOutput(Map<List<? extends DocTree>, ExecutableElement> throwTags,
TagletWriter writer, Set<String> alreadyDocumented, boolean allowDups) {
TagletWriter writer, Set<String> alreadyDocumented,
Map<String,TypeMirror> typeSubstitutions, boolean allowDups) {
Utils utils = writer.configuration().utils;
Content result = writer.getOutputInstance();
if (!throwTags.isEmpty()) {
@@ -184,21 +191,52 @@ protected Content throwsTagsOutput(Map<List<? extends DocTree>, ExecutableElemen
for (DocTree dt : entry.getKey()) {
Element te = ch.getException(utils.configuration, dt);
String excName = ch.getExceptionName(dt).toString();
TypeMirror substituteType = typeSubstitutions.get(excName);
if ((!allowDups) &&
(alreadyDocumented.contains(excName) ||
(te != null && alreadyDocumented.contains(utils.getFullyQualifiedName(te))))) {
(te != null && alreadyDocumented.contains(utils.getFullyQualifiedName(te, false)))) ||
(substituteType != null && alreadyDocumented.contains(substituteType.toString()))) {
continue;
}
if (alreadyDocumented.isEmpty()) {
result.add(writer.getThrowsHeader());
}
result.add(writer.throwsTagOutput(e, dt));
alreadyDocumented.add(te != null
? utils.getFullyQualifiedName(te)
: excName);
result.add(writer.throwsTagOutput(e, dt, substituteType));
if (substituteType != null) {
alreadyDocumented.add(substituteType.toString());
} else {
alreadyDocumented.add(te != null
? utils.getFullyQualifiedName(te, false)
: excName);
}
}
}
}
return result;
}

/**
* Returns a map of substitutions for a list of thrown types with the original type-variable
* name as key and the instantiated type as value. If no types need to be substituted
* an empty map is returned.
* @param declaredThrownTypes the originally declared thrown types.
* @param instantiatedThrownTypes the thrown types in the context of the current type.
* @return map of declared to instantiated thrown types or an empty map.
*/
private Map<String, TypeMirror> getSubstitutedThrownTypes(List<? extends TypeMirror> declaredThrownTypes,
List<? extends TypeMirror> instantiatedThrownTypes) {
if (!instantiatedThrownTypes.equals(declaredThrownTypes)) {
Map<String, TypeMirror> map = new HashMap<>();
Iterator<? extends TypeMirror> i1 = instantiatedThrownTypes.iterator();
Iterator<? extends TypeMirror> i2 = declaredThrownTypes.iterator();
while (i1.hasNext() && i2.hasNext()) {
TypeMirror t1 = i1.next();
TypeMirror t2 = i2.next();
if (!t1.equals(t2))
map.put(t2.toString(), t1);
}
return map;
}
return Collections.emptyMap();
}
}

0 comments on commit 5903e20

Please sign in to comment.