From e61829fa6edf7a2041080e6c3c59192762dae2e4 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Tue, 21 Jul 2020 15:55:34 +0200 Subject: [PATCH 1/7] Added implementation for PostGeneratedConstructor --- src/core/lombok/ConfigurationKeys.java | 9 ++ .../HandlePostGeneratedConstructor.java | 119 +++++++++++++++++ .../PostGeneratedConstructor.java | 35 +++++ .../HandlePostGeneratedConstructor.java | 126 ++++++++++++++++++ .../PostGeneratedConstructor.java | 26 ++++ .../PostGeneratedConstructorExceptions.java | 19 +++ .../PostGeneratedConstructorInvalid.java | 9 ++ .../after-ecj/PostGeneratedConstructor.java | 27 ++++ .../PostGeneratedConstructorExceptions.java | 18 +++ .../PostGeneratedConstructorInvalid.java | 11 ++ .../before/PostGeneratedConstructor.java | 18 +++ .../PostGeneratedConstructorExceptions.java | 23 ++++ .../PostGeneratedConstructorInvalid.java | 16 +++ ...tGeneratedConstructorInvalid.java.messages | 3 + ...tGeneratedConstructorInvalid.java.messages | 3 + 15 files changed, 462 insertions(+) create mode 100644 src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java create mode 100644 src/core/lombok/experimental/PostGeneratedConstructor.java create mode 100644 src/core/lombok/javac/handlers/HandlePostGeneratedConstructor.java create mode 100644 test/transform/resource/after-delombok/PostGeneratedConstructor.java create mode 100644 test/transform/resource/after-delombok/PostGeneratedConstructorExceptions.java create mode 100644 test/transform/resource/after-delombok/PostGeneratedConstructorInvalid.java create mode 100644 test/transform/resource/after-ecj/PostGeneratedConstructor.java create mode 100644 test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java create mode 100644 test/transform/resource/after-ecj/PostGeneratedConstructorInvalid.java create mode 100644 test/transform/resource/before/PostGeneratedConstructor.java create mode 100644 test/transform/resource/before/PostGeneratedConstructorExceptions.java create mode 100644 test/transform/resource/before/PostGeneratedConstructorInvalid.java create mode 100644 test/transform/resource/messages-delombok/PostGeneratedConstructorInvalid.java.messages create mode 100644 test/transform/resource/messages-ecj/PostGeneratedConstructorInvalid.java.messages diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 22d5a4c5a8..96721f854b 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -692,6 +692,15 @@ private ConfigurationKeys() {} */ public static final ConfigurationKey JACKSONIZED_FLAG_USAGE = new ConfigurationKey("lombok.jacksonized.flagUsage", "Emit a warning or error if @Jacksonized is used.") {}; + // ----- PostGeneratedConstructor ----- + + /** + * lombok configuration: {@code lombok.postGeneratedConstructor.flagUsage} = {@code WARNING} | {@code ERROR}. + * + * If set, any usage of {@code @PostGeneratedConstructor} results in a warning / error. + */ + public static final ConfigurationKey POST_GENERATED_CONSTRUCTOR_FLAG_USAGE = new ConfigurationKey("lombok.postGeneratedConstructor.flagUsage", "Emit a warning or error if @PostGeneratedConstructor is used.") {}; + // ----- Configuration System ----- /** diff --git a/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java b/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java new file mode 100644 index 0000000000..d7974f840b --- /dev/null +++ b/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2009-2020 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.handlers; + +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; +import static lombok.eclipse.Eclipse.pos; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.ThisReference; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.mangosdk.spi.ProviderFor; + +import lombok.ConfigurationKeys; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; +import lombok.eclipse.DeferUntilPostDiet; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; +import lombok.experimental.PostGeneratedConstructor; + +/** + * Handles the {@code lombok.experimental.PostGeneratedConstructor} annotation for eclipse. + */ +@ProviderFor(EclipseAnnotationHandler.class) +@DeferUntilPostDiet +@HandlerPriority(value = 1024) +public class HandlePostGeneratedConstructor extends EclipseAnnotationHandler { + + @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.POST_GENERATED_CONSTRUCTOR_FLAG_USAGE, "@PostGeneratedConstructor"); + + EclipseNode methodNode = annotationNode.up(); + if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof MethodDeclaration)) { + annotationNode.addError("@PostGeneratedConstructor is legal only on methods."); + return; + } + + MethodDeclaration method = (MethodDeclaration) methodNode.get(); + if (method.isAbstract()) { + annotationNode.addError("@PostGeneratedConstructor is legal only on concrete methods."); + return; + } + + if (method.isStatic()) { + annotationNode.addError("@PostGeneratedConstructor is legal only on instance methods."); + return; + } + + EclipseNode typeNode = upToTypeNode(annotationNode); + + int pS = source.sourceStart, pE = source.sourceEnd; + long p = pos(source); + + List generatedConstructors = findGeneratedConstructors(typeNode); + if (generatedConstructors.isEmpty()) { + annotationNode.addError("Cannot find a generated constructor."); + return; + } + + for (AbstractMethodDeclaration methodDecl : generatedConstructors) { + MessageSend call = new MessageSend(); + call.selector = method.selector; + call.receiver = ThisReference.implicitThis(); + + call.nameSourcePosition = p; + call.sourceStart = pS; + call.sourceEnd = call.statementEnd = pE; + setGeneratedBy(call, source); + + methodDecl.statements = concat(methodDecl.statements, new Statement[] {call}, Statement.class); + methodDecl.thrownExceptions = concat(methodDecl.thrownExceptions, method.thrownExceptions, TypeReference.class); + + typeNode.getAst().get(methodDecl).rebuild(); + } + } + + private List findGeneratedConstructors(EclipseNode typeNode) { + List constructors = new ArrayList(); + if (typeNode != null && typeNode.get() instanceof TypeDeclaration) { + TypeDeclaration typeDecl = (TypeDeclaration) typeNode.get(); + for (AbstractMethodDeclaration methodDecl : typeDecl.methods) { + if (methodDecl instanceof ConstructorDeclaration && isGenerated(methodDecl)) { + constructors.add(methodDecl); + } + } + } + return constructors; + } +} diff --git a/src/core/lombok/experimental/PostGeneratedConstructor.java b/src/core/lombok/experimental/PostGeneratedConstructor.java new file mode 100644 index 0000000000..fbbcab78bb --- /dev/null +++ b/src/core/lombok/experimental/PostGeneratedConstructor.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012-2017 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.experimental; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.SOURCE) +public @interface PostGeneratedConstructor { + +} diff --git a/src/core/lombok/javac/handlers/HandlePostGeneratedConstructor.java b/src/core/lombok/javac/handlers/HandlePostGeneratedConstructor.java new file mode 100644 index 0000000000..4c6e2bd656 --- /dev/null +++ b/src/core/lombok/javac/handlers/HandlePostGeneratedConstructor.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2009-2020 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.javac.handlers; + +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; +import static lombok.javac.handlers.JavacHandlerUtil.*; + +import org.mangosdk.spi.ProviderFor; + +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; +import com.sun.tools.javac.tree.JCTree.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; + +import lombok.ConfigurationKeys; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; +import lombok.experimental.PostGeneratedConstructor; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; +import lombok.javac.JavacTreeMaker; + +/** + * Handles the {@code lombok.experimental.PostGeneratedConstructor} annotation for javac. + */ +@ProviderFor(JavacAnnotationHandler.class) +@HandlerPriority(value = 1024) +public class HandlePostGeneratedConstructor extends JavacAnnotationHandler { + + @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.POST_GENERATED_CONSTRUCTOR_FLAG_USAGE, "@PostGeneratedConstructor"); + + if (inNetbeansEditor(annotationNode)) return; + + deleteAnnotationIfNeccessary(annotationNode, PostGeneratedConstructor.class); + JavacNode methodNode = annotationNode.up(); + + if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof JCMethodDecl)) { + annotationNode.addError("@PostGeneratedConstructor is legal only on methods."); + return; + } + + JCMethodDecl method = (JCMethodDecl)methodNode.get(); + + if ((method.mods.flags & Flags.ABSTRACT) != 0) { + annotationNode.addError("@PostGeneratedConstructor is legal only on concrete methods."); + return; + } + + if ((method.mods.flags & Flags.STATIC) != 0) { + annotationNode.addError("@PostGeneratedConstructor is legal only on instance methods."); + return; + } + + JavacTreeMaker maker = methodNode.getTreeMaker(); + Context context = methodNode.getContext(); + + JavacNode typeNode = upToTypeNode(annotationNode); + + List generatedConstructors = findGeneratedConstructors(typeNode); + if (generatedConstructors.isEmpty()) { + annotationNode.addError("Cannot find a generated constructor."); + return; + } + + for (JCMethodDecl constructor : generatedConstructors) { + JCStatement statement = maker.Exec(maker.Apply(List.nil(), maker.Ident(method.name), List.nil())); + recursiveSetGeneratedBy(statement, ast, context); + + constructor.body.stats = appendToList(constructor.body.stats, statement); + constructor.thrown = appendToList(constructor.thrown, method.thrown); + + typeNode.getAst().get(constructor).rebuild(); + } + } + + private List findGeneratedConstructors(JavacNode typeNode) { + ListBuffer constructors = new ListBuffer(); + if (typeNode != null && typeNode.get() instanceof JCClassDecl) { + JCClassDecl type = (JCClassDecl) typeNode.get(); + for (JCTree def : type.defs) { + if (def instanceof JCMethodDecl) { + JCMethodDecl methodDecl = (JCMethodDecl) def; + if (methodDecl.name.toString().equals("") && getGeneratedBy(methodDecl) != null) { + constructors.add(methodDecl); + } + } + } + } + return constructors.toList(); + } + + private List appendToList(List list, T append) { + return appendToList(list, List.of(append)); + } + + private List appendToList(List list, List append) { + return List.nil().appendList(list).appendList(append); + } +} diff --git a/test/transform/resource/after-delombok/PostGeneratedConstructor.java b/test/transform/resource/after-delombok/PostGeneratedConstructor.java new file mode 100644 index 0000000000..e49de18cbc --- /dev/null +++ b/test/transform/resource/after-delombok/PostGeneratedConstructor.java @@ -0,0 +1,26 @@ +class PostGeneratedConstructorTest { + private String name; + private final Integer start; + private final Integer end; + + private void validate() { + if (start == null || end == null || end < start) { + throw new IllegalArgumentException(); + } + } + + @java.lang.SuppressWarnings("all") + public PostGeneratedConstructorTest(final Integer start, final Integer end) { + this.start = start; + this.end = end; + validate(); + } + + @java.lang.SuppressWarnings("all") + public PostGeneratedConstructorTest(final String name, final Integer start, final Integer end) { + this.name = name; + this.start = start; + this.end = end; + validate(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/PostGeneratedConstructorExceptions.java b/test/transform/resource/after-delombok/PostGeneratedConstructorExceptions.java new file mode 100644 index 0000000000..b12f47af8e --- /dev/null +++ b/test/transform/resource/after-delombok/PostGeneratedConstructorExceptions.java @@ -0,0 +1,19 @@ +class PostGeneratedConstructorExceptions { + private String a; + + PostGeneratedConstructorExceptions() { + } + + private void post() throws IllegalArgumentException { + } + + private void post2() throws InterruptedException { + } + + @java.lang.SuppressWarnings("all") + public PostGeneratedConstructorExceptions(final String a) throws IllegalArgumentException, InterruptedException { + this.a = a; + post(); + post2(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/PostGeneratedConstructorInvalid.java b/test/transform/resource/after-delombok/PostGeneratedConstructorInvalid.java new file mode 100644 index 0000000000..4b4f3cfc35 --- /dev/null +++ b/test/transform/resource/after-delombok/PostGeneratedConstructorInvalid.java @@ -0,0 +1,9 @@ +abstract class PostGeneratedConstructorInvalid { + private void noConstructor() { + } + + private static void staticMethod() { + } + + public abstract void abstractMethod(); +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/PostGeneratedConstructor.java b/test/transform/resource/after-ecj/PostGeneratedConstructor.java new file mode 100644 index 0000000000..aa2a588121 --- /dev/null +++ b/test/transform/resource/after-ecj/PostGeneratedConstructor.java @@ -0,0 +1,27 @@ +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.experimental.PostGeneratedConstructor; +@RequiredArgsConstructor @AllArgsConstructor class PostGeneratedConstructorTest { + private String name; + private final Integer start; + private final Integer end; + private @PostGeneratedConstructor void validate() { + if ((((start == null) || (end == null)) || (end < start))) + { + throw new IllegalArgumentException(); + } + } + public @java.lang.SuppressWarnings("all") PostGeneratedConstructorTest(final Integer start, final Integer end) { + super(); + this.start = start; + this.end = end; + validate(); + } + public @java.lang.SuppressWarnings("all") PostGeneratedConstructorTest(final String name, final Integer start, final Integer end) { + super(); + this.name = name; + this.start = start; + this.end = end; + validate(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java b/test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java new file mode 100644 index 0000000000..b9df170f17 --- /dev/null +++ b/test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java @@ -0,0 +1,18 @@ +import lombok.AllArgsConstructor; +import lombok.experimental.PostGeneratedConstructor; +@AllArgsConstructor class PostGeneratedConstructorExceptions { + private String a; + PostGeneratedConstructorExceptions() { + super(); + } + private @PostGeneratedConstructor void post() throws IllegalArgumentException { + } + private @lombok.experimental.PostGeneratedConstructor void post2() throws InterruptedException { + } + public @java.lang.SuppressWarnings("all") PostGeneratedConstructorExceptions(final String a) throws IllegalArgumentException, InterruptedException { + super(); + this.a = a; + post(); + post2(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/PostGeneratedConstructorInvalid.java b/test/transform/resource/after-ecj/PostGeneratedConstructorInvalid.java new file mode 100644 index 0000000000..2231d19ecd --- /dev/null +++ b/test/transform/resource/after-ecj/PostGeneratedConstructorInvalid.java @@ -0,0 +1,11 @@ +import lombok.experimental.PostGeneratedConstructor; +abstract class PostGeneratedConstructorInvalid { + PostGeneratedConstructorInvalid() { + super(); + } + private @PostGeneratedConstructor void noConstructor() { + } + private static @PostGeneratedConstructor void staticMethod() { + } + public abstract @PostGeneratedConstructor void abstractMethod(); +} \ No newline at end of file diff --git a/test/transform/resource/before/PostGeneratedConstructor.java b/test/transform/resource/before/PostGeneratedConstructor.java new file mode 100644 index 0000000000..104d9e8383 --- /dev/null +++ b/test/transform/resource/before/PostGeneratedConstructor.java @@ -0,0 +1,18 @@ +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.experimental.PostGeneratedConstructor; + +@RequiredArgsConstructor +@AllArgsConstructor +class PostGeneratedConstructorTest { + private String name; + private final Integer start; + private final Integer end; + + @PostGeneratedConstructor + private void validate() { + if (start == null || end == null || end < start) { + throw new IllegalArgumentException(); + } + } +} \ No newline at end of file diff --git a/test/transform/resource/before/PostGeneratedConstructorExceptions.java b/test/transform/resource/before/PostGeneratedConstructorExceptions.java new file mode 100644 index 0000000000..9b5ead607c --- /dev/null +++ b/test/transform/resource/before/PostGeneratedConstructorExceptions.java @@ -0,0 +1,23 @@ +import lombok.AllArgsConstructor; +import lombok.experimental.PostGeneratedConstructor; + +@AllArgsConstructor +class PostGeneratedConstructorExceptions { + + private String a; + + PostGeneratedConstructorExceptions() { + + } + + @PostGeneratedConstructor + private void post() throws IllegalArgumentException { + + } + + @lombok.experimental.PostGeneratedConstructor + private void post2() throws InterruptedException { + + } + +} \ No newline at end of file diff --git a/test/transform/resource/before/PostGeneratedConstructorInvalid.java b/test/transform/resource/before/PostGeneratedConstructorInvalid.java new file mode 100644 index 0000000000..662fbc5c14 --- /dev/null +++ b/test/transform/resource/before/PostGeneratedConstructorInvalid.java @@ -0,0 +1,16 @@ +import lombok.experimental.PostGeneratedConstructor; + +abstract class PostGeneratedConstructorInvalid { + @PostGeneratedConstructor + private void noConstructor() { + + } + + @PostGeneratedConstructor + private static void staticMethod() { + + } + + @PostGeneratedConstructor + public abstract void abstractMethod(); +} \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/PostGeneratedConstructorInvalid.java.messages b/test/transform/resource/messages-delombok/PostGeneratedConstructorInvalid.java.messages new file mode 100644 index 0000000000..eba5eea247 --- /dev/null +++ b/test/transform/resource/messages-delombok/PostGeneratedConstructorInvalid.java.messages @@ -0,0 +1,3 @@ +4 Cannot find a generated constructor. +9 @PostGeneratedConstructor is legal only on instance methods. +14 @PostGeneratedConstructor is legal only on concrete methods. \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/PostGeneratedConstructorInvalid.java.messages b/test/transform/resource/messages-ecj/PostGeneratedConstructorInvalid.java.messages new file mode 100644 index 0000000000..eba5eea247 --- /dev/null +++ b/test/transform/resource/messages-ecj/PostGeneratedConstructorInvalid.java.messages @@ -0,0 +1,3 @@ +4 Cannot find a generated constructor. +9 @PostGeneratedConstructor is legal only on instance methods. +14 @PostGeneratedConstructor is legal only on concrete methods. \ No newline at end of file From e3561ca89489175659d4c21411af3a368fd2e5fe Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Tue, 21 Jul 2020 15:56:58 +0200 Subject: [PATCH 2/7] [website] Add PostGeneratedConstructor to feature section --- .../PostGeneratedConstructor.html | 37 +++++++++++++++++++ .../features/experimental/index.html | 4 ++ ...PostGeneratedConstructorExample_post.jpage | 24 ++++++++++++ .../PostGeneratedConstructorExample_pre.jpage | 18 +++++++++ 4 files changed, 83 insertions(+) create mode 100644 website/templates/features/experimental/PostGeneratedConstructor.html create mode 100644 website/usageExamples/experimental/PostGeneratedConstructorExample_post.jpage create mode 100644 website/usageExamples/experimental/PostGeneratedConstructorExample_pre.jpage diff --git a/website/templates/features/experimental/PostGeneratedConstructor.html b/website/templates/features/experimental/PostGeneratedConstructor.html new file mode 100644 index 0000000000..2d5c5a2e16 --- /dev/null +++ b/website/templates/features/experimental/PostGeneratedConstructor.html @@ -0,0 +1,37 @@ +<#import "../_features.html" as f> + +<@f.scaffold title="@PostGeneratedConstructor" logline="Call methods after construction"> + <@f.history> +

