[javadoc] Generate package documentation when no package-info is present

Somewhat improves IDEA-302001

GitOrigin-RevId: 46864735a2d442d3cacebab96ec4d49b783c82a0
This commit is contained in:
Tagir Valeev
2022-10-12 17:24:22 +00:00
committed by intellij-monorepo-bot
parent f59b68df2e
commit ccf6ab043e
10 changed files with 65 additions and 7 deletions
@@ -689,7 +689,16 @@ public class JavaDocInfoGenerator {
@NlsSafe String ownerLink = null;
String ownerIcon = null;
if (element instanceof PsiClass) {
if (element instanceof PsiPackage pkg) {
return HtmlChunk.div()
.setClass("bottom")
.children(
HtmlChunk.tag("icon").attr("src", "AllIcons.Nodes.Package"),
HtmlChunk.nbsp(),
HtmlChunk.tag("code").addText(pkg.getQualifiedName())
);
}
else if (element instanceof PsiClass) {
PsiFile file = element.getContainingFile();
if (file instanceof PsiJavaFile javaFile) {
String packageName = javaFile.getPackageName();
@@ -1041,6 +1050,7 @@ public class JavaDocInfoGenerator {
}
private void generatePackageJavaDoc(StringBuilder buffer, PsiPackage psiPackage, boolean generatePrologue) {
boolean hasInfo = false;
for (PsiDirectory directory : psiPackage.getDirectories(GlobalSearchScope.everythingScope(myProject))) {
PsiFile packageInfoFile = directory.findFile(PsiPackage.PACKAGE_INFO_FILE);
if (packageInfoFile != null) {
@@ -1049,6 +1059,7 @@ public class JavaDocInfoGenerator {
ASTNode docCommentNode = findRelevantCommentNode(node);
if (docCommentNode != null) {
generatePackageJavaDoc(buffer, (PsiDocComment)docCommentNode.getPsi(), generatePrologue);
hasInfo = true;
break;
}
}
@@ -1056,9 +1067,43 @@ public class JavaDocInfoGenerator {
PsiFile packageHtmlFile = directory.findFile("package.html");
if (packageHtmlFile != null) {
generatePackageHtmlJavaDoc(buffer, packageHtmlFile, generatePrologue);
hasInfo = true;
break;
}
}
if (!hasInfo) {
generateDefaultPackageDoc(buffer, psiPackage, generatePrologue);
}
}
private void generateDefaultPackageDoc(StringBuilder buffer, PsiPackage aPackage, boolean generatePrologue) {
if (generatePrologue) generatePrologue(buffer);
HtmlBuilder hb = new HtmlBuilder();
hb.append(HtmlChunk.tag("h3").addText(JavaBundle.message("package.classes")));
Comparator<PsiClass> comparator = Comparator.comparing(PsiClass::getName, Comparator.nullsLast(Comparator.naturalOrder()));
Arrays.stream(aPackage.getClasses()).sorted(comparator).forEach(psiClass -> {
String link = generateLink(psiClass, psiClass.getName(), false, false);
if (link != null) {
hb.append(HtmlChunk.tag("div")
.children(
HtmlChunk.tag("icon").attr("src", getIcon(psiClass)),
HtmlChunk.nbsp(),
HtmlChunk.raw(link)
));
}
});
buffer.append(hb);
buffer.append(DocumentationMarkup.SECTIONS_END);
}
@NotNull
private static String getIcon(@NotNull PsiClass psiClass) {
return psiClass.isEnum() ? "AllIcons.Nodes.Enum" :
psiClass.isRecord() ? "AllIcons.Nodes.Record" :
psiClass.isAnnotationType() ? "AllIcons.Nodes.Annotationtype" :
psiClass.isInterface() ? "AllIcons.Nodes.Interface" :
psiClass.hasModifierProperty(PsiModifier.ABSTRACT) ? "AllIcons.Nodes.AbstractClass" :
"AllIcons.Nodes.Class";
}
private void generatePackageJavaDoc(StringBuilder buffer, PsiDocComment comment, boolean generatePrologue) {
@@ -2456,7 +2501,10 @@ public class JavaDocInfoGenerator {
appendMaybeUnresolvedLink(buffer, target, label, target.getProject(), false);
}
private static @Nullable String generateLink(@NotNull PsiElement element, String label, boolean plainLink, boolean isRenderedDoc) {
private static @Nullable @NlsSafe String generateLink(@NotNull PsiElement element,
String label,
boolean plainLink,
boolean isRenderedDoc) {
String refText = JavaDocUtil.getReferenceText(element.getProject(), element);
if (refText != null) {
StringBuilder linkBuilder = new StringBuilder();
@@ -1,3 +1,3 @@
<div class='content'>
<div class="bottom"><icon src="AllIcons.Nodes.Package">&nbsp;<code>com.jetbrains</code></div><div class='content'>
Description of com.jetbrains package
</div><table class='sections'><p></table>
@@ -1,3 +1,3 @@
<div class='content'>
<div class="bottom"><icon src="AllIcons.Nodes.Package">&nbsp;<code>packageHtml</code></div><div class='content'>
Some text.
</div><table class='sections'><p></table>
@@ -1,3 +1,3 @@
<div class='content'>
<div class="bottom"><icon src="AllIcons.Nodes.Package">&nbsp;<code>packageInfo</code></div><div class='content'>
This package contains nothing but package-info.java
</div><table class='sections'><p></table>
@@ -1,3 +1,3 @@
<div class='content-only'>
<div class="bottom"><icon src="AllIcons.Nodes.Package">&nbsp;<code>packageInfoFromComment</code></div><div class='content-only'>
some text
</div>
@@ -1,3 +1,3 @@
<div class='content-only'>
<div class="bottom"><icon src="AllIcons.Nodes.Package">&nbsp;<code>packageInfoWithCopyright</code></div><div class='content-only'>
This package contains nothing but package-info.java
</div>
@@ -0,0 +1,7 @@
package packageWithoutPackageInfo;
class A {}
interface B {}
enum C {}
@interface D{}
abstract class E{}
@@ -0,0 +1 @@
<div class="bottom"><icon src="AllIcons.Nodes.Package">&nbsp;<code>packageWithoutPackageInfo</code></div><h3>Package classes:</h3><div><icon src="AllIcons.Nodes.Class">&nbsp;<a href="psi_element://packageWithoutPackageInfo.A"><code>A</code></a></div><div><icon src="AllIcons.Nodes.Interface">&nbsp;<a href="psi_element://packageWithoutPackageInfo.B"><code>B</code></a></div><div><icon src="AllIcons.Nodes.Enum">&nbsp;<a href="psi_element://packageWithoutPackageInfo.C"><code>C</code></a></div><div><icon src="AllIcons.Nodes.Annotationtype">&nbsp;<a href="psi_element://packageWithoutPackageInfo.D"><code>D</code></a></div><div><icon src="AllIcons.Nodes.AbstractClass">&nbsp;<a href="psi_element://packageWithoutPackageInfo.E"><code>E</code></a></div></table>
@@ -109,6 +109,7 @@ public class JavaDocInfoGeneratorTest extends JavaCodeInsightTestCase {
public void testSuperJavadocExactResolve() { doTestAtCaret(); }
public void testSuperJavadocErasureResolve() { doTestAtCaret(); }
public void testPackageInfo() { doTestPackageInfo(); }
public void testPackageWithoutPackageInfo() { doTestPackageInfo(); }
public void testPackageHtml() { doTestPackageInfo(); }
public void testSyntheticEnumValues() { doTestAtCaret(); }
public void testVariableDoc() { doTestAtCaret(); }
@@ -1785,3 +1785,4 @@ adds.library.preview=Adds {0, choice, 1#library ''''{1}''''|2#one of {2}} to mod
notification.content.added.annotations=Added {0} {0, choice, 1#annotation|2#annotations}
intention.make.final.fixer.stream=Make ''{0}'' effectively final using stream API
intention.make.final.fixer.if=Make ''{0}'' effectively final by moving initializer to the ''if'' statement
package.classes=Package classes: