diff --git a/src/net/fabricmc/fernflower/api/FabricJavadocStyle.java b/src/net/fabricmc/fernflower/api/FabricJavadocStyle.java new file mode 100644 index 0000000000..984163fb68 --- /dev/null +++ b/src/net/fabricmc/fernflower/api/FabricJavadocStyle.java @@ -0,0 +1,12 @@ +package net.fabricmc.fernflower.api; + +public enum FabricJavadocStyle { + /** + * The traditional Javadoc style (default) + */ + HTML, + /** + * The Markdown Javadoc style introduced in Java 23 + */ + MARKDOWN, +} diff --git a/src/net/fabricmc/fernflower/api/IFabricJavadocProvider.java b/src/net/fabricmc/fernflower/api/IFabricJavadocProvider.java index ed4fe7d836..b6a8885cd5 100644 --- a/src/net/fabricmc/fernflower/api/IFabricJavadocProvider.java +++ b/src/net/fabricmc/fernflower/api/IFabricJavadocProvider.java @@ -9,7 +9,7 @@ * Provides (optional) javadoc for Classes/Methods/Fields encountered by * {@link org.jetbrains.java.decompiler.main.ClassWriter}. * - * May be set as a property in the constructor of {@link org.jetbrains.java.decompiler.main.Fernflower} by using + *

