From 8c0081a806a3c772f29be5c038024a5a941c4be6 Mon Sep 17 00:00:00 2001 From: Rawi01 Date: Sun, 12 Mar 2023 09:05:24 +0100 Subject: [fixes #3364] Generate JCTree clones to prevent duplicate nodes --- test/core/src/lombok/RunTestsViaDelombok.java | 67 ++++++++++++++++++++++ .../resource/after-delombok/BuilderCustomName.java | 50 ---------------- .../after-delombok/SuperBuilderCustomName.java | 50 ++++++++++++++++ .../resource/after-ecj/BuilderCustomName.java | 40 ------------- .../resource/after-ecj/SuperBuilderCustomName.java | 40 +++++++++++++ .../resource/before/BuilderCustomName.java | 7 --- .../resource/before/SuperBuilderCustomName.java | 7 +++ .../messages-delombok/NonNullPlain.java.messages | 4 +- 8 files changed, 167 insertions(+), 98 deletions(-) delete mode 100644 test/transform/resource/after-delombok/BuilderCustomName.java create mode 100644 test/transform/resource/after-delombok/SuperBuilderCustomName.java delete mode 100644 test/transform/resource/after-ecj/BuilderCustomName.java create mode 100644 test/transform/resource/after-ecj/SuperBuilderCustomName.java delete mode 100644 test/transform/resource/before/BuilderCustomName.java create mode 100644 test/transform/resource/before/SuperBuilderCustomName.java (limited to 'test') diff --git a/test/core/src/lombok/RunTestsViaDelombok.java b/test/core/src/lombok/RunTestsViaDelombok.java index e4eb1a30..adfb1fce 100644 --- a/test/core/src/lombok/RunTestsViaDelombok.java +++ b/test/core/src/lombok/RunTestsViaDelombok.java @@ -29,9 +29,12 @@ import java.io.PrintStream; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Deque; +import java.util.IdentityHashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -56,6 +59,7 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCModifiers; +import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.JCTree.TypeBoundKind; import com.sun.tools.javac.tree.TreeScanner; @@ -81,6 +85,7 @@ public class RunTestsViaDelombok extends AbstractRunTests { if (checkPositions) delombok.addAdditionalAnnotationProcessor(new ValidatePositionProcessor(version)); delombok.addAdditionalAnnotationProcessor(new ValidateTypesProcessor()); + delombok.addAdditionalAnnotationProcessor(new ValidateNoDuplicateTreeNodeProcessor()); delombok.addFile(file.getAbsoluteFile().getParentFile(), file.getName()); delombok.setSourcepath(file.getAbsoluteFile().getParent()); @@ -232,6 +237,68 @@ public class RunTestsViaDelombok extends AbstractRunTests { } } + public static class ValidateNoDuplicateTreeNodeProcessor extends TreeProcessor { + + private String craftFailMsg(Collection astContext) { + StringBuilder msg = new StringBuilder(); + for (JCTree t : astContext) { + msg.append("\n ").append(t.getClass().getSimpleName()); + String asStr = t.toString(); + if (asStr.length() < 80) msg.append(": ").append(asStr); + else if (t instanceof JCClassDecl) msg.append(": ").append(((JCClassDecl) t).name); + else if (t instanceof JCMethodDecl) msg.append(": ").append(((JCMethodDecl) t).name); + else if (t instanceof JCVariableDecl) msg.append(": ").append(((JCVariableDecl) t).name); + } + return msg.append("\n-------").toString(); + } + + @Override + void processCompilationUnit(JCCompilationUnit unit) { + final Deque parents = new ArrayDeque(); + parents.add(unit); + + final Map> knownTreeNode = new IdentityHashMap>(); + + unit.accept(new TreeScanner() { + private JCTree parent; + + @Override + public void scan(JCTree tree) { + parent = parents.peek(); + + if (tree == null) return; + if (tree instanceof JCPrimitiveTypeTree) return; + // javac generates duplicates for record members + if (tree instanceof JCVariableDecl && (((JCVariableDecl) tree).mods.flags & Javac.GENERATED_MEMBER) != 0) return; + + List knownNodeContext = knownTreeNode.put(tree, new ArrayList(parents)); + if (knownNodeContext != null) { + // javac generates two JCVariableDecl elements for 'int a, b;' + if (parent instanceof JCVariableDecl) { + if (tree instanceof JCModifiers) return; + if (tree instanceof JCIdent) return; + } + + fail("Node " + tree + " found twice:" + craftFailMsg(knownNodeContext) + craftFailMsg(parents)); + } + + parents.push(tree); + super.scan(tree); + parents.pop(); + } + + /** + * We always generate shallow copies for annotations + */ + @Override + public void visitAnnotation(JCAnnotation tree) { + return; + } + }); + } + + } + public static abstract class TreeProcessor extends AbstractProcessor { private Trees trees; @Override public synchronized void init(ProcessingEnvironment processingEnv) { diff --git a/test/transform/resource/after-delombok/BuilderCustomName.java b/test/transform/resource/after-delombok/BuilderCustomName.java deleted file mode 100644 index 900fbb03..00000000 --- a/test/transform/resource/after-delombok/BuilderCustomName.java +++ /dev/null @@ -1,50 +0,0 @@ -import java.util.List; -class BuilderCustomName { - private final int field; - @java.lang.SuppressWarnings("all") - public static abstract class SimpleTestBuilder, B extends BuilderCustomName.SimpleTestBuilder> { - @java.lang.SuppressWarnings("all") - private int field; - /** - * @return {@code this}. - */ - @java.lang.SuppressWarnings("all") - public B field(final int field) { - this.field = field; - return self(); - } - @java.lang.SuppressWarnings("all") - protected abstract B self(); - @java.lang.SuppressWarnings("all") - public abstract C build(); - @java.lang.Override - @java.lang.SuppressWarnings("all") - public java.lang.String toString() { - return "BuilderCustomName.SimpleTestBuilder(field=" + this.field + ")"; - } - } - @java.lang.SuppressWarnings("all") - private static final class SimpleTestBuilderImpl extends BuilderCustomName.SimpleTestBuilder, BuilderCustomName.SimpleTestBuilderImpl> { - @java.lang.SuppressWarnings("all") - private SimpleTestBuilderImpl() { - } - @java.lang.Override - @java.lang.SuppressWarnings("all") - protected BuilderCustomName.SimpleTestBuilderImpl self() { - return this; - } - @java.lang.Override - @java.lang.SuppressWarnings("all") - public BuilderCustomName build() { - return new BuilderCustomName(this); - } - } - @java.lang.SuppressWarnings("all") - protected BuilderCustomName(final BuilderCustomName.SimpleTestBuilder b) { - this.field = b.field; - } - @java.lang.SuppressWarnings("all") - public static BuilderCustomName.SimpleTestBuilder builder() { - return new BuilderCustomName.SimpleTestBuilderImpl(); - } -} \ No newline at end of file diff --git a/test/transform/resource/after-delombok/SuperBuilderCustomName.java b/test/transform/resource/after-delombok/SuperBuilderCustomName.java new file mode 100644 index 00000000..cad2716c --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderCustomName.java @@ -0,0 +1,50 @@ +import java.util.List; +class SuperBuilderCustomName { + private final int field; + @java.lang.SuppressWarnings("all") + public static abstract class SimpleTestBuilder, B extends SuperBuilderCustomName.SimpleTestBuilder> { + @java.lang.SuppressWarnings("all") + private int field; + /** + * @return {@code this}. + */ + @java.lang.SuppressWarnings("all") + public B field(final int field) { + this.field = field; + return self(); + } + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderCustomName.SimpleTestBuilder(field=" + this.field + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class SimpleTestBuilderImpl extends SuperBuilderCustomName.SimpleTestBuilder, SuperBuilderCustomName.SimpleTestBuilderImpl> { + @java.lang.SuppressWarnings("all") + private SimpleTestBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected SuperBuilderCustomName.SimpleTestBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public SuperBuilderCustomName build() { + return new SuperBuilderCustomName(this); + } + } + @java.lang.SuppressWarnings("all") + protected SuperBuilderCustomName(final SuperBuilderCustomName.SimpleTestBuilder b) { + this.field = b.field; + } + @java.lang.SuppressWarnings("all") + public static SuperBuilderCustomName.SimpleTestBuilder builder() { + return new SuperBuilderCustomName.SimpleTestBuilderImpl(); + } +} \ No newline at end of file diff --git a/test/transform/resource/after-ecj/BuilderCustomName.java b/test/transform/resource/after-ecj/BuilderCustomName.java deleted file mode 100644 index cb578ccd..00000000 --- a/test/transform/resource/after-ecj/BuilderCustomName.java +++ /dev/null @@ -1,40 +0,0 @@ -import java.util.List; -@lombok.experimental.SuperBuilder class BuilderCustomName { - public static abstract @java.lang.SuppressWarnings("all") class SimpleTestBuilder, B extends BuilderCustomName.SimpleTestBuilder> { - private @java.lang.SuppressWarnings("all") int field; - public SimpleTestBuilder() { - super(); - } - /** - * @return {@code this}. - */ - public @java.lang.SuppressWarnings("all") B field(final int field) { - this.field = field; - return self(); - } - protected abstract @java.lang.SuppressWarnings("all") B self(); - public abstract @java.lang.SuppressWarnings("all") C build(); - public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { - return (("BuilderCustomName.SimpleTestBuilder(field=" + this.field) + ")"); - } - } - private static final @java.lang.SuppressWarnings("all") class SimpleTestBuilderImpl extends BuilderCustomName.SimpleTestBuilder, BuilderCustomName.SimpleTestBuilderImpl> { - private SimpleTestBuilderImpl() { - super(); - } - protected @java.lang.Override @java.lang.SuppressWarnings("all") BuilderCustomName.SimpleTestBuilderImpl self() { - return this; - } - public @java.lang.Override @java.lang.SuppressWarnings("all") BuilderCustomName build() { - return new BuilderCustomName(this); - } - } - private final int field; - protected @java.lang.SuppressWarnings("all") BuilderCustomName(final BuilderCustomName.SimpleTestBuilder b) { - super(); - this.field = b.field; - } - public static @java.lang.SuppressWarnings("all") BuilderCustomName.SimpleTestBuilder builder() { - return new BuilderCustomName.SimpleTestBuilderImpl(); - } -} diff --git a/test/transform/resource/after-ecj/SuperBuilderCustomName.java b/test/transform/resource/after-ecj/SuperBuilderCustomName.java new file mode 100644 index 00000000..fc834090 --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderCustomName.java @@ -0,0 +1,40 @@ +import java.util.List; +@lombok.experimental.SuperBuilder class SuperBuilderCustomName { + public static abstract @java.lang.SuppressWarnings("all") class SimpleTestBuilder, B extends SuperBuilderCustomName.SimpleTestBuilder> { + private @java.lang.SuppressWarnings("all") int field; + public SimpleTestBuilder() { + super(); + } + /** + * @return {@code this}. + */ + public @java.lang.SuppressWarnings("all") B field(final int field) { + this.field = field; + return self(); + } + protected abstract @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.SuppressWarnings("all") C build(); + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("SuperBuilderCustomName.SimpleTestBuilder(field=" + this.field) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class SimpleTestBuilderImpl extends SuperBuilderCustomName.SimpleTestBuilder, SuperBuilderCustomName.SimpleTestBuilderImpl> { + private SimpleTestBuilderImpl() { + super(); + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") SuperBuilderCustomName.SimpleTestBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") SuperBuilderCustomName build() { + return new SuperBuilderCustomName(this); + } + } + private final int field; + protected @java.lang.SuppressWarnings("all") SuperBuilderCustomName(final SuperBuilderCustomName.SimpleTestBuilder b) { + super(); + this.field = b.field; + } + public static @java.lang.SuppressWarnings("all") SuperBuilderCustomName.SimpleTestBuilder builder() { + return new SuperBuilderCustomName.SimpleTestBuilderImpl(); + } +} diff --git a/test/transform/resource/before/BuilderCustomName.java b/test/transform/resource/before/BuilderCustomName.java deleted file mode 100644 index d5709e63..00000000 --- a/test/transform/resource/before/BuilderCustomName.java +++ /dev/null @@ -1,7 +0,0 @@ -//CONF: lombok.builder.className = SimpleTestBuilder -import java.util.List; - -@lombok.experimental.SuperBuilder -class BuilderCustomName { - private final int field; -} diff --git a/test/transform/resource/before/SuperBuilderCustomName.java b/test/transform/resource/before/SuperBuilderCustomName.java new file mode 100644 index 00000000..7308e282 --- /dev/null +++ b/test/transform/resource/before/SuperBuilderCustomName.java @@ -0,0 +1,7 @@ +//CONF: lombok.builder.className = SimpleTestBuilder +import java.util.List; + +@lombok.experimental.SuperBuilder +class SuperBuilderCustomName { + private final int field; +} diff --git a/test/transform/resource/messages-delombok/NonNullPlain.java.messages b/test/transform/resource/messages-delombok/NonNullPlain.java.messages index 7b0c540b..385efa23 100644 --- a/test/transform/resource/messages-delombok/NonNullPlain.java.messages +++ b/test/transform/resource/messages-delombok/NonNullPlain.java.messages @@ -1 +1,3 @@ -5 @NonNull is meaningless on a primitive. \ No newline at end of file +8 @NonNull is meaningless on a primitive. +4 @NonNull is meaningless on a primitive. +6 @NonNull is meaningless on a primitive. \ No newline at end of file -- cgit