+ @PostGeneratedConstructor was introduced as experimental feature in lombok v1.18.13. +

+ + + <@f.experimental> +
    +
  • + New feature +
  • + Might be replaced by a more powerful implementation that can also handle explicit written constructors. +
  • +
+ + + <@f.overview> +

+ The method annotated with @PostGeneratedConstructor gets called as last method in any constructor generated by lombok e.g. @AllArgsConstructor. This method can be used for validation, precomputation, caching, ... +

+ It ignores explicit written constructors. +

+ + + <@f.snippets name="experimental/PostGeneratedConstructor" /> + + <@f.confKeys> +
+ lombok.postGeneratedConstructor.flagUsage = [warning | error] (default: not set) +
+ Lombok will flag any usage of @PostGeneratedConstructor as a warning or error if configured. +
+ + diff --git a/website/templates/features/experimental/index.html b/website/templates/features/experimental/index.html index a50a467006..7d384eee31 100644 --- a/website/templates/features/experimental/index.html +++ b/website/templates/features/experimental/index.html @@ -75,6 +75,10 @@ <@main.feature title="@StandardException" href="StandardException"> Standard.. Exceptional? This is not just an oxymoron, it's convenient! + + <@main.feature title="@PostGeneratedConstructor" href="PostGeneratedConstructor"> + Call methods after construction. + <@f.confKeys> diff --git a/website/usageExamples/experimental/PostGeneratedConstructorExample_post.jpage b/website/usageExamples/experimental/PostGeneratedConstructorExample_post.jpage new file mode 100644 index 0000000000..403b496ca1 --- /dev/null +++ b/website/usageExamples/experimental/PostGeneratedConstructorExample_post.jpage @@ -0,0 +1,24 @@ +class PostGeneratedConstructorExample { + private String name; + private final Integer start; + private final Integer end; + + public PostGeneratedConstructorTest(final String name, final Integer start, final Integer end) { + this.name = name; + this.start = start; + this.end = end; + validate(); + } + + public PostGeneratedConstructorTest(final Integer start, final Integer end) { + this.start = start; + this.end = end; + validate(); + } + + private void validate() { + if (start == null || end == null || end < start) { + throw new IllegalArgumentException(); + } + } +} \ No newline at end of file diff --git a/website/usageExamples/experimental/PostGeneratedConstructorExample_pre.jpage b/website/usageExamples/experimental/PostGeneratedConstructorExample_pre.jpage new file mode 100644 index 0000000000..e959545fbe --- /dev/null +++ b/website/usageExamples/experimental/PostGeneratedConstructorExample_pre.jpage @@ -0,0 +1,18 @@ +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.experimental.PostGeneratedConstructor; + +@AllArgsConstructor +@RequiredArgsConstructor +class PostGeneratedConstructorExample { + private String name; + private final Integer start; + private final Integer end; + + @PostGeneratedConstructor + private void validate() { + if (start == null || end == null || end < start) { + throw new IllegalArgumentException(); + } + } +} \ No newline at end of file From d542b3dd98c88f9a75b866ce8c87df9016210296 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Fri, 24 Jul 2020 16:45:40 +0200 Subject: [PATCH 3/7] Update copyright notice --- .../lombok/eclipse/handlers/HandlePostGeneratedConstructor.java | 2 +- src/core/lombok/experimental/PostGeneratedConstructor.java | 2 +- .../lombok/javac/handlers/HandlePostGeneratedConstructor.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java b/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java index d7974f840b..3e0cf6469f 100644 --- a/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2020 The Project Lombok Authors. + * Copyright (C) 2020 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 diff --git a/src/core/lombok/experimental/PostGeneratedConstructor.java b/src/core/lombok/experimental/PostGeneratedConstructor.java index fbbcab78bb..54598bbdeb 100644 --- a/src/core/lombok/experimental/PostGeneratedConstructor.java +++ b/src/core/lombok/experimental/PostGeneratedConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2017 The Project Lombok Authors. + * Copyright (C) 2020 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 diff --git a/src/core/lombok/javac/handlers/HandlePostGeneratedConstructor.java b/src/core/lombok/javac/handlers/HandlePostGeneratedConstructor.java index 4c6e2bd656..2852a1ec4d 100644 --- a/src/core/lombok/javac/handlers/HandlePostGeneratedConstructor.java +++ b/src/core/lombok/javac/handlers/HandlePostGeneratedConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2020 The Project Lombok Authors. + * Copyright (C) 2020 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 From bdecc310195d6b6396338abaf50c52473c98da63 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Wed, 29 Jul 2020 16:45:55 +0200 Subject: [PATCH 4/7] Add empty arguments check for PostGeneratedConstructor method --- .../eclipse/handlers/HandlePostGeneratedConstructor.java | 5 +++++ .../javac/handlers/HandlePostGeneratedConstructor.java | 7 ++++++- .../after-delombok/PostGeneratedConstructorInvalid.java | 3 +++ .../after-ecj/PostGeneratedConstructorInvalid.java | 2 ++ .../resource/before/PostGeneratedConstructorInvalid.java | 5 +++++ .../PostGeneratedConstructorInvalid.java.messages | 3 ++- .../PostGeneratedConstructorInvalid.java.messages | 3 ++- 7 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java b/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java index 3e0cf6469f..210d065911 100644 --- a/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java @@ -76,6 +76,11 @@ public class HandlePostGeneratedConstructor extends EclipseAnnotationHandler Date: Wed, 29 Jul 2020 16:47:02 +0200 Subject: [PATCH 5/7] Add test for overlapping exceptions on PostGeneratedConstructor method --- .../after-delombok/PostGeneratedConstructorExceptions.java | 4 ++-- .../after-ecj/PostGeneratedConstructorExceptions.java | 4 ++-- .../resource/before/PostGeneratedConstructorExceptions.java | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/test/transform/resource/after-delombok/PostGeneratedConstructorExceptions.java b/test/transform/resource/after-delombok/PostGeneratedConstructorExceptions.java index b12f47af8e..73f57c0c68 100644 --- a/test/transform/resource/after-delombok/PostGeneratedConstructorExceptions.java +++ b/test/transform/resource/after-delombok/PostGeneratedConstructorExceptions.java @@ -7,11 +7,11 @@ class PostGeneratedConstructorExceptions { private void post() throws IllegalArgumentException { } - private void post2() throws InterruptedException { + private void post2() throws InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { } @java.lang.SuppressWarnings("all") - public PostGeneratedConstructorExceptions(final String a) throws IllegalArgumentException, InterruptedException { + public PostGeneratedConstructorExceptions(final String a) throws IllegalArgumentException, InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { this.a = a; post(); post2(); diff --git a/test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java b/test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java index b9df170f17..b98587d95e 100644 --- a/test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java +++ b/test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java @@ -7,9 +7,9 @@ } private @PostGeneratedConstructor void post() throws IllegalArgumentException { } - private @lombok.experimental.PostGeneratedConstructor void post2() throws InterruptedException { + private @lombok.experimental.PostGeneratedConstructor void post2() throws InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { } - public @java.lang.SuppressWarnings("all") PostGeneratedConstructorExceptions(final String a) throws IllegalArgumentException, InterruptedException { + public @java.lang.SuppressWarnings("all") PostGeneratedConstructorExceptions(final String a) throws IllegalArgumentException, InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { super(); this.a = a; post(); diff --git a/test/transform/resource/before/PostGeneratedConstructorExceptions.java b/test/transform/resource/before/PostGeneratedConstructorExceptions.java index 9b5ead607c..2663abeb8d 100644 --- a/test/transform/resource/before/PostGeneratedConstructorExceptions.java +++ b/test/transform/resource/before/PostGeneratedConstructorExceptions.java @@ -16,8 +16,7 @@ private void post() throws IllegalArgumentException { } @lombok.experimental.PostGeneratedConstructor - private void post2() throws InterruptedException { + private void post2() throws InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { } - } \ No newline at end of file From 0af861d4bb7bef576ede77e93eb0cc60c73b4204 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Wed, 9 Feb 2022 18:35:39 +0100 Subject: [PATCH 6/7] Rename to PostConstructor --- src/core/lombok/ConfigurationKeys.java | 8 ++-- ...ructor.java => HandlePostConstructor.java} | 22 +++++------ ...dConstructor.java => PostConstructor.java} | 2 +- ...ructor.java => HandlePostConstructor.java} | 32 +++++++--------- ...dConstructor.java => PostConstructor.java} | 6 +-- ...ns.java => PostConstructorExceptions.java} | 6 +-- ...valid.java => PostConstructorInvalid.java} | 2 +- ...dConstructor.java => PostConstructor.java} | 10 ++--- .../after-ecj/PostConstructorExceptions.java | 18 +++++++++ .../after-ecj/PostConstructorInvalid.java | 13 +++++++ .../PostGeneratedConstructorExceptions.java | 18 --------- .../PostGeneratedConstructorInvalid.java | 13 ------- ...dConstructor.java => PostConstructor.java} | 6 +-- ...ns.java => PostConstructorExceptions.java} | 10 ++--- .../before/PostConstructorInvalid.java | 21 +++++++++++ .../PostGeneratedConstructorInvalid.java | 21 ----------- .../PostConstructorInvalid.java.messages | 4 ++ ...tGeneratedConstructorInvalid.java.messages | 4 -- .../PostConstructorInvalid.java.messages | 4 ++ ...tGeneratedConstructorInvalid.java.messages | 4 -- .../experimental/PostConstructor.html | 35 ++++++++++++++++++ .../PostGeneratedConstructor.html | 37 ------------------- .../features/experimental/index.html | 2 +- ...page => PostConstructorExample_post.jpage} | 6 +-- ...jpage => PostConstructorExample_pre.jpage} | 6 +-- 25 files changed, 152 insertions(+), 158 deletions(-) rename src/core/lombok/eclipse/handlers/{HandlePostGeneratedConstructor.java => HandlePostConstructor.java} (81%) rename src/core/lombok/experimental/{PostGeneratedConstructor.java => PostConstructor.java} (96%) rename src/core/lombok/javac/handlers/{HandlePostGeneratedConstructor.java => HandlePostConstructor.java} (76%) rename test/transform/resource/after-delombok/{PostGeneratedConstructor.java => PostConstructor.java} (65%) rename test/transform/resource/after-delombok/{PostGeneratedConstructorExceptions.java => PostConstructorExceptions.java} (51%) rename test/transform/resource/after-delombok/{PostGeneratedConstructorInvalid.java => PostConstructorInvalid.java} (76%) rename test/transform/resource/after-ecj/{PostGeneratedConstructor.java => PostConstructor.java} (51%) create mode 100644 test/transform/resource/after-ecj/PostConstructorExceptions.java create mode 100644 test/transform/resource/after-ecj/PostConstructorInvalid.java delete mode 100644 test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java delete mode 100644 test/transform/resource/after-ecj/PostGeneratedConstructorInvalid.java rename test/transform/resource/before/{PostGeneratedConstructor.java => PostConstructor.java} (73%) rename test/transform/resource/before/{PostGeneratedConstructorExceptions.java => PostConstructorExceptions.java} (55%) create mode 100644 test/transform/resource/before/PostConstructorInvalid.java delete mode 100644 test/transform/resource/before/PostGeneratedConstructorInvalid.java create mode 100644 test/transform/resource/messages-delombok/PostConstructorInvalid.java.messages delete mode 100644 test/transform/resource/messages-delombok/PostGeneratedConstructorInvalid.java.messages create mode 100644 test/transform/resource/messages-ecj/PostConstructorInvalid.java.messages delete mode 100644 test/transform/resource/messages-ecj/PostGeneratedConstructorInvalid.java.messages create mode 100644 website/templates/features/experimental/PostConstructor.html delete mode 100644 website/templates/features/experimental/PostGeneratedConstructor.html rename website/usageExamples/experimental/{PostGeneratedConstructorExample_post.jpage => PostConstructorExample_post.jpage} (61%) rename website/usageExamples/experimental/{PostGeneratedConstructorExample_pre.jpage => PostConstructorExample_pre.jpage} (73%) diff --git a/src/core/lombok/ConfigurationKeys.java b/src/core/lombok/ConfigurationKeys.java index 96721f854b..a95b1cb3cd 100644 --- a/src/core/lombok/ConfigurationKeys.java +++ b/src/core/lombok/ConfigurationKeys.java @@ -692,14 +692,14 @@ private ConfigurationKeys() {} */ public static final ConfigurationKey JACKSONIZED_FLAG_USAGE = new ConfigurationKey("lombok.jacksonized.flagUsage", "Emit a warning or error if @Jacksonized is used.") {}; - // ----- PostGeneratedConstructor ----- + // ----- PostConstructor ----- /** - * lombok configuration: {@code lombok.postGeneratedConstructor.flagUsage} = {@code WARNING} | {@code ERROR}. + * lombok configuration: {@code lombok.postConstructor.flagUsage} = {@code WARNING} | {@code ERROR}. * - * If set, any usage of {@code @PostGeneratedConstructor} results in a warning / error. + * If set, any usage of {@code @PostConstructor} results in a warning / error. */ - public static final ConfigurationKey POST_GENERATED_CONSTRUCTOR_FLAG_USAGE = new ConfigurationKey("lombok.postGeneratedConstructor.flagUsage", "Emit a warning or error if @PostGeneratedConstructor is used.") {}; + public static final ConfigurationKey POST_CONSTRUCTOR_FLAG_USAGE = new ConfigurationKey("lombok.postConstructor.flagUsage", "Emit a warning or error if @PostConstructor is used.") {}; // ----- Configuration System ----- diff --git a/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java b/src/core/lombok/eclipse/handlers/HandlePostConstructor.java similarity index 81% rename from src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java rename to src/core/lombok/eclipse/handlers/HandlePostConstructor.java index 210d065911..2e9a81083c 100644 --- a/src/core/lombok/eclipse/handlers/HandlePostGeneratedConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandlePostConstructor.java @@ -37,7 +37,6 @@ import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; -import org.mangosdk.spi.ProviderFor; import lombok.ConfigurationKeys; import lombok.core.AST.Kind; @@ -46,38 +45,39 @@ import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.experimental.PostGeneratedConstructor; +import lombok.experimental.PostConstructor; +import lombok.spi.Provides; /** - * Handles the {@code lombok.experimental.PostGeneratedConstructor} annotation for eclipse. + * Handles the {@code lombok.experimental.PostConstructor} annotation for eclipse. */ -@ProviderFor(EclipseAnnotationHandler.class) @DeferUntilPostDiet +@Provides @HandlerPriority(value = 1024) -public class HandlePostGeneratedConstructor extends EclipseAnnotationHandler { +public class HandlePostConstructor extends EclipseAnnotationHandler { - @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { - handleFlagUsage(annotationNode, ConfigurationKeys.POST_GENERATED_CONSTRUCTOR_FLAG_USAGE, "@PostGeneratedConstructor"); + @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.POST_CONSTRUCTOR_FLAG_USAGE, "@PostConstructor"); EclipseNode methodNode = annotationNode.up(); if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof MethodDeclaration)) { - annotationNode.addError("@PostGeneratedConstructor is legal only on methods."); + annotationNode.addError("@PostConstructor is legal only on methods."); return; } MethodDeclaration method = (MethodDeclaration) methodNode.get(); if (method.isAbstract()) { - annotationNode.addError("@PostGeneratedConstructor is legal only on concrete methods."); + annotationNode.addError("@PostConstructor is legal only on concrete methods."); return; } if (method.isStatic()) { - annotationNode.addError("@PostGeneratedConstructor is legal only on instance methods."); + annotationNode.addError("@PostConstructor is legal only on instance methods."); return; } if (method.arguments != null) { - annotationNode.addError("@PostGeneratedConstructor is legal only on methods without parameters."); + annotationNode.addError("@PostConstructor is legal only on methods without parameters."); return; } diff --git a/src/core/lombok/experimental/PostGeneratedConstructor.java b/src/core/lombok/experimental/PostConstructor.java similarity index 96% rename from src/core/lombok/experimental/PostGeneratedConstructor.java rename to src/core/lombok/experimental/PostConstructor.java index 54598bbdeb..a4293b2858 100644 --- a/src/core/lombok/experimental/PostGeneratedConstructor.java +++ b/src/core/lombok/experimental/PostConstructor.java @@ -30,6 +30,6 @@ */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) -public @interface PostGeneratedConstructor { +public @interface PostConstructor { } diff --git a/src/core/lombok/javac/handlers/HandlePostGeneratedConstructor.java b/src/core/lombok/javac/handlers/HandlePostConstructor.java similarity index 76% rename from src/core/lombok/javac/handlers/HandlePostGeneratedConstructor.java rename to src/core/lombok/javac/handlers/HandlePostConstructor.java index dfcdbdee71..f89906946e 100644 --- a/src/core/lombok/javac/handlers/HandlePostGeneratedConstructor.java +++ b/src/core/lombok/javac/handlers/HandlePostConstructor.java @@ -21,11 +21,9 @@ */ package lombok.javac.handlers; -import static lombok.core.handlers.HandlerUtil.*; +import static lombok.core.handlers.HandlerUtil.handleFlagUsage; import static lombok.javac.handlers.JavacHandlerUtil.*; -import org.mangosdk.spi.ProviderFor; - import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotation; @@ -33,7 +31,6 @@ import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCStatement; -import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; @@ -41,51 +38,50 @@ import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; -import lombok.experimental.PostGeneratedConstructor; +import lombok.experimental.PostConstructor; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; +import lombok.spi.Provides; /** - * Handles the {@code lombok.experimental.PostGeneratedConstructor} annotation for javac. + * Handles the {@code lombok.experimental.PostConstructor} annotation for javac. */ -@ProviderFor(JavacAnnotationHandler.class) +@Provides @HandlerPriority(value = 1024) -public class HandlePostGeneratedConstructor extends JavacAnnotationHandler { +public class HandlePostConstructor extends JavacAnnotationHandler { - @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { - handleFlagUsage(annotationNode, ConfigurationKeys.POST_GENERATED_CONSTRUCTOR_FLAG_USAGE, "@PostGeneratedConstructor"); + @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { + handleFlagUsage(annotationNode, ConfigurationKeys.POST_CONSTRUCTOR_FLAG_USAGE, "@PostConstructor"); if (inNetbeansEditor(annotationNode)) return; - deleteAnnotationIfNeccessary(annotationNode, PostGeneratedConstructor.class); + deleteAnnotationIfNeccessary(annotationNode, PostConstructor.class); JavacNode methodNode = annotationNode.up(); if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof JCMethodDecl)) { - annotationNode.addError("@PostGeneratedConstructor is legal only on methods."); + annotationNode.addError("@PostConstructor is legal only on methods."); return; } JCMethodDecl method = (JCMethodDecl)methodNode.get(); if ((method.mods.flags & Flags.ABSTRACT) != 0) { - annotationNode.addError("@PostGeneratedConstructor is legal only on concrete methods."); + annotationNode.addError("@PostConstructor is legal only on concrete methods."); return; } if ((method.mods.flags & Flags.STATIC) != 0) { - annotationNode.addError("@PostGeneratedConstructor is legal only on instance methods."); + annotationNode.addError("@PostConstructor is legal only on instance methods."); return; } if (method.params.nonEmpty()) { - annotationNode.addError("@PostGeneratedConstructor is legal only on methods without parameters."); + annotationNode.addError("@PostConstructor is legal only on methods without parameters."); return; } JavacTreeMaker maker = methodNode.getTreeMaker(); - Context context = methodNode.getContext(); - JavacNode typeNode = upToTypeNode(annotationNode); List generatedConstructors = findGeneratedConstructors(typeNode); @@ -96,7 +92,7 @@ public class HandlePostGeneratedConstructor extends JavacAnnotationHandlernil(), maker.Ident(method.name), List.nil())); - recursiveSetGeneratedBy(statement, ast, context); + recursiveSetGeneratedBy(statement, annotationNode); constructor.body.stats = appendToList(constructor.body.stats, statement); constructor.thrown = appendToList(constructor.thrown, method.thrown); diff --git a/test/transform/resource/after-delombok/PostGeneratedConstructor.java b/test/transform/resource/after-delombok/PostConstructor.java similarity index 65% rename from test/transform/resource/after-delombok/PostGeneratedConstructor.java rename to test/transform/resource/after-delombok/PostConstructor.java index e49de18cbc..d81bd8b76e 100644 --- a/test/transform/resource/after-delombok/PostGeneratedConstructor.java +++ b/test/transform/resource/after-delombok/PostConstructor.java @@ -1,4 +1,4 @@ -class PostGeneratedConstructorTest { +class PostConstructorTest { private String name; private final Integer start; private final Integer end; @@ -10,14 +10,14 @@ private void validate() { } @java.lang.SuppressWarnings("all") - public PostGeneratedConstructorTest(final Integer start, final Integer end) { + public PostConstructorTest(final Integer start, final Integer end) { this.start = start; this.end = end; validate(); } @java.lang.SuppressWarnings("all") - public PostGeneratedConstructorTest(final String name, final Integer start, final Integer end) { + public PostConstructorTest(final String name, final Integer start, final Integer end) { this.name = name; this.start = start; this.end = end; diff --git a/test/transform/resource/after-delombok/PostGeneratedConstructorExceptions.java b/test/transform/resource/after-delombok/PostConstructorExceptions.java similarity index 51% rename from test/transform/resource/after-delombok/PostGeneratedConstructorExceptions.java rename to test/transform/resource/after-delombok/PostConstructorExceptions.java index 73f57c0c68..adcf54a52f 100644 --- a/test/transform/resource/after-delombok/PostGeneratedConstructorExceptions.java +++ b/test/transform/resource/after-delombok/PostConstructorExceptions.java @@ -1,7 +1,7 @@ -class PostGeneratedConstructorExceptions { +class PostConstructorExceptions { private String a; - PostGeneratedConstructorExceptions() { + PostConstructorExceptions() { } private void post() throws IllegalArgumentException { @@ -11,7 +11,7 @@ private void post2() throws InterruptedException, java.lang.IllegalArgumentExcep } @java.lang.SuppressWarnings("all") - public PostGeneratedConstructorExceptions(final String a) throws IllegalArgumentException, InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { + public PostConstructorExceptions(final String a) throws IllegalArgumentException, InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { this.a = a; post(); post2(); diff --git a/test/transform/resource/after-delombok/PostGeneratedConstructorInvalid.java b/test/transform/resource/after-delombok/PostConstructorInvalid.java similarity index 76% rename from test/transform/resource/after-delombok/PostGeneratedConstructorInvalid.java rename to test/transform/resource/after-delombok/PostConstructorInvalid.java index 3d46ee9588..e87e512510 100644 --- a/test/transform/resource/after-delombok/PostGeneratedConstructorInvalid.java +++ b/test/transform/resource/after-delombok/PostConstructorInvalid.java @@ -1,4 +1,4 @@ -abstract class PostGeneratedConstructorInvalid { +abstract class PostConstructorInvalid { private void noConstructor() { } diff --git a/test/transform/resource/after-ecj/PostGeneratedConstructor.java b/test/transform/resource/after-ecj/PostConstructor.java similarity index 51% rename from test/transform/resource/after-ecj/PostGeneratedConstructor.java rename to test/transform/resource/after-ecj/PostConstructor.java index aa2a588121..5f0bce7517 100644 --- a/test/transform/resource/after-ecj/PostGeneratedConstructor.java +++ b/test/transform/resource/after-ecj/PostConstructor.java @@ -1,23 +1,23 @@ import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; -import lombok.experimental.PostGeneratedConstructor; -@RequiredArgsConstructor @AllArgsConstructor class PostGeneratedConstructorTest { +import lombok.experimental.PostConstructor; +@RequiredArgsConstructor @AllArgsConstructor class PostConstructorTest { private String name; private final Integer start; private final Integer end; - private @PostGeneratedConstructor void validate() { + private @PostConstructor void validate() { if ((((start == null) || (end == null)) || (end < start))) { throw new IllegalArgumentException(); } } - public @java.lang.SuppressWarnings("all") PostGeneratedConstructorTest(final Integer start, final Integer end) { + public @java.lang.SuppressWarnings("all") PostConstructorTest(final Integer start, final Integer end) { super(); this.start = start; this.end = end; validate(); } - public @java.lang.SuppressWarnings("all") PostGeneratedConstructorTest(final String name, final Integer start, final Integer end) { + public @java.lang.SuppressWarnings("all") PostConstructorTest(final String name, final Integer start, final Integer end) { super(); this.name = name; this.start = start; diff --git a/test/transform/resource/after-ecj/PostConstructorExceptions.java b/test/transform/resource/after-ecj/PostConstructorExceptions.java new file mode 100644 index 0000000000..86b6588fb2 --- /dev/null +++ b/test/transform/resource/after-ecj/PostConstructorExceptions.java @@ -0,0 +1,18 @@ +import lombok.AllArgsConstructor; +import lombok.experimental.PostConstructor; +@AllArgsConstructor class PostConstructorExceptions { + private String a; + PostConstructorExceptions() { + super(); + } + private @PostConstructor void post() throws IllegalArgumentException { + } + private @lombok.experimental.PostConstructor void post2() throws InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { + } + public @java.lang.SuppressWarnings("all") PostConstructorExceptions(final String a) throws IllegalArgumentException, InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { + super(); + this.a = a; + post(); + post2(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/PostConstructorInvalid.java b/test/transform/resource/after-ecj/PostConstructorInvalid.java new file mode 100644 index 0000000000..7aac9b0a2e --- /dev/null +++ b/test/transform/resource/after-ecj/PostConstructorInvalid.java @@ -0,0 +1,13 @@ +import lombok.experimental.PostConstructor; +abstract class PostConstructorInvalid { + PostConstructorInvalid() { + super(); + } + private @PostConstructor void noConstructor() { + } + private static @PostConstructor void staticMethod() { + } + public abstract @PostConstructor void abstractMethod(); + private @PostConstructor void withArgument(String arg) { + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java b/test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java deleted file mode 100644 index b98587d95e..0000000000 --- a/test/transform/resource/after-ecj/PostGeneratedConstructorExceptions.java +++ /dev/null @@ -1,18 +0,0 @@ -import lombok.AllArgsConstructor; -import lombok.experimental.PostGeneratedConstructor; -@AllArgsConstructor class PostGeneratedConstructorExceptions { - private String a; - PostGeneratedConstructorExceptions() { - super(); - } - private @PostGeneratedConstructor void post() throws IllegalArgumentException { - } - private @lombok.experimental.PostGeneratedConstructor void post2() throws InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { - } - public @java.lang.SuppressWarnings("all") PostGeneratedConstructorExceptions(final String a) throws IllegalArgumentException, InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { - super(); - this.a = a; - post(); - post2(); - } -} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/PostGeneratedConstructorInvalid.java b/test/transform/resource/after-ecj/PostGeneratedConstructorInvalid.java deleted file mode 100644 index c7cacfff90..0000000000 --- a/test/transform/resource/after-ecj/PostGeneratedConstructorInvalid.java +++ /dev/null @@ -1,13 +0,0 @@ -import lombok.experimental.PostGeneratedConstructor; -abstract class PostGeneratedConstructorInvalid { - PostGeneratedConstructorInvalid() { - super(); - } - private @PostGeneratedConstructor void noConstructor() { - } - private static @PostGeneratedConstructor void staticMethod() { - } - public abstract @PostGeneratedConstructor void abstractMethod(); - private @PostGeneratedConstructor void withArgument(String arg) { - } -} \ No newline at end of file diff --git a/test/transform/resource/before/PostGeneratedConstructor.java b/test/transform/resource/before/PostConstructor.java similarity index 73% rename from test/transform/resource/before/PostGeneratedConstructor.java rename to test/transform/resource/before/PostConstructor.java index 104d9e8383..861aac536c 100644 --- a/test/transform/resource/before/PostGeneratedConstructor.java +++ b/test/transform/resource/before/PostConstructor.java @@ -1,15 +1,15 @@ import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; -import lombok.experimental.PostGeneratedConstructor; +import lombok.experimental.PostConstructor; @RequiredArgsConstructor @AllArgsConstructor -class PostGeneratedConstructorTest { +class PostConstructorTest { private String name; private final Integer start; private final Integer end; - @PostGeneratedConstructor + @PostConstructor private void validate() { if (start == null || end == null || end < start) { throw new IllegalArgumentException(); diff --git a/test/transform/resource/before/PostGeneratedConstructorExceptions.java b/test/transform/resource/before/PostConstructorExceptions.java similarity index 55% rename from test/transform/resource/before/PostGeneratedConstructorExceptions.java rename to test/transform/resource/before/PostConstructorExceptions.java index 2663abeb8d..77dce64ca9 100644 --- a/test/transform/resource/before/PostGeneratedConstructorExceptions.java +++ b/test/transform/resource/before/PostConstructorExceptions.java @@ -1,21 +1,21 @@ import lombok.AllArgsConstructor; -import lombok.experimental.PostGeneratedConstructor; +import lombok.experimental.PostConstructor; @AllArgsConstructor -class PostGeneratedConstructorExceptions { +class PostConstructorExceptions { private String a; - PostGeneratedConstructorExceptions() { + PostConstructorExceptions() { } - @PostGeneratedConstructor + @PostConstructor private void post() throws IllegalArgumentException { } - @lombok.experimental.PostGeneratedConstructor + @lombok.experimental.PostConstructor private void post2() throws InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { } diff --git a/test/transform/resource/before/PostConstructorInvalid.java b/test/transform/resource/before/PostConstructorInvalid.java new file mode 100644 index 0000000000..8635f88e56 --- /dev/null +++ b/test/transform/resource/before/PostConstructorInvalid.java @@ -0,0 +1,21 @@ +import lombok.experimental.PostConstructor; + +abstract class PostConstructorInvalid { + @PostConstructor + private void noConstructor() { + + } + + @PostConstructor + private static void staticMethod() { + + } + + @PostConstructor + public abstract void abstractMethod(); + + @PostConstructor + private void withArgument(String arg) { + + } +} \ No newline at end of file diff --git a/test/transform/resource/before/PostGeneratedConstructorInvalid.java b/test/transform/resource/before/PostGeneratedConstructorInvalid.java deleted file mode 100644 index 37bb26bb56..0000000000 --- a/test/transform/resource/before/PostGeneratedConstructorInvalid.java +++ /dev/null @@ -1,21 +0,0 @@ -import lombok.experimental.PostGeneratedConstructor; - -abstract class PostGeneratedConstructorInvalid { - @PostGeneratedConstructor - private void noConstructor() { - - } - - @PostGeneratedConstructor - private static void staticMethod() { - - } - - @PostGeneratedConstructor - public abstract void abstractMethod(); - - @PostGeneratedConstructor - private void withArgument(String arg) { - - } -} \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/PostConstructorInvalid.java.messages b/test/transform/resource/messages-delombok/PostConstructorInvalid.java.messages new file mode 100644 index 0000000000..acef115424 --- /dev/null +++ b/test/transform/resource/messages-delombok/PostConstructorInvalid.java.messages @@ -0,0 +1,4 @@ +4 Cannot find a generated constructor. +9 @PostConstructor is legal only on instance methods. +14 @PostConstructor is legal only on concrete methods. +17 @PostConstructor is legal only on methods without parameters. \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/PostGeneratedConstructorInvalid.java.messages b/test/transform/resource/messages-delombok/PostGeneratedConstructorInvalid.java.messages deleted file mode 100644 index 24b1d695f2..0000000000 --- a/test/transform/resource/messages-delombok/PostGeneratedConstructorInvalid.java.messages +++ /dev/null @@ -1,4 +0,0 @@ -4 Cannot find a generated constructor. -9 @PostGeneratedConstructor is legal only on instance methods. -14 @PostGeneratedConstructor is legal only on concrete methods. -17 @PostGeneratedConstructor is legal only on methods without parameters. \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/PostConstructorInvalid.java.messages b/test/transform/resource/messages-ecj/PostConstructorInvalid.java.messages new file mode 100644 index 0000000000..acef115424 --- /dev/null +++ b/test/transform/resource/messages-ecj/PostConstructorInvalid.java.messages @@ -0,0 +1,4 @@ +4 Cannot find a generated constructor. +9 @PostConstructor is legal only on instance methods. +14 @PostConstructor is legal only on concrete methods. +17 @PostConstructor is legal only on methods without parameters. \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/PostGeneratedConstructorInvalid.java.messages b/test/transform/resource/messages-ecj/PostGeneratedConstructorInvalid.java.messages deleted file mode 100644 index 24b1d695f2..0000000000 --- a/test/transform/resource/messages-ecj/PostGeneratedConstructorInvalid.java.messages +++ /dev/null @@ -1,4 +0,0 @@ -4 Cannot find a generated constructor. -9 @PostGeneratedConstructor is legal only on instance methods. -14 @PostGeneratedConstructor is legal only on concrete methods. -17 @PostGeneratedConstructor is legal only on methods without parameters. \ No newline at end of file diff --git a/website/templates/features/experimental/PostConstructor.html b/website/templates/features/experimental/PostConstructor.html new file mode 100644 index 0000000000..5f5e6eb880 --- /dev/null +++ b/website/templates/features/experimental/PostConstructor.html @@ -0,0 +1,35 @@ +<#import "../_features.html" as f> + +<@f.scaffold title="@PostConstructor" logline="Call methods after construction"> + <@f.history> +

