From eabcc3fb4a3f2ecc760f85c3d0787b2319428a8d Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Tue, 21 May 2024 00:09:45 +0200 Subject: [PATCH] [fixes #933] Add javadoc for generated constructors --- .../lombok/core/handlers/HandlerUtil.java | 18 ++++++++++- .../eclipse/handlers/EclipseHandlerUtil.java | 6 +++- .../eclipse/handlers/HandleConstructor.java | 31 +++++++++++++++++-- .../javac/handlers/HandleConstructor.java | 27 ++++++++++++++++ .../after-delombok/BuilderJavadoc.java | 9 ++++++ .../after-delombok/BuilderWithDeprecated.java | 8 +++++ .../after-delombok/ConstructorJavadoc.java | 28 +++++++++++++++++ .../resource/after-ecj/BuilderJavadoc.java | 9 ++++++ .../after-ecj/BuilderWithDeprecated.java | 8 +++++ .../after-ecj/ConstructorJavadoc.java | 16 ++++++++++ .../resource/before/ConstructorJavadoc.java | 20 ++++++++++++ 11 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 test/transform/resource/after-delombok/ConstructorJavadoc.java create mode 100644 test/transform/resource/after-ecj/ConstructorJavadoc.java create mode 100644 test/transform/resource/before/ConstructorJavadoc.java diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index 06bac16f..16274df9 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2022 The Project Lombok Authors. + * Copyright (C) 2013-2024 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -981,4 +981,20 @@ public class HandlerUtil { } return null; } + + public static String getConstructorJavadocHeader(String typeName) { + return "Creates a new {@code " + typeName + "} instance.\n\n"; + } + + public static String getConstructorParameterJavadoc(String paramName, String fieldJavadoc) { + String fieldBaseJavadoc = stripSectionsFromJavadoc(fieldJavadoc); + + String paramJavadoc = getParamJavadoc(fieldBaseJavadoc, paramName); + if (paramJavadoc == null) { + paramJavadoc = stripLinesWithTagFromJavadoc(fieldBaseJavadoc, JavadocTag.PARAM); + paramJavadoc = stripLinesWithTagFromJavadoc(paramJavadoc, JavadocTag.RETURN); + } + + return paramJavadoc; + } } diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index af1aa0fd..39e29e94 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -2815,10 +2815,14 @@ public class EclipseHandlerUtil { return null; } + public static void setDocComment(EclipseNode typeNode, EclipseNode eclipseNode, String doc) { + setDocComment((CompilationUnitDeclaration) eclipseNode.top().get(), (TypeDeclaration) typeNode.get(), eclipseNode.get(), doc); + } + public static void setDocComment(CompilationUnitDeclaration cud, EclipseNode eclipseNode, String doc) { setDocComment(cud, (TypeDeclaration) upToTypeNode(eclipseNode).get(), eclipseNode.get(), doc); } - + public static void setDocComment(CompilationUnitDeclaration cud, TypeDeclaration type, ASTNode node, String doc) { if (doc == null) return; diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index 8d9c5f7b..e60ca15f 100755 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -22,7 +22,7 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.*; -import static lombok.eclipse.Eclipse.*; +import static lombok.eclipse.Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; @@ -286,7 +286,8 @@ public class HandleConstructor { ConstructorDeclaration constr = createConstructor( staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fieldsToParam, forceDefaults, sourceNode, onConstructor); - injectMethod(typeNode, constr); + EclipseNode constructorNode = injectMethod(typeNode, constr); + generateConstructorJavadoc(typeNode, constructorNode, fieldsToParam); } generateStaticConstructor(staticConstrRequired, typeNode, staticName, level, fieldsToParam, source); } @@ -294,7 +295,8 @@ public class HandleConstructor { private void generateStaticConstructor(boolean staticConstrRequired, EclipseNode typeNode, String staticName, AccessLevel level, Collection fields, ASTNode source) { if (staticConstrRequired) { MethodDeclaration staticConstr = createStaticConstructor(level, staticName, typeNode, fields, source); - injectMethod(typeNode, staticConstr); + EclipseNode constructorNode = injectMethod(typeNode, staticConstr); + generateConstructorJavadoc(typeNode, constructorNode, fields); } } @@ -584,4 +586,27 @@ public class HandleConstructor { constructor.traverse(new SetGeneratedByVisitor(source), typeDecl.scope); return constructor; } + + private void generateConstructorJavadoc(EclipseNode typeNode, EclipseNode constructorNode, Collection fields) { + if (fields.isEmpty()) return; + + String constructorJavadoc = getConstructorJavadocHeader(typeNode.getName()); + boolean fieldDescriptionAdded = false; + for (EclipseNode fieldNode : fields) { + String paramName = String.valueOf(removePrefixFromField(fieldNode)); + String fieldJavadoc = getDocComment(fieldNode); + String paramJavadoc = getConstructorParameterJavadoc(paramName, fieldJavadoc); + + if (paramJavadoc == null) { + paramJavadoc = ""; + } else { + fieldDescriptionAdded = true; + } + + constructorJavadoc = addJavadocLine(constructorJavadoc, "@param " + paramName + " " + paramJavadoc); + } + if (fieldDescriptionAdded) { + setDocComment(typeNode, constructorNode, constructorJavadoc); + } + } } diff --git a/src/core/lombok/javac/handlers/HandleConstructor.java b/src/core/lombok/javac/handlers/HandleConstructor.java index 372bc57d..27dba4a0 100644 --- a/src/core/lombok/javac/handlers/HandleConstructor.java +++ b/src/core/lombok/javac/handlers/HandleConstructor.java @@ -30,6 +30,7 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; @@ -251,6 +252,7 @@ public class HandleConstructor { if (!(skipIfConstructorExists != SkipIfConstructorExists.NO && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS)) { JCMethodDecl constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, onConstructor, typeNode, fields, allToDefault, source); + generateConstructorJavadoc(constr, typeNode, fields); injectMethod(typeNode, constr); } generateStaticConstructor(staticConstrRequired, typeNode, staticName, level, allToDefault, fields, source); @@ -259,6 +261,7 @@ public class HandleConstructor { private void generateStaticConstructor(boolean staticConstrRequired, JavacNode typeNode, String staticName, AccessLevel level, boolean allToDefault, List fields, JavacNode source) { if (staticConstrRequired) { JCMethodDecl staticConstr = createStaticConstructor(staticName, level, typeNode, allToDefault ? List.nil() : fields, source); + generateConstructorJavadoc(staticConstr, typeNode, fields); injectMethod(typeNode, staticConstr); } } @@ -474,4 +477,28 @@ public class HandleConstructor { createRelevantNonNullAnnotation(typeNode, methodDef); return recursiveSetGeneratedBy(methodDef, source); } + + private void generateConstructorJavadoc(JCMethodDecl constructor, JavacNode typeNode, List fields) { + if (fields.isEmpty()) return; + + JCCompilationUnit cu = ((JCCompilationUnit) typeNode.top().get()); + String constructorJavadoc = getConstructorJavadocHeader(typeNode.getName()); + boolean fieldDescriptionAdded = false; + for (JavacNode fieldNode : fields) { + String paramName = removePrefixFromField(fieldNode).toString(); + String fieldJavadoc = getDocComment(cu, fieldNode.get()); + String paramJavadoc = getConstructorParameterJavadoc(paramName, fieldJavadoc); + + if (paramJavadoc == null) { + paramJavadoc = ""; + } else { + fieldDescriptionAdded = true; + } + + constructorJavadoc = addJavadocLine(constructorJavadoc, "@param " + paramName + " " + paramJavadoc); + } + if (fieldDescriptionAdded) { + setDocComment(cu, constructor, constructorJavadoc); + } + } } diff --git a/test/transform/resource/after-delombok/BuilderJavadoc.java b/test/transform/resource/after-delombok/BuilderJavadoc.java index 34de4ab8..55e9db8c 100644 --- a/test/transform/resource/after-delombok/BuilderJavadoc.java +++ b/test/transform/resource/after-delombok/BuilderJavadoc.java @@ -87,6 +87,15 @@ class BuilderJavadoc { return "BuilderJavadoc.BuilderJavadocBuilder(basic=" + this.basic + ", getsetwith=" + this.getsetwith + ", predef=" + this.predef + ", predefWithJavadoc=" + this.predefWithJavadoc + ")"; } } + /** + * Creates a new {@code BuilderJavadoc} instance. + * + * @param basic basic gets only a builder setter. + * @see #getsetwith + * @param getsetwith getsetwith gets a builder setter, an instance getter and setter, and a wither. + * @param predef Predef has a predefined builder setter with no javadoc, and the builder setter does not get this one. + * @param predefWithJavadoc predefWithJavadoc has a predefined builder setter with javadoc, so it keeps that one untouched. + */ @java.lang.SuppressWarnings("all") @lombok.Generated BuilderJavadoc(final int basic, final int getsetwith, final int predef, final int predefWithJavadoc) { diff --git a/test/transform/resource/after-delombok/BuilderWithDeprecated.java b/test/transform/resource/after-delombok/BuilderWithDeprecated.java index 26a02b44..1e2d4e8d 100644 --- a/test/transform/resource/after-delombok/BuilderWithDeprecated.java +++ b/test/transform/resource/after-delombok/BuilderWithDeprecated.java @@ -10,6 +10,14 @@ public class BuilderWithDeprecated { java.util.List strings; @Deprecated ImmutableList numbers; + /** + * Creates a new {@code BuilderWithDeprecated} instance. + * + * @param dep1 @deprecated since always + * @param dep2 + * @param strings + * @param numbers + */ @java.lang.SuppressWarnings("all") @lombok.Generated BuilderWithDeprecated(final String dep1, final int dep2, final java.util.List strings, final ImmutableList numbers) { diff --git a/test/transform/resource/after-delombok/ConstructorJavadoc.java b/test/transform/resource/after-delombok/ConstructorJavadoc.java new file mode 100644 index 00000000..bd55b585 --- /dev/null +++ b/test/transform/resource/after-delombok/ConstructorJavadoc.java @@ -0,0 +1,28 @@ +public class ConstructorJavadoc { + /** + * Some text + * + * @param fieldName Hello, World1 + * --- GETTER --- + * Getter section + * + * @return Sky is blue1 + */ + private int fieldName; + /** + * Sky is blue + */ + private int fieldName2; + /** + * Creates a new {@code ConstructorJavadoc} instance. + * + * @param fieldName Some text + * @param fieldName2 Sky is blue + */ + @java.lang.SuppressWarnings("all") + @lombok.Generated + public ConstructorJavadoc(final int fieldName, final int fieldName2) { + this.fieldName = fieldName; + this.fieldName2 = fieldName2; + } +} diff --git a/test/transform/resource/after-ecj/BuilderJavadoc.java b/test/transform/resource/after-ecj/BuilderJavadoc.java index 718b1c45..75ac875a 100644 --- a/test/transform/resource/after-ecj/BuilderJavadoc.java +++ b/test/transform/resource/after-ecj/BuilderJavadoc.java @@ -46,6 +46,15 @@ import java.util.List; private @lombok.Getter @lombok.Setter @lombok.experimental.Wither int getsetwith; private final int predef; private final int predefWithJavadoc; + /** + * Creates a new {@code BuilderJavadoc} instance. + * + * @param basic basic gets only a builder setter. + * @see #getsetwith + * @param getsetwith getsetwith gets a builder setter, an instance getter and setter, and a wither. + * @param predef Predef has a predefined builder setter with no javadoc, and the builder setter does not get this one. + * @param predefWithJavadoc predefWithJavadoc has a predefined builder setter with javadoc, so it keeps that one untouched. + */ @java.lang.SuppressWarnings("all") @lombok.Generated BuilderJavadoc(final int basic, final int getsetwith, final int predef, final int predefWithJavadoc) { super(); this.basic = basic; diff --git a/test/transform/resource/after-ecj/BuilderWithDeprecated.java b/test/transform/resource/after-ecj/BuilderWithDeprecated.java index 1d18360a..52f43725 100644 --- a/test/transform/resource/after-ecj/BuilderWithDeprecated.java +++ b/test/transform/resource/after-ecj/BuilderWithDeprecated.java @@ -89,6 +89,14 @@ public @Builder class BuilderWithDeprecated { @Deprecated int dep2; @Singular @Deprecated java.util.List strings; @Singular @Deprecated ImmutableList numbers; + /** + * Creates a new {@code BuilderWithDeprecated} instance. + * + * @param dep1 @deprecated since always + * @param dep2 + * @param strings + * @param numbers + */ @java.lang.SuppressWarnings("all") @lombok.Generated BuilderWithDeprecated(final String dep1, final int dep2, final java.util.List strings, final ImmutableList numbers) { super(); this.dep1 = dep1; diff --git a/test/transform/resource/after-ecj/ConstructorJavadoc.java b/test/transform/resource/after-ecj/ConstructorJavadoc.java new file mode 100644 index 00000000..4b861ab7 --- /dev/null +++ b/test/transform/resource/after-ecj/ConstructorJavadoc.java @@ -0,0 +1,16 @@ +import lombok.AllArgsConstructor; +public @AllArgsConstructor class ConstructorJavadoc { + private int fieldName; + private int fieldName2; + /** + * Creates a new {@code ConstructorJavadoc} instance. + * + * @param fieldName Some text + * @param fieldName2 Sky is blue + */ + public @java.lang.SuppressWarnings("all") @lombok.Generated ConstructorJavadoc(final int fieldName, final int fieldName2) { + super(); + this.fieldName = fieldName; + this.fieldName2 = fieldName2; + } +} diff --git a/test/transform/resource/before/ConstructorJavadoc.java b/test/transform/resource/before/ConstructorJavadoc.java new file mode 100644 index 00000000..feeabf72 --- /dev/null +++ b/test/transform/resource/before/ConstructorJavadoc.java @@ -0,0 +1,20 @@ +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public class ConstructorJavadoc { + /** + * Some text + * + * @param fieldName Hello, World1 + * --- GETTER --- + * Getter section + * + * @return Sky is blue1 + */ + private int fieldName; + + /** + * Sky is blue + */ + private int fieldName2; +}