From 6b0b1a6a7ba73a2c43bb8ab413375505d61aacc6 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 29 Mar 2018 03:36:29 +0200 Subject: [builderParentClass] test cases --- .../resource/before/BuilderWithInherit.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 test/transform/resource/before/BuilderWithInherit.java (limited to 'test') diff --git a/test/transform/resource/before/BuilderWithInherit.java b/test/transform/resource/before/BuilderWithInherit.java new file mode 100644 index 00000000..dcc7b5ad --- /dev/null +++ b/test/transform/resource/before/BuilderWithInherit.java @@ -0,0 +1,20 @@ +import lombok.Builder; +import lombok.Singular; +import java.util.List; + +public class BuilderWithInherit { + @Builder(extensible = true) + public static class Parent { + int field1; + @Singular List items; + } + + @Builder(inherit = true) + public static class Child extends Parent { + double field3; + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} -- cgit From 3eea3b958946dd813197f00a1292b7a72380878a Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 4 Apr 2018 23:26:01 +0200 Subject: introduction of `@SuperBuilder` and a testcase. --- src/core/lombok/Builder.java | 50 +-------- src/core/lombok/experimental/SuperBuilder.java | 66 ++++++++++++ .../resource/after-delombok/SuperBuilderBasic.java | 112 +++++++++++++++++++++ .../resource/before/BuilderWithInherit.java | 20 ---- .../resource/before/SuperBuilderBasic.java | 20 ++++ 5 files changed, 203 insertions(+), 65 deletions(-) create mode 100644 src/core/lombok/experimental/SuperBuilder.java create mode 100644 test/transform/resource/after-delombok/SuperBuilderBasic.java delete mode 100644 test/transform/resource/before/BuilderWithInherit.java create mode 100644 test/transform/resource/before/SuperBuilderBasic.java (limited to 'test') diff --git a/src/core/lombok/Builder.java b/src/core/lombok/Builder.java index 7ae43bfa..d7a2a109 100644 --- a/src/core/lombok/Builder.java +++ b/src/core/lombok/Builder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2017 The Project Lombok Authors. + * Copyright (C) 2013-2018 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 @@ -55,8 +55,8 @@ import java.lang.annotation.Target; * *
  * @Builder
- * class Example {
- * 	private int foo;
+ * class Example<T> {
+ * 	private T foo;
  * 	private final String bar;
  * }
  * 
@@ -103,6 +103,8 @@ import java.lang.annotation.Target; * } * } * + * + * @see Singular */ @Target({TYPE, METHOD, CONSTRUCTOR}) @Retention(SOURCE) @@ -131,48 +133,6 @@ public @interface Builder { */ String builderClassName() default ""; - /** - * Should the generated builder extend the parent class's builder? - * - * If {@code true}, the generated builder class will extend the builder of the - * superclass. This means the builder also contains the methods for fields from - * the superclass. - *

- * Note that both this builder and the superclass' builder must be a builder - * for a type (so, not for a static method or a constructor). You must mark - * the parent extendable: {@code @Builder(extensible = true)}. - *

- * This builder will also be {@code extensible = true} if you set {@code inherit = true}. - * - * @see #extensible() - */ - boolean inherit() default false; - - /** - * Should the generated builder be extensible by subclasses? - * - * If {@code true} the generated builder class will be extensible by - * {@code @Builder} classes of this class's subclasses, by marking them - * with {@code @Builder(inherit = true)}. - *

- * The {@code @Builder} extensible system only works for {@code @Builder} - * annotations on types (so, not on a static method or a constructor). - * - * @see #inherit() - */ - boolean extensible() default false; - - /** - * Name of the builder class in the superclass. - * - * Only relevant if {@code inherit = true} - * - * Default: {@code (SuperclassTypeName)Builder}. - * - * @see #inherit() - */ - String superclassBuilderClassName() default ""; - /** * If true, generate an instance method to obtain a builder that is initialized with the values of this instance. * Legal only if {@code @Builder} is used on a constructor, on the type itself, or on a static method that returns diff --git a/src/core/lombok/experimental/SuperBuilder.java b/src/core/lombok/experimental/SuperBuilder.java new file mode 100644 index 00000000..26127a5f --- /dev/null +++ b/src/core/lombok/experimental/SuperBuilder.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2018 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 static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import lombok.Singular; + +/** + * The SuperBuilder annotation creates a so-called 'builder' aspect to the class that is annotated with {@code @SuperBuilder}, but which works well when extending. + * It is similar to {@code @Builder}, except it is only legal on types, is less configurable, but allows you to {@code extends} other builder-able classes. + *

+ * All classes in the hierarchy must be annotated with {@code @SuperBuilder}. + *

+ * Lombok generates 2 inner 'builder' classes, which extend the parent class' builder class (unless your class doesn't have an extends clause). + * Lombok also generates a static method named {@code builder()}, and a protected constructor that takes 1 argument of the builderclass type. + *

+ * The TBuilder class contains 1 method for each parameter of the annotated + * constructor / method (each field, when annotating a class), which returns the builder itself. + * The builder also has a build() method which returns a completed instance of the original type. + *

+ * Complete documentation is found at the project lombok features page for @SuperBuilder. + * + * @see Singular + */ +@Target(TYPE) +@Retention(SOURCE) +public @interface SuperBuilder { + /** @return Name of the method that creates a new builder instance. Default: {@code builder}. */ + String builderMethodName() default "builder"; + + /** @return Name of the method in the builder class that creates an instance of your {@code @Builder}-annotated class. */ + String buildMethodName() default "build"; + + // toBuilder also requires a two-stage system where each class gets its own toBuilder but calls on a second method (and also calls parentclass's method) + // to fill the builder, as this class does not know what fields to pass on to the builder. Let's consider this, but only for milestone 2. + /* + * If true, generate an instance method to obtain a builder that is initialized with the values of this instance. + * + * @return Whether to generate a {@code toBuilder()} method. + */ +// boolean toBuilder() default false; +} diff --git a/test/transform/resource/after-delombok/SuperBuilderBasic.java b/test/transform/resource/after-delombok/SuperBuilderBasic.java new file mode 100644 index 00000000..ffb56e0e --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderBasic.java @@ -0,0 +1,112 @@ +import java.util.List; + +public class SuperBuilderBasic { + public static class Parent { + int field1; + List items; + protected Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + private static class ParentBuilderImpl extends ParentBuilder { + @Override + public Parent build() { + return new Parent(this); + } + + @Override + public ParentBuilderImpl self() { + return this; + } + } + public abstract static class ParentBuilder> { + @java.lang.SuppressWarnings("all") + private int field1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList items; + @java.lang.SuppressWarnings("all") + ParentBuilder() { + } + @java.lang.SuppressWarnings("all") + public B field1(final int field1) { + this.field1 = field1; + return self(); + } + @java.lang.SuppressWarnings("all") + public B item(final String item) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + @java.lang.SuppressWarnings("all") + public B items(final java.util.Collection items) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + @java.lang.SuppressWarnings("all") + public B clearItems() { + if (this.items != null) this.items.clear(); + return self(); + } + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + } + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static class Child extends Parent { + double field3; + protected Child(ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + private static class ChildBuilderImpl extends ChildBuilder { + @Override + public Child build() { + return new Child(this); + } + + @Override + public ChildBuilderImpl self() { + return this; + } + } + public abstract static class ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private double field3; + @java.lang.SuppressWarnings("all") + ChildBuilder() { + } + @java.lang.SuppressWarnings("all") + public B field3(final double field3) { + this.field3 = field3; + return self(); + } + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + } + public static ChildBuilder builder() { + return new ChildBuilderImpl(); + } + } + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} diff --git a/test/transform/resource/before/BuilderWithInherit.java b/test/transform/resource/before/BuilderWithInherit.java deleted file mode 100644 index dcc7b5ad..00000000 --- a/test/transform/resource/before/BuilderWithInherit.java +++ /dev/null @@ -1,20 +0,0 @@ -import lombok.Builder; -import lombok.Singular; -import java.util.List; - -public class BuilderWithInherit { - @Builder(extensible = true) - public static class Parent { - int field1; - @Singular List items; - } - - @Builder(inherit = true) - public static class Child extends Parent { - double field3; - } - - public static void test() { - Child x = Child.builder().field3(0.0).field1(5).item("").build(); - } -} diff --git a/test/transform/resource/before/SuperBuilderBasic.java b/test/transform/resource/before/SuperBuilderBasic.java new file mode 100644 index 00000000..bf3eea64 --- /dev/null +++ b/test/transform/resource/before/SuperBuilderBasic.java @@ -0,0 +1,20 @@ +import lombok.experimental.SuperBuilder; +import lombok.Singular; +import java.util.List; + +public class SuperBuilderBasic { + @SuperBuilder + public static class Parent { + int field1; + @Singular List items; + } + + @SuperBuilder + public static class Child extends Parent { + double field3; + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} -- cgit From 6dd21ad7e04cec9405fd798e236808ed4acac954 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Sat, 14 Apr 2018 20:13:59 +0200 Subject: adjusted expected result of test case --- .../lombok/javac/handlers/HandleSuperBuilder.java | 1 + .../resource/after-delombok/SuperBuilderBasic.java | 278 ++++++++++++--------- 2 files changed, 167 insertions(+), 112 deletions(-) (limited to 'test') diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index 7f0858d2..d30740c0 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -236,6 +236,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { for (BuilderFieldData bfd : builderFields) { fieldNodes.addAll(bfd.createdFields); } + // TODO: toString() should also call super.toString(), so that it also shows fields from the superclass. JCMethodDecl md = HandleToString.createToString(builderType, fieldNodes, true, false, FieldAccess.ALWAYS_FIELD, ast); if (md != null) injectMethod(builderType, md); } diff --git a/test/transform/resource/after-delombok/SuperBuilderBasic.java b/test/transform/resource/after-delombok/SuperBuilderBasic.java index ffb56e0e..ed1f9bdc 100644 --- a/test/transform/resource/after-delombok/SuperBuilderBasic.java +++ b/test/transform/resource/after-delombok/SuperBuilderBasic.java @@ -1,112 +1,166 @@ -import java.util.List; - -public class SuperBuilderBasic { - public static class Parent { - int field1; - List items; - protected Parent(final ParentBuilder b) { - this.field1 = b.field1; - java.util.List items; - switch (b.items == null ? 0 : b.items.size()) { - case 0: - items = java.util.Collections.emptyList(); - break; - case 1: - items = java.util.Collections.singletonList(b.items.get(0)); - break; - default: - items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); - } - this.items = items; - } - private static class ParentBuilderImpl extends ParentBuilder { - @Override - public Parent build() { - return new Parent(this); - } - - @Override - public ParentBuilderImpl self() { - return this; - } - } - public abstract static class ParentBuilder> { - @java.lang.SuppressWarnings("all") - private int field1; - @java.lang.SuppressWarnings("all") - private java.util.ArrayList items; - @java.lang.SuppressWarnings("all") - ParentBuilder() { - } - @java.lang.SuppressWarnings("all") - public B field1(final int field1) { - this.field1 = field1; - return self(); - } - @java.lang.SuppressWarnings("all") - public B item(final String item) { - if (this.items == null) this.items = new java.util.ArrayList(); - this.items.add(item); - return self(); - } - @java.lang.SuppressWarnings("all") - public B items(final java.util.Collection items) { - if (this.items == null) this.items = new java.util.ArrayList(); - this.items.addAll(items); - return self(); - } - @java.lang.SuppressWarnings("all") - public B clearItems() { - if (this.items != null) this.items.clear(); - return self(); - } - @java.lang.SuppressWarnings("all") - protected abstract B self(); - @java.lang.SuppressWarnings("all") - public abstract C build(); - } - public static ParentBuilder builder() { - return new ParentBuilderImpl(); - } - } - public static class Child extends Parent { - double field3; - protected Child(ChildBuilder b) { - super(b); - this.field3 = b.field3; - } - private static class ChildBuilderImpl extends ChildBuilder { - @Override - public Child build() { - return new Child(this); - } - - @Override - public ChildBuilderImpl self() { - return this; - } - } - public abstract static class ChildBuilder> extends Parent.ParentBuilder { - @java.lang.SuppressWarnings("all") - private double field3; - @java.lang.SuppressWarnings("all") - ChildBuilder() { - } - @java.lang.SuppressWarnings("all") - public B field3(final double field3) { - this.field3 = field3; - return self(); - } - @java.lang.SuppressWarnings("all") - protected abstract B self(); - @java.lang.SuppressWarnings("all") - public abstract C build(); - } - public static ChildBuilder builder() { - return new ChildBuilderImpl(); - } - } - public static void test() { - Child x = Child.builder().field3(0.0).field1(5).item("").build(); - } -} +import java.util.List; + +public class SuperBuilderBasic { + public static class Parent { + int field1; + List items; + + @java.lang.SuppressWarnings("all") + protected Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder> { + @java.lang.SuppressWarnings("all") + private int field1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList items; + + @java.lang.SuppressWarnings("all") + protected abstract B self(); + + @java.lang.SuppressWarnings("all") + public abstract C build(); + + @java.lang.SuppressWarnings("all") + public B field1(final int field1) { + this.field1 = field1; + return self(); + } + + @java.lang.SuppressWarnings("all") + public B item(final String item) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + + @java.lang.SuppressWarnings("all") + public B items(final java.util.Collection items) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + + @java.lang.SuppressWarnings("all") + public B clearItems() { + if (this.items != null) this.items.clear(); + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderBasic.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder { + @java.lang.SuppressWarnings("all") + private ParentBuilderImpl() { + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ParentBuilderImpl self() { + return this; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Parent build() { + return new Parent(this); + } + } + + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + + + public static class Child extends Parent { + double field3; + + @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private double field3; + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected abstract B self(); + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public abstract C build(); + + @java.lang.SuppressWarnings("all") + public B field3(final double field3) { + this.field3 = field3; + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderBasic.Child.ChildBuilder(field3=" + this.field3 + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ChildBuilderImpl extends ChildBuilder { + @java.lang.SuppressWarnings("all") + private ChildBuilderImpl() { + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ChildBuilderImpl self() { + return this; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Child build() { + return new Child(this); + } + } + + @java.lang.SuppressWarnings("all") + public static ChildBuilder builder() { + return new ChildBuilderImpl(); + } + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} -- cgit From 9df65559122a572e7ee0ea355f05d2f9a934c7e5 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Sun, 15 Apr 2018 23:06:19 +0200 Subject: added SuperBuilder with generics test case --- .../after-delombok/SuperBuilderWithGenerics.java | 166 +++++++++++++++++++++ .../resource/before/SuperBuilderWithGenerics.java | 20 +++ 2 files changed, 186 insertions(+) create mode 100644 test/transform/resource/after-delombok/SuperBuilderWithGenerics.java create mode 100644 test/transform/resource/before/SuperBuilderWithGenerics.java (limited to 'test') diff --git a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java new file mode 100644 index 00000000..bfd6e4b7 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java @@ -0,0 +1,166 @@ +import java.util.List; + +public class SuperBuilderWithGenerics { + public static class Parent { + A field1; + List items; + + @java.lang.SuppressWarnings("all") + protected Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder, B extends ParentBuilder> { + @java.lang.SuppressWarnings("all") + private A field1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList items; + + @java.lang.SuppressWarnings("all") + protected abstract B self(); + + @java.lang.SuppressWarnings("all") + public abstract C build(); + + @java.lang.SuppressWarnings("all") + public B field1(final A field1) { + this.field1 = field1; + return self(); + } + + @java.lang.SuppressWarnings("all") + public B item(final String item) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + + @java.lang.SuppressWarnings("all") + public B items(final java.util.Collection items) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + + @java.lang.SuppressWarnings("all") + public B clearItems() { + if (this.items != null) this.items.clear(); + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + @java.lang.SuppressWarnings("all") + private ParentBuilderImpl() { + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ParentBuilderImpl self() { + return this; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Parent build() { + return new Parent(this); + } + } + + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + + + public static class Child extends Parent { + double field3; + + @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private double field3; + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected abstract B self(); + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public abstract C build(); + + @java.lang.SuppressWarnings("all") + public B field3(final double field3) { + this.field3 = field3; + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics.Child.ChildBuilder(field3=" + this.field3 + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { + @java.lang.SuppressWarnings("all") + private ChildBuilderImpl() { + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ChildBuilderImpl self() { + return this; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Child build() { + return new Child(this); + } + } + + @java.lang.SuppressWarnings("all") + public static ChildBuilder builder() { + return new ChildBuilderImpl(); + } + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} diff --git a/test/transform/resource/before/SuperBuilderWithGenerics.java b/test/transform/resource/before/SuperBuilderWithGenerics.java new file mode 100644 index 00000000..7b8d459f --- /dev/null +++ b/test/transform/resource/before/SuperBuilderWithGenerics.java @@ -0,0 +1,20 @@ +import lombok.experimental.SuperBuilder; +import lombok.Singular; +import java.util.List; + +public class SuperBuilderWithGenerics { + @SuperBuilder + public static class Parent { + A field1; + @Singular List items; + } + + @SuperBuilder + public static class Child extends Parent { + double field3; + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} -- cgit From 4f5d5b108dada037137c209e3b8a3b86af8643ae Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Fri, 27 Apr 2018 13:36:08 +0200 Subject: fixed javac tests (toString calls super now) --- test/transform/resource/after-delombok/SuperBuilderBasic.java | 5 +++-- .../resource/after-delombok/SuperBuilderWithGenerics.java | 5 +++-- test/transform/resource/before/SuperBuilderBasic.java | 8 +++----- test/transform/resource/before/SuperBuilderWithGenerics.java | 8 +++----- 4 files changed, 12 insertions(+), 14 deletions(-) (limited to 'test') diff --git a/test/transform/resource/after-delombok/SuperBuilderBasic.java b/test/transform/resource/after-delombok/SuperBuilderBasic.java index ed1f9bdc..da745b58 100644 --- a/test/transform/resource/after-delombok/SuperBuilderBasic.java +++ b/test/transform/resource/after-delombok/SuperBuilderBasic.java @@ -1,6 +1,7 @@ import java.util.List; public class SuperBuilderBasic { + @lombok.experimental.SuperBuilder public static class Parent { int field1; List items; @@ -97,7 +98,7 @@ public class SuperBuilderBasic { } } - + @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; @@ -130,7 +131,7 @@ public class SuperBuilderBasic { @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { - return "SuperBuilderBasic.Child.ChildBuilder(field3=" + this.field3 + ")"; + return "SuperBuilderBasic.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; } } diff --git a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java index bfd6e4b7..ff080f6c 100644 --- a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java +++ b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java @@ -1,6 +1,7 @@ import java.util.List; public class SuperBuilderWithGenerics { + @lombok.experimental.SuperBuilder public static class Parent { A field1; List items; @@ -97,7 +98,7 @@ public class SuperBuilderWithGenerics { } } - + @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; @@ -130,7 +131,7 @@ public class SuperBuilderWithGenerics { @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { - return "SuperBuilderWithGenerics.Child.ChildBuilder(field3=" + this.field3 + ")"; + return "SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; } } diff --git a/test/transform/resource/before/SuperBuilderBasic.java b/test/transform/resource/before/SuperBuilderBasic.java index bf3eea64..f4e8c670 100644 --- a/test/transform/resource/before/SuperBuilderBasic.java +++ b/test/transform/resource/before/SuperBuilderBasic.java @@ -1,15 +1,13 @@ -import lombok.experimental.SuperBuilder; -import lombok.Singular; import java.util.List; public class SuperBuilderBasic { - @SuperBuilder + @lombok.experimental.SuperBuilder public static class Parent { int field1; - @Singular List items; + @lombok.Singular List items; } - @SuperBuilder + @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; } diff --git a/test/transform/resource/before/SuperBuilderWithGenerics.java b/test/transform/resource/before/SuperBuilderWithGenerics.java index 7b8d459f..c3cd4277 100644 --- a/test/transform/resource/before/SuperBuilderWithGenerics.java +++ b/test/transform/resource/before/SuperBuilderWithGenerics.java @@ -1,15 +1,13 @@ -import lombok.experimental.SuperBuilder; -import lombok.Singular; import java.util.List; public class SuperBuilderWithGenerics { - @SuperBuilder + @lombok.experimental.SuperBuilder public static class Parent { A field1; - @Singular List items; + @lombok.Singular List items; } - @SuperBuilder + @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; } -- cgit From 9f3e8509f7564b82eb13d3e4d7d0fc22a6d13cc3 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Fri, 27 Apr 2018 16:07:41 +0200 Subject: no empty lines for expected test result --- .../resource/after-delombok/SuperBuilderBasic.java | 32 ---------------------- .../after-delombok/SuperBuilderWithGenerics.java | 32 ---------------------- 2 files changed, 64 deletions(-) (limited to 'test') diff --git a/test/transform/resource/after-delombok/SuperBuilderBasic.java b/test/transform/resource/after-delombok/SuperBuilderBasic.java index da745b58..acad9c03 100644 --- a/test/transform/resource/after-delombok/SuperBuilderBasic.java +++ b/test/transform/resource/after-delombok/SuperBuilderBasic.java @@ -1,11 +1,9 @@ import java.util.List; - public class SuperBuilderBasic { @lombok.experimental.SuperBuilder public static class Parent { int field1; List items; - @java.lang.SuppressWarnings("all") protected Parent(final ParentBuilder b) { this.field1 = b.field1; @@ -14,153 +12,123 @@ public class SuperBuilderBasic { case 0: items = java.util.Collections.emptyList(); break; - case 1: items = java.util.Collections.singletonList(b.items.get(0)); break; - default: items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); } this.items = items; } - - @java.lang.SuppressWarnings("all") public static abstract class ParentBuilder> { @java.lang.SuppressWarnings("all") private int field1; @java.lang.SuppressWarnings("all") private java.util.ArrayList items; - @java.lang.SuppressWarnings("all") protected abstract B self(); - @java.lang.SuppressWarnings("all") public abstract C build(); - @java.lang.SuppressWarnings("all") public B field1(final int field1) { this.field1 = field1; return self(); } - @java.lang.SuppressWarnings("all") public B item(final String item) { if (this.items == null) this.items = new java.util.ArrayList(); this.items.add(item); return self(); } - @java.lang.SuppressWarnings("all") public B items(final java.util.Collection items) { if (this.items == null) this.items = new java.util.ArrayList(); this.items.addAll(items); return self(); } - @java.lang.SuppressWarnings("all") public B clearItems() { if (this.items != null) this.items.clear(); return self(); } - @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { return "SuperBuilderBasic.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; } } - - @java.lang.SuppressWarnings("all") private static final class ParentBuilderImpl extends ParentBuilder { @java.lang.SuppressWarnings("all") private ParentBuilderImpl() { } - @java.lang.Override @java.lang.SuppressWarnings("all") protected ParentBuilderImpl self() { return this; } - @java.lang.Override @java.lang.SuppressWarnings("all") public Parent build() { return new Parent(this); } } - @java.lang.SuppressWarnings("all") public static ParentBuilder builder() { return new ParentBuilderImpl(); } } - @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; - @java.lang.SuppressWarnings("all") protected Child(final ChildBuilder b) { super(b); this.field3 = b.field3; } - - @java.lang.SuppressWarnings("all") public static abstract class ChildBuilder> extends Parent.ParentBuilder { @java.lang.SuppressWarnings("all") private double field3; - @java.lang.Override @java.lang.SuppressWarnings("all") protected abstract B self(); - @java.lang.Override @java.lang.SuppressWarnings("all") public abstract C build(); - @java.lang.SuppressWarnings("all") public B field3(final double field3) { this.field3 = field3; return self(); } - @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { return "SuperBuilderBasic.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; } } - - @java.lang.SuppressWarnings("all") private static final class ChildBuilderImpl extends ChildBuilder { @java.lang.SuppressWarnings("all") private ChildBuilderImpl() { } - @java.lang.Override @java.lang.SuppressWarnings("all") protected ChildBuilderImpl self() { return this; } - @java.lang.Override @java.lang.SuppressWarnings("all") public Child build() { return new Child(this); } } - @java.lang.SuppressWarnings("all") public static ChildBuilder builder() { return new ChildBuilderImpl(); } } - public static void test() { Child x = Child.builder().field3(0.0).field1(5).item("").build(); } diff --git a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java index ff080f6c..e7615c66 100644 --- a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java +++ b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java @@ -1,11 +1,9 @@ import java.util.List; - public class SuperBuilderWithGenerics { @lombok.experimental.SuperBuilder public static class Parent { A field1; List items; - @java.lang.SuppressWarnings("all") protected Parent(final ParentBuilder b) { this.field1 = b.field1; @@ -14,153 +12,123 @@ public class SuperBuilderWithGenerics { case 0: items = java.util.Collections.emptyList(); break; - case 1: items = java.util.Collections.singletonList(b.items.get(0)); break; - default: items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); } this.items = items; } - - @java.lang.SuppressWarnings("all") public static abstract class ParentBuilder, B extends ParentBuilder> { @java.lang.SuppressWarnings("all") private A field1; @java.lang.SuppressWarnings("all") private java.util.ArrayList items; - @java.lang.SuppressWarnings("all") protected abstract B self(); - @java.lang.SuppressWarnings("all") public abstract C build(); - @java.lang.SuppressWarnings("all") public B field1(final A field1) { this.field1 = field1; return self(); } - @java.lang.SuppressWarnings("all") public B item(final String item) { if (this.items == null) this.items = new java.util.ArrayList(); this.items.add(item); return self(); } - @java.lang.SuppressWarnings("all") public B items(final java.util.Collection items) { if (this.items == null) this.items = new java.util.ArrayList(); this.items.addAll(items); return self(); } - @java.lang.SuppressWarnings("all") public B clearItems() { if (this.items != null) this.items.clear(); return self(); } - @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { return "SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; } } - - @java.lang.SuppressWarnings("all") private static final class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { @java.lang.SuppressWarnings("all") private ParentBuilderImpl() { } - @java.lang.Override @java.lang.SuppressWarnings("all") protected ParentBuilderImpl self() { return this; } - @java.lang.Override @java.lang.SuppressWarnings("all") public Parent build() { return new Parent(this); } } - @java.lang.SuppressWarnings("all") public static ParentBuilder builder() { return new ParentBuilderImpl(); } } - @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; - @java.lang.SuppressWarnings("all") protected Child(final ChildBuilder b) { super(b); this.field3 = b.field3; } - - @java.lang.SuppressWarnings("all") public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { @java.lang.SuppressWarnings("all") private double field3; - @java.lang.Override @java.lang.SuppressWarnings("all") protected abstract B self(); - @java.lang.Override @java.lang.SuppressWarnings("all") public abstract C build(); - @java.lang.SuppressWarnings("all") public B field3(final double field3) { this.field3 = field3; return self(); } - @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { return "SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; } } - - @java.lang.SuppressWarnings("all") private static final class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { @java.lang.SuppressWarnings("all") private ChildBuilderImpl() { } - @java.lang.Override @java.lang.SuppressWarnings("all") protected ChildBuilderImpl self() { return this; } - @java.lang.Override @java.lang.SuppressWarnings("all") public Child build() { return new Child(this); } } - @java.lang.SuppressWarnings("all") public static ChildBuilder builder() { return new ChildBuilderImpl(); } } - public static void test() { Child x = Child.builder().field3(0.0).field1(5).item("").build(); } -- cgit From eec57b87509c0a2841878aecb0e8f8f0839fa30c Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Fri, 4 May 2018 18:22:32 +0200 Subject: added @SuperBuilder test results for ecj --- .../resource/after-ecj/SuperBuilderBasic.java | 164 ++++++++++++++++++++ .../after-ecj/SuperBuilderWithGenerics.java | 166 +++++++++++++++++++++ 2 files changed, 330 insertions(+) create mode 100644 test/transform/resource/after-ecj/SuperBuilderBasic.java create mode 100644 test/transform/resource/after-ecj/SuperBuilderWithGenerics.java (limited to 'test') diff --git a/test/transform/resource/after-ecj/SuperBuilderBasic.java b/test/transform/resource/after-ecj/SuperBuilderBasic.java new file mode 100644 index 00000000..cc86e05c --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderBasic.java @@ -0,0 +1,164 @@ +import java.util.List; + +public class SuperBuilderBasic { + public static @lombok.experimental.SuperBuilder class Parent { + int field1; + @lombok.Singular List items; + + protected Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder> { + @java.lang.SuppressWarnings("all") + private int field1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList items; + + @java.lang.SuppressWarnings("all") + protected abstract B self(); + + @java.lang.SuppressWarnings("all") + public abstract C build(); + + @java.lang.SuppressWarnings("all") + public B field1(final int field1) { + this.field1 = field1; + return self(); + } + + @java.lang.SuppressWarnings("all") + public B item(final String item) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + + @java.lang.SuppressWarnings("all") + public B items(final java.util.Collection items) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + + @java.lang.SuppressWarnings("all") + public B clearItems() { + if (this.items != null) this.items.clear(); + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderBasic.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder { + @java.lang.SuppressWarnings("all") + private ParentBuilderImpl() { + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ParentBuilderImpl self() { + return this; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Parent build() { + return new Parent(this); + } + } + + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + + public static @lombok.experimental.SuperBuilder class Child extends Parent { + double field3; + + @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private double field3; + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected abstract B self(); + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public abstract C build(); + + @java.lang.SuppressWarnings("all") + public B field3(final double field3) { + this.field3 = field3; + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderBasic.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ChildBuilderImpl extends ChildBuilder { + @java.lang.SuppressWarnings("all") + private ChildBuilderImpl() { + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ChildBuilderImpl self() { + return this; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Child build() { + return new Child(this); + } + } + + @java.lang.SuppressWarnings("all") + public static ChildBuilder builder() { + return new ChildBuilderImpl(); + } + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} diff --git a/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java b/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java new file mode 100644 index 00000000..9f71be5a --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java @@ -0,0 +1,166 @@ +import java.util.List; + +public class SuperBuilderWithGenerics { + public static @lombok.experimental.SuperBuilder class Parent { + A field1; + List items; + + @java.lang.SuppressWarnings("all") + protected Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder, B extends ParentBuilder> { + @java.lang.SuppressWarnings("all") + private A field1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList items; + + @java.lang.SuppressWarnings("all") + protected abstract B self(); + + @java.lang.SuppressWarnings("all") + public abstract C build(); + + @java.lang.SuppressWarnings("all") + public B field1(final A field1) { + this.field1 = field1; + return self(); + } + + @java.lang.SuppressWarnings("all") + public B item(final String item) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + + @java.lang.SuppressWarnings("all") + public B items(final java.util.Collection items) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + + @java.lang.SuppressWarnings("all") + public B clearItems() { + if (this.items != null) this.items.clear(); + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + @java.lang.SuppressWarnings("all") + private ParentBuilderImpl() { + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ParentBuilderImpl self() { + return this; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Parent build() { + return new Parent(this); + } + } + + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + + @lombok.experimental.SuperBuilder + public static class Child extends Parent { + double field3; + + @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private double field3; + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected abstract B self(); + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public abstract C build(); + + @java.lang.SuppressWarnings("all") + public B field3(final double field3) { + this.field3 = field3; + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { + @java.lang.SuppressWarnings("all") + private ChildBuilderImpl() { + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ChildBuilderImpl self() { + return this; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Child build() { + return new Child(this); + } + } + + @java.lang.SuppressWarnings("all") + public static ChildBuilder builder() { + return new ChildBuilderImpl(); + } + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} -- cgit From ee51d77dd664ec13d3d3748798bfc74531594171 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Fri, 11 May 2018 14:41:38 +0200 Subject: ecj: type params for constructor, abstract builder class, self method --- .../eclipse/handlers/HandleSuperBuilder.java | 79 ++++++---------- .../resource/after-ecj/SuperBuilderBasic.java | 100 +++++++-------------- 2 files changed, 58 insertions(+), 121 deletions(-) (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 486e8f91..3a0b76f9 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -58,6 +58,7 @@ import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeParameter; import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; @@ -393,7 +394,10 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart; constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd; - constructor.arguments = null; + + TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND)}; + TypeReference builderType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), wildcards, 0, p); + constructor.arguments = new Argument[] {new Argument("b".toCharArray(), p, builderType, Modifier.FINAL)}; List statements = new ArrayList(); List nullChecks = new ArrayList(); @@ -428,7 +432,6 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { nullChecks.addAll(statements); constructor.statements = nullChecks.isEmpty() ? null : nullChecks.toArray(new Statement[nullChecks.size()]); - constructor.arguments = new Argument[] {new Argument("b".toCharArray(), p, new SingleTypeReference(builderClassName.toCharArray(), p), Modifier.FINAL)}; constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope); @@ -448,21 +451,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { // } private MethodDeclaration generateAbstractSelfMethod(EclipseNode tdParent, boolean override, String builderGenericName) { -// JavacTreeMaker maker = tdParent.getTreeMaker(); -// List annotations = List.nil(); -// if (override) { -// JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(tdParent, "Override"), List.nil()); -// annotations = List.of(overrideAnnotation); -// } -// JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED | Flags.ABSTRACT, annotations); -// Name name = tdParent.toName(SELF_METHOD); -// JCExpression returnType = maker.Ident(tdParent.toName(builderGenericName)); -// -// return maker.MthodDef(modifiers, name, returnType, List.nil(), List.nil(), List.nil(), null, null); + // TODO: @Override annotation if override == true. MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); out.selector = SELF_METHOD.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.modifiers = ClassFileConstants.AccAbstract; + out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected; out.returnType = new SingleTypeReference(builderGenericName.toCharArray(), 0); return out; } @@ -770,22 +763,6 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { return null; } - private TypeParameter[] copyTypeParamsAndAddBuilderParams(TypeParameter[] typeParams, ASTNode source, String classGenericName, String builderGenericName) { - TypeParameter[] result = Arrays.copyOf(copyTypeParams(typeParams, source), typeParams.length + 2); - - TypeParameter o = new TypeParameter(); - setGeneratedBy(o, source); - o.name = classGenericName.toCharArray(); - result[result.length - 2] = o; - - o = new TypeParameter(); - setGeneratedBy(o, source); - o.name = builderGenericName.toCharArray(); - result[result.length - 1] = o; - - return result; - } - public EclipseNode makeBuilderAbstractClass(EclipseNode tdParent, String builderClass, TypeReference superclassBuilderClass, TypeParameter[] typeParams, TypeParameter[] superclassTypeParams, ASTNode source, String classGenericName, String builderGenericName) { @@ -795,28 +772,26 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; builder.modifiers |= ClassFileConstants.AccPublic | ClassFileConstants.AccStatic | ClassFileConstants.AccAbstract; builder.name = builderClass.toCharArray(); - builder.typeParameters = copyTypeParamsAndAddBuilderParams(typeParams, source, classGenericName, builderGenericName); - builder.superclass = superclassBuilderClass; -// // Keep any type params of the annotated class. -// ListBuffer allTypeParams = new ListBuffer(); -// allTypeParams.addAll(copyTypeParams(source, typeParams)); -// // Add builder-specific type params required for inheritable builders. -// // 1. The return type for the build() method, named "C", which extends the annotated class. -// JCExpression annotatedClass = maker.Ident(tdParent.toName(tdParent.getName())); -// if (typeParams.nonEmpty()) { -// // Add type params of the annotated class. -// annotatedClass = maker.TypeApply(annotatedClass, getTypeParamExpressions(typeParams, maker).toList()); -// } -// allTypeParams.add(maker.TypeParameter(tdParent.toName(classGenericName), List.of(annotatedClass))); -// // 2. The return type for all setter methods, named "B", which extends this builder class. -// Name builderClassName = tdParent.toName(builderClass); -// ListBuffer typeParamsForBuilder = getTypeParamExpressions(typeParams, maker); -// typeParamsForBuilder.add(maker.Ident(tdParent.toName(classGenericName))); -// typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName))); -// JCTypeApply typeApply = maker.TypeApply(maker.Ident(builderClassName), typeParamsForBuilder.toList()); -// allTypeParams.add(maker.TypeParameter(tdParent.toName(builderGenericName), List.of(typeApply))); -// + // Keep any type params of the annotated class. + builder.typeParameters = Arrays.copyOf(copyTypeParams(typeParams, source), typeParams.length + 2); + // Add builder-specific type params required for inheritable builders. + // 1. The return type for the build() method, named "C", which extends the annotated class. + TypeParameter o = new TypeParameter(); + o.name = classGenericName.toCharArray(); + o.type = cloneSelfType(tdParent, source); + builder.typeParameters[builder.typeParameters.length - 2] = o; + // 2. The return type for all setter methods, named "B", which extends this builder class. + o = new TypeParameter(); + o.name = builderGenericName.toCharArray(); + TypeReference[] typerefs = new TypeReference[] { + new SingleTypeReference(classGenericName.toCharArray(), 0), + new SingleTypeReference(builderGenericName.toCharArray(), 0) + }; + o.type = new ParameterizedSingleTypeReference(builderClass.toCharArray(), typerefs, 0, 0); + builder.typeParameters[builder.typeParameters.length - 1] = o; + + builder.superclass = superclassBuilderClass; // JCExpression extending = null; // if (superclassBuilderClassExpression != null) { // // If the annotated class extends another class, we want this builder to extend the builder of the superclass. @@ -827,8 +802,6 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { // typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName))); // extending = maker.TypeApply(superclassBuilderClassExpression, typeParamsForBuilder.toList()); // } -// -// JCClassDecl builder = maker.ClassDef(mods, builderClassName, allTypeParams.toList(), extending, List.nil(), List.nil()); builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return injectType(tdParent, builder); diff --git a/test/transform/resource/after-ecj/SuperBuilderBasic.java b/test/transform/resource/after-ecj/SuperBuilderBasic.java index cc86e05c..cecf82f7 100644 --- a/test/transform/resource/after-ecj/SuperBuilderBasic.java +++ b/test/transform/resource/after-ecj/SuperBuilderBasic.java @@ -1,99 +1,63 @@ import java.util.List; - public class SuperBuilderBasic { public static @lombok.experimental.SuperBuilder class Parent { - int field1; - @lombok.Singular List items; - - protected Parent(final ParentBuilder b) { - this.field1 = b.field1; - java.util.List items; - switch (b.items == null ? 0 : b.items.size()) { - case 0: - items = java.util.Collections.emptyList(); - break; - - case 1: - items = java.util.Collections.singletonList(b.items.get(0)); - break; - - default: - items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); - } - this.items = items; - } - - - @java.lang.SuppressWarnings("all") - public static abstract class ParentBuilder> { - @java.lang.SuppressWarnings("all") - private int field1; - @java.lang.SuppressWarnings("all") - private java.util.ArrayList items; - - @java.lang.SuppressWarnings("all") - protected abstract B self(); - - @java.lang.SuppressWarnings("all") - public abstract C build(); - - @java.lang.SuppressWarnings("all") - public B field1(final int field1) { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder> { + private @java.lang.SuppressWarnings("all") int field1; + private @java.lang.SuppressWarnings("all") java.util.ArrayList items; + protected abstract @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B field1(final int field1) { this.field1 = field1; return self(); } - - @java.lang.SuppressWarnings("all") - public B item(final String item) { + public @java.lang.SuppressWarnings("all") B item(final String item) { if (this.items == null) this.items = new java.util.ArrayList(); this.items.add(item); return self(); } - - @java.lang.SuppressWarnings("all") - public B items(final java.util.Collection items) { + public @java.lang.SuppressWarnings("all") B items(final java.util.Collection items) { if (this.items == null) this.items = new java.util.ArrayList(); this.items.addAll(items); return self(); } - - @java.lang.SuppressWarnings("all") - public B clearItems() { + public @java.lang.SuppressWarnings("all") B clearItems() { if (this.items != null) this.items.clear(); return self(); } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - public java.lang.String toString() { + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { return "SuperBuilderBasic.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; } } - - - @java.lang.SuppressWarnings("all") - private static final class ParentBuilderImpl extends ParentBuilder { - @java.lang.SuppressWarnings("all") - private ParentBuilderImpl() { + private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder { + private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - protected ParentBuilderImpl self() { + protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { return this; } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - public Parent build() { + public @java.lang.Override @java.lang.SuppressWarnings("all") Parent build() { return new Parent(this); } } - - @java.lang.SuppressWarnings("all") - public static ParentBuilder builder() { + public @java.lang.SuppressWarnings("all") static ParentBuilder builder() { return new ParentBuilderImpl(); } + int field1; + @lombok.Singular List items; + protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } } public static @lombok.experimental.SuperBuilder class Child extends Parent { -- cgit From fb401d4887895d1ebb8529d6323797f1bc8072a2 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Fri, 11 May 2018 17:19:47 +0200 Subject: ecj: setter methods now return self() --- .../eclipse/handlers/EclipseSingularsRecipes.java | 35 +++++++++- src/core/lombok/eclipse/handlers/HandleSetter.java | 34 ++++++---- .../eclipse/handlers/HandleSuperBuilder.java | 79 +++++++++------------- .../singulars/EclipseGuavaSingularizer.java | 18 ++--- .../EclipseJavaUtilListSetSingularizer.java | 20 ++---- .../singulars/EclipseJavaUtilMapSingularizer.java | 20 ++---- .../javac/handlers/JavacSingularsRecipes.java | 2 +- .../resource/after-ecj/SuperBuilderBasic.java | 13 ++-- 8 files changed, 114 insertions(+), 107 deletions(-) (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java index 2cec2388..ac4e5c7b 100644 --- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java +++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java @@ -30,6 +30,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; @@ -46,6 +47,7 @@ import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.Reference; +import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.Statement; @@ -55,6 +57,7 @@ import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import lombok.core.LombokImmutableList; import lombok.core.SpiLoadUtil; @@ -217,7 +220,37 @@ public class EclipseSingularsRecipes { } public abstract List generateFields(SingularData data, EclipseNode builderType); - public abstract void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, boolean chain); + + /** + * Generates the singular, plural, and clear methods for the given + * {@link SingularData}.
+ * Uses the given builderType as return type if + * chain == true, void otherwise. If you need more + * control over the return type and value, use + * {@link #generateMethods(SingularData, boolean, EclipseNode, boolean, Supplier, Supplier)}. + */ + public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, boolean chain) { + // TODO: Make these lambdas when switching to a source level >= 1.8. + Supplier returnType = new Supplier() { + @Override public TypeReference get() { + return chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); + } + }; + Supplier returnStatement = new Supplier() { + @Override public ReturnStatement get() { + return chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; + } + }; + generateMethods(data, deprecate, builderType, fluent, returnType, returnStatement); + } + + /** + * Generates the singular, plural, and clear methods for the given + * {@link SingularData}.
+ * Uses the given returnType and returnStatement for the generated methods. + */ + public abstract void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, Supplier returnType, Supplier returnStatement); + public abstract void appendBuildCode(SingularData data, EclipseNode builderType, List statements, char[] targetVariableName, String builderVariable); public boolean requiresCleaning() { diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index 6a9a5123..434939a6 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -119,7 +119,7 @@ public class HandleSetter extends EclipseAnnotationHandler { createSetterForField(level, fieldNode, sourceNode, false, empty, empty); } - public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { + @Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) { handleFlagUsage(annotationNode, ConfigurationKeys.SETTER_FLAG_USAGE, "@Setter"); EclipseNode node = annotationNode.up(); @@ -196,22 +196,34 @@ public class HandleSetter extends EclipseAnnotationHandler { MethodDeclaration method = createSetter((TypeDeclaration) fieldNode.up().get(), false, fieldNode, setterName, null, shouldReturnThis, modifier, sourceNode, onMethod, onParam); injectMethod(fieldNode.up(), method); } - + static MethodDeclaration createSetter(TypeDeclaration parent, boolean deprecate, EclipseNode fieldNode, String name, char[] booleanFieldToSet, boolean shouldReturnThis, int modifier, EclipseNode sourceNode, List onMethod, List onParam) { + ASTNode source = sourceNode.get(); + int pS = source.sourceStart, pE = source.sourceEnd; + + TypeReference returnType = null; + ReturnStatement returnThis = null; + if (shouldReturnThis) { + returnType = cloneSelfType(fieldNode, source); + ThisReference thisRef = new ThisReference(pS, pE); + returnThis = new ReturnStatement(thisRef, pS, pE); + } + + return createSetter(parent, deprecate, fieldNode, name, booleanFieldToSet, returnType, returnThis, modifier, sourceNode, onMethod, onParam); + } + + static MethodDeclaration createSetter(TypeDeclaration parent, boolean deprecate, EclipseNode fieldNode, String name, char[] booleanFieldToSet, TypeReference returnType, ReturnStatement returnStatement, int modifier, EclipseNode sourceNode, List onMethod, List onParam) { FieldDeclaration field = (FieldDeclaration) fieldNode.get(); ASTNode source = sourceNode.get(); int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; MethodDeclaration method = new MethodDeclaration(parent.compilationResult); method.modifiers = modifier; - if (shouldReturnThis) { - method.returnType = cloneSelfType(fieldNode, source); - } - - if (method.returnType == null) { + if (returnType != null) { + method.returnType = returnType; + } else { method.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0); method.returnType.sourceStart = pS; method.returnType.sourceEnd = pE; - shouldReturnThis = false; } Annotation[] deprecated = null; if (isFieldDeprecated(fieldNode) || deprecate) { @@ -248,10 +260,8 @@ public class HandleSetter extends EclipseAnnotationHandler { statements.add(new Assignment(new SingleNameReference(booleanFieldToSet, p), new TrueLiteral(pS, pE), pE)); } - if (shouldReturnThis) { - ThisReference thisRef = new ThisReference(pS, pE); - ReturnStatement returnThis = new ReturnStatement(thisRef, pS, pE); - statements.add(returnThis); + if (returnType != null && returnStatement != null) { + statements.add(returnStatement); } method.statements = statements.toArray(new Statement[0]); param.annotations = copyAnnotations(source, nonNulls, nullables, onParam.toArray(new Annotation[0])); diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 3a0b76f9..473a2b9b 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.function.Supplier; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; @@ -45,6 +46,7 @@ import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FalseLiteral; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldReference; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; @@ -208,7 +210,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { // } if (extendsClause instanceof QualifiedTypeReference) { QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference)extendsClause; - String superclassClassName = qualifiedTypeReference.getLastToken().toString(); + String superclassClassName = String.valueOf(qualifiedTypeReference.getLastToken()); String superclassBuilderClassName = superclassClassName + "Builder"; char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1); tokens[tokens.length] = superclassBuilderClassName.toCharArray(); @@ -216,8 +218,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { Arrays.fill(poss, p); superclassBuilderClass = new QualifiedTypeReference(tokens, poss); } else if (extendsClause != null) { - String superclassBuilderClassName = extendsClause.getTypeName().toString() + "Builder"; - char[][] tokens = new char[][] {extendsClause.getTypeName().toString().toCharArray(), superclassBuilderClassName.toCharArray()}; + String superClass = String.valueOf(extendsClause.getTypeName()[0]); + String superclassBuilderClassName = superClass + "Builder"; + char[][] tokens = new char[][] {superClass.toCharArray(), superclassBuilderClassName.toCharArray()}; long[] poss = new long[tokens.length]; Arrays.fill(poss, p); superclassBuilderClass = new QualifiedTypeReference(tokens, poss); @@ -563,7 +566,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { // return maker.MethodDef(modifiers, type.toName(buildName), returnType, List.nil(), List.nil(), thrownExceptions, body, null); // } - public MethodDeclaration generateDefaultProvider(char[] methodName, TypeParameter[] typeParameters, EclipseNode fieldNode, ASTNode source) { + private MethodDeclaration generateDefaultProvider(char[] methodName, TypeParameter[] typeParameters, EclipseNode fieldNode, ASTNode source) { int pS = source.sourceStart, pE = source.sourceEnd; MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) fieldNode.top().get()).compilationResult); @@ -591,7 +594,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { // return maker.MethodDef(maker.Modifiers(modifiers), methodName, cloneType(maker, field.vartype, field, fieldNode.getContext()), copyTypeParams(fieldNode, params), List.nil(), List.nil(), body, null); // } - public MethodDeclaration generateBuilderMethod(String builderMethodName, String builderClassName, String builderImplClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { + private MethodDeclaration generateBuilderMethod(String builderMethodName, String builderClassName, String builderImplClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long) pS << 32 | pE; @@ -635,7 +638,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { // return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.nil(), List.nil(), body, null); // } - public void generateBuilderFields(EclipseNode builderType, List builderFields, ASTNode source) { + private void generateBuilderFields(EclipseNode builderType, List builderFields, ASTNode source) { List existing = new ArrayList(); for (EclipseNode child : builderType.down()) { if (child.getKind() == Kind.FIELD) { @@ -679,28 +682,32 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { } } - public void makeSetterMethodsForBuilder(EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, String builderGenericName) { + private void makeSetterMethodsForBuilder(EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, String builderGenericName) { boolean deprecate = isFieldDeprecated(bfd.originalFieldNode); + + // TODO: Make these lambdas when switching to a source level >= 1.8. + Supplier returnType = new Supplier() { + @Override public TypeReference get() { + return new SingleTypeReference(builderGenericName.toCharArray(), 0); + } + }; + Supplier returnStatement = new Supplier() { + @Override public ReturnStatement get() { + MessageSend returnCall = new MessageSend(); + returnCall.receiver = ThisReference.implicitThis(); + returnCall.selector = SELF_METHOD.toCharArray(); + return new ReturnStatement(returnCall, 0, 0); + } + }; if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) { - makeSimpleSetterMethodForBuilder(builderType, deprecate, bfd.createdFields.get(0), bfd.nameOfSetFlag, sourceNode); + makeSimpleSetterMethodForBuilder(builderType, deprecate, bfd.createdFields.get(0), bfd.nameOfSetFlag, returnType.get(), returnStatement.get(), sourceNode); } else { - bfd.singularData.getSingularizer().generateMethods(bfd.singularData, deprecate, builderType, true, true); + bfd.singularData.getSingularizer().generateMethods(bfd.singularData, deprecate, builderType, true, returnType, returnStatement); } } -// public void makeSetterMethodsForBuilder(EclipseNode builderType, BuilderFieldData fieldNode, EclipseNode source, String builderGenericName) { -// boolean deprecate = isFieldDeprecated(fieldNode.originalFieldNode); -// JavacTreeMaker maker = builderType.getTreeMaker(); -// JCExpression returnType = maker.Ident(builderType.toName(builderGenericName)); -// JCReturn returnStatement = maker.Return(maker.Apply(List.nil(), maker.Ident(builderType.toName(SELF_METHOD)), List.nil())); -// if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) { -// makeSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.nameOfSetFlag, source, true, true, returnType, returnStatement); -// } else { -// fieldNode.singularData.getSingularizer().generateMethods(fieldNode.singularData, deprecate, builderType, source.get(), true, returnType, returnStatement); -// } -// } private static final AbstractMethodDeclaration[] EMPTY = {}; - private void makeSimpleSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] nameOfSetFlag, EclipseNode sourceNode) { + private void makeSimpleSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] nameOfSetFlag, TypeReference returnType, ReturnStatement returnStatement, EclipseNode sourceNode) { TypeDeclaration td = (TypeDeclaration) builderType.get(); AbstractMethodDeclaration[] existing = td.methods; if (existing == null) { @@ -722,34 +729,12 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { String setterName = fieldNode.getName(); - MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, nameOfSetFlag, true, ClassFileConstants.AccPublic, + MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, nameOfSetFlag, returnType, returnStatement, ClassFileConstants.AccPublic, sourceNode, Collections.emptyList(), Collections.emptyList()); injectMethod(builderType, setter); } -// private void makeSimpleSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, Name nameOfSetFlag, EclipseNode source, boolean fluent, boolean chain, JCExpression returnType, JCReturn returnStatement) { -// Name fieldName = ((JCVariableDecl) fieldNode.get()).name; -// -// for (EclipseNode child : builderType.down()) { -// if (child.getKind() != Kind.METHOD) { -// continue; -// } -// MethodDeclaration methodDecl = (MethodDeclaration) child.get(); -// Name existingName = methodDecl.name; -// if (existingName.equals(fieldName) && !isTolerate(fieldNode, methodDecl)) { -// return; -// } -// } -// -// String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName()); -// -// JavacTreeMaker maker = fieldNode.getTreeMaker(); -// -// MethodDeclaration newMethod = HandleSetter.createSetter(Flags.PUBLIC, deprecate, fieldNode, maker, setterName, nameOfSetFlag, returnType, returnStatement, source, List.nil(), List.nil()); -// -// injectMethod(builderType, newMethod); -// } - public EclipseNode findInnerClass(EclipseNode parent, String name) { + private EclipseNode findInnerClass(EclipseNode parent, String name) { char[] c = name.toCharArray(); for (EclipseNode child : parent.down()) { if (child.getKind() != Kind.TYPE) { @@ -763,7 +748,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { return null; } - public EclipseNode makeBuilderAbstractClass(EclipseNode tdParent, String builderClass, + private EclipseNode makeBuilderAbstractClass(EclipseNode tdParent, String builderClass, TypeReference superclassBuilderClass, TypeParameter[] typeParams, TypeParameter[] superclassTypeParams, ASTNode source, String classGenericName, String builderGenericName) { @@ -807,7 +792,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { return injectType(tdParent, builder); } - public EclipseNode makeBuilderImplClass(EclipseNode tdParent, String builderImplClass, String builderAbstractClass, TypeParameter[] typeParams, ASTNode source) { + private EclipseNode makeBuilderImplClass(EclipseNode tdParent, String builderImplClass, String builderAbstractClass, TypeParameter[] typeParams, ASTNode source) { TypeDeclaration parent = (TypeDeclaration) tdParent.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java index eb2c9b35..d6c63944 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -27,6 +27,7 @@ import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.Supplier; import lombok.core.GuavaTypeMap; import lombok.core.LombokImmutableList; @@ -58,7 +59,6 @@ import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; abstract class EclipseGuavaSingularizer extends EclipseSingularizer { protected String getSimpleTargetTypeName(SingularData data) { @@ -97,18 +97,10 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField)); } - @Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, boolean chain) { - TypeReference returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); - Statement returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; - generateSingularMethod(deprecate, returnType, returnStatement, data, builderType, fluent); - - returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); - returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; - generatePluralMethod(deprecate, returnType, returnStatement, data, builderType, fluent); - - returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); - returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; - generateClearMethod(deprecate, returnType, returnStatement, data, builderType); + @Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, Supplier returnType, Supplier returnStatement) { + generateSingularMethod(deprecate, returnType.get(), returnStatement.get(), data, builderType, fluent); + generatePluralMethod(deprecate, returnType.get(), returnStatement.get(), data, builderType, fluent); + generateClearMethod(deprecate, returnType.get(), returnStatement.get(), data, builderType); } void generateClearMethod(boolean deprecate, TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType) { diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java index cfa48eaf..0851757f 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java @@ -27,6 +27,7 @@ import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.function.Supplier; import lombok.core.handlers.HandlerUtil; import lombok.eclipse.EclipseNode; @@ -52,7 +53,6 @@ import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingularizer { @Override public List listFieldsToBeGenerated(SingularData data, EclipseNode builderType) { @@ -88,23 +88,15 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula return Collections.singletonList(injectFieldAndMarkGenerated(builderType, buildField)); } - @Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, boolean chain) { + @Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, Supplier returnType, Supplier returnStatement) { if (useGuavaInstead(builderType)) { - guavaListSetSingularizer.generateMethods(data, deprecate, builderType, fluent, chain); + guavaListSetSingularizer.generateMethods(data, deprecate, builderType, fluent, returnType, returnStatement); return; } - TypeReference returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); - Statement returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; - generateSingularMethod(deprecate, returnType, returnStatement, data, builderType, fluent); - - returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); - returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; - generatePluralMethod(deprecate, returnType, returnStatement, data, builderType, fluent); - - returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); - returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; - generateClearMethod(deprecate, returnType, returnStatement, data, builderType); + generateSingularMethod(deprecate, returnType.get(), returnStatement.get(), data, builderType, fluent); + generatePluralMethod(deprecate, returnType.get(), returnStatement.get(), data, builderType, fluent); + generateClearMethod(deprecate, returnType.get(), returnStatement.get(), data, builderType); } private void generateClearMethod(boolean deprecate, TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType) { diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java index ee0e6409..976d9265 100644 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.function.Supplier; import org.eclipse.jdt.internal.compiler.ast.Annotation; import org.eclipse.jdt.internal.compiler.ast.Argument; @@ -51,7 +52,6 @@ import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.mangosdk.spi.ProviderFor; import lombok.core.LombokImmutableList; @@ -133,23 +133,15 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer return Arrays.asList(keyFieldNode, valueFieldNode); } - @Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, boolean chain) { + @Override public void generateMethods(SingularData data, boolean deprecate, EclipseNode builderType, boolean fluent, Supplier returnType, Supplier returnStatement) { if (useGuavaInstead(builderType)) { - guavaMapSingularizer.generateMethods(data, deprecate, builderType, fluent, chain); + guavaMapSingularizer.generateMethods(data, deprecate, builderType, fluent, returnType, returnStatement); return; } - TypeReference returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); - Statement returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; - generateSingularMethod(deprecate, returnType, returnStatement, data, builderType, fluent); - - returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); - returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; - generatePluralMethod(deprecate, returnType, returnStatement, data, builderType, fluent); - - returnType = chain ? cloneSelfType(builderType) : TypeReference.baseTypeReference(TypeIds.T_void, 0); - returnStatement = chain ? new ReturnStatement(new ThisReference(0, 0), 0, 0) : null; - generateClearMethod(deprecate, returnType, returnStatement, data, builderType); + generateSingularMethod(deprecate, returnType.get(), returnStatement.get(), data, builderType, fluent); + generatePluralMethod(deprecate, returnType.get(), returnStatement.get(), data, builderType, fluent); + generateClearMethod(deprecate, returnType.get(), returnStatement.get(), data, builderType); } private void generateClearMethod(boolean deprecate, TypeReference returnType, Statement returnStatement, SingularData data, EclipseNode builderType) { diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java index d6b1df44..67862355 100644 --- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java +++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java @@ -200,7 +200,7 @@ public class JavacSingularsRecipes { * Generates the singular, plural, and clear methods for the given * {@link SingularData}.
* Uses the given builderType as return type if - * chain == true, void otherwise.. If you need more + * chain == true, void otherwise. If you need more * control over the return type and value, use * {@link #generateMethods(SingularData, boolean, JavacNode, JCTree, boolean, JCExpression, JCStatement)}. */ diff --git a/test/transform/resource/after-ecj/SuperBuilderBasic.java b/test/transform/resource/after-ecj/SuperBuilderBasic.java index cecf82f7..7315760c 100644 --- a/test/transform/resource/after-ecj/SuperBuilderBasic.java +++ b/test/transform/resource/after-ecj/SuperBuilderBasic.java @@ -10,18 +10,21 @@ public class SuperBuilderBasic { this.field1 = field1; return self(); } - public @java.lang.SuppressWarnings("all") B item(final String item) { - if (this.items == null) this.items = new java.util.ArrayList(); + public @java.lang.SuppressWarnings("all") B item(String item) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); this.items.add(item); return self(); } - public @java.lang.SuppressWarnings("all") B items(final java.util.Collection items) { - if (this.items == null) this.items = new java.util.ArrayList(); + public @java.lang.SuppressWarnings("all") B items(java.util.Collection items) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); this.items.addAll(items); return self(); } public @java.lang.SuppressWarnings("all") B clearItems() { - if (this.items != null) this.items.clear(); + if ((this.items != null)) + this.items.clear(); return self(); } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { -- cgit From 5d35fe3bfbd46de7410bca96e29731e8f5236618 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Mon, 14 May 2018 17:59:45 +0200 Subject: ecj: method body for self(); type args for BuilderImpl extends clause --- .../eclipse/handlers/HandleSuperBuilder.java | 46 ++++++---------------- .../resource/after-ecj/SuperBuilderBasic.java | 34 ++++++++-------- 2 files changed, 30 insertions(+), 50 deletions(-) (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 473a2b9b..d01e250d 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -478,8 +478,10 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderImplType.top().get()).compilationResult); out.selector = SELF_METHOD.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.modifiers = ClassFileConstants.AccAbstract; + out.modifiers = ClassFileConstants.AccProtected; + out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, builderImplType.get())}; out.returnType = new SingleTypeReference(builderImplType.getName().toCharArray(), 0); + out.statements = new Statement[] {new ReturnStatement(new ThisReference(0, 0), 0, 0)}; return out; } @@ -536,6 +538,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { out.selector = name.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.returnType = returnType; + out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source)}; AllocationExpression allocationStatement = new AllocationExpression(); allocationStatement.type = copyType(out.returnType); @@ -777,6 +780,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { builder.typeParameters[builder.typeParameters.length - 1] = o; builder.superclass = superclassBuilderClass; + // TODO: Extends clause when there is a superclass. // JCExpression extending = null; // if (superclassBuilderClassExpression != null) { // // If the annotated class extends another class, we want this builder to extend the builder of the superclass. @@ -796,45 +800,19 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { TypeDeclaration parent = (TypeDeclaration) tdParent.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; - builder.modifiers |= ClassFileConstants.AccPublic; - builder.modifiers |= ClassFileConstants.AccStatic; - builder.typeParameters = copyTypeParams(typeParams, source); + builder.modifiers |= ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal; builder.name = builderImplClass.toCharArray(); if (builderAbstractClass != null) { - builder.superclass = new SingleTypeReference(builderAbstractClass.toCharArray(), 0); + // Extend the abstract builder. + // TODO: 1. Add any type params of the annotated class. + // 2. The return type for the build() method (named "C" in the abstract builder), which is the annotated class. + // 3. The return type for all setter methods (named "B" in the abstract builder), which is this builder class. + TypeReference[] typeArgs = new TypeReference[] {cloneSelfType(tdParent, source), new SingleTypeReference(builderImplClass.toCharArray(), 0)}; + builder.superclass = new ParameterizedSingleTypeReference(builderAbstractClass.toCharArray(), typeArgs, 0, 0); } builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return injectType(tdParent, builder); } -// public EclipseNode makeBuilderImplClass(EclipseNode source, EclipseNode tdParent, String builderImplClass, String builderAbstractClass, List typeParams, JCAnnotation ast) { -// JavacTreeMaker maker = tdParent.getTreeMaker(); -// JCModifiers mods = maker.Modifiers(Flags.STATIC | Flags.PRIVATE | Flags.FINAL); -// -// // Extend the abstract builder. -// JCExpression extending = maker.Ident(tdParent.toName(builderAbstractClass)); -// // Add any type params of the annotated class. -// ListBuffer allTypeParams = new ListBuffer(); -// allTypeParams.addAll(copyTypeParams(source, typeParams)); -// // Add builder-specific type params required for inheritable builders. -// // 1. The return type for the build() method (named "C" in the abstract builder), which is the annotated class. -// JCExpression annotatedClass = maker.Ident(tdParent.toName(tdParent.getName())); -// if (typeParams.nonEmpty()) { -// // Add type params of the annotated class. -// annotatedClass = maker.TypeApply(annotatedClass, getTypeParamExpressions(typeParams, maker).toList()); -// } -// // 2. The return type for all setter methods (named "B" in the abstract builder), which is this builder class. -// JCExpression builderImplClassExpression = maker.Ident(tdParent.toName(builderImplClass)); -// if (typeParams.nonEmpty()) { -// builderImplClassExpression = maker.TypeApply(builderImplClassExpression, getTypeParamExpressions(typeParams, maker).toList()); -// } -// ListBuffer typeParamsForBuilder = getTypeParamExpressions(typeParams, maker); -// typeParamsForBuilder.add(annotatedClass); -// typeParamsForBuilder.add(builderImplClassExpression); -// extending = maker.TypeApply(extending, typeParamsForBuilder.toList()); -// -// JCClassDecl builder = maker.ClassDef(mods, tdParent.toName(builderImplClass), copyTypeParams(source, typeParams), extending, List.nil(), List.nil()); -// return injectType(tdParent, builder); -// } private void addObtainVia(BuilderFieldData bfd, EclipseNode node) { for (EclipseNode child : node.down()) { diff --git a/test/transform/resource/after-ecj/SuperBuilderBasic.java b/test/transform/resource/after-ecj/SuperBuilderBasic.java index 7315760c..d293c8f8 100644 --- a/test/transform/resource/after-ecj/SuperBuilderBasic.java +++ b/test/transform/resource/after-ecj/SuperBuilderBasic.java @@ -12,27 +12,28 @@ public class SuperBuilderBasic { } public @java.lang.SuppressWarnings("all") B item(String item) { if ((this.items == null)) - this.items = new java.util.ArrayList(); + this.items = new java.util.ArrayList(); this.items.add(item); return self(); } public @java.lang.SuppressWarnings("all") B items(java.util.Collection items) { if ((this.items == null)) - this.items = new java.util.ArrayList(); + this.items = new java.util.ArrayList(); this.items.addAll(items); return self(); } public @java.lang.SuppressWarnings("all") B clearItems() { if ((this.items != null)) - this.items.clear(); + this.items.clear(); return self(); } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { - return "SuperBuilderBasic.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; + return (((("SuperBuilderBasic.Parent.ParentBuilder(field1=" + this.field1) + ", items=") + this.items) + ")"); } } private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder { private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { + super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { return this; @@ -41,26 +42,27 @@ public class SuperBuilderBasic { return new Parent(this); } } - public @java.lang.SuppressWarnings("all") static ParentBuilder builder() { - return new ParentBuilderImpl(); - } int field1; @lombok.Singular List items; protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + super(); this.field1 = b.field1; java.util.List items; - switch (b.items == null ? 0 : b.items.size()) { - case 0: - items = java.util.Collections.emptyList(); - break; - case 1: - items = java.util.Collections.singletonList(b.items.get(0)); - break; - default: - items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + switch (((b.items == null) ? 0 : b.items.size())) { + case 0 : + items = java.util.Collections.emptyList(); + break; + case 1 : + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default : + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); } this.items = items; } + public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { + return new ParentBuilderImpl(); + } } public static @lombok.experimental.SuperBuilder class Child extends Parent { -- cgit From 55976fec127e7674222f81e46532755081ffb454 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Thu, 17 May 2018 20:36:40 +0200 Subject: ecj: remaining type args for non-generic class builders --- .../eclipse/handlers/HandleSuperBuilder.java | 199 +++++++-------------- .../resource/after-ecj/SuperBuilderBasic.java | 71 +++----- 2 files changed, 82 insertions(+), 188 deletions(-) (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index d01e250d..71683516 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -199,49 +199,61 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { // Set the names of the builder classes. String builderClassName = String.valueOf(td.name) + "Builder"; String builderImplClassName = builderClassName + "Impl"; + + typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0]; + returnType = namePlusTypeParamsToTypeReference(td.name, typeParams, p); + + // are the generics for our builder. + String classGenericName = "C"; + String builderGenericName = "B"; + // If these generics' names collide with any generics on the annotated class, modify them. + // For instance, if there are generics on the annotated class, use "C2" and "B3" for our builder. + java.util.List typeParamStrings = new ArrayList(); + for (TypeParameter typeParam : typeParams) { + typeParamStrings.add(typeParam.toString()); + } + classGenericName = generateNonclashingNameFor(classGenericName, typeParamStrings); + builderGenericName = generateNonclashingNameFor(builderGenericName, typeParamStrings); TypeReference extendsClause = td.superclass; TypeReference superclassBuilderClass = null; -// if (extendsClause.getTypeArguments() != null) { -// // Remember the type arguments, because we need them for the extends clause of our abstract builder class. -// superclassTypeParams = ((JCTypeApply)extendsClause).getTypeArguments(); -// // A class name with a generics type, e.g., "Superclass
". -// extendsClause = ((JCTypeApply)extendsClause).getType(); -// } + TypeReference[] typeArguments = new TypeReference[] { + new SingleTypeReference(classGenericName.toCharArray(), 0), + new SingleTypeReference(builderGenericName.toCharArray(), 0) + }; if (extendsClause instanceof QualifiedTypeReference) { QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference)extendsClause; String superclassClassName = String.valueOf(qualifiedTypeReference.getLastToken()); String superclassBuilderClassName = superclassClassName + "Builder"; + char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1); tokens[tokens.length] = superclassBuilderClassName.toCharArray(); long[] poss = new long[tokens.length]; Arrays.fill(poss, p); - superclassBuilderClass = new QualifiedTypeReference(tokens, poss); + + // Every token may potentially have type args. Here, we only have + // type args for the last token, the superclass' builder. + TypeReference[][] typeArgsForTokens = new TypeReference[tokens.length][]; + typeArgsForTokens[typeArgsForTokens.length-1] = typeArguments; + + superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss); } else if (extendsClause != null) { String superClass = String.valueOf(extendsClause.getTypeName()[0]); String superclassBuilderClassName = superClass + "Builder"; + char[][] tokens = new char[][] {superClass.toCharArray(), superclassBuilderClassName.toCharArray()}; long[] poss = new long[tokens.length]; Arrays.fill(poss, p); - superclassBuilderClass = new QualifiedTypeReference(tokens, poss); - } - // If there is no superclass, superclassBuilderClassExpression is still == null at this point. - // You can use it to check whether to inherit or not. - typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0]; - returnType = namePlusTypeParamsToTypeReference(td.name, typeParams, p); + // Every token may potentially have type args. Here, we only have + // type args for the last token, the superclass' builder. + TypeReference[][] typeArgsForTokens = new TypeReference[tokens.length][]; + typeArgsForTokens[typeArgsForTokens.length-1] = typeArguments; - // are the generics for our builder. - String classGenericName = "C"; - String builderGenericName = "B"; - // If these generics' names collide with any generics on the annotated class, modify them. - // For instance, if there are generics on the annotated class, use "C2" and "B3" for our builder. - java.util.List typeParamStrings = new ArrayList(); - for (TypeParameter typeParam : typeParams) { - typeParamStrings.add(typeParam.toString()); + superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss); } - classGenericName = generateNonclashingNameFor(classGenericName, typeParamStrings); - builderGenericName = generateNonclashingNameFor(builderGenericName, typeParamStrings); + // If there is no superclass, superclassBuilderClassExpression is still == null at this point. + // You can use it to check whether to inherit or not. generateBuilderBasedConstructor(tdParent, typeParams, builderFields, annotationNode, builderClassName, superclassBuilderClass != null); @@ -335,14 +347,10 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { // Add the builder() method to the annotated class. if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) { MethodDeclaration md = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, tdParent, typeParams, ast); -// recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); if (md != null) { injectMethod(tdParent, md); } } - -// recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext()); -// recursiveSetGeneratedBy(builderImplType.get(), ast, annotationNode.getContext()); } private String generateNonclashingNameFor(String classGenericName, java.util.List typeParamStrings) { @@ -441,40 +449,19 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { injectMethod(typeNode, constructor); } -// private ListBuffer getTypeParamExpressions(List typeParams, JavacTreeMaker maker) { -// ListBuffer typeParamsForBuilderParameter = new ListBuffer(); -// for (JCTree typeParam : typeParams) { -// if (typeParam instanceof JCTypeParameter) { -// typeParamsForBuilderParameter.add(maker.Ident(((JCTypeParameter)typeParam).getName())); -// } else if (typeParam instanceof JCIdent) { -// typeParamsForBuilderParameter.add(maker.Ident(((JCIdent)typeParam).getName())); -// } -// } -// return typeParamsForBuilderParameter; -// } - private MethodDeclaration generateAbstractSelfMethod(EclipseNode tdParent, boolean override, String builderGenericName) { - // TODO: @Override annotation if override == true. MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); out.selector = SELF_METHOD.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected; + if (override) { + out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, tdParent.get())}; + } out.returnType = new SingleTypeReference(builderGenericName.toCharArray(), 0); return out; } private MethodDeclaration generateSelfMethod(EclipseNode builderImplType) { -// JavacTreeMaker maker = builderImplType.getTreeMaker(); -// -// JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(builderImplType, "Override"), List.nil()); -// JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED, List.of(overrideAnnotation)); -// Name name = builderImplType.toName(SELF_METHOD); -// JCExpression returnType = maker.Ident(builderImplType.toName(builderImplType.getName())); -// -// JCStatement statement = maker.Return(maker.Ident(builderImplType.toName("this"))); -// JCBlock body = maker.Block(0, List.of(statement)); -// -// return maker.MethodDef(modifiers, name, returnType, List.nil(), List.nil(), List.nil(), body, null); MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderImplType.top().get()).compilationResult); out.selector = SELF_METHOD.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; @@ -497,11 +484,6 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { if (override) { out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source)}; } - - AllocationExpression allocationStatement = new AllocationExpression(); - allocationStatement.type = copyType(out.returnType); - // Use a constructor that only has this builder as parameter. - allocationStatement.arguments = new Expression[] {new ThisReference(0, 0)}; out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return out; } @@ -550,51 +532,21 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { return out; } -// private MethodDeclaration generateBuildMethod(String buildName, JCExpression returnType, EclipseNode type, List thrownExceptions) { -// JavacTreeMaker maker = type.getTreeMaker(); -// -// JCExpression call; -// ListBuffer statements = new ListBuffer(); -// -// // Use a constructor that only has this builder as parameter. -// List builderArg = List.of(maker.Ident(type.toName("this"))); -// call = maker.NewClass(null, List.nil(), returnType, builderArg, null); -// statements.append(maker.Return(call)); -// -// JCBlock body = maker.Block(0, statements.toList()); -// -// JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.nil()); -// JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); -// -// return maker.MethodDef(modifiers, type.toName(buildName), returnType, List.nil(), List.nil(), thrownExceptions, body, null); -// } - - private MethodDeclaration generateDefaultProvider(char[] methodName, TypeParameter[] typeParameters, EclipseNode fieldNode, ASTNode source) { - int pS = source.sourceStart, pE = source.sourceEnd; - - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) fieldNode.top().get()).compilationResult); - out.typeParameters = copyTypeParams(typeParameters, source); - out.selector = methodName; - out.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic; - out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - FieldDeclaration fd = (FieldDeclaration) fieldNode.get(); - out.returnType = copyType(fd.type, source); - out.statements = new Statement[] {new ReturnStatement(fd.initialization, pS, pE)}; - fd.initialization = null; - - out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) fieldNode.up().get()).scope); - return out; - } -// public MethodDeclaration generateDefaultProvider(Name methodName, EclipseNode fieldNode, List params) { -// JavacTreeMaker maker = fieldNode.getTreeMaker(); -// JCVariableDecl field = (JCVariableDecl) fieldNode.get(); +// private MethodDeclaration generateDefaultProvider(char[] methodName, TypeParameter[] typeParameters, EclipseNode fieldNode, ASTNode source) { +// int pS = source.sourceStart, pE = source.sourceEnd; // -// JCStatement statement = maker.Return(field.init); -// field.init = null; +// MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) fieldNode.top().get()).compilationResult); +// out.typeParameters = copyTypeParams(typeParameters, source); +// out.selector = methodName; +// out.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic; +// out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; +// FieldDeclaration fd = (FieldDeclaration) fieldNode.get(); +// out.returnType = copyType(fd.type, source); +// out.statements = new Statement[] {new ReturnStatement(fd.initialization, pS, pE)}; +// fd.initialization = null; // -// JCBlock body = maker.Block(0, List.of(statement)); -// int modifiers = Flags.PRIVATE | Flags.STATIC; -// return maker.MethodDef(maker.Modifiers(modifiers), methodName, cloneType(maker, field.vartype, field, fieldNode.getContext()), copyTypeParams(fieldNode, params), List.nil(), List.nil(), body, null); +// out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) fieldNode.up().get()).scope); +// return out; // } private MethodDeclaration generateBuilderMethod(String builderMethodName, String builderClassName, String builderImplClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { @@ -605,41 +557,21 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { out.selector = builderMethodName.toCharArray(); out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.returnType = namePlusTypeParamsToTypeReference(builderClassName.toCharArray(), typeParams, p); + + // TODO: add type params //out.typeParameters = copyTypeParams(typeParams, source); + TypeReference[] returnTypeParams = new TypeReference[2]; + returnTypeParams[0] = new Wildcard(Wildcard.UNBOUND); + returnTypeParams[1] = new Wildcard(Wildcard.UNBOUND); + out.returnType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), returnTypeParams, 0, p); + AllocationExpression invoke = new AllocationExpression(); - invoke.type = namePlusTypeParamsToTypeReference(builderClassName.toCharArray(), typeParams, p); + invoke.type = namePlusTypeParamsToTypeReference(builderImplClassName.toCharArray(), typeParams, p); out.statements = new Statement[] {new ReturnStatement(invoke, pS, pE)}; out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope); return out; } -// public MethodDeclaration generateBuilderMethod(String builderMethodName, String builderClassName, String builderImplClassName, EclipseNode source, EclipseNode type, List typeParams) { -// JavacTreeMaker maker = type.getTreeMaker(); -// -// ListBuffer typeArgs = new ListBuffer(); -// for (JCTypeParameter typeParam : typeParams) { -// typeArgs.append(maker.Ident(typeParam.name)); -// } -// -// JCExpression call = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderImplClassName), typeParams), List.nil(), null); -// JCStatement statement = maker.Return(call); -// -// JCBlock body = maker.Block(0, List.of(statement)); -// int modifiers = Flags.PUBLIC; -// modifiers |= Flags.STATIC; -// -// // Add any type params of the annotated class to the return type. -// ListBuffer typeParameterNames = new ListBuffer(); -// typeParameterNames.addAll(typeParameterNames(maker, typeParams)); -// // Now add the . -// JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); -// typeParameterNames.add(wildcard); -// typeParameterNames.add(wildcard); -// JCTypeApply returnType = maker.TypeApply(maker.Ident(type.toName(builderClassName)), typeParameterNames.toList()); -// -// return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.nil(), List.nil(), body, null); -// } private void generateBuilderFields(EclipseNode builderType, List builderFields, ASTNode source) { List existing = new ArrayList(); @@ -779,18 +711,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { o.type = new ParameterizedSingleTypeReference(builderClass.toCharArray(), typerefs, 0, 0); builder.typeParameters[builder.typeParameters.length - 1] = o; - builder.superclass = superclassBuilderClass; - // TODO: Extends clause when there is a superclass. -// JCExpression extending = null; -// if (superclassBuilderClassExpression != null) { -// // If the annotated class extends another class, we want this builder to extend the builder of the superclass. -// // 1. Add the type parameters of the superclass. -// typeParamsForBuilder = getTypeParamExpressions(superclassTypeParams, maker); -// // 2. Add the builder type params . -// typeParamsForBuilder.add(maker.Ident(tdParent.toName(classGenericName))); -// typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName))); -// extending = maker.TypeApply(superclassBuilderClassExpression, typeParamsForBuilder.toList()); -// } + builder.superclass = copyType(superclassBuilderClass, source); builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return injectType(tdParent, builder); diff --git a/test/transform/resource/after-ecj/SuperBuilderBasic.java b/test/transform/resource/after-ecj/SuperBuilderBasic.java index d293c8f8..88ac7e70 100644 --- a/test/transform/resource/after-ecj/SuperBuilderBasic.java +++ b/test/transform/resource/after-ecj/SuperBuilderBasic.java @@ -61,72 +61,45 @@ public class SuperBuilderBasic { this.items = items; } public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { - return new ParentBuilderImpl(); + return new ParentBuilderImpl(); } } - public static @lombok.experimental.SuperBuilder class Child extends Parent { - double field3; - - @java.lang.SuppressWarnings("all") - protected Child(final ChildBuilder b) { - super(b); - this.field3 = b.field3; - } - - - @java.lang.SuppressWarnings("all") - public static abstract class ChildBuilder> extends Parent.ParentBuilder { - @java.lang.SuppressWarnings("all") - private double field3; - - @java.lang.Override - @java.lang.SuppressWarnings("all") - protected abstract B self(); - - @java.lang.Override - @java.lang.SuppressWarnings("all") - public abstract C build(); - - @java.lang.SuppressWarnings("all") - public B field3(final double field3) { + public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder> extends Parent.ParentBuilder { + private @java.lang.SuppressWarnings("all") double field3; + protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B field3(final double field3) { this.field3 = field3; return self(); } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - public java.lang.String toString() { - return "SuperBuilderBasic.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderBasic.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")"); } } - - - @java.lang.SuppressWarnings("all") - private static final class ChildBuilderImpl extends ChildBuilder { - @java.lang.SuppressWarnings("all") - private ChildBuilderImpl() { + private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder { + private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { + super(); } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - protected ChildBuilderImpl self() { + protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { return this; } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - public Child build() { + public @java.lang.Override @java.lang.SuppressWarnings("all") Child build() { return new Child(this); } } - - @java.lang.SuppressWarnings("all") - public static ChildBuilder builder() { + double field3; + protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + public static @java.lang.SuppressWarnings("all") ChildBuilder builder() { return new ChildBuilderImpl(); } } - + public SuperBuilderBasic() { + super(); + } public static void test() { Child x = Child.builder().field3(0.0).field1(5).item("").build(); } -- cgit From 9ee2491427f1522a7689d1c28a816294bcff315b Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Thu, 17 May 2018 21:26:42 +0200 Subject: ecj: SuperBuilderBasic test passes (removed superconstructor calls) --- src/core/lombok/eclipse/handlers/HandleConstructor.java | 12 +++++++----- src/core/lombok/eclipse/handlers/HandleSuperBuilder.java | 13 ++++++------- test/transform/resource/after-ecj/SuperBuilderBasic.java | 3 --- 3 files changed, 13 insertions(+), 15 deletions(-) (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index a2940b88..ccf71158 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -259,7 +259,7 @@ public class HandleConstructor { ConstructorDeclaration constr = createConstructor( staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, allToDefault, - sourceNode, onConstructor); + true, sourceNode, onConstructor); injectMethod(typeNode, constr); if (staticConstrRequired) { MethodDeclaration staticConstr = createStaticConstructor(level, staticName, typeNode, allToDefault ? Collections.emptyList() : fields, source); @@ -301,7 +301,7 @@ public class HandleConstructor { @SuppressWarnings("deprecation") public static ConstructorDeclaration createConstructor( AccessLevel level, EclipseNode type, Collection fields, boolean allToDefault, - EclipseNode sourceNode, List onConstructor) { + boolean superConstructorCall, EclipseNode sourceNode, List onConstructor) { ASTNode source = sourceNode.get(); TypeDeclaration typeDeclaration = ((TypeDeclaration) type.get()); @@ -324,9 +324,11 @@ public class HandleConstructor { constructor.modifiers = toEclipseModifier(level); constructor.selector = typeDeclaration.name; - constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); - constructor.constructorCall.sourceStart = source.sourceStart; - constructor.constructorCall.sourceEnd = source.sourceEnd; + if (superConstructorCall) { + constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + constructor.constructorCall.sourceStart = source.sourceStart; + constructor.constructorCall.sourceEnd = source.sourceEnd; + } constructor.thrownExceptions = null; constructor.typeParameters = null; constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 71683516..5586bc6b 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -63,6 +63,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; @@ -335,7 +336,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { } // Create a simple constructor for the BuilderImpl class. - ConstructorDeclaration cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, builderImplType, Collections.emptyList(), false, annotationNode, Collections.emptyList()); + ConstructorDeclaration cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, builderImplType, Collections.emptyList(), false, false, annotationNode, Collections.emptyList()); if (cd != null) { injectMethod(builderImplType, cd); } @@ -395,11 +396,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { if (callBuilderBasedSuperConstructor) { constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.Super); constructor.constructorCall.arguments = new Expression[] {new SingleNameReference("b".toCharArray(), p)}; - } else { - constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + constructor.constructorCall.sourceStart = source.sourceStart; + constructor.constructorCall.sourceEnd = source.sourceEnd; } - constructor.constructorCall.sourceStart = source.sourceStart; - constructor.constructorCall.sourceEnd = source.sourceEnd; constructor.thrownExceptions = null; constructor.typeParameters = null; constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; @@ -453,7 +452,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); out.selector = SELF_METHOD.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected; + out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected | ExtraCompilerModifiers.AccSemicolonBody; if (override) { out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, tdParent.get())}; } @@ -477,7 +476,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract; + out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract | ExtraCompilerModifiers.AccSemicolonBody; out.selector = methodName.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.returnType = new SingleTypeReference(classGenericName.toCharArray(), 0); diff --git a/test/transform/resource/after-ecj/SuperBuilderBasic.java b/test/transform/resource/after-ecj/SuperBuilderBasic.java index 88ac7e70..fc5f045b 100644 --- a/test/transform/resource/after-ecj/SuperBuilderBasic.java +++ b/test/transform/resource/after-ecj/SuperBuilderBasic.java @@ -33,7 +33,6 @@ public class SuperBuilderBasic { } private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder { private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { - super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { return this; @@ -45,7 +44,6 @@ public class SuperBuilderBasic { int field1; @lombok.Singular List items; protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { - super(); this.field1 = b.field1; java.util.List items; switch (((b.items == null) ? 0 : b.items.size())) { @@ -79,7 +77,6 @@ public class SuperBuilderBasic { } private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder { private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { - super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { return this; -- cgit From 61f0689f6bfb8de28c90eb786cd9e9e06a776287 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Wed, 30 May 2018 11:52:42 +0200 Subject: ecj: copy type parameters to builder class --- .../eclipse/handlers/HandleSuperBuilder.java | 33 ++- .../after-ecj/SuperBuilderWithGenerics.java | 261 ++++++++------------- 2 files changed, 125 insertions(+), 169 deletions(-) (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 5586bc6b..40c84a3e 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -681,6 +681,16 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { } return null; } + + private TypeReference[] appendBuilderTypeReferences(TypeParameter[] typeParams, String classGenericName, String builderGenericName) { + TypeReference[] typerefs = new TypeReference[typeParams.length + 2]; + for (int i = 0; i < typeParams.length; i++) { + typerefs[i] = new SingleTypeReference(typeParams[i].name, 0); + } + typerefs[typerefs.length - 2] = new SingleTypeReference(classGenericName.toCharArray(), 0); + typerefs[typerefs.length - 1] = new SingleTypeReference(builderGenericName.toCharArray(), 0); + return typerefs; + } private EclipseNode makeBuilderAbstractClass(EclipseNode tdParent, String builderClass, TypeReference superclassBuilderClass, TypeParameter[] typeParams, @@ -703,10 +713,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { // 2. The return type for all setter methods, named "B", which extends this builder class. o = new TypeParameter(); o.name = builderGenericName.toCharArray(); - TypeReference[] typerefs = new TypeReference[] { - new SingleTypeReference(classGenericName.toCharArray(), 0), - new SingleTypeReference(builderGenericName.toCharArray(), 0) - }; + TypeReference[] typerefs = appendBuilderTypeReferences(typeParams, classGenericName, builderGenericName); o.type = new ParameterizedSingleTypeReference(builderClass.toCharArray(), typerefs, 0, 0); builder.typeParameters[builder.typeParameters.length - 1] = o; @@ -722,12 +729,26 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; builder.modifiers |= ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal; builder.name = builderImplClass.toCharArray(); + builder.typeParameters = copyTypeParams(typeParams, source); if (builderAbstractClass != null) { // Extend the abstract builder. - // TODO: 1. Add any type params of the annotated class. + // 1. Add any type params of the annotated class. + TypeReference[] typeArgs = new TypeReference[typeParams.length + 2]; + for (int i = 0; i < typeParams.length; i++) { + typeArgs[i] = new SingleTypeReference(typeParams[i].name, 0); + } // 2. The return type for the build() method (named "C" in the abstract builder), which is the annotated class. // 3. The return type for all setter methods (named "B" in the abstract builder), which is this builder class. - TypeReference[] typeArgs = new TypeReference[] {cloneSelfType(tdParent, source), new SingleTypeReference(builderImplClass.toCharArray(), 0)}; + typeArgs[typeArgs.length - 2] = cloneSelfType(tdParent, source); + if (typeParams.length > 0) { + TypeReference[] typerefs = new TypeReference[typeParams.length]; + for (int i = 0; i < typeParams.length; i++) { + typerefs[i] = new SingleTypeReference(typeParams[i].name, 0); + } + typeArgs[typeArgs.length - 1] = new ParameterizedSingleTypeReference(builderImplClass.toCharArray(), typerefs, 0, 0); + } else { + typeArgs[typeArgs.length - 1] = new SingleTypeReference(builderImplClass.toCharArray(), 0); + } builder.superclass = new ParameterizedSingleTypeReference(builderAbstractClass.toCharArray(), typeArgs, 0, 0); } builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); diff --git a/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java b/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java index 9f71be5a..0ec8efe5 100644 --- a/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java +++ b/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java @@ -1,166 +1,101 @@ import java.util.List; - public class SuperBuilderWithGenerics { - public static @lombok.experimental.SuperBuilder class Parent { - A field1; - List items; - - @java.lang.SuppressWarnings("all") - protected Parent(final ParentBuilder b) { - this.field1 = b.field1; - java.util.List items; - switch (b.items == null ? 0 : b.items.size()) { - case 0: - items = java.util.Collections.emptyList(); - break; - - case 1: - items = java.util.Collections.singletonList(b.items.get(0)); - break; - - default: - items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); - } - this.items = items; - } - - - @java.lang.SuppressWarnings("all") - public static abstract class ParentBuilder, B extends ParentBuilder> { - @java.lang.SuppressWarnings("all") - private A field1; - @java.lang.SuppressWarnings("all") - private java.util.ArrayList items; - - @java.lang.SuppressWarnings("all") - protected abstract B self(); - - @java.lang.SuppressWarnings("all") - public abstract C build(); - - @java.lang.SuppressWarnings("all") - public B field1(final A field1) { - this.field1 = field1; - return self(); - } - - @java.lang.SuppressWarnings("all") - public B item(final String item) { - if (this.items == null) this.items = new java.util.ArrayList(); - this.items.add(item); - return self(); - } - - @java.lang.SuppressWarnings("all") - public B items(final java.util.Collection items) { - if (this.items == null) this.items = new java.util.ArrayList(); - this.items.addAll(items); - return self(); - } - - @java.lang.SuppressWarnings("all") - public B clearItems() { - if (this.items != null) this.items.clear(); - return self(); - } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - public java.lang.String toString() { - return "SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; - } - } - - - @java.lang.SuppressWarnings("all") - private static final class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { - @java.lang.SuppressWarnings("all") - private ParentBuilderImpl() { - } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - protected ParentBuilderImpl self() { - return this; - } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - public Parent build() { - return new Parent(this); - } - } - - @java.lang.SuppressWarnings("all") - public static ParentBuilder builder() { - return new ParentBuilderImpl(); - } - } - - @lombok.experimental.SuperBuilder - public static class Child extends Parent { - double field3; - - @java.lang.SuppressWarnings("all") - protected Child(final ChildBuilder b) { - super(b); - this.field3 = b.field3; - } - - - @java.lang.SuppressWarnings("all") - public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { - @java.lang.SuppressWarnings("all") - private double field3; - - @java.lang.Override - @java.lang.SuppressWarnings("all") - protected abstract B self(); - - @java.lang.Override - @java.lang.SuppressWarnings("all") - public abstract C build(); - - @java.lang.SuppressWarnings("all") - public B field3(final double field3) { - this.field3 = field3; - return self(); - } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - public java.lang.String toString() { - return "SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; - } - } - - - @java.lang.SuppressWarnings("all") - private static final class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { - @java.lang.SuppressWarnings("all") - private ChildBuilderImpl() { - } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - protected ChildBuilderImpl self() { - return this; - } - - @java.lang.Override - @java.lang.SuppressWarnings("all") - public Child build() { - return new Child(this); - } - } - - @java.lang.SuppressWarnings("all") - public static ChildBuilder builder() { - return new ChildBuilderImpl(); - } - } - - public static void test() { - Child x = Child.builder().field3(0.0).field1(5).item("").build(); - } + public static @lombok.experimental.SuperBuilder class Parent { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder, B extends ParentBuilder> { + private @java.lang.SuppressWarnings("all") A field1; + private @java.lang.SuppressWarnings("all") java.util.ArrayList items; + protected abstract @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B field1(final A field1) { + this.field1 = field1; + return self(); + } + public @java.lang.SuppressWarnings("all") B item(String item) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + public @java.lang.SuppressWarnings("all") B items(java.util.Collection items) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + public @java.lang.SuppressWarnings("all") B clearItems() { + if ((this.items != null)) + this.items.clear(); + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1) + ", items=") + this.items) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") Parent build() { + return new Parent(this); + } + } + A field1; + @lombok.Singular List items; + protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + @lombok.experimental.SuperBuilder + public static class Child extends Parent { + double field3; + protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + private @java.lang.SuppressWarnings("all") double field3; + protected @java.lang.Override @java.lang.SuppressWarnings("all") abstract B self(); + public @java.lang.Override @java.lang.SuppressWarnings("all") abstract C build(); + public @java.lang.SuppressWarnings("all") B field3(final double field3) { + this.field3 = field3; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return "SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; + } + } + private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { + private ChildBuilderImpl() { + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") Child build() { + return new Child(this); + } + } + public static @java.lang.SuppressWarnings("all") ChildBuilder builder() { + return new ChildBuilderImpl(); + } + } + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } } -- cgit From b2f44c326430fd2e46e2830af7bbaa010f571a44 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Wed, 30 May 2018 13:10:34 +0200 Subject: ecj: type parameters for methods and constructor param --- .../eclipse/handlers/HandleSuperBuilder.java | 100 ++++++++++++--------- .../after-ecj/SuperBuilderWithGenerics.java | 48 +++++----- 2 files changed, 84 insertions(+), 64 deletions(-) (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 40c84a3e..2e7d26a9 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -232,10 +232,12 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { long[] poss = new long[tokens.length]; Arrays.fill(poss, p); + TypeReference[] superclassTypeArgs = getTypeParametersFrom(extendsClause); + // Every token may potentially have type args. Here, we only have // type args for the last token, the superclass' builder. TypeReference[][] typeArgsForTokens = new TypeReference[tokens.length][]; - typeArgsForTokens[typeArgsForTokens.length-1] = typeArguments; + typeArgsForTokens[typeArgsForTokens.length-1] = mergeTypeReferences(superclassTypeArgs, typeArguments); superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss); } else if (extendsClause != null) { @@ -245,12 +247,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { char[][] tokens = new char[][] {superClass.toCharArray(), superclassBuilderClassName.toCharArray()}; long[] poss = new long[tokens.length]; Arrays.fill(poss, p); - + + TypeReference[] superclassTypeArgs = getTypeParametersFrom(extendsClause); + // Every token may potentially have type args. Here, we only have // type args for the last token, the superclass' builder. TypeReference[][] typeArgsForTokens = new TypeReference[tokens.length][]; - typeArgsForTokens[typeArgsForTokens.length-1] = typeArguments; - + typeArgsForTokens[typeArgsForTokens.length-1] = mergeTypeReferences(superclassTypeArgs, typeArguments); + superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss); } // If there is no superclass, superclassBuilderClassExpression is still == null at this point. @@ -365,7 +369,15 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { return classGenericName + counter; } - + private TypeReference[] getTypeParametersFrom(TypeReference typeRef) { + TypeReference[][] typeArgss = typeRef.getTypeArguments(); + TypeReference[] typeArgs = new TypeReference[0]; + if (typeArgss != null && typeArgss.length > 0) { + typeArgs = typeArgss[typeArgss.length - 1]; + } + return typeArgs; + } + /** * Generates a constructor that has a builder as the only parameter. * The values from the builder are used to initialize the fields of new instances. @@ -406,7 +418,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd; TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND)}; - TypeReference builderType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), wildcards, 0, p); + TypeReference builderType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), mergeToTypeReferences(typeParams, wildcards), 0, p); constructor.arguments = new Argument[] {new Argument("b".toCharArray(), p, builderType, Modifier.FINAL)}; List statements = new ArrayList(); @@ -531,23 +543,6 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { return out; } -// private MethodDeclaration generateDefaultProvider(char[] methodName, TypeParameter[] typeParameters, EclipseNode fieldNode, ASTNode source) { -// int pS = source.sourceStart, pE = source.sourceEnd; -// -// MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) fieldNode.top().get()).compilationResult); -// out.typeParameters = copyTypeParams(typeParameters, source); -// out.selector = methodName; -// out.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic; -// out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; -// FieldDeclaration fd = (FieldDeclaration) fieldNode.get(); -// out.returnType = copyType(fd.type, source); -// out.statements = new Statement[] {new ReturnStatement(fd.initialization, pS, pE)}; -// fd.initialization = null; -// -// out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) fieldNode.up().get()).scope); -// return out; -// } - private MethodDeclaration generateBuilderMethod(String builderMethodName, String builderClassName, String builderImplClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long) pS << 32 | pE; @@ -558,11 +553,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; // TODO: add type params - //out.typeParameters = copyTypeParams(typeParams, source); - TypeReference[] returnTypeParams = new TypeReference[2]; - returnTypeParams[0] = new Wildcard(Wildcard.UNBOUND); - returnTypeParams[1] = new Wildcard(Wildcard.UNBOUND); - out.returnType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), returnTypeParams, 0, p); + out.typeParameters = copyTypeParams(typeParams, source); + TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND) }; + out.returnType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), mergeToTypeReferences(typeParams, wildcards), 0, p); AllocationExpression invoke = new AllocationExpression(); invoke.type = namePlusTypeParamsToTypeReference(builderImplClassName.toCharArray(), typeParams, p); @@ -683,15 +676,48 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { } private TypeReference[] appendBuilderTypeReferences(TypeParameter[] typeParams, String classGenericName, String builderGenericName) { - TypeReference[] typerefs = new TypeReference[typeParams.length + 2]; + TypeReference[] typeReferencesToAppend = new TypeReference[2]; + typeReferencesToAppend[typeReferencesToAppend.length - 2] = new SingleTypeReference(classGenericName.toCharArray(), 0); + typeReferencesToAppend[typeReferencesToAppend.length - 1] = new SingleTypeReference(builderGenericName.toCharArray(), 0); + return mergeToTypeReferences(typeParams, typeReferencesToAppend); + } + + private TypeReference[] mergeToTypeReferences(TypeParameter[] typeParams, TypeReference[] typeReferencesToAppend) { + TypeReference[] typerefs = new TypeReference[typeParams.length + typeReferencesToAppend.length]; for (int i = 0; i < typeParams.length; i++) { typerefs[i] = new SingleTypeReference(typeParams[i].name, 0); } - typerefs[typerefs.length - 2] = new SingleTypeReference(classGenericName.toCharArray(), 0); - typerefs[typerefs.length - 1] = new SingleTypeReference(builderGenericName.toCharArray(), 0); + for (int i = 0; i < typeReferencesToAppend.length; i++) { + typerefs[typeParams.length + i] = typeReferencesToAppend[i]; + } return typerefs; } + private TypeReference[] mergeTypeReferences(TypeReference[] refs1, TypeReference[] refs2) { + TypeReference[] result = new TypeReference[refs1.length + refs2.length]; + for (int i = 0; i < refs1.length; i++) { + result[i] = refs1[i]; + } + for (int i = 0; i < refs2.length; i++) { + result[refs1.length + i] = refs2[i]; + } + return result; + } + + private static SingleTypeReference createTypeReferenceWithTypeParameters(String referenceName, TypeParameter[] typeParams) { + if (typeParams.length > 0) { + TypeReference[] typerefs = new TypeReference[typeParams.length]; + for (int i = 0; i < typeParams.length; i++) { + typerefs[i] = new SingleTypeReference(typeParams[i].name, 0); + } + return new ParameterizedSingleTypeReference(referenceName.toCharArray(), typerefs, 0, 0); + } else { + return new SingleTypeReference(referenceName.toCharArray(), 0); + } + + } + + private EclipseNode makeBuilderAbstractClass(EclipseNode tdParent, String builderClass, TypeReference superclassBuilderClass, TypeParameter[] typeParams, TypeParameter[] superclassTypeParams, ASTNode source, String classGenericName, String builderGenericName) { @@ -722,7 +748,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return injectType(tdParent, builder); } - + private EclipseNode makeBuilderImplClass(EclipseNode tdParent, String builderImplClass, String builderAbstractClass, TypeParameter[] typeParams, ASTNode source) { TypeDeclaration parent = (TypeDeclaration) tdParent.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); @@ -740,15 +766,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { // 2. The return type for the build() method (named "C" in the abstract builder), which is the annotated class. // 3. The return type for all setter methods (named "B" in the abstract builder), which is this builder class. typeArgs[typeArgs.length - 2] = cloneSelfType(tdParent, source); - if (typeParams.length > 0) { - TypeReference[] typerefs = new TypeReference[typeParams.length]; - for (int i = 0; i < typeParams.length; i++) { - typerefs[i] = new SingleTypeReference(typeParams[i].name, 0); - } - typeArgs[typeArgs.length - 1] = new ParameterizedSingleTypeReference(builderImplClass.toCharArray(), typerefs, 0, 0); - } else { - typeArgs[typeArgs.length - 1] = new SingleTypeReference(builderImplClass.toCharArray(), 0); - } + typeArgs[typeArgs.length - 1] = createTypeReferenceWithTypeParameters(builderImplClass, typeParams); builder.superclass = new ParameterizedSingleTypeReference(builderAbstractClass.toCharArray(), typeArgs, 0, 0); } builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); diff --git a/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java b/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java index 0ec8efe5..cb717bcf 100644 --- a/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java +++ b/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java @@ -46,43 +46,37 @@ public class SuperBuilderWithGenerics { protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { this.field1 = b.field1; java.util.List items; - switch (b.items == null ? 0 : b.items.size()) { - case 0: - items = java.util.Collections.emptyList(); - break; - case 1: - items = java.util.Collections.singletonList(b.items.get(0)); - break; - default: - items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + switch (((b.items == null) ? 0 : b.items.size())) { + case 0 : + items = java.util.Collections.emptyList(); + break; + case 1 : + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default : + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); } this.items = items; } - public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { + public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { return new ParentBuilderImpl(); } } - @lombok.experimental.SuperBuilder - public static class Child extends Parent { - double field3; - protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { - super(b); - this.field3 = b.field3; - } - public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + public static @lombok.experimental.SuperBuilder class Child extends Parent { + public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { private @java.lang.SuppressWarnings("all") double field3; - protected @java.lang.Override @java.lang.SuppressWarnings("all") abstract B self(); - public @java.lang.Override @java.lang.SuppressWarnings("all") abstract C build(); + protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); public @java.lang.SuppressWarnings("all") B field3(final double field3) { this.field3 = field3; return self(); } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { - return "SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; + return (((("SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")"); } } private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { - private ChildBuilderImpl() { + private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { } protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { return this; @@ -91,10 +85,18 @@ public class SuperBuilderWithGenerics { return new Child(this); } } - public static @java.lang.SuppressWarnings("all") ChildBuilder builder() { + double field3; + protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + public static @java.lang.SuppressWarnings("all") ChildBuilder builder() { return new ChildBuilderImpl(); } } + public SuperBuilderWithGenerics() { + super(); + } public static void test() { Child x = Child.builder().field3(0.0).field1(5).item("").build(); } -- cgit From 4c5a7cddab109391d7494be2a0fc575b466dfa43 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Wed, 30 May 2018 22:38:08 +0200 Subject: code formatting, reordering, rename etc. --- .../lombok/javac/handlers/HandleSuperBuilder.java | 532 +++++++++++---------- .../resource/after-delombok/SuperBuilderBasic.java | 42 +- .../after-delombok/SuperBuilderWithGenerics.java | 42 +- 3 files changed, 329 insertions(+), 287 deletions(-) (limited to 'test') diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index 0004ddcb..0bb16d56 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -1,16 +1,16 @@ /* * Copyright (C) 2013-2018 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 @@ -88,33 +88,41 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { ObtainVia obtainVia; JavacNode obtainViaNode; JavacNode originalFieldNode; - + java.util.List createdFields = new ArrayList(); } - + @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { - SuperBuilder builderInstance = annotation.getInstance(); - - String builderMethodName = builderInstance.builderMethodName(); - String buildMethodName = builderInstance.buildMethodName(); - - if (builderMethodName == null) builderMethodName = "builder"; - if (buildMethodName == null) buildMethodName = "build"; - - if (!checkName("builderMethodName", builderMethodName, annotationNode)) return; - if (!checkName("buildMethodName", buildMethodName, annotationNode)) return; - + SuperBuilder superbuilderAnnotation = annotation.getInstance(); + + String builderMethodName = superbuilderAnnotation.builderMethodName(); + String buildMethodName = superbuilderAnnotation.buildMethodName(); + + if (builderMethodName == null) { + builderMethodName = "builder"; + } + if (buildMethodName == null) { + buildMethodName = "build"; + } + + if (!checkName("builderMethodName", builderMethodName, annotationNode)) { + return; + } + if (!checkName("buildMethodName", buildMethodName, annotationNode)) { + return; + } + JavacNode tdParent = annotationNode.up(); - + java.util.List builderFields = new ArrayList(); JCExpression returnType; List typeParams = List.nil(); List thrownExceptions = List.nil(); List superclassTypeParams = List.nil(); - + boolean addCleaning = false; - + if (!(tdParent.get() instanceof JCClassDecl)) { annotationNode.addError("@SuperBuilder is only supported on types."); return; @@ -134,28 +142,32 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { bfd.type = fd.vartype; bfd.singularData = getSingularData(fieldNode); bfd.originalFieldNode = fieldNode; - + if (bfd.singularData != null && isDefault != null) { isDefault.addError("@Builder.Default and @Singular cannot be mixed."); isDefault = null; } - + if (fd.init == null && isDefault != null) { isDefault.addWarning("@Builder.Default requires an initializing expression (' = something;')."); isDefault = null; } - + if (fd.init != null && isDefault == null) { - if (isFinal) continue; + if (isFinal) { + continue; + } fieldNode.addWarning("@SuperBuilder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final."); } - + if (isDefault != null) { bfd.nameOfDefaultProvider = tdParent.toName("$default$" + bfd.name); bfd.nameOfSetFlag = tdParent.toName(bfd.name + "$set"); JCMethodDecl md = generateDefaultProvider(bfd.nameOfDefaultProvider, fieldNode, td.typarams); recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); - if (md != null) injectMethod(tdParent, md); + if (md != null) { + injectMethod(tdParent, md); + } } addObtainVia(bfd, fieldNode); builderFields.add(bfd); @@ -172,11 +184,11 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { superclassTypeParams = ((JCTypeApply)extendsClause).getTypeArguments(); // A class name with a generics type, e.g., "Superclass". extendsClause = ((JCTypeApply)extendsClause).getType(); - } + } if (extendsClause instanceof JCFieldAccess) { Name superclassClassName = ((JCFieldAccess)extendsClause).getIdentifier(); String superclassBuilderClassName = superclassClassName + "Builder"; - superclassBuilderClassExpression = tdParent.getTreeMaker().Select((JCFieldAccess)extendsClause, + superclassBuilderClassExpression = tdParent.getTreeMaker().Select((JCFieldAccess)extendsClause, tdParent.toName(superclassBuilderClassName)); } else if (extendsClause != null) { String superclassBuilderClassName = extendsClause.toString() + "Builder"; @@ -187,7 +199,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams); typeParams = td.typarams; - + // are the generics for our builder. String classGenericName = "C"; String builderGenericName = "B"; @@ -199,22 +211,9 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } classGenericName = generateNonclashingNameFor(classGenericName, typeParamStrings); builderGenericName = generateNonclashingNameFor(builderGenericName, typeParamStrings); - - thrownExceptions = List.nil(); - generateBuilderBasedConstructor(tdParent, typeParams, builderFields, annotationNode, builderClassName, - superclassBuilderClassExpression != null); + thrownExceptions = List.nil(); - // Create the abstract builder class. - JavacNode builderType = findInnerClass(tdParent, builderClassName); - if (builderType == null) { - builderType = makeBuilderAbstractClass(annotationNode, tdParent, builderClassName, superclassBuilderClassExpression, - typeParams, superclassTypeParams, ast, classGenericName, builderGenericName); - } else { - annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead."); - return; - } - // Check validity of @ObtainVia fields, and add check if adding cleaning for @Singular is necessary. for (BuilderFieldData bfd : builderFields) { if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { @@ -235,7 +234,17 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } } - // Generate the fields in the abstract builder class that hold the values for the instance. + // Create the abstract builder class. + JavacNode builderType = findInnerClass(tdParent, builderClassName); + if (builderType == null) { + builderType = generateBuilderAbstractClass(annotationNode, tdParent, builderClassName, superclassBuilderClassExpression, + typeParams, superclassTypeParams, ast, classGenericName, builderGenericName); + } else { + annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead."); + return; + } + + // Generate the fields in the abstract builder class that hold the values for the instance. generateBuilderFields(builderType, builderFields, ast); if (addCleaning) { JavacTreeMaker maker = builderType.getTreeMaker(); @@ -249,9 +258,9 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { // Create the setter methods in the abstract builder. for (BuilderFieldData bfd : builderFields) { - makeSetterMethodsForBuilder(builderType, bfd, annotationNode, builderGenericName); + generateSetterMethodsForBuilder(builderType, bfd, annotationNode, builderGenericName); } - + // Create the toString() method for the abstract builder. if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) { java.util.List fieldNodes = new ArrayList(); @@ -260,15 +269,19 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } // Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder. JCMethodDecl md = HandleToString.createToString(builderType, fieldNodes, true, superclassBuilderClassExpression != null, FieldAccess.ALWAYS_FIELD, ast); - if (md != null) injectMethod(builderType, md); + if (md != null) { + injectMethod(builderType, md); + } + } + + if (addCleaning) { + injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast)); } - - if (addCleaning) injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast)); - + // Create the builder implementation class. JavacNode builderImplType = findInnerClass(tdParent, builderImplClassName); if (builderImplType == null) { - builderImplType = makeBuilderImplClass(annotationNode, tdParent, builderImplClassName, builderClassName, typeParams, ast); + builderImplType = generateBuilderImplClass(annotationNode, tdParent, builderImplClassName, builderClassName, typeParams, ast); } else { annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead."); return; @@ -276,33 +289,107 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { // Create a simple constructor for the BuilderImpl class. JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, List.nil(), builderImplType, List.nil(), false, annotationNode); - if (cd != null) injectMethod(builderImplType, cd); + if (cd != null) { + injectMethod(builderImplType, cd); + } // Create the self() and build() methods in the BuilderImpl. injectMethod(builderImplType, generateSelfMethod(builderImplType)); injectMethod(builderImplType, generateBuildMethod(buildMethodName, returnType, builderImplType, thrownExceptions)); - + + // Generate a constructor in the annotated class that takes a builder as argument. + generateBuilderBasedConstructor(tdParent, typeParams, builderFields, annotationNode, builderClassName, + superclassBuilderClassExpression != null); + // Add the builder() method to the annotated class. + // Allow users to specify their own builder() methods, e.g., to provide default values. if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) { JCMethodDecl md = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); - if (md != null) injectMethod(tdParent, md); + if (md != null) { + injectMethod(tdParent, md); + } } - + recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext()); recursiveSetGeneratedBy(builderImplType.get(), ast, annotationNode.getContext()); } - - private String generateNonclashingNameFor(String classGenericName, java.util.List typeParamStrings) { - if (!typeParamStrings.contains(classGenericName)) - return classGenericName; - int counter = 2; - while (typeParamStrings.contains(classGenericName + counter)) { - counter++; + + /** + * Creates and returns the abstract builder class and injects it into the annotated class. + */ + private JavacNode generateBuilderAbstractClass(JavacNode source, JavacNode tdParent, String builderClass, + JCExpression superclassBuilderClassExpression, List typeParams, + List superclassTypeParams, JCAnnotation ast, String classGenericName, String builderGenericName) { + JavacTreeMaker maker = tdParent.getTreeMaker(); + JCModifiers mods = maker.Modifiers(Flags.STATIC | Flags.ABSTRACT | Flags.PUBLIC); + + // Keep any type params of the annotated class. + ListBuffer allTypeParams = new ListBuffer(); + allTypeParams.addAll(copyTypeParams(source, typeParams)); + // Add builder-specific type params required for inheritable builders. + // 1. The return type for the build() method, named "C", which extends the annotated class. + JCExpression annotatedClass = maker.Ident(tdParent.toName(tdParent.getName())); + if (typeParams.nonEmpty()) { + // Add type params of the annotated class. + annotatedClass = maker.TypeApply(annotatedClass, getTypeParamExpressions(typeParams, maker).toList()); } - return classGenericName + counter; + allTypeParams.add(maker.TypeParameter(tdParent.toName(classGenericName), List.of(annotatedClass))); + // 2. The return type for all setter methods, named "B", which extends this builder class. + Name builderClassName = tdParent.toName(builderClass); + ListBuffer typeParamsForBuilder = getTypeParamExpressions(typeParams, maker); + typeParamsForBuilder.add(maker.Ident(tdParent.toName(classGenericName))); + typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName))); + JCTypeApply typeApply = maker.TypeApply(maker.Ident(builderClassName), typeParamsForBuilder.toList()); + allTypeParams.add(maker.TypeParameter(tdParent.toName(builderGenericName), List.of(typeApply))); + + JCExpression extending = null; + if (superclassBuilderClassExpression != null) { + // If the annotated class extends another class, we want this builder to extend the builder of the superclass. + // 1. Add the type parameters of the superclass. + typeParamsForBuilder = getTypeParamExpressions(superclassTypeParams, maker); + // 2. Add the builder type params . + typeParamsForBuilder.add(maker.Ident(tdParent.toName(classGenericName))); + typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName))); + extending = maker.TypeApply(superclassBuilderClassExpression, typeParamsForBuilder.toList()); + } + + JCClassDecl builder = maker.ClassDef(mods, builderClassName, allTypeParams.toList(), extending, List.nil(), List.nil()); + return injectType(tdParent, builder); + } + + /** + * Creates and returns the concrete builder implementation class and injects it into the annotated class. + */ + private JavacNode generateBuilderImplClass(JavacNode source, JavacNode tdParent, String builderImplClass, String builderAbstractClass, List typeParams, JCAnnotation ast) { + JavacTreeMaker maker = tdParent.getTreeMaker(); + JCModifiers mods = maker.Modifiers(Flags.STATIC | Flags.PRIVATE | Flags.FINAL); + + // Extend the abstract builder. + JCExpression extending = maker.Ident(tdParent.toName(builderAbstractClass)); + // Add any type params of the annotated class. + ListBuffer allTypeParams = new ListBuffer(); + allTypeParams.addAll(copyTypeParams(source, typeParams)); + // Add builder-specific type params required for inheritable builders. + // 1. The return type for the build() method (named "C" in the abstract builder), which is the annotated class. + JCExpression annotatedClass = maker.Ident(tdParent.toName(tdParent.getName())); + if (typeParams.nonEmpty()) { + // Add type params of the annotated class. + annotatedClass = maker.TypeApply(annotatedClass, getTypeParamExpressions(typeParams, maker).toList()); + } + // 2. The return type for all setter methods (named "B" in the abstract builder), which is this builder class. + JCExpression builderImplClassExpression = maker.Ident(tdParent.toName(builderImplClass)); + if (typeParams.nonEmpty()) { + builderImplClassExpression = maker.TypeApply(builderImplClassExpression, getTypeParamExpressions(typeParams, maker).toList()); + } + ListBuffer typeParamsForBuilder = getTypeParamExpressions(typeParams, maker); + typeParamsForBuilder.add(annotatedClass); + typeParamsForBuilder.add(builderImplClassExpression); + extending = maker.TypeApply(extending, typeParamsForBuilder.toList()); + + JCClassDecl builder = maker.ClassDef(mods, tdParent.toName(builderImplClass), copyTypeParams(source, typeParams), extending, List.nil(), List.nil()); + return injectType(tdParent, builder); } - /** * Generates a constructor that has a builder as the only parameter. @@ -311,7 +398,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { * @param typeNode * the type (with the {@code @Builder} annotation) for which a * constructor should be generated. - * @param typeParams + * @param typeParams * @param builderFields a list of fields in the builder which should be assigned to new instances. * @param source the annotation (used for setting source code locations for the generated code). * @param callBuilderBasedSuperConstructor @@ -321,16 +408,12 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { */ private void generateBuilderBasedConstructor(JavacNode typeNode, List typeParams, java.util.List builderFields, JavacNode source, String builderClassName, boolean callBuilderBasedSuperConstructor) { JavacTreeMaker maker = typeNode.getTreeMaker(); - + AccessLevel level = AccessLevel.PROTECTED; - boolean isEnum = (((JCClassDecl) typeNode.get()).mods.flags & Flags.ENUM) != 0; - if (isEnum) { - level = AccessLevel.PRIVATE; - } - + ListBuffer nullChecks = new ListBuffer(); ListBuffer statements = new ListBuffer(); - + Name builderVariableName = typeNode.toName("b"); for (BuilderFieldData bfd : builderFields) { List nonNulls = findAnnotations(bfd.originalFieldNode, NON_NULL_PATTERN); @@ -340,7 +423,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { nullChecks.append(nullCheck); } } - + JCExpression rhs; if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, bfd.originalFieldNode, bfd.type, statements, bfd.name, "b"); @@ -348,15 +431,15 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } else { rhs = maker.Select(maker.Ident(builderVariableName), bfd.rawName); } - JCFieldAccess thisX = maker.Select(maker.Ident(bfd.originalFieldNode.toName("this")), bfd.rawName); - + JCFieldAccess thisX = maker.Select(maker.Ident(typeNode.toName("this")), bfd.rawName); + JCExpression assign = maker.Assign(thisX, rhs); - + statements.append(maker.Exec(assign)); } - + JCModifiers mods = maker.Modifiers(toJavacModifier(level), List.nil()); - + // Create a constructor that has just the builder as parameter. ListBuffer params = new ListBuffer(); long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext()); @@ -387,16 +470,31 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { injectMethod(typeNode, constr, null, Javac.createVoidType(typeNode.getSymbolTable(), CTC_VOID)); } - private ListBuffer getTypeParamExpressions(List typeParams, JavacTreeMaker maker) { - ListBuffer typeParamsForBuilderParameter = new ListBuffer(); - for (JCTree typeParam : typeParams) { - if (typeParam instanceof JCTypeParameter) { - typeParamsForBuilderParameter.add(maker.Ident(((JCTypeParameter)typeParam).getName())); - } else if (typeParam instanceof JCIdent) { - typeParamsForBuilderParameter.add(maker.Ident(((JCIdent)typeParam).getName())); - } + private JCMethodDecl generateBuilderMethod(String builderMethodName, String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List typeParams) { + JavacTreeMaker maker = type.getTreeMaker(); + + ListBuffer typeArgs = new ListBuffer(); + for (JCTypeParameter typeParam : typeParams) { + typeArgs.append(maker.Ident(typeParam.name)); } - return typeParamsForBuilderParameter; + + JCExpression call = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderImplClassName), typeParams), List.nil(), null); + JCStatement statement = maker.Return(call); + + JCBlock body = maker.Block(0, List.of(statement)); + int modifiers = Flags.PUBLIC; + modifiers |= Flags.STATIC; + + // Add any type params of the annotated class to the return type. + ListBuffer typeParameterNames = new ListBuffer(); + typeParameterNames.addAll(typeParameterNames(maker, typeParams)); + // Now add the . + JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); + typeParameterNames.add(wildcard); + typeParameterNames.add(wildcard); + JCTypeApply returnType = maker.TypeApply(maker.Ident(type.toName(builderClassName)), typeParameterNames.toList()); + + return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.nil(), List.nil(), body, null); } private JCMethodDecl generateAbstractSelfMethod(JavacNode type, boolean override, String builderGenericName) { @@ -412,7 +510,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { return maker.MethodDef(modifiers, name, returnType, List.nil(), List.nil(), List.nil(), null, null); } - + private JCMethodDecl generateSelfMethod(JavacNode builderImplType) { JavacTreeMaker maker = builderImplType.getTreeMaker(); @@ -426,7 +524,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { return maker.MethodDef(modifiers, name, returnType, List.nil(), List.nil(), List.nil(), body, null); } - + private JCMethodDecl generateAbstractBuildMethod(JavacNode type, String methodName, boolean override, String classGenericName) { JavacTreeMaker maker = type.getTreeMaker(); List annotations = List.nil(); @@ -440,87 +538,62 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { return maker.MethodDef(modifiers, name, returnType, List.nil(), List.nil(), List.nil(), null, null); } - - private JCMethodDecl generateCleanMethod(java.util.List builderFields, JavacNode type, JCTree source) { - JavacTreeMaker maker = type.getTreeMaker(); - ListBuffer statements = new ListBuffer(); - - for (BuilderFieldData bfd : builderFields) { - if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { - bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, type, source, statements); - } - } - - statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, 0)))); - JCBlock body = maker.Block(0, statements.toList()); - return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName("$lombokClean"), maker.Type(Javac.createVoidType(type.getSymbolTable(), CTC_VOID)), List.nil(), List.nil(), List.nil(), body, null); - } - + private JCMethodDecl generateBuildMethod(String buildName, JCExpression returnType, JavacNode type, List thrownExceptions) { JavacTreeMaker maker = type.getTreeMaker(); - + JCExpression call; ListBuffer statements = new ListBuffer(); - + // Use a constructor that only has this builder as parameter. List builderArg = List.of(maker.Ident(type.toName("this"))); call = maker.NewClass(null, List.nil(), returnType, builderArg, null); statements.append(maker.Return(call)); - + JCBlock body = maker.Block(0, statements.toList()); JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.nil()); JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); - + return maker.MethodDef(modifiers, type.toName(buildName), returnType, List.nil(), List.nil(), thrownExceptions, body, null); } - - public JCMethodDecl generateDefaultProvider(Name methodName, JavacNode fieldNode, List params) { + + private JCMethodDecl generateCleanMethod(java.util.List builderFields, JavacNode type, JCTree source) { + JavacTreeMaker maker = type.getTreeMaker(); + ListBuffer statements = new ListBuffer(); + + for (BuilderFieldData bfd : builderFields) { + if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { + bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, type, source, statements); + } + } + + statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, 0)))); + JCBlock body = maker.Block(0, statements.toList()); + return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName("$lombokClean"), maker.Type(Javac.createVoidType(type.getSymbolTable(), CTC_VOID)), List.nil(), List.nil(), List.nil(), body, null); + } + + private JCMethodDecl generateDefaultProvider(Name methodName, JavacNode fieldNode, List params) { JavacTreeMaker maker = fieldNode.getTreeMaker(); JCVariableDecl field = (JCVariableDecl) fieldNode.get(); - + JCStatement statement = maker.Return(field.init); field.init = null; - + JCBlock body = maker.Block(0, List.of(statement)); int modifiers = Flags.PRIVATE | Flags.STATIC; return maker.MethodDef(maker.Modifiers(modifiers), methodName, cloneType(maker, field.vartype, field, fieldNode.getContext()), copyTypeParams(fieldNode, params), List.nil(), List.nil(), body, null); } - - public JCMethodDecl generateBuilderMethod(String builderMethodName, String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List typeParams) { - JavacTreeMaker maker = type.getTreeMaker(); - - ListBuffer typeArgs = new ListBuffer(); - for (JCTypeParameter typeParam : typeParams) { - typeArgs.append(maker.Ident(typeParam.name)); - } - - JCExpression call = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderImplClassName), typeParams), List.nil(), null); - JCStatement statement = maker.Return(call); - - JCBlock body = maker.Block(0, List.of(statement)); - int modifiers = Flags.PUBLIC; - modifiers |= Flags.STATIC; - - // Add any type params of the annotated class to the return type. - ListBuffer typeParameterNames = new ListBuffer(); - typeParameterNames.addAll(typeParameterNames(maker, typeParams)); - // Now add the . - JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); - typeParameterNames.add(wildcard); - typeParameterNames.add(wildcard); - JCTypeApply returnType = maker.TypeApply(maker.Ident(type.toName(builderClassName)), typeParameterNames.toList()); - return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.nil(), List.nil(), body, null); - } - - public void generateBuilderFields(JavacNode builderType, java.util.List builderFields, JCTree source) { + private void generateBuilderFields(JavacNode builderType, java.util.List builderFields, JCTree source) { int len = builderFields.size(); java.util.List existing = new ArrayList(); for (JavacNode child : builderType.down()) { - if (child.getKind() == Kind.FIELD) existing.add(child); + if (child.getKind() == Kind.FIELD) { + existing.add(child); + } } - + for (int i = len - 1; i >= 0; i--) { BuilderFieldData bfd = builderFields.get(i); if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) { @@ -529,8 +602,12 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { JavacNode field = null, setFlag = null; for (JavacNode exists : existing) { Name n = ((JCVariableDecl) exists.get()).name; - if (n.equals(bfd.name)) field = exists; - if (n.equals(bfd.nameOfSetFlag)) setFlag = exists; + if (n.equals(bfd.name)) { + field = exists; + } + if (n.equals(bfd.nameOfSetFlag)) { + setFlag = exists; + } } JavacTreeMaker maker = builderType.getTreeMaker(); if (field == null) { @@ -547,8 +624,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } } } - - public void makeSetterMethodsForBuilder(final JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, final String builderGenericName) { + + private void generateSetterMethodsForBuilder(final JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, final String builderGenericName) { boolean deprecate = isFieldDeprecated(fieldNode.originalFieldNode); final JavacTreeMaker maker = builderType.getTreeMaker(); // TODO: Make these lambdas when switching to a source level >= 1.8. @@ -559,113 +636,40 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { return maker.Return(maker.Apply(List.nil(), maker.Ident(builderType.toName(SELF_METHOD)), List.nil())); }}; if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) { - makeSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.nameOfSetFlag, source, true, true, returnType.get(), returnStatement.get()); + generateSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.nameOfSetFlag, source, true, true, returnType.get(), returnStatement.get()); } else { fieldNode.singularData.getSingularizer().generateMethods(fieldNode.singularData, deprecate, builderType, source.get(), true, returnType, returnStatement); } } - - private void makeSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, JCExpression returnType, JCReturn returnStatement) { + + private void generateSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, JCExpression returnType, JCReturn returnStatement) { Name fieldName = ((JCVariableDecl) fieldNode.get()).name; - + for (JavacNode child : builderType.down()) { - if (child.getKind() != Kind.METHOD) continue; + if (child.getKind() != Kind.METHOD) { + continue; + } JCMethodDecl methodDecl = (JCMethodDecl) child.get(); Name existingName = methodDecl.name; - if (existingName.equals(fieldName) && !isTolerate(fieldNode, methodDecl)) return; + if (existingName.equals(fieldName) && !isTolerate(fieldNode, methodDecl)) { + return; + } } - + String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName()); - + JavacTreeMaker maker = fieldNode.getTreeMaker(); - + JCMethodDecl newMethod = HandleSetter.createSetter(Flags.PUBLIC, deprecate, fieldNode, maker, setterName, nameOfSetFlag, returnType, returnStatement, source, List.nil(), List.nil()); - + injectMethod(builderType, newMethod); } - - public JavacNode findInnerClass(JavacNode parent, String name) { - for (JavacNode child : parent.down()) { - if (child.getKind() != Kind.TYPE) continue; - JCClassDecl td = (JCClassDecl) child.get(); - if (td.name.contentEquals(name)) return child; - } - return null; - } - - public JavacNode makeBuilderAbstractClass(JavacNode source, JavacNode tdParent, String builderClass, - JCExpression superclassBuilderClassExpression, List typeParams, - List superclassTypeParams, JCAnnotation ast, String classGenericName, String builderGenericName) { - JavacTreeMaker maker = tdParent.getTreeMaker(); - JCModifiers mods = maker.Modifiers(Flags.STATIC | Flags.ABSTRACT | Flags.PUBLIC); - // Keep any type params of the annotated class. - ListBuffer allTypeParams = new ListBuffer(); - allTypeParams.addAll(copyTypeParams(source, typeParams)); - // Add builder-specific type params required for inheritable builders. - // 1. The return type for the build() method, named "C", which extends the annotated class. - JCExpression annotatedClass = maker.Ident(tdParent.toName(tdParent.getName())); - if (typeParams.nonEmpty()) { - // Add type params of the annotated class. - annotatedClass = maker.TypeApply(annotatedClass, getTypeParamExpressions(typeParams, maker).toList()); - } - allTypeParams.add(maker.TypeParameter(tdParent.toName(classGenericName), List.of(annotatedClass))); - // 2. The return type for all setter methods, named "B", which extends this builder class. - Name builderClassName = tdParent.toName(builderClass); - ListBuffer typeParamsForBuilder = getTypeParamExpressions(typeParams, maker); - typeParamsForBuilder.add(maker.Ident(tdParent.toName(classGenericName))); - typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName))); - JCTypeApply typeApply = maker.TypeApply(maker.Ident(builderClassName), typeParamsForBuilder.toList()); - allTypeParams.add(maker.TypeParameter(tdParent.toName(builderGenericName), List.of(typeApply))); - - JCExpression extending = null; - if (superclassBuilderClassExpression != null) { - // If the annotated class extends another class, we want this builder to extend the builder of the superclass. - // 1. Add the type parameters of the superclass. - typeParamsForBuilder = getTypeParamExpressions(superclassTypeParams, maker); - // 2. Add the builder type params . - typeParamsForBuilder.add(maker.Ident(tdParent.toName(classGenericName))); - typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName))); - extending = maker.TypeApply(superclassBuilderClassExpression, typeParamsForBuilder.toList()); - } - - JCClassDecl builder = maker.ClassDef(mods, builderClassName, allTypeParams.toList(), extending, List.nil(), List.nil()); - return injectType(tdParent, builder); - } - - public JavacNode makeBuilderImplClass(JavacNode source, JavacNode tdParent, String builderImplClass, String builderAbstractClass, List typeParams, JCAnnotation ast) { - JavacTreeMaker maker = tdParent.getTreeMaker(); - JCModifiers mods = maker.Modifiers(Flags.STATIC | Flags.PRIVATE | Flags.FINAL); - - // Extend the abstract builder. - JCExpression extending = maker.Ident(tdParent.toName(builderAbstractClass)); - // Add any type params of the annotated class. - ListBuffer allTypeParams = new ListBuffer(); - allTypeParams.addAll(copyTypeParams(source, typeParams)); - // Add builder-specific type params required for inheritable builders. - // 1. The return type for the build() method (named "C" in the abstract builder), which is the annotated class. - JCExpression annotatedClass = maker.Ident(tdParent.toName(tdParent.getName())); - if (typeParams.nonEmpty()) { - // Add type params of the annotated class. - annotatedClass = maker.TypeApply(annotatedClass, getTypeParamExpressions(typeParams, maker).toList()); - } - // 2. The return type for all setter methods (named "B" in the abstract builder), which is this builder class. - JCExpression builderImplClassExpression = maker.Ident(tdParent.toName(builderImplClass)); - if (typeParams.nonEmpty()) { - builderImplClassExpression = maker.TypeApply(builderImplClassExpression, getTypeParamExpressions(typeParams, maker).toList()); - } - ListBuffer typeParamsForBuilder = getTypeParamExpressions(typeParams, maker); - typeParamsForBuilder.add(annotatedClass); - typeParamsForBuilder.add(builderImplClassExpression); - extending = maker.TypeApply(extending, typeParamsForBuilder.toList()); - - JCClassDecl builder = maker.ClassDef(mods, tdParent.toName(builderImplClass), copyTypeParams(source, typeParams), extending, List.nil(), List.nil()); - return injectType(tdParent, builder); - } - private void addObtainVia(BuilderFieldData bfd, JavacNode node) { for (JavacNode child : node.down()) { - if (!annotationTypeMatches(ObtainVia.class, child)) continue; + if (!annotationTypeMatches(ObtainVia.class, child)) { + continue; + } AnnotationValues ann = createAnnotation(ObtainVia.class, child); bfd.obtainVia = ann.getInstance(); bfd.obtainViaNode = child; @@ -673,16 +677,18 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { return; } } - + /** * Returns the explicitly requested singular annotation on this node (field * or parameter), or null if there's no {@code @Singular} annotation on it. - * + * * @param node The node (field or method param) to inspect for its name and potential {@code @Singular} annotation. */ private SingularData getSingularData(JavacNode node) { for (JavacNode child : node.down()) { - if (!annotationTypeMatches(Singular.class, child)) continue; + if (!annotationTypeMatches(Singular.class, child)) { + continue; + } Name pluralName = node.getKind() == Kind.FIELD ? removePrefixFromField(node) : ((JCVariableDecl) node.get()).name; AnnotationValues ann = createAnnotation(Singular.class, child); deleteAnnotationIfNeccessary(child, Singular.class); @@ -700,31 +706,67 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } } Name singularName = node.toName(explicitSingular); - + JCExpression type = null; if (node.get() instanceof JCVariableDecl) { type = ((JCVariableDecl) node.get()).vartype; } - + String name = null; List typeArgs = List.nil(); if (type instanceof JCTypeApply) { typeArgs = ((JCTypeApply) type).arguments; type = ((JCTypeApply) type).clazz; } - + name = type.toString(); - + String targetFqn = JavacSingularsRecipes.get().toQualified(name); JavacSingularizer singularizer = JavacSingularsRecipes.get().getSingularizer(targetFqn); if (singularizer == null) { node.addError("Lombok does not know how to create the singular-form builder methods for type '" + name + "'; they won't be generated."); return null; } - + return new SingularData(child, singularName, pluralName, typeArgs, targetFqn, singularizer); } - + return null; } + + private String generateNonclashingNameFor(String classGenericName, java.util.List typeParamStrings) { + if (!typeParamStrings.contains(classGenericName)) { + return classGenericName; + } + int counter = 2; + while (typeParamStrings.contains(classGenericName + counter)) { + counter++; + } + return classGenericName + counter; + } + + private JavacNode findInnerClass(JavacNode parent, String name) { + for (JavacNode child : parent.down()) { + if (child.getKind() != Kind.TYPE) { + continue; + } + JCClassDecl td = (JCClassDecl) child.get(); + if (td.name.contentEquals(name)) { + return child; + } + } + return null; + } + + private ListBuffer getTypeParamExpressions(List typeParams, JavacTreeMaker maker) { + ListBuffer typeParamsForBuilderParameter = new ListBuffer(); + for (JCTree typeParam : typeParams) { + if (typeParam instanceof JCTypeParameter) { + typeParamsForBuilderParameter.add(maker.Ident(((JCTypeParameter)typeParam).getName())); + } else if (typeParam instanceof JCIdent) { + typeParamsForBuilderParameter.add(maker.Ident(((JCIdent)typeParam).getName())); + } + } + return typeParamsForBuilderParameter; + } } diff --git a/test/transform/resource/after-delombok/SuperBuilderBasic.java b/test/transform/resource/after-delombok/SuperBuilderBasic.java index acad9c03..47f0ff3f 100644 --- a/test/transform/resource/after-delombok/SuperBuilderBasic.java +++ b/test/transform/resource/after-delombok/SuperBuilderBasic.java @@ -5,22 +5,6 @@ public class SuperBuilderBasic { int field1; List items; @java.lang.SuppressWarnings("all") - protected Parent(final ParentBuilder b) { - this.field1 = b.field1; - java.util.List items; - switch (b.items == null ? 0 : b.items.size()) { - case 0: - items = java.util.Collections.emptyList(); - break; - case 1: - items = java.util.Collections.singletonList(b.items.get(0)); - break; - default: - items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); - } - this.items = items; - } - @java.lang.SuppressWarnings("all") public static abstract class ParentBuilder> { @java.lang.SuppressWarnings("all") private int field1; @@ -75,6 +59,22 @@ public class SuperBuilderBasic { } } @java.lang.SuppressWarnings("all") + protected Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + @java.lang.SuppressWarnings("all") public static ParentBuilder builder() { return new ParentBuilderImpl(); } @@ -83,11 +83,6 @@ public class SuperBuilderBasic { public static class Child extends Parent { double field3; @java.lang.SuppressWarnings("all") - protected Child(final ChildBuilder b) { - super(b); - this.field3 = b.field3; - } - @java.lang.SuppressWarnings("all") public static abstract class ChildBuilder> extends Parent.ParentBuilder { @java.lang.SuppressWarnings("all") private double field3; @@ -125,6 +120,11 @@ public class SuperBuilderBasic { } } @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + @java.lang.SuppressWarnings("all") public static ChildBuilder builder() { return new ChildBuilderImpl(); } diff --git a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java index e7615c66..34a61f09 100644 --- a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java +++ b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java @@ -5,22 +5,6 @@ public class SuperBuilderWithGenerics { A field1; List items; @java.lang.SuppressWarnings("all") - protected Parent(final ParentBuilder b) { - this.field1 = b.field1; - java.util.List items; - switch (b.items == null ? 0 : b.items.size()) { - case 0: - items = java.util.Collections.emptyList(); - break; - case 1: - items = java.util.Collections.singletonList(b.items.get(0)); - break; - default: - items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); - } - this.items = items; - } - @java.lang.SuppressWarnings("all") public static abstract class ParentBuilder, B extends ParentBuilder> { @java.lang.SuppressWarnings("all") private A field1; @@ -75,6 +59,22 @@ public class SuperBuilderWithGenerics { } } @java.lang.SuppressWarnings("all") + protected Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + @java.lang.SuppressWarnings("all") public static ParentBuilder builder() { return new ParentBuilderImpl(); } @@ -83,11 +83,6 @@ public class SuperBuilderWithGenerics { public static class Child extends Parent { double field3; @java.lang.SuppressWarnings("all") - protected Child(final ChildBuilder b) { - super(b); - this.field3 = b.field3; - } - @java.lang.SuppressWarnings("all") public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { @java.lang.SuppressWarnings("all") private double field3; @@ -125,6 +120,11 @@ public class SuperBuilderWithGenerics { } } @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + @java.lang.SuppressWarnings("all") public static ChildBuilder builder() { return new ChildBuilderImpl(); } -- cgit From 1e87330f1825f1072fd2ce7eba15fb10e9e080e7 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Wed, 30 May 2018 22:50:09 +0200 Subject: test case for custom builder method --- .../SuperBuilderWithCustomBuilderMethod.java | 134 +++++++++++++++++++++ .../SuperBuilderWithCustomBuilderMethod.java | 103 ++++++++++++++++ .../SuperBuilderWithCustomBuilderMethod.java | 21 ++++ 3 files changed, 258 insertions(+) create mode 100644 test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java create mode 100644 test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java create mode 100644 test/transform/resource/before/SuperBuilderWithCustomBuilderMethod.java (limited to 'test') diff --git a/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java b/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java new file mode 100644 index 00000000..19e7a2b3 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java @@ -0,0 +1,134 @@ +import java.util.List; +public class SuperBuilderWithCustomBuilderMethod { + @lombok.experimental.SuperBuilder + public static class Parent { + A field1; + List items; + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder, B extends ParentBuilder> { + @java.lang.SuppressWarnings("all") + private A field1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList items; + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B field1(final A field1) { + this.field1 = field1; + return self(); + } + @java.lang.SuppressWarnings("all") + public B item(final String item) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + @java.lang.SuppressWarnings("all") + public B items(final java.util.Collection items) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + @java.lang.SuppressWarnings("all") + public B clearItems() { + if (this.items != null) this.items.clear(); + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + @java.lang.SuppressWarnings("all") + private ParentBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ParentBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Parent build() { + return new Parent(this); + } + } + @java.lang.SuppressWarnings("all") + protected Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + @lombok.experimental.SuperBuilder + public static class Child extends Parent { + double field3; + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private double field3; + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.Override + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B field3(final double field3) { + this.field3 = field3; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { + @java.lang.SuppressWarnings("all") + private ChildBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ChildBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Child build() { + return new Child(this); + } + } + @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + public static ChildBuilder builder() { + return new ChildBuilderImpl().item("default item"); + } + } + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} diff --git a/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java b/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java new file mode 100644 index 00000000..2f4048d6 --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java @@ -0,0 +1,103 @@ +import java.util.List; +public class SuperBuilderWithCustomBuilderMethod { + public static @lombok.experimental.SuperBuilder class Parent { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder, B extends ParentBuilder> { + private @java.lang.SuppressWarnings("all") A field1; + private @java.lang.SuppressWarnings("all") java.util.ArrayList items; + protected abstract @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B field1(final A field1) { + this.field1 = field1; + return self(); + } + public @java.lang.SuppressWarnings("all") B item(String item) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + public @java.lang.SuppressWarnings("all") B items(java.util.Collection items) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + public @java.lang.SuppressWarnings("all") B clearItems() { + if ((this.items != null)) + this.items.clear(); + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1) + ", items=") + this.items) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") Parent build() { + return new Parent(this); + } + } + A field1; + @lombok.Singular List items; + protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (((b.items == null) ? 0 : b.items.size())) { + case 0 : + items = java.util.Collections.emptyList(); + break; + case 1 : + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default : + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static @lombok.experimental.SuperBuilder class Child extends Parent { + public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + private @java.lang.SuppressWarnings("all") double field3; + protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B field3(final double field3) { + this.field3 = field3; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { + private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") Child build() { + return new Child(this); + } + } + double field3; + protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + public static @java.lang.SuppressWarnings("all") ChildBuilder builder() { + return new ChildBuilderImpl().item("default item"); + } + } + public SuperBuilderWithGenerics() { + super(); + } + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} diff --git a/test/transform/resource/before/SuperBuilderWithCustomBuilderMethod.java b/test/transform/resource/before/SuperBuilderWithCustomBuilderMethod.java new file mode 100644 index 00000000..d52cbded --- /dev/null +++ b/test/transform/resource/before/SuperBuilderWithCustomBuilderMethod.java @@ -0,0 +1,21 @@ +import java.util.List; + +public class SuperBuilderWithCustomBuilderMethod { + @lombok.experimental.SuperBuilder + public static class Parent { + A field1; + @lombok.Singular List items; + } + + @lombok.experimental.SuperBuilder + public static class Child extends Parent { + double field3; + public static ChildBuilder builder() { + return new ChildBuilderImpl().item("default item"); + } + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} -- cgit From 65b248ec62ffe87d9f4fe234c47f786f420d58dc Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Thu, 31 May 2018 14:41:40 +0200 Subject: fixed expected test results --- .../after-delombok/SuperBuilderWithCustomBuilderMethod.java | 10 +++++----- .../after-ecj/SuperBuilderWithCustomBuilderMethod.java | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'test') diff --git a/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java b/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java index 19e7a2b3..4d451558 100644 --- a/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java +++ b/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java @@ -39,7 +39,7 @@ public class SuperBuilderWithCustomBuilderMethod { @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { - return "SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; + return "SuperBuilderWithCustomBuilderMethod.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; } } @java.lang.SuppressWarnings("all") @@ -82,6 +82,9 @@ public class SuperBuilderWithCustomBuilderMethod { @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; + public static ChildBuilder builder() { + return new ChildBuilderImpl().item("default item"); + } @java.lang.SuppressWarnings("all") public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { @java.lang.SuppressWarnings("all") @@ -100,7 +103,7 @@ public class SuperBuilderWithCustomBuilderMethod { @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { - return "SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; + return "SuperBuilderWithCustomBuilderMethod.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; } } @java.lang.SuppressWarnings("all") @@ -124,9 +127,6 @@ public class SuperBuilderWithCustomBuilderMethod { super(b); this.field3 = b.field3; } - public static ChildBuilder builder() { - return new ChildBuilderImpl().item("default item"); - } } public static void test() { Child x = Child.builder().field3(0.0).field1(5).item("").build(); diff --git a/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java b/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java index 2f4048d6..119fb5bb 100644 --- a/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java +++ b/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java @@ -28,7 +28,7 @@ public class SuperBuilderWithCustomBuilderMethod { return self(); } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { - return (((("SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1) + ", items=") + this.items) + ")"); + return (((("SuperBuilderWithCustomBuilderMethod.Parent.ParentBuilder(field1=" + this.field1) + ", items=") + this.items) + ")"); } } private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { @@ -72,7 +72,7 @@ public class SuperBuilderWithCustomBuilderMethod { return self(); } public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { - return (((("SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")"); + return (((("SuperBuilderWithCustomBuilderMethod.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")"); } } private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { @@ -86,15 +86,15 @@ public class SuperBuilderWithCustomBuilderMethod { } } double field3; + public static ChildBuilder builder() { + return new ChildBuilderImpl().item("default item"); + } protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { super(b); this.field3 = b.field3; } - public static @java.lang.SuppressWarnings("all") ChildBuilder builder() { - return new ChildBuilderImpl().item("default item"); - } } - public SuperBuilderWithGenerics() { + public SuperBuilderWithCustomBuilderMethod() { super(); } public static void test() { -- cgit From 664ed48460eba30b9cab7f9298ac563c4a23c993 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Thu, 31 May 2018 14:53:20 +0200 Subject: javac: delete @SuperBuilder when processing it --- src/core/lombok/javac/handlers/HandleSuperBuilder.java | 1 + test/transform/resource/after-delombok/SuperBuilderBasic.java | 2 -- .../resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java | 2 -- test/transform/resource/after-delombok/SuperBuilderWithGenerics.java | 2 -- 4 files changed, 1 insertion(+), 6 deletions(-) (limited to 'test') diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index 116de47b..1055a11a 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -95,6 +95,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCAnnotation ast, JavacNode annotationNode) { SuperBuilder superbuilderAnnotation = annotation.getInstance(); + deleteAnnotationIfNeccessary(annotationNode, SuperBuilder.class); String builderMethodName = superbuilderAnnotation.builderMethodName(); String buildMethodName = superbuilderAnnotation.buildMethodName(); diff --git a/test/transform/resource/after-delombok/SuperBuilderBasic.java b/test/transform/resource/after-delombok/SuperBuilderBasic.java index 47f0ff3f..18a98af3 100644 --- a/test/transform/resource/after-delombok/SuperBuilderBasic.java +++ b/test/transform/resource/after-delombok/SuperBuilderBasic.java @@ -1,6 +1,5 @@ import java.util.List; public class SuperBuilderBasic { - @lombok.experimental.SuperBuilder public static class Parent { int field1; List items; @@ -79,7 +78,6 @@ public class SuperBuilderBasic { return new ParentBuilderImpl(); } } - @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; @java.lang.SuppressWarnings("all") diff --git a/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java b/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java index 4d451558..21a9db07 100644 --- a/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java +++ b/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java @@ -1,6 +1,5 @@ import java.util.List; public class SuperBuilderWithCustomBuilderMethod { - @lombok.experimental.SuperBuilder public static class Parent { A field1; List items; @@ -79,7 +78,6 @@ public class SuperBuilderWithCustomBuilderMethod { return new ParentBuilderImpl(); } } - @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; public static ChildBuilder builder() { diff --git a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java index 34a61f09..c24b473e 100644 --- a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java +++ b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java @@ -1,6 +1,5 @@ import java.util.List; public class SuperBuilderWithGenerics { - @lombok.experimental.SuperBuilder public static class Parent { A field1; List items; @@ -79,7 +78,6 @@ public class SuperBuilderWithGenerics { return new ParentBuilderImpl(); } } - @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; @java.lang.SuppressWarnings("all") -- cgit From 7bd60ea6e68699b9b75f6fb4ce8c68abfa69f5de Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Thu, 31 May 2018 16:32:14 +0200 Subject: second generics test case --- .../eclipse/handlers/HandleSuperBuilder.java | 5 +- .../after-delombok/SuperBuilderWithGenerics2.java | 133 +++++++++++++++++++++ .../after-ecj/SuperBuilderWithGenerics2.java | 103 ++++++++++++++++ .../resource/before/SuperBuilderWithGenerics2.java | 18 +++ 4 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 test/transform/resource/after-delombok/SuperBuilderWithGenerics2.java create mode 100644 test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java create mode 100644 test/transform/resource/before/SuperBuilderWithGenerics2.java (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index d452261a..d4441831 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -141,7 +141,6 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { java.util.List builderFields = new ArrayList(); TypeReference returnType; TypeParameter[] typeParams; - TypeParameter[] superclassTypeParams = new TypeParameter[] {}; //TODO boolean addCleaning = false; @@ -267,7 +266,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { EclipseNode builderType = findInnerClass(tdParent, builderClassName); if (builderType == null) { builderType = generateBuilderAbstractClass(tdParent, builderClassName, superclassBuilderClass, - typeParams, superclassTypeParams, ast, classGenericName, builderGenericName); + typeParams, ast, classGenericName, builderGenericName); } else { annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead."); @@ -360,7 +359,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { private EclipseNode generateBuilderAbstractClass(EclipseNode tdParent, String builderClass, TypeReference superclassBuilderClass, TypeParameter[] typeParams, - TypeParameter[] superclassTypeParams, ASTNode source, String classGenericName, String builderGenericName) { + ASTNode source, String classGenericName, String builderGenericName) { TypeDeclaration parent = (TypeDeclaration) tdParent.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); diff --git a/test/transform/resource/after-delombok/SuperBuilderWithGenerics2.java b/test/transform/resource/after-delombok/SuperBuilderWithGenerics2.java new file mode 100644 index 00000000..811fd7e8 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderWithGenerics2.java @@ -0,0 +1,133 @@ +import java.util.List; +public class SuperBuilderWithGenerics2 { + public static class Parent { + A field1; + List items; + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder, B extends ParentBuilder> { + @java.lang.SuppressWarnings("all") + private A field1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList items; + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B field1(final A field1) { + this.field1 = field1; + return self(); + } + @java.lang.SuppressWarnings("all") + public B item(final String item) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + @java.lang.SuppressWarnings("all") + public B items(final java.util.Collection items) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + @java.lang.SuppressWarnings("all") + public B clearItems() { + if (this.items != null) this.items.clear(); + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics2.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + @java.lang.SuppressWarnings("all") + private ParentBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ParentBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Parent build() { + return new Parent(this); + } + } + @java.lang.SuppressWarnings("all") + protected Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static class Child extends Parent { + A field3; + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private A field3; + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.Override + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B field3(final A field3) { + this.field3 = field3; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics2.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { + @java.lang.SuppressWarnings("all") + private ChildBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ChildBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Child build() { + return new Child(this); + } + } + @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + @java.lang.SuppressWarnings("all") + public static ChildBuilder builder2() { + return new ChildBuilderImpl(); + } + } + public static void test() { + Child x = Child.builder2().field3(1).field1("value").item("").build(); + } +} diff --git a/test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java b/test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java new file mode 100644 index 00000000..74cf376e --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java @@ -0,0 +1,103 @@ +import java.util.List; +public class SuperBuilderWithGenerics2 { + public static @lombok.experimental.SuperBuilder class Parent { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder, B extends ParentBuilder> { + private @java.lang.SuppressWarnings("all") A field1; + private @java.lang.SuppressWarnings("all") java.util.ArrayList items; + protected abstract @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B field1(final A field1) { + this.field1 = field1; + return self(); + } + public @java.lang.SuppressWarnings("all") B item(String item) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + public @java.lang.SuppressWarnings("all") B items(java.util.Collection items) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + public @java.lang.SuppressWarnings("all") B clearItems() { + if ((this.items != null)) + this.items.clear(); + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithGenerics2.Parent.ParentBuilder(field1=" + this.field1) + ", items=") + this.items) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") Parent build() { + return new Parent(this); + } + } + A field1; + @lombok.Singular List items; + protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (((b.items == null) ? 0 : b.items.size())) { + case 0 : + items = java.util.Collections.emptyList(); + break; + case 1 : + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default : + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static @lombok.experimental.SuperBuilder(builderMethodName = "builder2") class Child extends Parent { + public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + private @java.lang.SuppressWarnings("all") A field3; + protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B field3(final A field3) { + this.field3 = field3; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithGenerics2.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { + private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") Child build() { + return new Child(this); + } + } + A field3; + protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + public static @java.lang.SuppressWarnings("all") ChildBuilder builder2() { + return new ChildBuilderImpl(); + } + } + public SuperBuilderWithGenerics2() { + super(); + } + public static void test() { + Child x = Child.builder2().field3(1).field1("value").item("").build(); + } +} diff --git a/test/transform/resource/before/SuperBuilderWithGenerics2.java b/test/transform/resource/before/SuperBuilderWithGenerics2.java new file mode 100644 index 00000000..f84ff1f5 --- /dev/null +++ b/test/transform/resource/before/SuperBuilderWithGenerics2.java @@ -0,0 +1,18 @@ +import java.util.List; + +public class SuperBuilderWithGenerics2 { + @lombok.experimental.SuperBuilder + public static class Parent { + A field1; + @lombok.Singular List items; + } + + @lombok.experimental.SuperBuilder(builderMethodName="builder2") + public static class Child extends Parent { + A field3; + } + + public static void test() { + Child x = Child.builder2().field3(1).field1("value").item("").build(); + } +} -- cgit From 795e3c84875de0a01f4d5e1321312f592139c7aa Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Thu, 31 May 2018 16:40:08 +0200 Subject: Revert "ecj: SuperBuilderBasic test passes (removed superconstructor calls)" This reverts commit 9ee2491427f1522a7689d1c28a816294bcff315b. --- src/core/lombok/eclipse/handlers/HandleConstructor.java | 12 +++++------- src/core/lombok/eclipse/handlers/HandleSuperBuilder.java | 13 +++++++------ test/transform/resource/after-ecj/SuperBuilderBasic.java | 3 +++ 3 files changed, 15 insertions(+), 13 deletions(-) (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index ccf71158..a2940b88 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -259,7 +259,7 @@ public class HandleConstructor { ConstructorDeclaration constr = createConstructor( staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, allToDefault, - true, sourceNode, onConstructor); + sourceNode, onConstructor); injectMethod(typeNode, constr); if (staticConstrRequired) { MethodDeclaration staticConstr = createStaticConstructor(level, staticName, typeNode, allToDefault ? Collections.emptyList() : fields, source); @@ -301,7 +301,7 @@ public class HandleConstructor { @SuppressWarnings("deprecation") public static ConstructorDeclaration createConstructor( AccessLevel level, EclipseNode type, Collection fields, boolean allToDefault, - boolean superConstructorCall, EclipseNode sourceNode, List onConstructor) { + EclipseNode sourceNode, List onConstructor) { ASTNode source = sourceNode.get(); TypeDeclaration typeDeclaration = ((TypeDeclaration) type.get()); @@ -324,11 +324,9 @@ public class HandleConstructor { constructor.modifiers = toEclipseModifier(level); constructor.selector = typeDeclaration.name; - if (superConstructorCall) { - constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); - constructor.constructorCall.sourceStart = source.sourceStart; - constructor.constructorCall.sourceEnd = source.sourceEnd; - } + constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + constructor.constructorCall.sourceStart = source.sourceStart; + constructor.constructorCall.sourceEnd = source.sourceEnd; constructor.thrownExceptions = null; constructor.typeParameters = null; constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index d4441831..3b7e95ca 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -63,7 +63,6 @@ import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; @@ -339,7 +338,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { } // Create a simple constructor for the BuilderImpl class. - ConstructorDeclaration cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, builderImplType, Collections.emptyList(), false, false, annotationNode, Collections.emptyList()); + ConstructorDeclaration cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, builderImplType, Collections.emptyList(), false, annotationNode, Collections.emptyList()); if (cd != null) { injectMethod(builderImplType, cd); } @@ -445,9 +444,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { if (callBuilderBasedSuperConstructor) { constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.Super); constructor.constructorCall.arguments = new Expression[] {new SingleNameReference("b".toCharArray(), p)}; - constructor.constructorCall.sourceStart = source.sourceStart; - constructor.constructorCall.sourceEnd = source.sourceEnd; + } else { + constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); } + constructor.constructorCall.sourceStart = source.sourceStart; + constructor.constructorCall.sourceEnd = source.sourceEnd; constructor.thrownExceptions = null; constructor.typeParameters = null; constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; @@ -525,7 +526,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); out.selector = SELF_METHOD.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected | ExtraCompilerModifiers.AccSemicolonBody; + out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected; if (override) { out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, tdParent.get())}; } @@ -549,7 +550,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract | ExtraCompilerModifiers.AccSemicolonBody; + out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract; out.selector = methodName.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.returnType = new SingleTypeReference(classGenericName.toCharArray(), 0); diff --git a/test/transform/resource/after-ecj/SuperBuilderBasic.java b/test/transform/resource/after-ecj/SuperBuilderBasic.java index fc5f045b..88ac7e70 100644 --- a/test/transform/resource/after-ecj/SuperBuilderBasic.java +++ b/test/transform/resource/after-ecj/SuperBuilderBasic.java @@ -33,6 +33,7 @@ public class SuperBuilderBasic { } private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder { private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { + super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { return this; @@ -44,6 +45,7 @@ public class SuperBuilderBasic { int field1; @lombok.Singular List items; protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + super(); this.field1 = b.field1; java.util.List items; switch (((b.items == null) ? 0 : b.items.size())) { @@ -77,6 +79,7 @@ public class SuperBuilderBasic { } private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder { private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { + super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { return this; -- cgit From 32bed51fede1eebef2006d54b3e364de22ae9ac0 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Thu, 31 May 2018 18:01:43 +0200 Subject: ecj: generate default constructor for builder classes --- src/core/lombok/eclipse/handlers/HandleBuilder.java | 2 +- .../lombok/eclipse/handlers/HandleSuperBuilder.java | 17 +++++++++-------- .../transform/resource/after-ecj/SuperBuilderBasic.java | 10 ++++++++-- .../after-ecj/SuperBuilderWithCustomBuilderMethod.java | 13 +++++++++++-- .../resource/after-ecj/SuperBuilderWithGenerics.java | 13 +++++++++++-- .../resource/after-ecj/SuperBuilderWithGenerics2.java | 13 +++++++++++-- 6 files changed, 51 insertions(+), 17 deletions(-) (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 331fbde4..fe19decd 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -434,7 +434,7 @@ public class HandleBuilder extends EclipseAnnotationHandler { if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) { ConstructorDeclaration cd = HandleConstructor.createConstructor( - AccessLevel.PACKAGE, builderType, Collections.emptyList(), false, true, + AccessLevel.PACKAGE, builderType, Collections.emptyList(), false, annotationNode, Collections.emptyList()); if (cd != null) injectMethod(builderType, cd); } diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 3b7e95ca..04c3b2fe 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -63,6 +63,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; @@ -337,12 +338,6 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { return; } - // Create a simple constructor for the BuilderImpl class. - ConstructorDeclaration cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, builderImplType, Collections.emptyList(), false, annotationNode, Collections.emptyList()); - if (cd != null) { - injectMethod(builderImplType, cd); - } - // Create the self() and build() methods in the BuilderImpl. injectMethod(builderImplType, generateSelfMethod(builderImplType)); injectMethod(builderImplType, generateBuildMethod(tdParent, buildMethodName, returnType, ast)); @@ -383,6 +378,8 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { builder.superclass = copyType(superclassBuilderClass, source); + builder.createDefaultConstructor(false, true); + builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return injectType(tdParent, builder); } @@ -393,6 +390,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { builder.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; builder.modifiers |= ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal; builder.name = builderImplClass.toCharArray(); + // Add type params if there are any. if (typeParams != null && typeParams.length > 0) { builder.typeParameters = copyTypeParams(typeParams, source); @@ -410,6 +408,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { typeArgs[typeArgs.length - 1] = createTypeReferenceWithTypeParameters(builderImplClass, typeParams); builder.superclass = new ParameterizedSingleTypeReference(builderAbstractClass.toCharArray(), typeArgs, 0, 0); } + + builder.createDefaultConstructor(false, true); + builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return injectType(tdParent, builder); } @@ -526,7 +527,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); out.selector = SELF_METHOD.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected; + out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected | ExtraCompilerModifiers.AccSemicolonBody; if (override) { out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, tdParent.get())}; } @@ -550,7 +551,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract; + out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract | ExtraCompilerModifiers.AccSemicolonBody; out.selector = methodName.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.returnType = new SingleTypeReference(classGenericName.toCharArray(), 0); diff --git a/test/transform/resource/after-ecj/SuperBuilderBasic.java b/test/transform/resource/after-ecj/SuperBuilderBasic.java index 88ac7e70..11fd8498 100644 --- a/test/transform/resource/after-ecj/SuperBuilderBasic.java +++ b/test/transform/resource/after-ecj/SuperBuilderBasic.java @@ -4,6 +4,9 @@ public class SuperBuilderBasic { public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder> { private @java.lang.SuppressWarnings("all") int field1; private @java.lang.SuppressWarnings("all") java.util.ArrayList items; + public ParentBuilder() { + super(); + } protected abstract @java.lang.SuppressWarnings("all") B self(); public abstract @java.lang.SuppressWarnings("all") C build(); public @java.lang.SuppressWarnings("all") B field1(final int field1) { @@ -32,7 +35,7 @@ public class SuperBuilderBasic { } } private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder { - private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { + private ParentBuilderImpl() { super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { @@ -67,6 +70,9 @@ public class SuperBuilderBasic { public static @lombok.experimental.SuperBuilder class Child extends Parent { public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder> extends Parent.ParentBuilder { private @java.lang.SuppressWarnings("all") double field3; + public ChildBuilder() { + super(); + } protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); public @java.lang.SuppressWarnings("all") B field3(final double field3) { @@ -78,7 +84,7 @@ public class SuperBuilderBasic { } } private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder { - private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { + private ChildBuilderImpl() { super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { diff --git a/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java b/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java index 119fb5bb..fe4938bf 100644 --- a/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java +++ b/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java @@ -4,6 +4,9 @@ public class SuperBuilderWithCustomBuilderMethod { public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder, B extends ParentBuilder> { private @java.lang.SuppressWarnings("all") A field1; private @java.lang.SuppressWarnings("all") java.util.ArrayList items; + public ParentBuilder() { + super(); + } protected abstract @java.lang.SuppressWarnings("all") B self(); public abstract @java.lang.SuppressWarnings("all") C build(); public @java.lang.SuppressWarnings("all") B field1(final A field1) { @@ -32,7 +35,8 @@ public class SuperBuilderWithCustomBuilderMethod { } } private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { - private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { + private ParentBuilderImpl() { + super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { return this; @@ -44,6 +48,7 @@ public class SuperBuilderWithCustomBuilderMethod { A field1; @lombok.Singular List items; protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + super(); this.field1 = b.field1; java.util.List items; switch (((b.items == null) ? 0 : b.items.size())) { @@ -65,6 +70,9 @@ public class SuperBuilderWithCustomBuilderMethod { public static @lombok.experimental.SuperBuilder class Child extends Parent { public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { private @java.lang.SuppressWarnings("all") double field3; + public ChildBuilder() { + super(); + } protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); public @java.lang.SuppressWarnings("all") B field3(final double field3) { @@ -76,7 +84,8 @@ public class SuperBuilderWithCustomBuilderMethod { } } private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { - private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { + private ChildBuilderImpl() { + super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { return this; diff --git a/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java b/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java index cb717bcf..b82f25cb 100644 --- a/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java +++ b/test/transform/resource/after-ecj/SuperBuilderWithGenerics.java @@ -4,6 +4,9 @@ public class SuperBuilderWithGenerics { public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder, B extends ParentBuilder> { private @java.lang.SuppressWarnings("all") A field1; private @java.lang.SuppressWarnings("all") java.util.ArrayList items; + public ParentBuilder() { + super(); + } protected abstract @java.lang.SuppressWarnings("all") B self(); public abstract @java.lang.SuppressWarnings("all") C build(); public @java.lang.SuppressWarnings("all") B field1(final A field1) { @@ -32,7 +35,8 @@ public class SuperBuilderWithGenerics { } } private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { - private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { + private ParentBuilderImpl() { + super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { return this; @@ -44,6 +48,7 @@ public class SuperBuilderWithGenerics { A field1; @lombok.Singular List items; protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + super(); this.field1 = b.field1; java.util.List items; switch (((b.items == null) ? 0 : b.items.size())) { @@ -65,6 +70,9 @@ public class SuperBuilderWithGenerics { public static @lombok.experimental.SuperBuilder class Child extends Parent { public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { private @java.lang.SuppressWarnings("all") double field3; + public ChildBuilder() { + super(); + } protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); public @java.lang.SuppressWarnings("all") B field3(final double field3) { @@ -76,7 +84,8 @@ public class SuperBuilderWithGenerics { } } private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { - private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { + private ChildBuilderImpl() { + super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { return this; diff --git a/test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java b/test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java index 74cf376e..7db95ea0 100644 --- a/test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java +++ b/test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java @@ -4,6 +4,9 @@ public class SuperBuilderWithGenerics2 { public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder, B extends ParentBuilder> { private @java.lang.SuppressWarnings("all") A field1; private @java.lang.SuppressWarnings("all") java.util.ArrayList items; + public ParentBuilder() { + super(); + } protected abstract @java.lang.SuppressWarnings("all") B self(); public abstract @java.lang.SuppressWarnings("all") C build(); public @java.lang.SuppressWarnings("all") B field1(final A field1) { @@ -32,7 +35,8 @@ public class SuperBuilderWithGenerics2 { } } private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { - private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { + private ParentBuilderImpl() { + super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { return this; @@ -44,6 +48,7 @@ public class SuperBuilderWithGenerics2 { A field1; @lombok.Singular List items; protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + super(); this.field1 = b.field1; java.util.List items; switch (((b.items == null) ? 0 : b.items.size())) { @@ -65,6 +70,9 @@ public class SuperBuilderWithGenerics2 { public static @lombok.experimental.SuperBuilder(builderMethodName = "builder2") class Child extends Parent { public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { private @java.lang.SuppressWarnings("all") A field3; + public ChildBuilder() { + super(); + } protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); public @java.lang.SuppressWarnings("all") B field3(final A field3) { @@ -76,7 +84,8 @@ public class SuperBuilderWithGenerics2 { } } private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { - private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { + private ChildBuilderImpl() { + super(); } protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { return this; -- cgit From d11263a6c60008894213a1b465f2b16be3a03468 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Fri, 1 Jun 2018 13:48:38 +0200 Subject: support @Builder.Default --- .../eclipse/handlers/HandleBuilderDefault.java | 6 +- .../eclipse/handlers/HandleSuperBuilder.java | 40 ++++--- .../javac/handlers/HandleBuilderDefault.java | 6 +- .../lombok/javac/handlers/HandleSuperBuilder.java | 42 ++++---- .../after-delombok/SuperBuilderWithDefaults.java | 119 +++++++++++++++++++++ .../after-ecj/SuperBuilderWithDefaults.java | 97 +++++++++++++++++ .../resource/before/SuperBuilderWithDefaults.java | 18 ++++ .../features/experimental/SuperBuilder.html | 4 +- 8 files changed, 290 insertions(+), 42 deletions(-) create mode 100644 test/transform/resource/after-delombok/SuperBuilderWithDefaults.java create mode 100644 test/transform/resource/after-ecj/SuperBuilderWithDefaults.java create mode 100644 test/transform/resource/before/SuperBuilderWithDefaults.java (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java b/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java index be2b986d..d0c597fd 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java @@ -31,6 +31,7 @@ import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; +import lombok.experimental.SuperBuilder; @ProviderFor(EclipseAnnotationHandler.class) @HandlerPriority(-1025) //HandleBuilder's level, minus one. @@ -39,8 +40,9 @@ public class HandleBuilderDefault extends EclipseAnnotationHandler { private static final char[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray(); private static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray(); - private static final char[] DEFAULT_PREFIX = {'$', 'd', 'e', 'f', 'a', 'u', 'l', 't', '$'}; - private static final char[] SET_PREFIX = {'$', 's', 'e', 't'}; - private static final String SELF_METHOD = "self"; + private static final char[] SET_PREFIX = "$set".toCharArray(); + private static final char[] SELF_METHOD_NAME = "self".toCharArray(); private static final AbstractMethodDeclaration[] EMPTY_METHODS = {}; @@ -103,7 +103,6 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { TypeReference type; char[] rawName; char[] name; - char[] nameOfDefaultProvider; char[] nameOfSetFlag; SingularData singularData; ObtainVia obtainVia; @@ -185,13 +184,16 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { } if (isDefault != null) { - bfd.nameOfDefaultProvider = prefixWith(DEFAULT_PREFIX, bfd.name); bfd.nameOfSetFlag = prefixWith(bfd.name, SET_PREFIX); - - MethodDeclaration md = HandleBuilder.generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast); - if (md != null) { - injectMethod(tdParent, md); - } + // The @Builder annotation removes the initializing expression on the field and moves + // it to a method called "$default$FIELDNAME". This method is then called upon building. + // We do NOT do this, because this is unexpected and may lead to bugs when using other + // constructors (see, e.g., issue #1347). + // Instead, we keep the init expression and only set a new value in the builder-based + // constructor if it was set in the builder. Drawback is that the init expression is + // always executed, even if it was unnecessary because its value is overwritten by the + // builder. + // TODO: Once the issue is resolved in @Builder, we can adapt the solution here. } addObtainVia(bfd, fieldNode); builderFields.add(bfd); @@ -481,9 +483,17 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { long[] positions = new long[] {p, p}; assignmentExpr = new QualifiedNameReference(variableInBuilder, positions, s, e); } - - Assignment assignment = new Assignment(thisX, assignmentExpr, (int) p); + Statement assignment = new Assignment(thisX, assignmentExpr, (int) p); + + // In case of @Builder.Default, only set the value if it really was set in the builder. + if (fieldNode.nameOfSetFlag != null) { + char[][] variableInBuilder = new char[][] {"b".toCharArray(), fieldNode.nameOfSetFlag}; + long[] positions = new long[] {p, p}; + QualifiedNameReference builderRef = new QualifiedNameReference(variableInBuilder, positions, s, e); + assignment = new IfStatement(builderRef, assignment, s, e); + } statements.add(assignment); + Annotation[] nonNulls = findAnnotations((FieldDeclaration)fieldNode.originalFieldNode.get(), NON_NULL_PATTERN); if (nonNulls.length != 0) { Statement nullCheck = generateNullCheck((FieldDeclaration)fieldNode.originalFieldNode.get(), sourceNode); @@ -527,7 +537,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { private MethodDeclaration generateAbstractSelfMethod(EclipseNode tdParent, boolean override, String builderGenericName) { MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); - out.selector = SELF_METHOD.toCharArray(); + out.selector = SELF_METHOD_NAME; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected | ExtraCompilerModifiers.AccSemicolonBody; if (override) { @@ -539,7 +549,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { private MethodDeclaration generateSelfMethod(EclipseNode builderImplType) { MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderImplType.top().get()).compilationResult); - out.selector = SELF_METHOD.toCharArray(); + out.selector = SELF_METHOD_NAME; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccProtected; out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, builderImplType.get())}; @@ -665,7 +675,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { @Override public ReturnStatement get() { MessageSend returnCall = new MessageSend(); returnCall.receiver = ThisReference.implicitThis(); - returnCall.selector = SELF_METHOD.toCharArray(); + returnCall.selector = SELF_METHOD_NAME; return new ReturnStatement(returnCall, 0, 0); } }; diff --git a/src/core/lombok/javac/handlers/HandleBuilderDefault.java b/src/core/lombok/javac/handlers/HandleBuilderDefault.java index 4c4ba0e8..af45a620 100644 --- a/src/core/lombok/javac/handlers/HandleBuilderDefault.java +++ b/src/core/lombok/javac/handlers/HandleBuilderDefault.java @@ -31,6 +31,7 @@ import lombok.Builder; import lombok.core.AST.Kind; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; +import lombok.experimental.SuperBuilder; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; @@ -41,8 +42,9 @@ public class HandleBuilderDefault extends JavacAnnotationHandler { JCExpression type; Name rawName; Name name; - Name nameOfDefaultProvider; Name nameOfSetFlag; SingularData singularData; ObtainVia obtainVia; @@ -164,13 +164,16 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } if (isDefault != null) { - bfd.nameOfDefaultProvider = tdParent.toName("$default$" + bfd.name); bfd.nameOfSetFlag = tdParent.toName(bfd.name + "$set"); - JCMethodDecl md = generateDefaultProvider(bfd.nameOfDefaultProvider, fieldNode, td.typarams); - recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); - if (md != null) { - injectMethod(tdParent, md); - } + // The @Builder annotation removes the initializing expression on the field and moves + // it to a method called "$default$FIELDNAME". This method is then called upon building. + // We do NOT do this, because this is unexpected and may lead to bugs when using other + // constructors (see, e.g., issue #1347). + // Instead, we keep the init expression and only set a new value in the builder-based + // constructor if it was set in the builder. Drawback is that the init expression is + // always executed, even if it was unnecessary because its value is overwritten by the + // builder. + // TODO: Once the issue is resolved in @Builder, we can adapt the solution here. } addObtainVia(bfd, fieldNode); builderFields.add(bfd); @@ -435,9 +438,16 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } JCFieldAccess thisX = maker.Select(maker.Ident(typeNode.toName("this")), bfd.rawName); - JCExpression assign = maker.Assign(thisX, rhs); - - statements.append(maker.Exec(assign)); + JCStatement assign = maker.Exec(maker.Assign(thisX, rhs)); + + // In case of @Builder.Default, only set the value if it really was set in the builder. + if (bfd.nameOfSetFlag != null) { + JCFieldAccess setField = maker.Select(maker.Ident(builderVariableName), bfd.nameOfSetFlag); + JCIf ifSet = maker.If(setField, assign, null); + statements.append(ifSet); + } else { + statements.append(assign); + } } JCModifiers mods = maker.Modifiers(toJavacModifier(level), List.nil()); @@ -575,18 +585,6 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName("$lombokClean"), maker.Type(Javac.createVoidType(type.getSymbolTable(), CTC_VOID)), List.nil(), List.nil(), List.nil(), body, null); } - private JCMethodDecl generateDefaultProvider(Name methodName, JavacNode fieldNode, List params) { - JavacTreeMaker maker = fieldNode.getTreeMaker(); - JCVariableDecl field = (JCVariableDecl) fieldNode.get(); - - JCStatement statement = maker.Return(field.init); - field.init = null; - - JCBlock body = maker.Block(0, List.of(statement)); - int modifiers = Flags.PRIVATE | Flags.STATIC; - return maker.MethodDef(maker.Modifiers(modifiers), methodName, cloneType(maker, field.vartype, field, fieldNode.getContext()), copyTypeParams(fieldNode, params), List.nil(), List.nil(), body, null); - } - private void generateBuilderFields(JavacNode builderType, java.util.List builderFields, JCTree source) { int len = builderFields.size(); java.util.List existing = new ArrayList(); diff --git a/test/transform/resource/after-delombok/SuperBuilderWithDefaults.java b/test/transform/resource/after-delombok/SuperBuilderWithDefaults.java new file mode 100644 index 00000000..7b6b4578 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderWithDefaults.java @@ -0,0 +1,119 @@ +import java.util.List; +public class SuperBuilderWithDefaults { + public static class Parent { + private long millis = System.currentTimeMillis(); + private N numberField = null; + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder, B extends ParentBuilder> { + @java.lang.SuppressWarnings("all") + private boolean millis$set; + @java.lang.SuppressWarnings("all") + private long millis; + @java.lang.SuppressWarnings("all") + private boolean numberField$set; + @java.lang.SuppressWarnings("all") + private N numberField; + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B millis(final long millis) { + this.millis = millis; + millis$set = true; + return self(); + } + @java.lang.SuppressWarnings("all") + public B numberField(final N numberField) { + this.numberField = numberField; + numberField$set = true; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithDefaults.Parent.ParentBuilder(millis=" + this.millis + ", numberField=" + this.numberField + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + @java.lang.SuppressWarnings("all") + private ParentBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ParentBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Parent build() { + return new Parent(this); + } + } + @java.lang.SuppressWarnings("all") + protected Parent(final ParentBuilder b) { + if (b.millis$set) this.millis = b.millis; + if (b.numberField$set) this.numberField = b.numberField; + } + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static class Child extends Parent { + private double doubleField = Math.PI; + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private boolean doubleField$set; + @java.lang.SuppressWarnings("all") + private double doubleField; + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.Override + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B doubleField(final double doubleField) { + this.doubleField = doubleField; + doubleField$set = true; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithDefaults.Child.ChildBuilder(super=" + super.toString() + ", doubleField=" + this.doubleField + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ChildBuilderImpl extends ChildBuilder { + @java.lang.SuppressWarnings("all") + private ChildBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ChildBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Child build() { + return new Child(this); + } + } + @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + if (b.doubleField$set) this.doubleField = b.doubleField; + } + @java.lang.SuppressWarnings("all") + public static ChildBuilder builder() { + return new ChildBuilderImpl(); + } + } + public static void test() { + Child x = Child.builder().doubleField(0.1).numberField(5).millis(1234567890L).build(); + } +} diff --git a/test/transform/resource/after-ecj/SuperBuilderWithDefaults.java b/test/transform/resource/after-ecj/SuperBuilderWithDefaults.java new file mode 100644 index 00000000..f0e3d8be --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderWithDefaults.java @@ -0,0 +1,97 @@ +import java.util.List; +public class SuperBuilderWithDefaults { + public static @lombok.experimental.SuperBuilder class Parent { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder, B extends ParentBuilder> { + private @java.lang.SuppressWarnings("all") long millis; + private @java.lang.SuppressWarnings("all") boolean millis$set; + private @java.lang.SuppressWarnings("all") N numberField; + private @java.lang.SuppressWarnings("all") boolean numberField$set; + public ParentBuilder() { + super(); + } + protected abstract @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B millis(final long millis) { + this.millis = millis; + millis$set = true; + return self(); + } + public @java.lang.SuppressWarnings("all") B numberField(final N numberField) { + this.numberField = numberField; + numberField$set = true; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithDefaults.Parent.ParentBuilder(millis=" + this.millis) + ", numberField=") + this.numberField) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + private ParentBuilderImpl() { + super(); + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") Parent build() { + return new Parent(this); + } + } + private @lombok.Builder.Default long millis = System.currentTimeMillis(); + private @lombok.Builder.Default N numberField = null; + protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + super(); + if (b.millis$set) + this.millis = b.millis; + if (b.numberField$set) + this.numberField = b.numberField; + } + public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static @lombok.experimental.SuperBuilder class Child extends Parent { + public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder> extends Parent.ParentBuilder { + private @java.lang.SuppressWarnings("all") double doubleField; + private @java.lang.SuppressWarnings("all") boolean doubleField$set; + public ChildBuilder() { + super(); + } + protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B doubleField(final double doubleField) { + this.doubleField = doubleField; + doubleField$set = true; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithDefaults.Child.ChildBuilder(super=" + super.toString()) + ", doubleField=") + this.doubleField) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder { + private ChildBuilderImpl() { + super(); + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") Child build() { + return new Child(this); + } + } + private @lombok.Builder.Default double doubleField = Math.PI; + protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { + super(b); + if (b.doubleField$set) + this.doubleField = b.doubleField; + } + public static @java.lang.SuppressWarnings("all") ChildBuilder builder() { + return new ChildBuilderImpl(); + } + } + public SuperBuilderWithDefaults() { + super(); + } + public static void test() { + Child x = Child.builder().doubleField(0.1).numberField(5).millis(1234567890L).build(); + } +} diff --git a/test/transform/resource/before/SuperBuilderWithDefaults.java b/test/transform/resource/before/SuperBuilderWithDefaults.java new file mode 100644 index 00000000..d6859a78 --- /dev/null +++ b/test/transform/resource/before/SuperBuilderWithDefaults.java @@ -0,0 +1,18 @@ +import java.util.List; + +public class SuperBuilderWithDefaults { + @lombok.experimental.SuperBuilder + public static class Parent { + @lombok.Builder.Default private long millis = System.currentTimeMillis(); + @lombok.Builder.Default private N numberField = null; + } + + @lombok.experimental.SuperBuilder + public static class Child extends Parent { + @lombok.Builder.Default private double doubleField = Math.PI; + } + + public static void test() { + Child x = Child.builder().doubleField(0.1).numberField(5).millis(1234567890L).build(); + } +} diff --git a/website/templates/features/experimental/SuperBuilder.html b/website/templates/features/experimental/SuperBuilder.html index a1e8cb4d..a36ae499 100644 --- a/website/templates/features/experimental/SuperBuilder.html +++ b/website/templates/features/experimental/SuperBuilder.html @@ -23,6 +23,8 @@ Therefore, a @SuperBuilder must extend the @SuperBuilder of the superclass in order to include those methods. Furthermore, the generated builder code heavily relies on generics to avoid class casting when using the builder. @SuperBuilder generates a private constructor on the class that takes a builder instances as a parameter. This constructor sets the fields of the new instance to the values from the builder. +

+ @SuperBuilder is not compatible with @Builder.

To ensure type-safety, @SuperBuilder generates two inner builder classes for each annotated class, one abstract and one concrete class named FoobarBuilder and FoobarBuilderImpl (where Foobar is the name of the annotated class).

@@ -43,7 +45,7 @@ <@f.confKeys>

- lombok.builder.flagUsage = [warning | error] (default: not set) + lombok.superBuilder.flagUsage = [warning | error] (default: not set)
Lombok will flag any usage of @SuperBuilder as a warning or error if configured.
-- cgit From e2fc6fa56433e5a62939bc2a3d92a4372539f3db Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Mon, 4 Jun 2018 17:52:38 +0200 Subject: SuperBuilder support for abstract classes --- .../eclipse/handlers/HandleSuperBuilder.java | 5 + .../lombok/javac/handlers/HandleSuperBuilder.java | 61 +++++----- .../after-delombok/SuperBuilderAbstract.java | 129 +++++++++++++++++++++ .../resource/after-ecj/SuperBuilderAbstract.java | 102 ++++++++++++++++ .../resource/before/SuperBuilderAbstract.java | 20 ++++ 5 files changed, 291 insertions(+), 26 deletions(-) create mode 100644 test/transform/resource/after-delombok/SuperBuilderAbstract.java create mode 100644 test/transform/resource/after-ecj/SuperBuilderAbstract.java create mode 100644 test/transform/resource/before/SuperBuilderAbstract.java (limited to 'test') diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 3a92da4a..1100cbf0 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -333,6 +333,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast)); } + if ((td.modifiers & ClassFileConstants.AccAbstract) != 0) { + // Abstract classes to not get the Builder implementation nor the builder() method. + return; + } + // Create the builder implementation class. EclipseNode builderImplType = findInnerClass(tdParent, builderImplClassName); if (builderImplType == null) { diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index beee47a9..1835bd48 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -282,42 +282,51 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { if (addCleaning) { injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast)); } + + recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext()); - // Create the builder implementation class. - JavacNode builderImplType = findInnerClass(tdParent, builderImplClassName); - if (builderImplType == null) { - builderImplType = generateBuilderImplClass(annotationNode, tdParent, builderImplClassName, builderClassName, typeParams, ast); - } else { - annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead."); - return; - } + if ((td.mods.flags & Flags.ABSTRACT) == 0) { + // Only non-abstract classes get the Builder implementation. - // Create a simple constructor for the BuilderImpl class. - JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, List.nil(), builderImplType, List.nil(), false, annotationNode); - if (cd != null) { - injectMethod(builderImplType, cd); - } + // Create the builder implementation class. + JavacNode builderImplType = findInnerClass(tdParent, builderImplClassName); + if (builderImplType == null) { + builderImplType = generateBuilderImplClass(annotationNode, tdParent, builderImplClassName, builderClassName, typeParams, ast); + } else { + annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead."); + return; + } + + // Create a simple constructor for the BuilderImpl class. + JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, List.nil(), builderImplType, List.nil(), false, annotationNode); + if (cd != null) { + injectMethod(builderImplType, cd); + } - // Create the self() and build() methods in the BuilderImpl. - injectMethod(builderImplType, generateSelfMethod(builderImplType)); - injectMethod(builderImplType, generateBuildMethod(buildMethodName, returnType, builderImplType, thrownExceptions)); + // Create the self() and build() methods in the BuilderImpl. + injectMethod(builderImplType, generateSelfMethod(builderImplType)); + injectMethod(builderImplType, generateBuildMethod(buildMethodName, returnType, builderImplType, thrownExceptions)); + + recursiveSetGeneratedBy(builderImplType.get(), ast, annotationNode.getContext()); + } // Generate a constructor in the annotated class that takes a builder as argument. generateBuilderBasedConstructor(tdParent, typeParams, builderFields, annotationNode, builderClassName, superclassBuilderClassExpression != null); - // Add the builder() method to the annotated class. - // Allow users to specify their own builder() methods, e.g., to provide default values. - if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl builderMethod = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); - recursiveSetGeneratedBy(builderMethod, ast, annotationNode.getContext()); - if (builderMethod != null) { - injectMethod(tdParent, builderMethod); + if ((td.mods.flags & Flags.ABSTRACT) == 0) { + // Only non-abstract classes get the Builder implementation and the builder() method. + + // Add the builder() method to the annotated class. + // Allow users to specify their own builder() methods, e.g., to provide default values. + if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) { + JCMethodDecl builderMethod = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); + recursiveSetGeneratedBy(builderMethod, ast, annotationNode.getContext()); + if (builderMethod != null) { + injectMethod(tdParent, builderMethod); + } } } - - recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext()); - recursiveSetGeneratedBy(builderImplType.get(), ast, annotationNode.getContext()); } /** diff --git a/test/transform/resource/after-delombok/SuperBuilderAbstract.java b/test/transform/resource/after-delombok/SuperBuilderAbstract.java new file mode 100644 index 00000000..d1e82c27 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderAbstract.java @@ -0,0 +1,129 @@ +public class SuperBuilderAbstract { + public static class Parent { + int parentField; + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder> { + @java.lang.SuppressWarnings("all") + private int parentField; + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B parentField(final int parentField) { + this.parentField = parentField; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderAbstract.Parent.ParentBuilder(parentField=" + this.parentField + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder { + @java.lang.SuppressWarnings("all") + private ParentBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected ParentBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public Parent build() { + return new Parent(this); + } + } + @java.lang.SuppressWarnings("all") + protected Parent(final ParentBuilder b) { + this.parentField = b.parentField; + } + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static abstract class Child extends Parent { + double childField; + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private double childField; + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.Override + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B childField(final double childField) { + this.childField = childField; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderAbstract.Child.ChildBuilder(super=" + super.toString() + ", childField=" + this.childField + ")"; + } + } + @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + this.childField = b.childField; + } + } + public static class GrandChild extends Child { + String grandChildField; + @java.lang.SuppressWarnings("all") + public static abstract class GrandChildBuilder> extends Child.ChildBuilder { + @java.lang.SuppressWarnings("all") + private String grandChildField; + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.Override + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B grandChildField(final String grandChildField) { + this.grandChildField = grandChildField; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderAbstract.GrandChild.GrandChildBuilder(super=" + super.toString() + ", grandChildField=" + this.grandChildField + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class GrandChildBuilderImpl extends GrandChildBuilder { + @java.lang.SuppressWarnings("all") + private GrandChildBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected GrandChildBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public GrandChild build() { + return new GrandChild(this); + } + } + @java.lang.SuppressWarnings("all") + protected GrandChild(final GrandChildBuilder b) { + super(b); + this.grandChildField = b.grandChildField; + } + @java.lang.SuppressWarnings("all") + public static GrandChildBuilder builder() { + return new GrandChildBuilderImpl(); + } + } + public static void test() { + GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build(); + } +} diff --git a/test/transform/resource/after-ecj/SuperBuilderAbstract.java b/test/transform/resource/after-ecj/SuperBuilderAbstract.java new file mode 100644 index 00000000..2839babd --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderAbstract.java @@ -0,0 +1,102 @@ +public class SuperBuilderAbstract { + public static @lombok.experimental.SuperBuilder class Parent { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder> { + private @java.lang.SuppressWarnings("all") int parentField; + public ParentBuilder() { + super(); + } + protected abstract @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B parentField(final int parentField) { + this.parentField = parentField; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("SuperBuilderAbstract.Parent.ParentBuilder(parentField=" + this.parentField) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder { + private ParentBuilderImpl() { + super(); + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") Parent build() { + return new Parent(this); + } + } + int parentField; + protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + super(); + this.parentField = b.parentField; + } + public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static abstract @lombok.experimental.SuperBuilder class Child extends Parent { + public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder> extends Parent.ParentBuilder { + private @java.lang.SuppressWarnings("all") double childField; + public ChildBuilder() { + super(); + } + protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B childField(final double childField) { + this.childField = childField; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderAbstract.Child.ChildBuilder(super=" + super.toString()) + ", childField=") + this.childField) + ")"); + } + } + double childField; + protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { + super(b); + this.childField = b.childField; + } + } + public static @lombok.experimental.SuperBuilder class GrandChild extends Child { + public static abstract @java.lang.SuppressWarnings("all") class GrandChildBuilder> extends Child.ChildBuilder { + private @java.lang.SuppressWarnings("all") String grandChildField; + public GrandChildBuilder() { + super(); + } + protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B grandChildField(final String grandChildField) { + this.grandChildField = grandChildField; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderAbstract.GrandChild.GrandChildBuilder(super=" + super.toString()) + ", grandChildField=") + this.grandChildField) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class GrandChildBuilderImpl extends GrandChildBuilder { + private GrandChildBuilderImpl() { + super(); + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") GrandChildBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") GrandChild build() { + return new GrandChild(this); + } + } + String grandChildField; + protected @java.lang.SuppressWarnings("all") GrandChild(final GrandChildBuilder b) { + super(b); + this.grandChildField = b.grandChildField; + } + public static @java.lang.SuppressWarnings("all") GrandChildBuilder builder() { + return new GrandChildBuilderImpl(); + } + } + public SuperBuilderAbstract() { + super(); + } + public static void test() { + GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build(); + } +} diff --git a/test/transform/resource/before/SuperBuilderAbstract.java b/test/transform/resource/before/SuperBuilderAbstract.java new file mode 100644 index 00000000..23f284e2 --- /dev/null +++ b/test/transform/resource/before/SuperBuilderAbstract.java @@ -0,0 +1,20 @@ +public class SuperBuilderAbstract { + @lombok.experimental.SuperBuilder + public static class Parent { + int parentField; + } + + @lombok.experimental.SuperBuilder + public abstract static class Child extends Parent { + double childField; + } + + @lombok.experimental.SuperBuilder + public static class GrandChild extends Child { + String grandChildField; + } + + public static void test() { + GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build(); + } +} -- cgit