+ @PostConstructor was introduced as experimental feature in lombok v1.18.24. +

+ + + <@f.experimental> +
    +
  • + New feature +
  • +
+ + + <@f.overview> +

+ The method annotated with @PostConstructor gets called as last method in any constructor generated by lombok e.g. @AllArgsConstructor. This method can be used for validation, precomputation, caching, ... +

+ It ignores explicit written constructors. +

+ + + <@f.snippets name="experimental/PostConstructor" /> + + <@f.confKeys> +
+ lombok.PostConstructor.flagUsage = [warning | error] (default: not set) +
+ Lombok will flag any usage of @PostConstructor as a warning or error if configured. +
+ + diff --git a/website/templates/features/experimental/PostGeneratedConstructor.html b/website/templates/features/experimental/PostGeneratedConstructor.html deleted file mode 100644 index 2d5c5a2e16..0000000000 --- a/website/templates/features/experimental/PostGeneratedConstructor.html +++ /dev/null @@ -1,37 +0,0 @@ -<#import "../_features.html" as f> - -<@f.scaffold title="@PostGeneratedConstructor" logline="Call methods after construction"> - <@f.history> -

- @PostGeneratedConstructor was introduced as experimental feature in lombok v1.18.13. -

- - - <@f.experimental> -
    -
  • - New feature -
  • - Might be replaced by a more powerful implementation that can also handle explicit written constructors. -
  • -