May be set as a property in the constructor of {@link org.jetbrains.java.decompiler.main.Fernflower} by using * the key {@code IFabricJavadocProvider.PROPERTY_NAME} */ public interface IFabricJavadocProvider { @@ -20,4 +20,16 @@ public interface IFabricJavadocProvider { String getFieldDoc(StructClass structClass, StructField structField); String getMethodDoc(StructClass structClass, StructMethod structMethod); + + default FabricJavadocStyle getClassJavadocStyle(StructClass structClass) { + return FabricJavadocStyle.HTML; + } + + default FabricJavadocStyle getFieldJavadocStyle(StructClass structClass, StructField structField) { + return getClassJavadocStyle(structClass); + } + + default FabricJavadocStyle getMethodJavadocStyle(StructClass structClass, StructMethod structMethod) { + return getClassJavadocStyle(structClass); + } } \ No newline at end of file diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 2a7ccf90d1..c9ea3c270a 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -2,6 +2,8 @@ package org.jetbrains.java.decompiler.main; import java.util.concurrent.atomic.AtomicBoolean; + +import net.fabricmc.fernflower.api.FabricJavadocStyle; import net.fabricmc.fernflower.api.IFabricJavadocProvider; import org.jetbrains.java.decompiler.api.plugin.StatementWriter; import org.jetbrains.java.decompiler.code.CodeConstants; @@ -689,7 +691,7 @@ private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent) } if (javadocProvider != null) { - appendJavadoc(buffer, javadocProvider.getClassDoc(cl), indent); + appendJavadoc(buffer, javadocProvider.getClassJavadocStyle(cl), javadocProvider.getClassDoc(cl), indent); } appendAnnotations(buffer, indent, cl, -1); @@ -876,7 +878,7 @@ public void writeField(ClassWrapper wrapper, StructClass cl, StructField fd, Tex } if (javadocProvider != null) { - appendJavadoc(buffer, javadocProvider.getFieldDoc(cl, fd), indent); + appendJavadoc(buffer, javadocProvider.getFieldJavadocStyle(cl, fd), javadocProvider.getFieldDoc(cl, fd), indent); } Set writtenAnnotations = appendAnnotations(buffer, indent, fd, TypeAnnotation.FIELD); @@ -1130,7 +1132,7 @@ public boolean writeMethod(ClassNode node, StructMethod mt, int methodIndex, Tex } if (javadocProvider != null) { - appendJavadoc(buffer, javadocProvider.getMethodDoc(cl, mt), indent); + appendJavadoc(buffer, javadocProvider.getMethodJavadocStyle(cl, mt), javadocProvider.getMethodDoc(cl, mt), indent); } Set writtenAnnotations = appendAnnotations(buffer, indent, mt, TypeAnnotation.METHOD_RETURN_TYPE); @@ -1786,13 +1788,22 @@ private static void appendComment(TextBuffer buffer, String comment, int indent) buffer.appendIndent(indent).append("// $VF: ").append(comment).appendLineSeparator(); } - private static void appendJavadoc(TextBuffer buffer, String javaDoc, int indent) { + private static void appendJavadoc(TextBuffer buffer, FabricJavadocStyle javadocStyle, String javaDoc, int indent) { if (javaDoc == null) return; - buffer.appendIndent(indent).append("/**").appendLineSeparator(); - for (String s : javaDoc.split("\n")) { - buffer.appendIndent(indent).append(" * ").append(s).appendLineSeparator(); + switch (javadocStyle) { + case HTML -> { + buffer.appendIndent(indent).append("/**").appendLineSeparator(); + for (String s : javaDoc.split("\n")) { + buffer.appendIndent(indent).append(" * ").append(s).appendLineSeparator(); + } + buffer.appendIndent(indent).append(" */").appendLineSeparator(); + } + case MARKDOWN -> { + for (String s : javaDoc.split("\n")) { + buffer.appendIndent(indent).append("/// ").append(s).appendLineSeparator(); + } + } } - buffer.appendIndent(indent).append(" */").appendLineSeparator(); } public static void appendSyntheticClassComment(StructClass cl, TextBuffer buffer) { diff --git a/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/test/org/jetbrains/java/decompiler/SingleClassesTest.java index 70bf9bc9c8..434cde8a67 100644 --- a/test/org/jetbrains/java/decompiler/SingleClassesTest.java +++ b/test/org/jetbrains/java/decompiler/SingleClassesTest.java @@ -1,6 +1,7 @@ // Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.java.decompiler; +import net.fabricmc.fernflower.api.FabricJavadocStyle; import net.fabricmc.fernflower.api.IFabricJavadocProvider; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.struct.StructClass; @@ -98,6 +99,29 @@ public String getMethodDoc(StructClass structClass, StructMethod structMethod) { return "Method javadoc for '" + structMethod.getName() + "'"; } }); + registerSet("Markdown Javadoc", () -> { + register(JAVA_8, "TestMarkdownJavadoc"); + }, IFabricJavadocProvider.PROPERTY_NAME, new IFabricJavadocProvider() { + @Override + public String getClassDoc(StructClass structClass) { + return "Class javadoc for '" + structClass.qualifiedName + "'"; + } + + @Override + public String getFieldDoc(StructClass structClass, StructField structField) { + return "Field javadoc for '" + structField.getName() + "'"; + } + + @Override + public String getMethodDoc(StructClass structClass, StructMethod structMethod) { + return "Method javadoc for '" + structMethod.getName() + "'"; + } + + @Override + public FabricJavadocStyle getClassJavadocStyle(StructClass structClass) { + return FabricJavadocStyle.MARKDOWN; + } + }); // TODO: converter renaming different on different platforms? registerSet("Renaming", () -> registerFailable(JAVA_8, "TestRenameEntities"), IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1", diff --git a/testData/results/pkg/TestMarkdownJavadoc.dec b/testData/results/pkg/TestMarkdownJavadoc.dec new file mode 100644 index 0000000000..504834c43e --- /dev/null +++ b/testData/results/pkg/TestMarkdownJavadoc.dec @@ -0,0 +1,11 @@ +package pkg; + +/// Class javadoc for 'pkg/TestMarkdownJavadoc' +public class TestMarkdownJavadoc { + /// Field javadoc for 'field' + public int field; + + /// Method javadoc for 'method' + public void method() { + } +} diff --git a/testData/src/java8/pkg/TestMarkdownJavadoc.java b/testData/src/java8/pkg/TestMarkdownJavadoc.java new file mode 100644 index 0000000000..d897d85946 --- /dev/null +++ b/testData/src/java8/pkg/TestMarkdownJavadoc.java @@ -0,0 +1,9 @@ +package pkg; + +public class TestMarkdownJavadoc { + public int field; + + public void method() { + + } +} \ No newline at end of file