diff options
-rw-r--r-- | buildScripts/tests.ant.xml | 6 | ||||
-rw-r--r-- | doc/changelog.markdown | 2 | ||||
-rw-r--r-- | src/core/lombok/javac/JavacAST.java | 28 | ||||
-rw-r--r-- | src/core/lombok/javac/apt/LombokProcessor.java | 41 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleVal.java | 24 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/JavacHandlerUtil.java | 48 | ||||
-rw-r--r-- | src/delombok/lombok/delombok/PrettyPrinter.java | 13 | ||||
-rw-r--r-- | test/pretty/resource/after/RecordPattern19.java (renamed from test/pretty/resource/after/RecordPattern.java) | 4 | ||||
-rw-r--r-- | test/pretty/resource/after/RecordPattern20.java | 22 | ||||
-rw-r--r-- | test/pretty/resource/before/RecordPattern19.java (renamed from test/pretty/resource/before/RecordPattern.java) | 6 | ||||
-rw-r--r-- | test/pretty/resource/before/RecordPattern20.java | 23 |
11 files changed, 163 insertions, 54 deletions
diff --git a/buildScripts/tests.ant.xml b/buildScripts/tests.ant.xml index d34e1f82..140983bc 100644 --- a/buildScripts/tests.ant.xml +++ b/buildScripts/tests.ant.xml @@ -150,8 +150,8 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn <!-- For non-LTS versions, feel free to aggressively update these to the current non-LTS openjdk version, and delete them once they roll out of the 6 month window. --> - <target name="test.javac19" depends="test.formatter.compile, test.compile" description="runs the tests on your default VM, using javac19 as underlying compiler"> - <test.javacX version="19" /> + <target name="test.javac20" depends="test.formatter.compile, test.compile" description="runs the tests on your default VM, using javac20 as underlying compiler"> + <test.javacX version="20" /> </target> <target name="test.javacCurrent" depends="test.formatter.compile, test.compile" description="runs the tests on your default VM, using its javac as underlying compiler"> @@ -293,5 +293,5 @@ This buildfile is part of projectlombok.org. It takes care of compiling and runn </target> <target name="test" depends="test.javacCurrent, test.eclipse-202212" description="runs the tests against the default JVM, javac, and eclipse" /> - <target name="test.broad" depends="test.javac8, test.javac17, test.javac19, test.eclipse-oxygen, test.eclipse-202212, test.eclipse-202006-jdk8" description="runs the tests against the default JVM, javac, and eclipse" /> + <target name="test.broad" depends="test.javac8, test.javac17, test.javac20, test.eclipse-oxygen, test.eclipse-202212, test.eclipse-202006-jdk8" description="runs the tests against the default JVM, javac, and eclipse" /> </project> diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 86ff40e8..47b7bcf1 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -2,7 +2,7 @@ Lombok Changelog ---------------- ### v1.18.27 "Edgy Guinea Pig" -* We recently released v1.18.26; there is no edge release since then. +* PLATFORM: JDK20 support added. [Issue #3353](https://github.com/projectlombok/lombok/issues/3353). ### v1.18.26 (Feb 3rd, 2023) diff --git a/src/core/lombok/javac/JavacAST.java b/src/core/lombok/javac/JavacAST.java index 0919c7d4..c09120c1 100644 --- a/src/core/lombok/javac/JavacAST.java +++ b/src/core/lombok/javac/JavacAST.java @@ -36,7 +36,6 @@ import javax.annotation.processing.Messager; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import com.sun.tools.javac.util.JCDiagnostic; import lombok.core.AST; import lombok.core.CleanupRegistry; import lombok.core.CleanupTask; @@ -53,6 +52,7 @@ import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCCatch; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCIdent; @@ -63,6 +63,7 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.JCTree.JCWildcard; import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Name; @@ -415,6 +416,18 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { JCANNOTATEDTYPE_FIELDS_INITIALIZED = true; } + + private static Field JCENHANCEDFORLOOP_VARORRECORDPATTERN_FIELD = Permit.permissiveGetField(JCEnhancedForLoop.class, "varOrRecordPattern"); + private static JCTree getVarOrRecordPattern(JCEnhancedForLoop loop) { + if (JCENHANCEDFORLOOP_VARORRECORDPATTERN_FIELD == null) { + return loop.var; + } + try { + return (JCTree) JCENHANCEDFORLOOP_VARORRECORDPATTERN_FIELD.get(loop); + } catch (Exception ignore) {} + return null; + } + private JavacNode buildTry(JCTry tryNode) { if (setAndGetAsHandled(tryNode)) return null; List<JavacNode> childNodes = new ArrayList<JavacNode>(); @@ -471,6 +484,7 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { if (statement instanceof JCVariableDecl) return buildLocalVar((JCVariableDecl) statement, Kind.LOCAL); if (statement instanceof JCTry) return buildTry((JCTry) statement); if (statement.getClass().getName().equals("com.sun.tools.javac.tree.JCTree$JCLambda")) return buildLambda(statement); + if (statement instanceof JCEnhancedForLoop) return buildEnhancedForLoop((JCEnhancedForLoop) statement); if (setAndGetAsHandled(statement)) return null; return drill(statement); @@ -500,6 +514,18 @@ public class JavacAST extends AST<JavacAST, JavacNode, JCTree> { return getBodyMethods.get(c); } + private JavacNode buildEnhancedForLoop(JCEnhancedForLoop loop) { + if (setAndGetAsHandled(loop)) return null; + + List<JavacNode> childNodes = new ArrayList<JavacNode>(); + // The order of the child elements is important and must be kept + addIfNotNull(childNodes, buildTree(getVarOrRecordPattern(loop), Kind.STATEMENT)); + addIfNotNull(childNodes, buildTree(loop.expr, Kind.STATEMENT)); + addIfNotNull(childNodes, buildStatement(loop.body)); + + return putInMap(new JavacNode(this, loop, childNodes, Kind.STATEMENT)); + } + private JavacNode drill(JCTree statement) { try { List<JavacNode> childNodes = new ArrayList<JavacNode>(); diff --git a/src/core/lombok/javac/apt/LombokProcessor.java b/src/core/lombok/javac/apt/LombokProcessor.java index ed713b1d..0467d758 100644 --- a/src/core/lombok/javac/apt/LombokProcessor.java +++ b/src/core/lombok/javac/apt/LombokProcessor.java @@ -25,7 +25,6 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.URL; @@ -305,10 +304,7 @@ public class LombokProcessor extends AbstractProcessor { // Step 1: Take all CUs which aren't already in the map. Give them the first priority level. - String randomModuleName = null; - for (Element element : roundEnv.getRootElements()) { - if (randomModuleName == null) randomModuleName = getModuleNameFor(element); JCCompilationUnit unit = toUnit(element); if (unit == null) continue; if (roots.containsKey(unit)) continue; @@ -353,7 +349,7 @@ public class LombokProcessor extends AbstractProcessor { newLevels.retainAll(priorityLevelsRequiringResolutionReset); if (!newLevels.isEmpty()) { // Force a new round to reset resolution. The next round will cause this method (process) to be called again. - forceNewRound(randomModuleName, javacFiler); + forceNewRound(javacFiler); return false; } // None of the new levels need resolution, so just keep going. @@ -361,7 +357,7 @@ public class LombokProcessor extends AbstractProcessor { } private int dummyCount = 0; - private void forceNewRound(String randomModuleName, JavacFiler filer) { + private void forceNewRound(JavacFiler filer) { if (!filer.newFiles()) { try { filer.getGeneratedSourceNames().add("lombok.dummy.ForceNewRound" + (dummyCount++)); @@ -372,38 +368,7 @@ public class LombokProcessor extends AbstractProcessor { } } } - - private String getModuleNameFor(Element element) { - while (element != null) { - if (element.getKind().name().equals("MODULE")) return getModuleName(element); - Element n = element.getEnclosingElement(); - if (n == element) return null; - element = n; - } - return null; - } - - private static Class<?> qualifiedNamableClass = null; - private static Method qualifiedNamableQualifiedNameMethod = null; - // QualifiedNameable isn't in java 6, so to remain compatible with java6, use reflection. - private static String getModuleName(Element element) { - try { - if (qualifiedNamableClass == null) qualifiedNamableClass = Class.forName("javax.lang.model.element.QualifiedNamable"); - if (!qualifiedNamableClass.isInstance(element)) return null; - if (qualifiedNamableQualifiedNameMethod == null) qualifiedNamableQualifiedNameMethod = Permit.getMethod(qualifiedNamableClass, "getQualifiedName"); - String name = Permit.invoke(qualifiedNamableQualifiedNameMethod, element).toString().trim(); - return name.isEmpty() ? null : name; - } catch (ClassNotFoundException e) { - return null; - } catch (NoSuchMethodException e) { - return null; - } catch (InvocationTargetException e) { - return null; - } catch (IllegalAccessException e) { - return null; - } - } - + private JCCompilationUnit toUnit(Element element) { TreePath path = null; if (trees != null) { diff --git a/src/core/lombok/javac/handlers/HandleVal.java b/src/core/lombok/javac/handlers/HandleVal.java index d4fb1027..8f4b1a86 100644 --- a/src/core/lombok/javac/handlers/HandleVal.java +++ b/src/core/lombok/javac/handlers/HandleVal.java @@ -24,15 +24,19 @@ package lombok.javac.handlers; import static lombok.core.handlers.HandlerUtil.handleFlagUsage; import static lombok.javac.handlers.HandleDelegate.HANDLE_DELEGATE_PRIORITY; import static lombok.javac.handlers.JavacHandlerUtil.*; + +import java.lang.reflect.Field; + import lombok.ConfigurationKeys; import lombok.val; -import lombok.core.HandlerPriority; import lombok.var; +import lombok.core.HandlerPriority; import lombok.javac.JavacASTAdapter; import lombok.javac.JavacASTVisitor; import lombok.javac.JavacNode; import lombok.javac.JavacResolution; import lombok.javac.ResolutionResetNeeded; +import lombok.permit.Permit; import lombok.spi.Provides; import com.sun.tools.javac.code.Flags; @@ -87,7 +91,8 @@ public class HandleVal extends JavacASTAdapter { if (local.init == null) { if (parentRaw instanceof JCEnhancedForLoop) { JCEnhancedForLoop efl = (JCEnhancedForLoop) parentRaw; - if (efl.var == local) rhsOfEnhancedForLoop = efl.expr; + JCTree var = EnhancedForLoopReflect.getVarOrRecordPattern(efl); + if (var == local) rhsOfEnhancedForLoop = efl.expr; } } @@ -191,4 +196,19 @@ public class HandleVal extends JavacASTAdapter { recursiveSetGeneratedBy(local.vartype, typeNode); } } + + private static class EnhancedForLoopReflect { + private static final Field varOrRecordPattern = Permit.permissiveGetField(JCEnhancedForLoop.class, "varOrRecordPattern"); + + private static JCTree getVarOrRecordPattern(JCEnhancedForLoop loop) { + if (varOrRecordPattern == null) { + return loop.var; + } + + try { + return (JCTree) varOrRecordPattern.get(loop); + } catch (Exception ignore) {} + return null; + } + } } diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index aaa7a022..ac947581 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -520,6 +520,13 @@ public class JavacHandlerUtil { case LOCAL: JCVariableDecl variable = (JCVariableDecl) parentNode.get(); variable.mods.annotations = filterList(variable.mods.annotations, annotation.get()); + + if ((variable.mods.flags & GENERATED_MEMBER) != 0) { + JavacNode typeNode = upToTypeNode(annotation); + if (isRecord(typeNode)) { + RecordComponentReflect.deleteAnnotation((JCClassDecl) typeNode.get(), variable, annotation.get()); + } + } break; case METHOD: JCMethodDecl method = (JCMethodDecl) parentNode.get(); @@ -567,6 +574,47 @@ public class JavacHandlerUtil { return newAnnotations.toList(); } + private static List<JCAnnotation> filterListByPos(List<JCAnnotation> annotations, JCTree jcTree) { + ListBuffer<JCAnnotation> newAnnotations = new ListBuffer<JCAnnotation>(); + for (JCAnnotation ann : annotations) { + if (jcTree.pos != ann.pos) newAnnotations.append(ann); + } + return newAnnotations.toList(); + } + + + static class RecordComponentReflect { + + private static final Field astField; + private static final Method findRecordComponentToRemove; + + static { + Field a = null; + Method m = null; + try { + Class<?> forName = Class.forName("com.sun.tools.javac.code.Symbol$RecordComponent"); + a = Permit.permissiveGetField(forName, "ast"); + m = Permit.permissiveGetMethod(ClassSymbol.class, "findRecordComponentToRemove", JCVariableDecl.class); + } catch (Throwable e) { + // Ignore + } + astField = a; + findRecordComponentToRemove = m; + } + + static void deleteAnnotation(JCClassDecl record, JCVariableDecl component, JCTree annotation) { + if (astField == null || findRecordComponentToRemove == null) return; + + try { + Object toRemove = Permit.invokeSneaky(findRecordComponentToRemove, record.sym, component); + JCVariableDecl variable = (JCVariableDecl) Permit.get(astField, toRemove); + variable.mods.annotations = filterListByPos(variable.mods.annotations, annotation); + } catch (Throwable e) { + // Ignore + } + } + } + /** Serves as return value for the methods that check for the existence of fields and methods. */ public enum MemberExistsResult { NOT_EXISTS, EXISTS_BY_LOMBOK, EXISTS_BY_USER; diff --git a/src/delombok/lombok/delombok/PrettyPrinter.java b/src/delombok/lombok/delombok/PrettyPrinter.java index 13836d77..b8b38da9 100644 --- a/src/delombok/lombok/delombok/PrettyPrinter.java +++ b/src/delombok/lombok/delombok/PrettyPrinter.java @@ -1253,7 +1253,14 @@ public class PrettyPrinter extends JCTree.Visitor { @Override public void visitForeachLoop(JCEnhancedForLoop tree) { aPrint("for ("); - printVarDefInline(tree.var); + JCTree varOrRecordPattern = readObject(tree, "varOrRecordPattern", null); + if (varOrRecordPattern instanceof JCVariableDecl) { + printVarDefInline((JCVariableDecl) varOrRecordPattern); + } else if (varOrRecordPattern != null) { + print(varOrRecordPattern); + } else { + printVarDefInline(tree.var); + } print(" : "); print(tree.expr); print(") "); @@ -1427,9 +1434,7 @@ public class PrettyPrinter extends JCTree.Visitor { void printBindingPattern(JCTree tree) { JCTree var = readObject(tree, "var", tree); - print((JCExpression) readObject(var, "vartype", null)); - print(" "); - print((Name) readObject(var, "name", null)); + printVarDef0((JCVariableDecl) var); } void printDefaultCase(JCTree tree) { diff --git a/test/pretty/resource/after/RecordPattern.java b/test/pretty/resource/after/RecordPattern19.java index ad9fae0b..68b39266 100644 --- a/test/pretty/resource/after/RecordPattern.java +++ b/test/pretty/resource/after/RecordPattern19.java @@ -3,13 +3,13 @@ record Point(int x, int y) { record Rectangle(Point upperLeft, Point lowerRight) { } -public class RecordPattern { +public class RecordPattern19 { void recordPattern(Object o) { if (o instanceof Point(int x, int y)) { } if (o instanceof Point(int x, int y) p) { } - if (o instanceof Rectangle(Point(int x1, int y1), Point(int x2, int y2))) { + if (o instanceof Rectangle(Point(var x1, var y1), Point(int x2, int y2))) { } } }
\ No newline at end of file diff --git a/test/pretty/resource/after/RecordPattern20.java b/test/pretty/resource/after/RecordPattern20.java new file mode 100644 index 00000000..365b139f --- /dev/null +++ b/test/pretty/resource/after/RecordPattern20.java @@ -0,0 +1,22 @@ +record Point(int x, int y) { +} +record Rectangle(Point upperLeft, Point lowerRight) { +} + +public class RecordPattern20 { + void recordPattern(Object o) { + if (o instanceof Point(int x, int y)) { + } + if (o instanceof Rectangle(Point(var x1, var y1), Point(int x2, int y2))) { + } + } + + void forEachSimple(Point[] pointArray) { + for (Point(var x, var y) : pointArray) { + } + } + void forEachNested(Rectangle[] rectangleArray) { + for (Rectangle(Point(var x1, var y1), Point p) : rectangleArray) { + } + } +}
\ No newline at end of file diff --git a/test/pretty/resource/before/RecordPattern.java b/test/pretty/resource/before/RecordPattern19.java index 93c07965..4c417174 100644 --- a/test/pretty/resource/before/RecordPattern.java +++ b/test/pretty/resource/before/RecordPattern19.java @@ -1,16 +1,16 @@ -// version 19: +// version 19:19 record Point(int x, int y) { } record Rectangle(Point upperLeft, Point lowerRight) { } -public class RecordPattern { +public class RecordPattern19 { void recordPattern(Object o) { if (o instanceof Point(int x, int y)) { } if (o instanceof Point(int x, int y) p) { } - if (o instanceof Rectangle(Point(int x1, int y1), Point(int x2, int y2))) { + if (o instanceof Rectangle(Point(var x1, var y1), Point(int x2, int y2))) { } } }
\ No newline at end of file diff --git a/test/pretty/resource/before/RecordPattern20.java b/test/pretty/resource/before/RecordPattern20.java new file mode 100644 index 00000000..8604215b --- /dev/null +++ b/test/pretty/resource/before/RecordPattern20.java @@ -0,0 +1,23 @@ +// version 20: +record Point(int x, int y) { +} +record Rectangle(Point upperLeft, Point lowerRight) { +} + +public class RecordPattern20 { + void recordPattern(Object o) { + if (o instanceof Point(int x, int y)) { + } + if (o instanceof Rectangle(Point(var x1, var y1), Point(int x2, int y2))) { + } + } + + void forEachSimple(Point[] pointArray) { + for (Point(var x, var y) : pointArray) { + } + } + void forEachNested(Rectangle[] rectangleArray) { + for (Rectangle(Point(var x1, var y1), Point p) : rectangleArray) { + } + } +}
\ No newline at end of file |