- - - <@f.overview> -

- The method annotated with @PostGeneratedConstructor gets called as last method in any constructor generated by lombok e.g. @AllArgsConstructor. This method can be used for validation, precomputation, caching, ... -

- It ignores explicit written constructors. -

- - - <@f.snippets name="experimental/PostGeneratedConstructor" /> - - <@f.confKeys> -
- lombok.postGeneratedConstructor.flagUsage = [warning | error] (default: not set) -
- Lombok will flag any usage of @PostGeneratedConstructor as a warning or error if configured. -
- - diff --git a/website/templates/features/experimental/index.html b/website/templates/features/experimental/index.html index 7d384eee31..5ab3381965 100644 --- a/website/templates/features/experimental/index.html +++ b/website/templates/features/experimental/index.html @@ -76,7 +76,7 @@ Standard.. Exceptional? This is not just an oxymoron, it's convenient! - <@main.feature title="@PostGeneratedConstructor" href="PostGeneratedConstructor"> + <@main.feature title="@PostConstructor" href="PostConstructor"> Call methods after construction. diff --git a/website/usageExamples/experimental/PostGeneratedConstructorExample_post.jpage b/website/usageExamples/experimental/PostConstructorExample_post.jpage similarity index 61% rename from website/usageExamples/experimental/PostGeneratedConstructorExample_post.jpage rename to website/usageExamples/experimental/PostConstructorExample_post.jpage index 403b496ca1..0748b4802c 100644 --- a/website/usageExamples/experimental/PostGeneratedConstructorExample_post.jpage +++ b/website/usageExamples/experimental/PostConstructorExample_post.jpage @@ -1,16 +1,16 @@ -class PostGeneratedConstructorExample { +class PostConstructorExample { private String name; private final Integer start; private final Integer end; - public PostGeneratedConstructorTest(final String name, final Integer start, final Integer end) { + public PostConstructorTest(final String name, final Integer start, final Integer end) { this.name = name; this.start = start; this.end = end; validate(); } - public PostGeneratedConstructorTest(final Integer start, final Integer end) { + public PostConstructorTest(final Integer start, final Integer end) { this.start = start; this.end = end; validate(); diff --git a/website/usageExamples/experimental/PostGeneratedConstructorExample_pre.jpage b/website/usageExamples/experimental/PostConstructorExample_pre.jpage similarity index 73% rename from website/usageExamples/experimental/PostGeneratedConstructorExample_pre.jpage rename to website/usageExamples/experimental/PostConstructorExample_pre.jpage index e959545fbe..a1eae05d26 100644 --- a/website/usageExamples/experimental/PostGeneratedConstructorExample_pre.jpage +++ b/website/usageExamples/experimental/PostConstructorExample_pre.jpage @@ -1,15 +1,15 @@ import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; -import lombok.experimental.PostGeneratedConstructor; +import lombok.experimental.PostConstructor; @AllArgsConstructor @RequiredArgsConstructor -class PostGeneratedConstructorExample { +class PostConstructorExample { private String name; private final Integer start; private final Integer end; - @PostGeneratedConstructor + @PostConstructor private void validate() { if (start == null || end == null || end < start) { throw new IllegalArgumentException(); From b0419e167c7782ab95b31ca6cfc8041a9a527419 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Wed, 9 Feb 2022 23:26:23 +0100 Subject: [PATCH 7/7] Add (Skip|Invoke)PostConstructor --- .../handlers/HandlePostConstructor.java | 184 +++++++++++++++--- .../lombok/experimental/PostConstructor.java | 29 ++- .../javac/handlers/HandlePostConstructor.java | 147 +++++++++++--- .../handlers/HandlePostConstructorInvoke.java | 50 +++++ .../handlers/HandlePostConstructorSkip.java | 50 +++++ .../javac/handlers/JavacHandlerUtil.java | 23 ++- .../after-delombok/PostConstructor.java | 12 +- .../PostConstructorBuilder.java | 48 +++++ .../PostConstructorExceptions.java | 4 +- .../PostConstructorExplicit.java | 34 ++++ .../PostConstructorExplicit2.java | 46 +++++ .../PostConstructorGenerated.java | 42 ++++ .../PostConstructorInvalid.java | 7 +- .../after-delombok/PostConstructorOrder.java | 21 ++ .../resource/after-ecj/PostConstructor.java | 17 +- .../after-ecj/PostConstructorBuilder.java | 34 ++++ .../after-ecj/PostConstructorExceptions.java | 6 +- .../after-ecj/PostConstructorExplicit.java | 32 +++ .../after-ecj/PostConstructorExplicit2.java | 57 ++++++ .../after-ecj/PostConstructorGenerated.java | 38 ++++ .../after-ecj/PostConstructorInvalid.java | 10 +- .../after-ecj/PostConstructorOrder.java | 18 ++ .../resource/before/PostConstructor.java | 7 +- .../before/PostConstructorBuilder.java | 11 ++ .../before/PostConstructorExceptions.java | 2 +- .../before/PostConstructorExplicit.java | 41 ++++ .../before/PostConstructorExplicit2.java | 37 ++++ .../before/PostConstructorGenerated.java | 32 +++ .../before/PostConstructorInvalid.java | 7 - .../resource/before/PostConstructorOrder.java | 19 ++ .../PostConstructorExplicit.java.messages | 3 + .../PostConstructorInvalid.java.messages | 7 +- .../PostConstructorExplicit.java.messages | 3 + .../PostConstructorInvalid.java.messages | 7 +- .../PostConstructorExample_post.jpage | 8 - .../PostConstructorExample_pre.jpage | 3 - 36 files changed, 973 insertions(+), 123 deletions(-) create mode 100644 src/core/lombok/javac/handlers/HandlePostConstructorInvoke.java create mode 100644 src/core/lombok/javac/handlers/HandlePostConstructorSkip.java create mode 100644 test/transform/resource/after-delombok/PostConstructorBuilder.java create mode 100644 test/transform/resource/after-delombok/PostConstructorExplicit.java create mode 100644 test/transform/resource/after-delombok/PostConstructorExplicit2.java create mode 100644 test/transform/resource/after-delombok/PostConstructorGenerated.java create mode 100644 test/transform/resource/after-delombok/PostConstructorOrder.java create mode 100644 test/transform/resource/after-ecj/PostConstructorBuilder.java create mode 100644 test/transform/resource/after-ecj/PostConstructorExplicit.java create mode 100644 test/transform/resource/after-ecj/PostConstructorExplicit2.java create mode 100644 test/transform/resource/after-ecj/PostConstructorGenerated.java create mode 100644 test/transform/resource/after-ecj/PostConstructorOrder.java create mode 100644 test/transform/resource/before/PostConstructorBuilder.java create mode 100644 test/transform/resource/before/PostConstructorExplicit.java create mode 100644 test/transform/resource/before/PostConstructorExplicit2.java create mode 100644 test/transform/resource/before/PostConstructorGenerated.java create mode 100644 test/transform/resource/before/PostConstructorOrder.java create mode 100644 test/transform/resource/messages-delombok/PostConstructorExplicit.java.messages create mode 100644 test/transform/resource/messages-ecj/PostConstructorExplicit.java.messages diff --git a/src/core/lombok/eclipse/handlers/HandlePostConstructor.java b/src/core/lombok/eclipse/handlers/HandlePostConstructor.java index 2e9a81083c..03b0b400bb 100644 --- a/src/core/lombok/eclipse/handlers/HandlePostConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandlePostConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Project Lombok Authors. + * Copyright (C) 2022 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 @@ -22,22 +22,42 @@ package lombok.eclipse.handlers; import static lombok.core.handlers.HandlerUtil.handleFlagUsage; -import static lombok.eclipse.Eclipse.pos; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; +import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; -import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.Argument; +import org.eclipse.jdt.internal.compiler.ast.Assignment; +import org.eclipse.jdt.internal.compiler.ast.Block; import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; +import org.eclipse.jdt.internal.compiler.ast.FalseLiteral; +import org.eclipse.jdt.internal.compiler.ast.IfStatement; +import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; +import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.ThisReference; +import org.eclipse.jdt.internal.compiler.ast.ThrowStatement; +import org.eclipse.jdt.internal.compiler.ast.TrueLiteral; +import org.eclipse.jdt.internal.compiler.ast.TryStatement; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; @@ -45,7 +65,10 @@ import lombok.eclipse.DeferUntilPostDiet; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.HandleConstructor.SkipIfConstructorExists; import lombok.experimental.PostConstructor; +import lombok.experimental.PostConstructor.InvokePostConstructors; +import lombok.experimental.PostConstructor.SkipPostConstructors; import lombok.spi.Provides; /** @@ -55,6 +78,12 @@ @Provides @HandlerPriority(value = 1024) public class HandlePostConstructor extends EclipseAnnotationHandler { + private HandleConstructor handleConstructor = new HandleConstructor(); + + @Override public void preHandle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + EclipseNode typeNode = upToTypeNode(annotationNode); + handleConstructor.generateConstructor(typeNode, AccessLevel.PUBLIC, Collections.emptyList(), false, null, SkipIfConstructorExists.YES, Collections.emptyList(), annotationNode); + } @Override public void handle(AnnotationValues annotation, Annotation source, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.POST_CONSTRUCTOR_FLAG_USAGE, "@PostConstructor"); @@ -83,42 +112,141 @@ public class HandlePostConstructor extends EclipseAnnotationHandler generatedConstructors = findGeneratedConstructors(typeNode); - if (generatedConstructors.isEmpty()) { - annotationNode.addError("Cannot find a generated constructor."); - return; - } + handleConstructor.generateConstructor(typeNode, AccessLevel.PUBLIC, Collections.emptyList(), false, null, SkipIfConstructorExists.YES, Collections.emptyList(), annotationNode); - for (AbstractMethodDeclaration methodDecl : generatedConstructors) { + List constructors = findConstructors(typeNode); + for (EclipseNode constructorNode : constructors) { + ConstructorDeclaration constructor = (ConstructorDeclaration) constructorNode.get(); + + boolean hasSkip = hasAnnotation(SkipPostConstructors.class, constructorNode); + boolean hasInvoke = hasAnnotation(InvokePostConstructors.class, constructorNode); + boolean hasThisCall = constructor.constructorCall != null && constructor.constructorCall.accessMode == ExplicitConstructorCall.This; + + if (hasSkip) { + if (hasInvoke) { + constructorNode.addError("@InvokePostConstructors and @SkipPostConstructors are mutually exclusive."); + } + if (hasThisCall) { + constructorNode.addWarning("@SkipPostConstructors is not needed; constructors calling this(...) are skipped anyway."); + } + continue; + } + + if (hasThisCall && !hasInvoke) { + continue; + } + + if (!isGenerated(constructor) && !hasInvoke) { + constructorNode.addError("Constructor needs to be annotated with @PostConstruct.(Invoke|Skip)PostConstructors or needs to start with a this(...) call."); + continue; + }; + MessageSend call = new MessageSend(); call.selector = method.selector; call.receiver = ThisReference.implicitThis(); + call.traverse(new SetGeneratedByVisitor(source), (BlockScope) null); - call.nameSourcePosition = p; - call.sourceStart = pS; - call.sourceEnd = call.statementEnd = pE; - setGeneratedBy(call, source); + Block block = getOrCreatePostConstructorBlock(constructor, source); + if (block != null) { + block.statements = concat(block.statements, new Statement[] {call}, Statement.class); + } else { + constructor.statements = concat(constructor.statements, new Statement[] {call}, Statement.class); + } - methodDecl.statements = concat(methodDecl.statements, new Statement[] {call}, Statement.class); - methodDecl.thrownExceptions = concat(methodDecl.thrownExceptions, method.thrownExceptions, TypeReference.class); + constructor.thrownExceptions = concat(constructor.thrownExceptions, method.thrownExceptions, TypeReference.class); - typeNode.getAst().get(methodDecl).rebuild(); + constructorNode.rebuild(); } } - private List findGeneratedConstructors(EclipseNode typeNode) { - List constructors = new ArrayList(); - if (typeNode != null && typeNode.get() instanceof TypeDeclaration) { - TypeDeclaration typeDecl = (TypeDeclaration) typeNode.get(); - for (AbstractMethodDeclaration methodDecl : typeDecl.methods) { - if (methodDecl instanceof ConstructorDeclaration && isGenerated(methodDecl)) { - constructors.add(methodDecl); - } - } + private List findConstructors(EclipseNode typeNode) { + List constructors = new ArrayList(); + + for (EclipseNode eclipseNode : typeNode.down()) { + if (eclipseNode.getKind() != Kind.METHOD) continue; + if (!(eclipseNode.get() instanceof ConstructorDeclaration)) continue; + constructors.add(eclipseNode); } + return constructors; } + + private Block getOrCreatePostConstructorBlock(ConstructorDeclaration constructor, ASTNode source) { + // Generated constructors and methods without return cannot exit early + if (isGenerated(constructor) || !containsReturn(constructor)) { + return null; + } + + // Search existing try ... catch ... finally and return + Statement[] statements = constructor.statements; + if (statements.length > 0 && statements[0] instanceof LocalDeclaration && isGenerated(statements[0])) { + LocalDeclaration localDeclaration = (LocalDeclaration) statements[0]; + if (Arrays.equals("$callPostConstructor".toCharArray(), localDeclaration.name)) { + return (Block) ((IfStatement)((TryStatement) statements[1]).finallyBlock.statements[0]).thenStatement; + } + } + + // Not found, create it ... + // boolean $callPostConstructor = true + LocalDeclaration callPostConstructorVar = new LocalDeclaration("$callPostConstructor".toCharArray(), 0, 0); + callPostConstructorVar.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0); + callPostConstructorVar.initialization = new TrueLiteral(0, 0); + callPostConstructorVar.traverse(new SetGeneratedByVisitor(source), null); + + // Throwable $ex + Argument catchArg = new Argument("$ex".toCharArray(), 0, createTypeReference("java.lang.Throwable", source), Modifier.FINAL); + + // { $callPostConstructor = false; throw $ex; } + Block catchBlock = new Block(0); + Assignment assignFalseStatement = new Assignment(new SingleNameReference("$callPostConstructor".toCharArray(), 0), new FalseLiteral(0, 0), 0); + ThrowStatement throwStatement = new ThrowStatement(new SingleNameReference("$ex".toCharArray(), 0), 0, 0); + catchBlock.statements = new Statement[] { assignFalseStatement, throwStatement }; + + // if ($callPostConstructor) { ... } + Block finallyBlock = new Block(0); + Block postConstructorBlock = new Block(0); + IfStatement callPostConstructorIf = new IfStatement(new SingleNameReference("$callPostConstructor".toCharArray(), 0), postConstructorBlock, 0, 0); + finallyBlock.statements = new Statement[] {callPostConstructorIf}; + + // try { ... } catch { ... } finally { ... } + TryStatement tryStatement = new TryStatement(); + tryStatement.tryBlock = new Block(0); + tryStatement.catchArguments = new Argument[] { catchArg }; + tryStatement.catchBlocks = new Block[] { catchBlock }; + tryStatement.finallyBlock = finallyBlock; + tryStatement.traverse(new SetGeneratedByVisitor(source), null); + tryStatement.tryBlock.statements = constructor.statements; + + constructor.statements = new Statement[] { callPostConstructorVar, tryStatement }; + + return postConstructorBlock; + } + private boolean containsReturn(ConstructorDeclaration method) { + ReturnVisitor returnVisitor = new ReturnVisitor(); + method.traverse(returnVisitor, (ClassScope) null); + return returnVisitor.found; + } + + private static class ReturnVisitor extends ASTVisitor { + private boolean found = false; + + @Override + public boolean visit(TypeDeclaration type, BlockScope scope) { + return false; + } + @Override + public boolean visit(TypeDeclaration type, ClassScope scope) { + return false; + } + + @Override + public boolean visit(LambdaExpression lambdaExpression, BlockScope scope) { + return false; + } + + @Override public boolean visit(ReturnStatement returnStatement, BlockScope scope) { + found = true; + return false; + } + } } diff --git a/src/core/lombok/experimental/PostConstructor.java b/src/core/lombok/experimental/PostConstructor.java index a4293b2858..b9633334ea 100644 --- a/src/core/lombok/experimental/PostConstructor.java +++ b/src/core/lombok/experimental/PostConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Project Lombok Authors. + * Copyright (C) 2022 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 @@ -27,9 +27,36 @@ import java.lang.annotation.Target; /** + * Put on any method to make lombok add a call to the annotated method in all constructors. + *

