From 01cc651540120947ae1081cea6434704e508574e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Gr=C3=B6nlund?= Date: Fri, 1 Jan 2021 12:13:20 +0100 Subject: [PATCH] Do not lose generic arguments when adding annotations #2689 --- .../javac/handlers/JavacHandlerUtil.java | 4 + ...AnnotatedCheckerFrameworkSuperBuilder.java | 236 ++++++++++++++++++ ...AnnotatedCheckerFrameworkSuperBuilder.java | 166 ++++++++++++ ...AnnotatedCheckerFrameworkSuperBuilder.java | 19 ++ 4 files changed, 425 insertions(+) create mode 100644 test/transform/resource/after-delombok/NullAnnotatedCheckerFrameworkSuperBuilder.java create mode 100644 test/transform/resource/after-ecj/NullAnnotatedCheckerFrameworkSuperBuilder.java create mode 100644 test/transform/resource/before/NullAnnotatedCheckerFrameworkSuperBuilder.java diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index fbde95685a..9b63a52399 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -2170,6 +2170,10 @@ private static void applyAnnotationToMethodDecl(JavacNode typeNode, JCMethodDecl JCExpression resType = mth.restype; if (resType instanceof JCTypeApply) { JCTypeApply ta = (JCTypeApply) resType; + if (ta.clazz instanceof JCFieldAccess) { + mth.restype = maker.TypeApply(maker.AnnotatedType(List.of(m), ta.clazz), ta.arguments); + return; + } resType = ta.clazz; } diff --git a/test/transform/resource/after-delombok/NullAnnotatedCheckerFrameworkSuperBuilder.java b/test/transform/resource/after-delombok/NullAnnotatedCheckerFrameworkSuperBuilder.java new file mode 100644 index 0000000000..62af2cb46c --- /dev/null +++ b/test/transform/resource/after-delombok/NullAnnotatedCheckerFrameworkSuperBuilder.java @@ -0,0 +1,236 @@ +//CONF: lombok.addNullAnnotations = checkerframework +import java.util.List; + +class NullAnnotatedCheckerFrameworkSuperBuilder { + + public static class Parent { + int x; + int y; + int z; + List names; + + @java.lang.SuppressWarnings("all") + private static int $default$x() { + return 5; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder> { + @java.lang.SuppressWarnings("all") + private boolean x$set; + @java.lang.SuppressWarnings("all") + private int x$value; + @java.lang.SuppressWarnings("all") + private int y; + @java.lang.SuppressWarnings("all") + private int z; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList names; + + @java.lang.SuppressWarnings("all") + protected abstract B self(); + + @java.lang.SuppressWarnings("all") + public abstract C build(); + + /** + * @return {@code this}. + */ + @org.checkerframework.checker.nullness.qual.NonNull + @java.lang.SuppressWarnings("all") + public B x(final int x) { + this.x$value = x; + x$set = true; + return self(); + } + + /** + * @return {@code this}. + */ + @org.checkerframework.checker.nullness.qual.NonNull + @java.lang.SuppressWarnings("all") + public B y(final int y) { + this.y = y; + return self(); + } + + /** + * @return {@code this}. + */ + @org.checkerframework.checker.nullness.qual.NonNull + @java.lang.SuppressWarnings("all") + public B z(final int z) { + this.z = z; + return self(); + } + + @org.checkerframework.checker.nullness.qual.NonNull + @java.lang.SuppressWarnings("all") + public B name(final String name) { + if (this.names == null) this.names = new java.util.ArrayList(); + this.names.add(name); + return self(); + } + + @org.checkerframework.checker.nullness.qual.NonNull + @java.lang.SuppressWarnings("all") + public B names(final java.util.@org.checkerframework.checker.nullness.qual.NonNull Collection names) { + if (names == null) { + throw new java.lang.NullPointerException("names cannot be null"); + } + if (this.names == null) this.names = new java.util.ArrayList(); + this.names.addAll(names); + return self(); + } + + @org.checkerframework.checker.nullness.qual.NonNull + @java.lang.SuppressWarnings("all") + public B clearNames() { + if (this.names != null) this.names.clear(); + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.@org.checkerframework.checker.nullness.qual.NonNull String toString() { + return "NullAnnotatedCheckerFrameworkSuperBuilder.Parent.ParentBuilder(x$value=" + this.x$value + ", y=" + this.y + ", z=" + this.z + ", names=" + this.names + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends NullAnnotatedCheckerFrameworkSuperBuilder.Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private ParentBuilderImpl() { + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected NullAnnotatedCheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl self() { + return this; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public NullAnnotatedCheckerFrameworkSuperBuilder.@org.checkerframework.checker.nullness.qual.NonNull Parent build() { + return new NullAnnotatedCheckerFrameworkSuperBuilder.Parent(this); + } + } + + @java.lang.SuppressWarnings("all") + protected Parent(final NullAnnotatedCheckerFrameworkSuperBuilder.Parent.ParentBuilder b) { + if (b.x$set) this.x = b.x$value; + else this.x = NullAnnotatedCheckerFrameworkSuperBuilder.Parent.$default$x(); + this.y = b.y; + this.z = b.z; + java.util.List names; + switch (b.names == null ? 0 : b.names.size()) { + case 0: + names = java.util.Collections.emptyList(); + break; + case 1: + names = java.util.Collections.singletonList(b.names.get(0)); + break; + default: + names = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.names)); + } + this.names = names; + } + + @java.lang.SuppressWarnings("all") + public static NullAnnotatedCheckerFrameworkSuperBuilder.Parent.@org.checkerframework.checker.nullness.qual.NonNull ParentBuilder builder() { + return new NullAnnotatedCheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl(); + } + } + + + public static class ZChild extends Parent { + int a; + int b; + + @java.lang.SuppressWarnings("all") + private static int $default$a() { + return 1; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ZChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private boolean a$set; + @java.lang.SuppressWarnings("all") + private int a$value; + @java.lang.SuppressWarnings("all") + private int b; + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected abstract B self(); + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public abstract C build(); + + /** + * @return {@code this}. + */ + @org.checkerframework.checker.nullness.qual.NonNull + @java.lang.SuppressWarnings("all") + public B a(final int a) { + this.a$value = a; + a$set = true; + return self(); + } + + /** + * @return {@code this}. + */ + @org.checkerframework.checker.nullness.qual.NonNull + @java.lang.SuppressWarnings("all") + public B b(final int b) { + this.b = b; + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.@org.checkerframework.checker.nullness.qual.NonNull String toString() { + return "NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.ZChildBuilder(super=" + super.toString() + ", a$value=" + this.a$value + ", b=" + this.b + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ZChildBuilderImpl extends NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.ZChildBuilder { + @java.lang.SuppressWarnings("all") + private ZChildBuilderImpl() { + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl self() { + return this; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public NullAnnotatedCheckerFrameworkSuperBuilder.@org.checkerframework.checker.nullness.qual.NonNull ZChild build() { + return new NullAnnotatedCheckerFrameworkSuperBuilder.ZChild(this); + } + } + + @java.lang.SuppressWarnings("all") + protected ZChild(final NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.ZChildBuilder b) { + super(b); + if (b.a$set) this.a = b.a$value; + else this.a = NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.$default$a(); + this.b = b.b; + } + + @java.lang.SuppressWarnings("all") + public static NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.@org.checkerframework.checker.nullness.qual.NonNull ZChildBuilder builder() { + return new NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl(); + } + } +} diff --git a/test/transform/resource/after-ecj/NullAnnotatedCheckerFrameworkSuperBuilder.java b/test/transform/resource/after-ecj/NullAnnotatedCheckerFrameworkSuperBuilder.java new file mode 100644 index 0000000000..a1c8e74e07 --- /dev/null +++ b/test/transform/resource/after-ecj/NullAnnotatedCheckerFrameworkSuperBuilder.java @@ -0,0 +1,166 @@ +import java.util.List; +import lombok.Singular; +class NullAnnotatedCheckerFrameworkSuperBuilder { + public static @lombok.experimental.SuperBuilder class Parent { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder> { + private @java.lang.SuppressWarnings("all") int x$value; + private @java.lang.SuppressWarnings("all") boolean x$set; + private @java.lang.SuppressWarnings("all") int y; + private @java.lang.SuppressWarnings("all") int z; + private @java.lang.SuppressWarnings("all") java.util.ArrayList names; + public ParentBuilder() { + super(); + } + protected abstract @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") B self(); + public abstract @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") C build(NullAnnotatedCheckerFrameworkSuperBuilder.Parent. @org.checkerframework.checker.calledmethods.qual.CalledMethods({"y", "z"}) ParentBuilder this); + /** + * @return {@code this}. + */ + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B x(NullAnnotatedCheckerFrameworkSuperBuilder.Parent. @org.checkerframework.checker.calledmethods.qual.NotCalledMethods("x") ParentBuilder this, final int x) { + this.x$value = x; + x$set = true; + return self(); + } + /** + * @return {@code this}. + */ + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B y(NullAnnotatedCheckerFrameworkSuperBuilder.Parent. @org.checkerframework.checker.calledmethods.qual.NotCalledMethods("y") ParentBuilder this, final int y) { + this.y = y; + return self(); + } + /** + * @return {@code this}. + */ + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B z(NullAnnotatedCheckerFrameworkSuperBuilder.Parent. @org.checkerframework.checker.calledmethods.qual.NotCalledMethods("z") ParentBuilder this, final int z) { + this.z = z; + return self(); + } + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B name(final String name) { + if ((this.names == null)) + this.names = new java.util.ArrayList(); + this.names.add(name); + return self(); + } + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B names(final java.util.Collection names) { + if ((names == null)) + { + throw new java.lang.NullPointerException("names cannot be null"); + } + if ((this.names == null)) + this.names = new java.util.ArrayList(); + this.names.addAll(names); + return self(); + } + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B clearNames() { + if ((this.names != null)) + this.names.clear(); + return self(); + } + public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((((((("NullAnnotatedCheckerFrameworkSuperBuilder.Parent.ParentBuilder(x$value=" + this.x$value) + ", y=") + this.y) + ", z=") + this.z) + ", names=") + this.names) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends NullAnnotatedCheckerFrameworkSuperBuilder.Parent.ParentBuilder { + private ParentBuilderImpl() { + super(); + } + protected @java.lang.Override @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") NullAnnotatedCheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl self() { + return this; + } + public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") NullAnnotatedCheckerFrameworkSuperBuilder.Parent build(NullAnnotatedCheckerFrameworkSuperBuilder.Parent.@org.checkerframework.checker.calledmethods.qual.CalledMethods({"y", "z"}) ParentBuilderImpl this) { + return new NullAnnotatedCheckerFrameworkSuperBuilder.Parent(this); + } + } + @lombok.Builder.Default int x; + int y; + int z; + @Singular List names; + private static @java.lang.SuppressWarnings("all") int $default$x() { + return 5; + } + protected @java.lang.SuppressWarnings("all") Parent(final NullAnnotatedCheckerFrameworkSuperBuilder.Parent.ParentBuilder b) { + super(); + if (b.x$set) + this.x = b.x$value; + else + this.x = NullAnnotatedCheckerFrameworkSuperBuilder.Parent.$default$x(); + this.y = b.y; + this.z = b.z; + java.util.List names; + switch (((b.names == null) ? 0 : b.names.size())) { + case 0 : + names = java.util.Collections.emptyList(); + break; + case 1 : + names = java.util.Collections.singletonList(b.names.get(0)); + break; + default : + names = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.names)); + } + this.names = names; + } + public static @java.lang.SuppressWarnings("all") NullAnnotatedCheckerFrameworkSuperBuilder.Parent. @org.checkerframework.common.aliasing.qual.Unique ParentBuilder builder() { + return new NullAnnotatedCheckerFrameworkSuperBuilder.Parent.ParentBuilderImpl(); + } + } + public static @lombok.experimental.SuperBuilder class ZChild extends Parent { + public static abstract @java.lang.SuppressWarnings("all") class ZChildBuilder> extends Parent.ParentBuilder { + private @java.lang.SuppressWarnings("all") int a$value; + private @java.lang.SuppressWarnings("all") boolean a$set; + private @java.lang.SuppressWarnings("all") int b; + public ZChildBuilder() { + super(); + } + protected abstract @java.lang.Override @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") C build(NullAnnotatedCheckerFrameworkSuperBuilder.ZChild. @org.checkerframework.checker.calledmethods.qual.CalledMethods("b") ZChildBuilder this); + /** + * @return {@code this}. + */ + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B a(NullAnnotatedCheckerFrameworkSuperBuilder.ZChild. @org.checkerframework.checker.calledmethods.qual.NotCalledMethods("a") ZChildBuilder this, final int a) { + this.a$value = a; + a$set = true; + return self(); + } + /** + * @return {@code this}. + */ + public @org.checkerframework.common.returnsreceiver.qual.This @java.lang.SuppressWarnings("all") B b(NullAnnotatedCheckerFrameworkSuperBuilder.ZChild. @org.checkerframework.checker.calledmethods.qual.NotCalledMethods("b") ZChildBuilder this, final int b) { + this.b = b; + return self(); + } + public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((((("NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.ZChildBuilder(super=" + super.toString()) + ", a$value=") + this.a$value) + ", b=") + this.b) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ZChildBuilderImpl extends NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.ZChildBuilder { + private ZChildBuilderImpl() { + super(); + } + protected @java.lang.Override @org.checkerframework.common.returnsreceiver.qual.This @org.checkerframework.dataflow.qual.Pure @java.lang.SuppressWarnings("all") NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl self() { + return this; + } + public @java.lang.Override @org.checkerframework.dataflow.qual.SideEffectFree @java.lang.SuppressWarnings("all") NullAnnotatedCheckerFrameworkSuperBuilder.ZChild build(NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.@org.checkerframework.checker.calledmethods.qual.CalledMethods("b") ZChildBuilderImpl this) { + return new NullAnnotatedCheckerFrameworkSuperBuilder.ZChild(this); + } + } + @lombok.Builder.Default int a; + int b; + private static @java.lang.SuppressWarnings("all") int $default$a() { + return 1; + } + protected @java.lang.SuppressWarnings("all") ZChild(final NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.ZChildBuilder b) { + super(b); + if (b.a$set) + this.a = b.a$value; + else + this.a = NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.$default$a(); + this.b = b.b; + } + public static @java.lang.SuppressWarnings("all") NullAnnotatedCheckerFrameworkSuperBuilder.ZChild. @org.checkerframework.common.aliasing.qual.Unique ZChildBuilder builder() { + return new NullAnnotatedCheckerFrameworkSuperBuilder.ZChild.ZChildBuilderImpl(); + } + } + NullAnnotatedCheckerFrameworkSuperBuilder() { + super(); + } +} diff --git a/test/transform/resource/before/NullAnnotatedCheckerFrameworkSuperBuilder.java b/test/transform/resource/before/NullAnnotatedCheckerFrameworkSuperBuilder.java new file mode 100644 index 0000000000..39bb0fcc55 --- /dev/null +++ b/test/transform/resource/before/NullAnnotatedCheckerFrameworkSuperBuilder.java @@ -0,0 +1,19 @@ +//CONF: lombok.addNullAnnotations = checkerframework +import java.util.List; +import lombok.Singular; + +class NullAnnotatedCheckerFrameworkSuperBuilder { + @lombok.experimental.SuperBuilder + public static class Parent { + @lombok.Builder.Default int x = 5; + int y; + int z; + @Singular List names; + } + + @lombok.experimental.SuperBuilder + public static class ZChild extends Parent { + @lombok.Builder.Default int a = 1; + int b; + } +}