Skip to content

Commit

Permalink
fix: Do not inherit the return tag if an inline return is present (#5645
Browse files Browse the repository at this point in the history
)
  • Loading branch information
I-Al-Istannen committed Apr 3, 2024
1 parent e7d4b9b commit 93a1ac6
Show file tree
Hide file tree
Showing 3 changed files with 305 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package spoon.javadoc.api.elements;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import spoon.javadoc.api.JavadocTagType;

Expand Down Expand Up @@ -45,4 +46,24 @@ public List<JavadocElement> getBody() {
.filter(it -> !(it instanceof JavadocBlockTag))
.collect(Collectors.toList());
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
JavadocCommentView view = (JavadocCommentView) o;
return Objects.equals(elements, view.elements);
}

@Override
public int hashCode() {
return Objects.hash(elements);
}

@Override
public String toString() {
return "JavadocCommentView{" +
"elements=" + elements +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -63,11 +64,8 @@ public List<CtMethod<?>> findSuperMethodsInCommentInheritanceOrder(CtType<?> sta
if (method != null) {
methods.add(method);
}
}

// If Step 1 failed to find a documentation comment, then recursively apply this entire algorithm to each
// directly implemented (or extended) interface in the same order they were examined in Step 1.
for (CtType<?> type : superInterfaces) {
// Recursively find super methods in parent types. This is not the way it is
// specified in <22, but the way it works in the standard doclet.
methods.addAll(findSuperMethodsInCommentInheritanceOrder(type, target));
}

Expand All @@ -76,7 +74,15 @@ public List<CtMethod<?>> findSuperMethodsInCommentInheritanceOrder(CtType<?> sta
// but not an interface:

// If the superclass has a documentation comment for this method, then use it.
addSuperclassMethods(startType, target, methods);
List<CtMethod<?>> superclassMethods = new ArrayList<>();
addSuperclassMethods(startType, target, superclassMethods);

// From Java 22 onwards the direct superclass methods come first
if (startType.getFactory().getEnvironment().getComplianceLevel() >= 22) {
methods.addAll(0, superclassMethods);
} else {
methods.addAll(superclassMethods);
}
}

return methods;
Expand Down Expand Up @@ -133,31 +139,31 @@ private List<CtTypeReference<?>> sortByPosition(Collection<CtTypeReference<?>> r
* @return the new and completed javadoc
*/
public List<JavadocElement> completeJavadocWithInheritedTags(CtElement element, JavadocCommentView view) {
if (!(element instanceof CtMethod<?>)) {
if (!(element instanceof CtMethod<?> method)) {
return view.getElements();
}
CtMethod<?> method = (CtMethod<?>) element;
Set<String> paramsToFind = method.getParameters()
.stream()
.map(CtNamedElement::getSimpleName)
.collect(Collectors.toCollection(HashSet::new));
.collect(Collectors.toCollection(LinkedHashSet::new)); // keep decl order
view.getBlockTagArguments(StandardJavadocTagType.PARAM, JavadocText.class)
.forEach(it -> paramsToFind.remove(it.getText()));

Set<String> throwsToFind = method.getThrownTypes()
.stream()
.map(CtTypeInformation::getQualifiedName)
.collect(Collectors.toCollection(HashSet::new));
.collect(Collectors.toCollection(LinkedHashSet::new)); // keep decl order
view.getBlockTagArguments(StandardJavadocTagType.THROWS, JavadocText.class)
.forEach(it -> throwsToFind.remove(it.getText()));
view.getBlockTagArguments(StandardJavadocTagType.EXCEPTION, JavadocText.class)
.forEach(it -> throwsToFind.remove(it.getText()));

boolean needsReturn = view.getBlockTag(StandardJavadocTagType.RETURN).isEmpty();
boolean needsReturn = needsReturn(view);
boolean needsBody = view.getBody().isEmpty();

InheritedJavadoc inheritedJavadoc = lookupInheritedDocForMethod(method);

// Order by body -> param -> return -> throws
List<JavadocElement> newElements = new ArrayList<>();
if (needsBody) {
newElements.addAll(inheritedJavadoc.getBody());
Expand All @@ -166,13 +172,13 @@ public List<JavadocElement> completeJavadocWithInheritedTags(CtElement element,
.map(it -> inheritedJavadoc.getParams().get(it))
.filter(Objects::nonNull)
.forEach(newElements::add);
if (needsReturn && inheritedJavadoc.getReturnTag() != null) {
newElements.add(inheritedJavadoc.getReturnTag());
}
throwsToFind.stream()
.map(it -> inheritedJavadoc.getThrowsClauses().get(it))
.filter(Objects::nonNull)
.forEach(newElements::add);
if (needsReturn && inheritedJavadoc.getReturnTag() != null) {
newElements.add(inheritedJavadoc.getReturnTag());
}

List<JavadocElement> finalElements = new ArrayList<>(view.getElements());
finalElements.addAll(newElements);
Expand All @@ -183,7 +189,22 @@ public List<JavadocElement> completeJavadocWithInheritedTags(CtElement element,
.collect(Collectors.toList());
}

public static InheritedJavadoc lookupInheritedDocForMethod(CtMethod<?> method) {
private static boolean needsReturn(JavadocCommentView view) {
// Block tags are always allowed
if (!view.getBlockTag(StandardJavadocTagType.RETURN).isEmpty()) {
return false;
}
// As an inline tag, it may only occur at the beginning of a method's main description.
if (view.getBody().isEmpty()) {
return true;
}
if (!(view.getBody().get(0) instanceof JavadocInlineTag start)) {
return true;
}
return start.getTagType() != StandardJavadocTagType.RETURN;
}

private static InheritedJavadoc lookupInheritedDocForMethod(CtMethod<?> method) {
List<CtMethod<?>> targets = new InheritanceResolver()
.findSuperMethodsInCommentInheritanceOrder(method.getDeclaringType(), method);

Expand Down Expand Up @@ -297,9 +318,12 @@ public Void visitBlockTag(JavadocBlockTag tag) {
params.put(arg, tag);
});
}
if (tag.getTagType() == StandardJavadocTagType.THROWS) {
tag.getArgument(JavadocText.class)
.map(JavadocText::getText)
if (
tag.getTagType() == StandardJavadocTagType.THROWS
|| tag.getTagType() == StandardJavadocTagType.EXCEPTION
) {
tag.getArgument(JavadocReference.class)
.map(it -> it.getReference().toString())
.filter(missingThrowsClauses::contains)
.ifPresent(arg -> {
missingThrowsClauses.remove(arg);
Expand Down

0 comments on commit 93a1ac6

Please sign in to comment.