+ * Every explicit constructor requires either a {@code this(...)} statement, + * {@link InvokePostConstructors @InvokePostConstructors} or {@link SkipPostConstructors @SkipPostConstructors}. + *

+ * Complete documentation is found at the project lombok features page for @PostConstructor. */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) public @interface PostConstructor { + /** + * If present lombok modifies this constructor to call all methods annotated with + * {@link PostConstructor @PostConstructor}. + *

+ * If this constructor contains a {@code return} statement lombok wraps all statements with a {@code try {...} catch + * {...} finally {...}} block otherwise the calls are appended at the end + */ + @Target({ElementType.CONSTRUCTOR}) + @Retention(RetentionPolicy.SOURCE) + public @interface InvokePostConstructors { + + } + /** + * If present lombok will not modify this constructor and will not call methods annotated with + * {@link PostConstructor @PostConstructor}. + */ + @Target({ElementType.CONSTRUCTOR}) + @Retention(RetentionPolicy.SOURCE) + public @interface SkipPostConstructors { + + } } diff --git a/src/core/lombok/javac/handlers/HandlePostConstructor.java b/src/core/lombok/javac/handlers/HandlePostConstructor.java index f89906946e..977893c927 100644 --- a/src/core/lombok/javac/handlers/HandlePostConstructor.java +++ b/src/core/lombok/javac/handlers/HandlePostConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Project Lombok Authors. + * Copyright (C) 2022 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 @@ -22,26 +22,39 @@ package lombok.javac.handlers; import static lombok.core.handlers.HandlerUtil.handleFlagUsage; +import static lombok.javac.Javac.CTC_BOOLEAN; import static lombok.javac.handlers.JavacHandlerUtil.*; import com.sun.tools.javac.code.Flags; 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.JCExpression; +import com.sun.tools.javac.tree.JCTree.JCIf; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCReturn; import com.sun.tools.javac.tree.JCTree.JCStatement; +import com.sun.tools.javac.tree.JCTree.JCThrow; +import com.sun.tools.javac.tree.JCTree.JCTry; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; +import lombok.AccessLevel; import lombok.ConfigurationKeys; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.experimental.PostConstructor; +import lombok.experimental.PostConstructor.InvokePostConstructors; +import lombok.experimental.PostConstructor.SkipPostConstructors; +import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; +import lombok.javac.handlers.HandleConstructor.SkipIfConstructorExists; import lombok.spi.Provides; /** @@ -50,6 +63,8 @@ @Provides @HandlerPriority(value = 1024) public class HandlePostConstructor extends JavacAnnotationHandler { + + private HandleConstructor handleConstructor = new HandleConstructor(); @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.POST_CONSTRUCTOR_FLAG_USAGE, "@PostConstructor"); @@ -84,44 +99,124 @@ public class HandlePostConstructor extends JavacAnnotationHandler generatedConstructors = findGeneratedConstructors(typeNode); - if (generatedConstructors.isEmpty()) { - annotationNode.addError("Cannot find a generated constructor."); - return; - } + handleConstructor.generateConstructor(typeNode, AccessLevel.PUBLIC, List.nil(), List.nil(), false, null, SkipIfConstructorExists.YES, annotationNode); - for (JCMethodDecl constructor : generatedConstructors) { + List constructors = findConstructors(typeNode); + for (JavacNode constructorNode : constructors) { + JCMethodDecl constructor = (JCMethodDecl) constructorNode.get(); + + boolean hasSkip = hasAnnotation(SkipPostConstructors.class, constructorNode); + boolean hasInvoke = hasAnnotation(InvokePostConstructors.class, constructorNode); + boolean hasThisCall = isThisCall(((JCMethodDecl) constructorNode.get()).body.stats.head); + + if (hasSkip) { + if (hasInvoke) { + constructorNode.addError("@InvokePostConstructors and @SkipPostConstructors are mutually exclusive."); + } + if (hasThisCall) { + constructorNode.addWarning("@SkipPostConstructors is not needed; constructors calling this(...) are skipped anyway."); + } + continue; + } + + if (hasThisCall && !hasInvoke) { + continue; + } + + if (!isGenerated(constructor) && !hasInvoke) { + constructorNode.addError("Constructor needs to be annotated with @PostConstruct.(Invoke|Skip)PostConstructors or needs to start with a this(...) call."); + continue; + }; + JCStatement statement = maker.Exec(maker.Apply(List.nil(), maker.Ident(method.name), List.nil())); recursiveSetGeneratedBy(statement, annotationNode); - constructor.body.stats = appendToList(constructor.body.stats, statement); - constructor.thrown = appendToList(constructor.thrown, method.thrown); + JCBlock block = getOrCreatePostConstructorBlock(constructor, annotationNode); + block.stats = block.stats.append(statement); + + for (JCExpression t : method.thrown) { + constructor.thrown = constructor.thrown.append(cloneType(maker, t, annotationNode)); + } - typeNode.getAst().get(constructor).rebuild(); + constructorNode.rebuild(); } } - private List findGeneratedConstructors(JavacNode typeNode) { - ListBuffer constructors = new ListBuffer(); - if (typeNode != null && typeNode.get() instanceof JCClassDecl) { - JCClassDecl type = (JCClassDecl) typeNode.get(); - for (JCTree def : type.defs) { - if (def instanceof JCMethodDecl) { - JCMethodDecl methodDecl = (JCMethodDecl) def; - if (methodDecl.name.toString().equals("") && getGeneratedBy(methodDecl) != null) { - constructors.add(methodDecl); - } - } - } + private List findConstructors(JavacNode typeNode) { + ListBuffer constructors = new ListBuffer(); + for (JavacNode methodNode : typeNode.down()) { + if (methodNode.getKind() != Kind.METHOD) continue; + if (!methodNode.getName().equals("")) continue; + + constructors.add(methodNode); } return constructors.toList(); } - private List appendToList(List list, T append) { - return appendToList(list, List.of(append)); + private JCBlock getOrCreatePostConstructorBlock(JCMethodDecl method, JavacNode source) { + // Generated constructors and methods without return cannot exit early + if (isGenerated(method) || !containsReturn(method)) { + return method.body; + } + + List statements = method.body.stats; + JCStatement head = statements.head; + + // Search existing try ... catch ... finally and return + if (head instanceof JCVariableDecl) { + JCVariableDecl jcVariableDecl = (JCVariableDecl) head; + if (jcVariableDecl.name.toString().equals("$callPostConstructor") && isGenerated(jcVariableDecl)) { + return (JCBlock) ((JCIf)((JCTry) statements.tail.head).finalizer.stats.head).thenpart; + } + } + + // Not found, create it ... + JavacTreeMaker maker = source.getTreeMaker(); + // boolean $callPostConstructor = true + JCVariableDecl callPostConstructorVar = maker.VarDef(maker.Modifiers(0), source.toName("$callPostConstructor"), maker.TypeIdent(CTC_BOOLEAN), maker.Literal(Javac.CTC_BOOLEAN, 1)); + recursiveSetGeneratedBy(callPostConstructorVar, source); + + // Throwable $ex + JCVariableDecl catchParam = maker.VarDef(maker.Modifiers(Flags.FINAL | Flags.PARAMETER), source.toName("$ex"), genJavaLangTypeRef(source, "Throwable"), null); + // { $callPostConstructor = false; throw $ex; } + JCStatement assignStatement = maker.Exec(maker.Assign(maker.Ident(source.toName("$callPostConstructor")), maker.Literal(Javac.CTC_BOOLEAN, 0))); + JCThrow throwStatement = maker.Throw(maker.Ident(source.toName("$ex"))); + JCBlock catchBody = maker.Block(0, List.of(assignStatement, throwStatement)); + // if ($callPostConstructor) { ... } + JCBlock postConstructorBlock = maker.Block(0, List.nil()); + JCIf callPostConstructorIf = maker.If(maker.Ident(source.toName("$callPostConstructor")), postConstructorBlock, null); + JCBlock finallyBody = maker.Block(0, List.of(callPostConstructorIf)); + // try { ... } catch { ... } finally { ... } + JCTry tryStatement = maker.Try(maker.Block(0, List.nil()), List.of(maker.Catch(catchParam, catchBody)), finallyBody); + recursiveSetGeneratedBy(tryStatement, source); + tryStatement.body.stats = statements; + + method.body.stats = List.of(callPostConstructorVar, tryStatement); + + return postConstructorBlock; + } + + private boolean containsReturn(JCMethodDecl method) { + ReturnTreeScanner returnTreeScanner = new ReturnTreeScanner(); + method.accept(returnTreeScanner); + return returnTreeScanner.found; } - private List appendToList(List list, List append) { - return List.nil().appendList(list).appendList(append); + private static final class ReturnTreeScanner extends TreeScanner { + private boolean found = false; + + @Override public void scan(JCTree tree) { + if (tree == null || found) return; + if (tree.getClass().getName().equals("com.sun.tools.javac.tree.JCTree$JCLambda")) return; + super.scan(tree); + } + + @Override public void visitClassDef(JCClassDecl arg0) { + return; + } + + @Override public void visitReturn(JCReturn tree) { + found = true; + } } } diff --git a/src/core/lombok/javac/handlers/HandlePostConstructorInvoke.java b/src/core/lombok/javac/handlers/HandlePostConstructorInvoke.java new file mode 100644 index 0000000000..776e6c830d --- /dev/null +++ b/src/core/lombok/javac/handlers/HandlePostConstructorInvoke.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.javac.handlers; + +import static lombok.javac.handlers.JavacHandlerUtil.deleteAnnotationIfNeccessary; + +import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; + +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; +import lombok.experimental.PostConstructor.InvokePostConstructors; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; +import lombok.spi.Provides; + +@Provides +@HandlerPriority(value = 2048) +public class HandlePostConstructorInvoke extends JavacAnnotationHandler { + @Override + public void handle(AnnotationValues annotation, JCAnnotation ast, final JavacNode annotationNode) { + deleteAnnotationIfNeccessary(annotationNode, InvokePostConstructors.class); + JavacNode methodNode = annotationNode.up(); + + if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof JCMethodDecl) || !methodNode.getName().equals("")) { + annotationNode.addError("@InvokePostConstructors is legal only on constructors."); + return; + } + } +} \ No newline at end of file diff --git a/src/core/lombok/javac/handlers/HandlePostConstructorSkip.java b/src/core/lombok/javac/handlers/HandlePostConstructorSkip.java new file mode 100644 index 0000000000..a6e1bc3510 --- /dev/null +++ b/src/core/lombok/javac/handlers/HandlePostConstructorSkip.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.javac.handlers; + +import static lombok.javac.handlers.JavacHandlerUtil.deleteAnnotationIfNeccessary; + +import com.sun.tools.javac.tree.JCTree.JCAnnotation; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; + +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.core.HandlerPriority; +import lombok.experimental.PostConstructor.SkipPostConstructors; +import lombok.javac.JavacAnnotationHandler; +import lombok.javac.JavacNode; +import lombok.spi.Provides; + +@Provides +@HandlerPriority(value = 2048) +public class HandlePostConstructorSkip extends JavacAnnotationHandler { + @Override + public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { + deleteAnnotationIfNeccessary(annotationNode, SkipPostConstructors.class); + JavacNode methodNode = annotationNode.up(); + + if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof JCMethodDecl) || !methodNode.getName().equals("")) { + annotationNode.addError("@SkipPostConstructors is legal only on constructors."); + return; + } + } +} \ No newline at end of file diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 53a518b4e6..cf001a0cfb 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -532,7 +532,7 @@ private static void deleteAnnotationIfNeccessary0(JavacNode annotation, String.. parentNode.getAst().setChanged(); for (String annotationType : annotationTypes) { - deleteImportFromCompilationUnit(annotation, annotationType); + deleteImportFromCompilationUnit(annotation, annotationType.replace("$", ".")); } } @@ -902,20 +902,27 @@ public static MemberExistsResult constructorExists(JavacNode node) { } public static boolean isConstructorCall(final JCStatement statement) { - if (!(statement instanceof JCExpressionStatement)) return false; + String name = findMethodInvocationName(statement); + return "this".equals(name) || "super".equals(name); + } + + public static boolean isThisCall(final JCStatement statement) { + String name = findMethodInvocationName(statement); + return "this".equals(name); + } + + private static String findMethodInvocationName(final JCStatement statement) { + if (!(statement instanceof JCExpressionStatement)) return null; JCExpression expr = ((JCExpressionStatement) statement).expr; - if (!(expr instanceof JCMethodInvocation)) return false; + if (!(expr instanceof JCMethodInvocation)) return null; JCExpression invocation = ((JCMethodInvocation) expr).meth; - String name; + String name = null; if (invocation instanceof JCFieldAccess) { name = ((JCFieldAccess) invocation).name.toString(); } else if (invocation instanceof JCIdent) { name = ((JCIdent) invocation).name.toString(); - } else { - name = ""; } - - return "super".equals(name) || "this".equals(name); + return name; } /** diff --git a/test/transform/resource/after-delombok/PostConstructor.java b/test/transform/resource/after-delombok/PostConstructor.java index d81bd8b76e..a80ffc0068 100644 --- a/test/transform/resource/after-delombok/PostConstructor.java +++ b/test/transform/resource/after-delombok/PostConstructor.java @@ -2,6 +2,7 @@ class PostConstructorTest { private String name; private final Integer start; private final Integer end; + private Integer range; private void validate() { if (start == null || end == null || end < start) { @@ -9,18 +10,15 @@ private void validate() { } } - @java.lang.SuppressWarnings("all") - public PostConstructorTest(final Integer start, final Integer end) { - this.start = start; - this.end = end; - validate(); + private void calculateRange() { + range = end - start; } @java.lang.SuppressWarnings("all") - public PostConstructorTest(final String name, final Integer start, final Integer end) { - this.name = name; + public PostConstructorTest(final Integer start, final Integer end) { this.start = start; this.end = end; validate(); + calculateRange(); } } \ No newline at end of file diff --git a/test/transform/resource/after-delombok/PostConstructorBuilder.java b/test/transform/resource/after-delombok/PostConstructorBuilder.java new file mode 100644 index 0000000000..aa629fdd08 --- /dev/null +++ b/test/transform/resource/after-delombok/PostConstructorBuilder.java @@ -0,0 +1,48 @@ +class PostConstructorBuilder { + private String field; + + private void postConstructor() { + } + + @java.lang.SuppressWarnings("all") + PostConstructorBuilder(final String field) { + this.field = field; + postConstructor(); + } + + + @java.lang.SuppressWarnings("all") + public static class PostConstructorBuilderBuilder { + @java.lang.SuppressWarnings("all") + private String field; + + @java.lang.SuppressWarnings("all") + PostConstructorBuilderBuilder() { + } + + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public PostConstructorBuilder.PostConstructorBuilderBuilder field(final String field) { + this.field = field; + return this; + } + + @java.lang.SuppressWarnings("all") + public PostConstructorBuilder build() { + return new PostConstructorBuilder(this.field); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "PostConstructorBuilder.PostConstructorBuilderBuilder(field=" + this.field + ")"; + } + } + + @java.lang.SuppressWarnings("all") + public static PostConstructorBuilder.PostConstructorBuilderBuilder builder() { + return new PostConstructorBuilder.PostConstructorBuilderBuilder(); + } +} diff --git a/test/transform/resource/after-delombok/PostConstructorExceptions.java b/test/transform/resource/after-delombok/PostConstructorExceptions.java index adcf54a52f..0becf5e739 100644 --- a/test/transform/resource/after-delombok/PostConstructorExceptions.java +++ b/test/transform/resource/after-delombok/PostConstructorExceptions.java @@ -1,7 +1,9 @@ class PostConstructorExceptions { private String a; - PostConstructorExceptions() { + PostConstructorExceptions() throws IllegalArgumentException, InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { + post(); + post2(); } private void post() throws IllegalArgumentException { diff --git a/test/transform/resource/after-delombok/PostConstructorExplicit.java b/test/transform/resource/after-delombok/PostConstructorExplicit.java new file mode 100644 index 0000000000..cb99e6a91e --- /dev/null +++ b/test/transform/resource/after-delombok/PostConstructorExplicit.java @@ -0,0 +1,34 @@ +class PostConstructorExplicit { + private void postConstructor1() { + } + private void postConstructor2() { + } + + public PostConstructorExplicit(long a) { + this(); + } + + public PostConstructorExplicit(int a) { + } + + public PostConstructorExplicit(short a) { + postConstructor1(); + postConstructor2(); + } + + public PostConstructorExplicit(byte a) { + } + + public PostConstructorExplicit(boolean a) { + this(); + postConstructor1(); + postConstructor2(); + } + + public PostConstructorExplicit(double a) { + this(); + } + + public PostConstructorExplicit() { + } +} diff --git a/test/transform/resource/after-delombok/PostConstructorExplicit2.java b/test/transform/resource/after-delombok/PostConstructorExplicit2.java new file mode 100644 index 0000000000..54ca38822e --- /dev/null +++ b/test/transform/resource/after-delombok/PostConstructorExplicit2.java @@ -0,0 +1,46 @@ +// version 8: +class PostConstructorExplicit2 { + private void first() { + } + + private void second() { + } + + public PostConstructorExplicit2(long tryFinally) throws java.io.IOException { + boolean $callPostConstructor = true; + try { + if ("a".equals("b")) { + return; + } + if ("a".equals("b")) { + throw new java.io.IOException(""); + } + } catch (final java.lang.Throwable $ex) { + $callPostConstructor = false; + throw $ex; + } finally { + if ($callPostConstructor) { + first(); + second(); + } + } + } + + public PostConstructorExplicit2(int innerExit) { + Runnable r1 = new Runnable() { + public void run() { + return; + } + }; + first(); + second(); + } + + public PostConstructorExplicit2(short lambdaExit) { + Runnable r2 = () -> { + return; + }; + first(); + second(); + } +} diff --git a/test/transform/resource/after-delombok/PostConstructorGenerated.java b/test/transform/resource/after-delombok/PostConstructorGenerated.java new file mode 100644 index 0000000000..177a5f0576 --- /dev/null +++ b/test/transform/resource/after-delombok/PostConstructorGenerated.java @@ -0,0 +1,42 @@ +class PostConstructorGeneratedNoArgs { + private String a; + private String b; + + private void postConstructor() { + } + + @java.lang.SuppressWarnings("all") + public PostConstructorGeneratedNoArgs() { + postConstructor(); + } +} + +class PostConstructorGeneratedRequiredArgs { + private final String a; + private final String b; + + private void postConstructor() { + } + + @java.lang.SuppressWarnings("all") + public PostConstructorGeneratedRequiredArgs(final String a, final String b) { + this.a = a; + this.b = b; + postConstructor(); + } +} + +class PostConstructorGeneratedAllArgs { + private String a; + private String b; + + private void postConstructor() { + } + + @java.lang.SuppressWarnings("all") + public PostConstructorGeneratedAllArgs(final String a, final String b) { + this.a = a; + this.b = b; + postConstructor(); + } +} diff --git a/test/transform/resource/after-delombok/PostConstructorInvalid.java b/test/transform/resource/after-delombok/PostConstructorInvalid.java index e87e512510..c238410b8d 100644 --- a/test/transform/resource/after-delombok/PostConstructorInvalid.java +++ b/test/transform/resource/after-delombok/PostConstructorInvalid.java @@ -1,12 +1,9 @@ abstract class PostConstructorInvalid { - private void noConstructor() { - } - private static void staticMethod() { } public abstract void abstractMethod(); - + private void withArgument(String arg) { } -} \ No newline at end of file +} diff --git a/test/transform/resource/after-delombok/PostConstructorOrder.java b/test/transform/resource/after-delombok/PostConstructorOrder.java new file mode 100644 index 0000000000..e6312f0109 --- /dev/null +++ b/test/transform/resource/after-delombok/PostConstructorOrder.java @@ -0,0 +1,21 @@ +class PostConstructorOrder { + private void first() { + } + + private void second() { + } + + private void third() { + } + + private void fourth() { + } + + @java.lang.SuppressWarnings("all") + public PostConstructorOrder() { + first(); + second(); + third(); + fourth(); + } +} diff --git a/test/transform/resource/after-ecj/PostConstructor.java b/test/transform/resource/after-ecj/PostConstructor.java index 5f0bce7517..8e5bda65a7 100644 --- a/test/transform/resource/after-ecj/PostConstructor.java +++ b/test/transform/resource/after-ecj/PostConstructor.java @@ -1,27 +1,24 @@ -import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.experimental.PostConstructor; -@RequiredArgsConstructor @AllArgsConstructor class PostConstructorTest { +@RequiredArgsConstructor class PostConstructorTest { private String name; private final Integer start; private final Integer end; + private Integer range; private @PostConstructor void validate() { if ((((start == null) || (end == null)) || (end < start))) { throw new IllegalArgumentException(); } } - public @java.lang.SuppressWarnings("all") PostConstructorTest(final Integer start, final Integer end) { - super(); - this.start = start; - this.end = end; - validate(); + private @PostConstructor void calculateRange() { + range = (end - start); } - public @java.lang.SuppressWarnings("all") PostConstructorTest(final String name, final Integer start, final Integer end) { + public @java.lang.SuppressWarnings("all") PostConstructorTest(final Integer start, final Integer end) { super(); - this.name = name; this.start = start; this.end = end; validate(); + calculateRange(); } -} \ No newline at end of file +} diff --git a/test/transform/resource/after-ecj/PostConstructorBuilder.java b/test/transform/resource/after-ecj/PostConstructorBuilder.java new file mode 100644 index 0000000000..d51eee7597 --- /dev/null +++ b/test/transform/resource/after-ecj/PostConstructorBuilder.java @@ -0,0 +1,34 @@ +import lombok.Builder; +import lombok.experimental.PostConstructor; +@Builder class PostConstructorBuilder { + public static @java.lang.SuppressWarnings("all") class PostConstructorBuilderBuilder { + private @java.lang.SuppressWarnings("all") String field; + @java.lang.SuppressWarnings("all") PostConstructorBuilderBuilder() { + super(); + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") PostConstructorBuilder.PostConstructorBuilderBuilder field(final String field) { + this.field = field; + return this; + } + public @java.lang.SuppressWarnings("all") PostConstructorBuilder build() { + return new PostConstructorBuilder(this.field); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("PostConstructorBuilder.PostConstructorBuilderBuilder(field=" + this.field) + ")"); + } + } + private String field; + private @PostConstructor void postConstructor() { + } + @java.lang.SuppressWarnings("all") PostConstructorBuilder(final String field) { + super(); + this.field = field; + postConstructor(); + } + public static @java.lang.SuppressWarnings("all") PostConstructorBuilder.PostConstructorBuilderBuilder builder() { + return new PostConstructorBuilder.PostConstructorBuilderBuilder(); + } +} diff --git a/test/transform/resource/after-ecj/PostConstructorExceptions.java b/test/transform/resource/after-ecj/PostConstructorExceptions.java index 86b6588fb2..f78a536176 100644 --- a/test/transform/resource/after-ecj/PostConstructorExceptions.java +++ b/test/transform/resource/after-ecj/PostConstructorExceptions.java @@ -2,8 +2,10 @@ import lombok.experimental.PostConstructor; @AllArgsConstructor class PostConstructorExceptions { private String a; - PostConstructorExceptions() { + @PostConstructor.InvokePostConstructors PostConstructorExceptions() throws IllegalArgumentException, InterruptedException, java.lang.IllegalArgumentException, IllegalArgumentException { super(); + post(); + post2(); } private @PostConstructor void post() throws IllegalArgumentException { } @@ -15,4 +17,4 @@ post(); post2(); } -} \ No newline at end of file +} diff --git a/test/transform/resource/after-ecj/PostConstructorExplicit.java b/test/transform/resource/after-ecj/PostConstructorExplicit.java new file mode 100644 index 0000000000..eb8b4d7d19 --- /dev/null +++ b/test/transform/resource/after-ecj/PostConstructorExplicit.java @@ -0,0 +1,32 @@ +import lombok.experimental.PostConstructor; +class PostConstructorExplicit { + private @PostConstructor void postConstructor1() { + } + private @PostConstructor void postConstructor2() { + } + public PostConstructorExplicit(long a) { + this(); + } + public @PostConstructor.SkipPostConstructors PostConstructorExplicit(int a) { + super(); + } + public @PostConstructor.InvokePostConstructors PostConstructorExplicit(short a) { + super(); + postConstructor1(); + postConstructor2(); + } + public @PostConstructor.SkipPostConstructors @PostConstructor.InvokePostConstructors PostConstructorExplicit(byte a) { + super(); + } + public @PostConstructor.InvokePostConstructors PostConstructorExplicit(boolean a) { + this(); + postConstructor1(); + postConstructor2(); + } + public @PostConstructor.SkipPostConstructors PostConstructorExplicit(double a) { + this(); + } + public PostConstructorExplicit() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/PostConstructorExplicit2.java b/test/transform/resource/after-ecj/PostConstructorExplicit2.java new file mode 100644 index 0000000000..5d69f9658f --- /dev/null +++ b/test/transform/resource/after-ecj/PostConstructorExplicit2.java @@ -0,0 +1,57 @@ +import lombok.experimental.PostConstructor; +import lombok.experimental.PostConstructor.InvokePostConstructors; +class PostConstructorExplicit2 { + private @PostConstructor void first() { + } + private @PostConstructor void second() { + } + public @InvokePostConstructors PostConstructorExplicit2(long tryFinally) throws java.io.IOException { + super(); + boolean $callPostConstructor = true; + try + { + if ("a".equals("b")) + { + return ; + } + if ("a".equals("b")) + { + throw new java.io.IOException(""); + } + } + catch (final java.lang.Throwable $ex) + { + $callPostConstructor = false; + throw $ex; + } + finally + { + if ($callPostConstructor) + { + first(); + second(); + } + } + } + public @InvokePostConstructors PostConstructorExplicit2(int innerExit) { + super(); + Runnable r1 = new Runnable() { + x() { + super(); + } + public void run() { + return ; + } + }; + first(); + second(); + } + public @InvokePostConstructors PostConstructorExplicit2(short lambdaExit) { + super(); + Runnable r2 = () -> { + return ; + }; + first(); + second(); + } +} diff --git a/test/transform/resource/after-ecj/PostConstructorGenerated.java b/test/transform/resource/after-ecj/PostConstructorGenerated.java new file mode 100644 index 0000000000..1e98cd5057 --- /dev/null +++ b/test/transform/resource/after-ecj/PostConstructorGenerated.java @@ -0,0 +1,38 @@ +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.experimental.PostConstructor; +@NoArgsConstructor class PostConstructorGeneratedNoArgs { + private String a; + private String b; + private @PostConstructor void postConstructor() { + } + public @java.lang.SuppressWarnings("all") PostConstructorGeneratedNoArgs() { + super(); + postConstructor(); + } +} +@RequiredArgsConstructor class PostConstructorGeneratedRequiredArgs { + private final String a; + private final String b; + private @PostConstructor void postConstructor() { + } + public @java.lang.SuppressWarnings("all") PostConstructorGeneratedRequiredArgs(final String a, final String b) { + super(); + this.a = a; + this.b = b; + postConstructor(); + } +} +@AllArgsConstructor class PostConstructorGeneratedAllArgs { + private String a; + private String b; + private @PostConstructor void postConstructor() { + } + public @java.lang.SuppressWarnings("all") PostConstructorGeneratedAllArgs(final String a, final String b) { + super(); + this.a = a; + this.b = b; + postConstructor(); + } +} diff --git a/test/transform/resource/after-ecj/PostConstructorInvalid.java b/test/transform/resource/after-ecj/PostConstructorInvalid.java index 7aac9b0a2e..35176643f4 100644 --- a/test/transform/resource/after-ecj/PostConstructorInvalid.java +++ b/test/transform/resource/after-ecj/PostConstructorInvalid.java @@ -1,13 +1,11 @@ import lombok.experimental.PostConstructor; abstract class PostConstructorInvalid { - PostConstructorInvalid() { - super(); - } - private @PostConstructor void noConstructor() { - } private static @PostConstructor void staticMethod() { } public abstract @PostConstructor void abstractMethod(); private @PostConstructor void withArgument(String arg) { } -} \ No newline at end of file + public @java.lang.SuppressWarnings("all") PostConstructorInvalid() { + super(); + } +} diff --git a/test/transform/resource/after-ecj/PostConstructorOrder.java b/test/transform/resource/after-ecj/PostConstructorOrder.java new file mode 100644 index 0000000000..b67e7bcd7b --- /dev/null +++ b/test/transform/resource/after-ecj/PostConstructorOrder.java @@ -0,0 +1,18 @@ +import lombok.experimental.PostConstructor; +class PostConstructorOrder { + private @PostConstructor void first() { + } + private @PostConstructor void second() { + } + private @PostConstructor void third() { + } + private @PostConstructor void fourth() { + } + public @java.lang.SuppressWarnings("all") PostConstructorOrder() { + super(); + first(); + second(); + third(); + fourth(); + } +} diff --git a/test/transform/resource/before/PostConstructor.java b/test/transform/resource/before/PostConstructor.java index 861aac536c..b77f65c890 100644 --- a/test/transform/resource/before/PostConstructor.java +++ b/test/transform/resource/before/PostConstructor.java @@ -1,13 +1,12 @@ -import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.experimental.PostConstructor; @RequiredArgsConstructor -@AllArgsConstructor class PostConstructorTest { private String name; private final Integer start; private final Integer end; + private Integer range; @PostConstructor private void validate() { @@ -15,4 +14,8 @@ private void validate() { throw new IllegalArgumentException(); } } + @PostConstructor + private void calculateRange() { + range = end - start; + } } \ No newline at end of file diff --git a/test/transform/resource/before/PostConstructorBuilder.java b/test/transform/resource/before/PostConstructorBuilder.java new file mode 100644 index 0000000000..6e03c037f9 --- /dev/null +++ b/test/transform/resource/before/PostConstructorBuilder.java @@ -0,0 +1,11 @@ +import lombok.Builder; +import lombok.experimental.PostConstructor; + +@Builder +class PostConstructorBuilder { + private String field; + + @PostConstructor + private void postConstructor() { + } +} \ No newline at end of file diff --git a/test/transform/resource/before/PostConstructorExceptions.java b/test/transform/resource/before/PostConstructorExceptions.java index 77dce64ca9..c04b204fd3 100644 --- a/test/transform/resource/before/PostConstructorExceptions.java +++ b/test/transform/resource/before/PostConstructorExceptions.java @@ -6,8 +6,8 @@ class PostConstructorExceptions { private String a; + @PostConstructor.InvokePostConstructors PostConstructorExceptions() { - } @PostConstructor diff --git a/test/transform/resource/before/PostConstructorExplicit.java b/test/transform/resource/before/PostConstructorExplicit.java new file mode 100644 index 0000000000..6fbaefabca --- /dev/null +++ b/test/transform/resource/before/PostConstructorExplicit.java @@ -0,0 +1,41 @@ +import lombok.experimental.PostConstructor; + +class PostConstructorExplicit { + @PostConstructor + private void postConstructor1() { + } + + @PostConstructor + private void postConstructor2() { + } + + public PostConstructorExplicit(long a) { + this(); + } + + @PostConstructor.SkipPostConstructors + public PostConstructorExplicit(int a) { + } + + @PostConstructor.InvokePostConstructors + public PostConstructorExplicit(short a) { + } + + @PostConstructor.SkipPostConstructors + @PostConstructor.InvokePostConstructors + public PostConstructorExplicit(byte a) { + } + + @PostConstructor.InvokePostConstructors + public PostConstructorExplicit(boolean a) { + this(); + } + + @PostConstructor.SkipPostConstructors + public PostConstructorExplicit(double a) { + this(); + } + + public PostConstructorExplicit() { + } +} \ No newline at end of file diff --git a/test/transform/resource/before/PostConstructorExplicit2.java b/test/transform/resource/before/PostConstructorExplicit2.java new file mode 100644 index 0000000000..8ab3c6c7a7 --- /dev/null +++ b/test/transform/resource/before/PostConstructorExplicit2.java @@ -0,0 +1,37 @@ +// version 8: +import lombok.experimental.PostConstructor; +import lombok.experimental.PostConstructor.InvokePostConstructors; + +class PostConstructorExplicit2 { + @PostConstructor + private void first() { + } + + @PostConstructor + private void second() { + } + + @InvokePostConstructors + public PostConstructorExplicit2(long tryFinally) throws java.io.IOException { + if ("a".equals("b")) { + return; + } + if ("a".equals("b")) { + throw new java.io.IOException(""); + } + } + @InvokePostConstructors + public PostConstructorExplicit2(int innerExit) { + Runnable r1 = new Runnable() { + public void run() { + return; + } + }; + } + @InvokePostConstructors + public PostConstructorExplicit2(short lambdaExit) { + Runnable r2 = () -> { + return; + }; + } +} \ No newline at end of file diff --git a/test/transform/resource/before/PostConstructorGenerated.java b/test/transform/resource/before/PostConstructorGenerated.java new file mode 100644 index 0000000000..65b1dc0087 --- /dev/null +++ b/test/transform/resource/before/PostConstructorGenerated.java @@ -0,0 +1,32 @@ +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.experimental.PostConstructor; + +@NoArgsConstructor +class PostConstructorGeneratedNoArgs { + private String a; + private String b; + + @PostConstructor + private void postConstructor() { + } +} +@RequiredArgsConstructor +class PostConstructorGeneratedRequiredArgs { + private final String a; + private final String b; + + @PostConstructor + private void postConstructor() { + } +} +@AllArgsConstructor +class PostConstructorGeneratedAllArgs { + private String a; + private String b; + + @PostConstructor + private void postConstructor() { + } +} \ No newline at end of file diff --git a/test/transform/resource/before/PostConstructorInvalid.java b/test/transform/resource/before/PostConstructorInvalid.java index 8635f88e56..3907e58e21 100644 --- a/test/transform/resource/before/PostConstructorInvalid.java +++ b/test/transform/resource/before/PostConstructorInvalid.java @@ -1,14 +1,8 @@ import lombok.experimental.PostConstructor; abstract class PostConstructorInvalid { - @PostConstructor - private void noConstructor() { - - } - @PostConstructor private static void staticMethod() { - } @PostConstructor @@ -16,6 +10,5 @@ private static void staticMethod() { @PostConstructor private void withArgument(String arg) { - } } \ No newline at end of file diff --git a/test/transform/resource/before/PostConstructorOrder.java b/test/transform/resource/before/PostConstructorOrder.java new file mode 100644 index 0000000000..27dec2e885 --- /dev/null +++ b/test/transform/resource/before/PostConstructorOrder.java @@ -0,0 +1,19 @@ +import lombok.experimental.PostConstructor; + +class PostConstructorOrder { + @PostConstructor + private void first() { + } + + @PostConstructor + private void second() { + } + + @PostConstructor + private void third() { + } + + @PostConstructor + private void fourth() { + } +} \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/PostConstructorExplicit.java.messages b/test/transform/resource/messages-delombok/PostConstructorExplicit.java.messages new file mode 100644 index 0000000000..05bc359ecb --- /dev/null +++ b/test/transform/resource/messages-delombok/PostConstructorExplicit.java.messages @@ -0,0 +1,3 @@ +35 @SkipPostConstructors is not needed; constructors calling this(...) are skipped anyway. +26 @InvokePostConstructors and @SkipPostConstructors are mutually exclusive. +39 Constructor needs to be annotated with @PostConstruct.(Invoke|Skip)PostConstructors or needs to start with a this(...) call. \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/PostConstructorInvalid.java.messages b/test/transform/resource/messages-delombok/PostConstructorInvalid.java.messages index acef115424..cd03329839 100644 --- a/test/transform/resource/messages-delombok/PostConstructorInvalid.java.messages +++ b/test/transform/resource/messages-delombok/PostConstructorInvalid.java.messages @@ -1,4 +1,3 @@ -4 Cannot find a generated constructor. -9 @PostConstructor is legal only on instance methods. -14 @PostConstructor is legal only on concrete methods. -17 @PostConstructor is legal only on methods without parameters. \ No newline at end of file +4 @PostConstructor is legal only on instance methods. +8 @PostConstructor is legal only on concrete methods. +11 @PostConstructor is legal only on methods without parameters. \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/PostConstructorExplicit.java.messages b/test/transform/resource/messages-ecj/PostConstructorExplicit.java.messages new file mode 100644 index 0000000000..5a746f13ad --- /dev/null +++ b/test/transform/resource/messages-ecj/PostConstructorExplicit.java.messages @@ -0,0 +1,3 @@ +26 @InvokePostConstructors and @SkipPostConstructors are mutually exclusive. +35 @SkipPostConstructors is not needed; constructors calling this(...) are skipped anyway. +39 Constructor needs to be annotated with @PostConstruct.(Invoke|Skip)PostConstructors or needs to start with a this(...) call. \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/PostConstructorInvalid.java.messages b/test/transform/resource/messages-ecj/PostConstructorInvalid.java.messages index acef115424..cd03329839 100644 --- a/test/transform/resource/messages-ecj/PostConstructorInvalid.java.messages +++ b/test/transform/resource/messages-ecj/PostConstructorInvalid.java.messages @@ -1,4 +1,3 @@ -4 Cannot find a generated constructor. -9 @PostConstructor is legal only on instance methods. -14 @PostConstructor is legal only on concrete methods. -17 @PostConstructor is legal only on methods without parameters. \ No newline at end of file +4 @PostConstructor is legal only on instance methods. +8 @PostConstructor is legal only on concrete methods. +11 @PostConstructor is legal only on methods without parameters. \ No newline at end of file diff --git a/website/usageExamples/experimental/PostConstructorExample_post.jpage b/website/usageExamples/experimental/PostConstructorExample_post.jpage index 0748b4802c..9ae990d54f 100644 --- a/website/usageExamples/experimental/PostConstructorExample_post.jpage +++ b/website/usageExamples/experimental/PostConstructorExample_post.jpage @@ -1,15 +1,7 @@ class PostConstructorExample { - private String name; private final Integer start; private final Integer end; - public PostConstructorTest(final String name, final Integer start, final Integer end) { - this.name = name; - this.start = start; - this.end = end; - validate(); - } - public PostConstructorTest(final Integer start, final Integer end) { this.start = start; this.end = end; diff --git a/website/usageExamples/experimental/PostConstructorExample_pre.jpage b/website/usageExamples/experimental/PostConstructorExample_pre.jpage index a1eae05d26..d51300894a 100644 --- a/website/usageExamples/experimental/PostConstructorExample_pre.jpage +++ b/website/usageExamples/experimental/PostConstructorExample_pre.jpage @@ -1,11 +1,8 @@ -import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.experimental.PostConstructor; -@AllArgsConstructor @RequiredArgsConstructor class PostConstructorExample { - private String name; private final Integer start; private final Integer end;