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 +++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'test/core/src/lombok') 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) { -- cgit